Mercurial > python-compiler.rs
annotate src/ast_type.rs @ 85:09f5e0d7bcf3
Fix chained Compare dumping.
| author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
|---|---|
| date | Wed, 22 Jun 2016 22:50:12 +0100 |
| parents | 94ff501bf336 |
| children |
| rev | line source |
|---|---|
| 0 | 1 use python_ast::{Module, Statement, Expr, BinOp}; |
| 2 | |
| 3 use std::collections::HashMap; | |
| 4 | |
| 5 #[derive(Clone, Debug, PartialEq, Eq)] | |
| 6 enum Type { | |
| 7 Top(usize), | |
| 8 Unit, | |
| 9 Bool, | |
| 10 Int, | |
| 11 Str, | |
|
7
680d15073f55
Add ast.List literal.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
6
diff
changeset
|
12 List(Box<Type>), |
| 0 | 13 Function(Vec<Type>, Vec<Type>), |
| 14 Bottom | |
| 15 } | |
| 16 | |
| 17 struct TypeVariable { | |
| 18 id: usize, | |
| 19 instance: Box<TypeVariable>, | |
| 20 } | |
| 21 | |
| 22 trait Visitor<T> { | |
| 23 fn visit_module(&mut self, module: Module) -> T; | |
| 24 fn visit_statement(&mut self, statement: Statement) -> T; | |
| 25 fn visit_expr(&mut self, expr: Expr) -> T; | |
| 26 } | |
| 27 | |
| 28 struct Typing { | |
| 29 environment: Vec<HashMap<String, Type>>, | |
| 30 next_id: usize, | |
| 31 } | |
| 32 | |
| 33 impl Visitor<Type> for Typing { | |
| 34 fn visit_module(&mut self, module: Module) -> Type { | |
| 35 println!("{:?}", self.environment); | |
| 36 for statement in module.statements { | |
| 37 self.visit_statement(statement); | |
| 38 } | |
| 39 println!("{:?}", self.environment); | |
| 40 Type::Bottom | |
| 41 } | |
| 42 | |
| 43 fn visit_statement(&mut self, statement: Statement) -> Type { | |
| 44 match statement { | |
|
2
5fc7c2790d8c
Add class support.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
0
diff
changeset
|
45 Statement::ClassDef(name, classes, body) => { |
|
5fc7c2790d8c
Add class support.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
0
diff
changeset
|
46 Type::Bottom |
|
5fc7c2790d8c
Add class support.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
0
diff
changeset
|
47 }, |
|
3
326d7f2a94d4
Remove useless abstraction of function name as Expr.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
48 Statement::FunctionDef(name, arguments, body) => { |
| 0 | 49 let mut env = self.environment.pop().unwrap(); |
| 50 self.environment.push(env.clone()); | |
| 51 | |
| 52 let nb_args = arguments.len(); | |
| 53 for expr in arguments { | |
| 54 let type_ = self.visit_expr(expr.clone()); | |
| 55 let name = match expr { | |
| 56 Expr::Name(name) => name, | |
| 57 _ => panic!() | |
| 58 }; | |
| 59 env.insert(name.clone(), type_.clone()); | |
| 60 } | |
| 61 self.environment.push(env); | |
| 62 | |
| 63 for statement in body { | |
| 64 self.visit_statement(statement); | |
| 65 } | |
| 66 self.environment.pop(); | |
| 67 | |
| 68 let mut types = Vec::with_capacity(nb_args); | |
| 69 for _ in 0..nb_args { | |
| 70 self.next_id += 1; | |
| 71 types.push(Type::Top(self.next_id)); | |
| 72 } | |
| 73 Type::Bottom | |
| 74 }, | |
| 75 Statement::Global(_) => { | |
| 76 Type::Bottom | |
| 77 }, | |
| 78 Statement::If(test, body, orelse) => { | |
| 79 self.visit_expr(test); | |
| 80 for statement in body { | |
| 81 self.visit_statement(statement); | |
| 82 } | |
| 83 for statement in orelse { | |
| 84 self.visit_statement(statement); | |
| 85 } | |
| 86 Type::Bottom | |
| 87 }, | |
|
6
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
88 Statement::While(test, body, orelse) => { |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
89 self.visit_expr(test); |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
90 for statement in body { |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
91 self.visit_statement(statement); |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
92 } |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
93 for statement in orelse { |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
94 self.visit_statement(statement); |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
95 } |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
96 Type::Bottom |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
97 }, |
|
5
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
98 Statement::For(target, iter, body, orelse) => { |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
99 self.visit_expr(target); |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
100 self.visit_expr(iter); |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
101 for statement in body { |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
102 self.visit_statement(statement); |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
103 } |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
104 for statement in orelse { |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
105 self.visit_statement(statement); |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
106 } |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
107 Type::Bottom |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
108 }, |
| 0 | 109 Statement::Assign(targets, value) => { |
| 110 let type_ = self.visit_expr(value); | |
| 111 if targets.len() != 1 { | |
| 112 panic!(); | |
| 113 } | |
| 114 println!("{:?}", self.environment.clone()); | |
| 115 let mut env = self.environment.pop().unwrap(); | |
| 116 for target in targets { | |
| 117 let name = match target { | |
| 118 Expr::Name(name) => name, | |
| 119 _ => panic!() | |
| 120 }; | |
| 121 println!("{} => {:?}", name, type_); | |
| 122 env.insert(name, type_.clone()); | |
| 123 } | |
| 124 self.environment.push(env); | |
| 125 println!("{:?}", self.environment.clone()); | |
| 126 Type::Bottom | |
| 127 }, | |
|
8
94ff501bf336
Add ast.AugAssign.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
7
diff
changeset
|
128 Statement::AugAssign(target, op, value) => { |
|
94ff501bf336
Add ast.AugAssign.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
7
diff
changeset
|
129 let value = self.visit_expr(value); |
|
94ff501bf336
Add ast.AugAssign.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
7
diff
changeset
|
130 let target = self.visit_expr(target); |
|
94ff501bf336
Add ast.AugAssign.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
7
diff
changeset
|
131 Type::Bottom |
|
94ff501bf336
Add ast.AugAssign.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
7
diff
changeset
|
132 }, |
| 0 | 133 Statement::Return(expr) => { |
| 134 self.visit_expr(expr) | |
| 135 }, | |
| 136 Statement::ImportFrom(module, names) => { | |
| 137 for alias in names { | |
| 138 self.visit_expr(alias); | |
| 139 } | |
| 140 Type::Bottom | |
| 141 }, | |
| 142 Statement::Expr(expr) => { | |
| 143 self.visit_expr(expr) | |
| 144 }, | |
|
6
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
145 Statement::Break => { |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
146 Type::Bottom |
|
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
147 }, |
| 0 | 148 Statement::Error => { |
| 149 println!("Statement::Error"); | |
| 150 panic!() | |
| 151 }, | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 fn visit_expr(&mut self, expr: Expr) -> Type { | |
| 156 let expr_str = format!("{:?}", expr); | |
| 157 let type_ = match expr { | |
|
5
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
158 Expr::UnaryOp(op, operand) => { |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
159 let type_operand = self.visit_expr(*operand); |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
160 type_operand |
|
ddf372373a77
Add ast.For, ast.UnaryOp, and Sub and Div to ast.BinOp.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
4
diff
changeset
|
161 }, |
| 0 | 162 Expr::BinOp(left, op, right) => { |
| 163 let type_left = self.visit_expr(*left); | |
| 164 let type_right = self.visit_expr(*right); | |
| 165 | |
| 166 if op == BinOp::BinMult && type_left == Type::Str && type_right == Type::Int { | |
| 167 return Type::Str; | |
| 168 } | |
| 169 | |
| 170 if type_left != type_right { | |
| 171 return Type::Bottom; | |
| 172 } | |
| 173 if op == BinOp::BinAdd || op == BinOp::BinMult { | |
| 174 if type_left == Type::Int { | |
| 175 Type::Int | |
| 176 } else if type_left == Type::Str { | |
| 177 Type::Str | |
| 178 } else { | |
| 179 Type::Bottom | |
| 180 } | |
| 181 } else if op == BinOp::BinEq || op == BinOp::BinLt { | |
| 182 Type::Bool | |
| 183 } else { | |
| 184 Type::Bottom | |
| 185 } | |
| 186 }, | |
| 187 Expr::Compare(_, _, _) => Type::Bool, | |
| 188 Expr::Call(func, args) => { | |
| 189 let func = *func; | |
| 190 let func = match func { | |
| 191 Expr::Name(arg) => arg, | |
| 192 _ => panic!() | |
| 193 }; | |
| 194 let mut types = vec!(); | |
| 195 for expr in args { | |
| 196 let type_ = self.visit_expr(expr); | |
| 197 types.push(type_); | |
| 198 } | |
| 199 println!("types: {:?}", types); | |
| 200 let env = match self.environment.pop() { | |
| 201 Some(env) => env, | |
| 202 None => return Type::Bottom | |
| 203 }; | |
| 204 if env.contains_key(&func) { | |
| 205 let value = env.get(&func).unwrap().clone(); | |
| 206 self.environment.push(env); | |
| 207 value | |
| 208 } else { | |
| 209 self.environment.push(env); | |
| 210 Type::Bottom | |
| 211 } | |
| 212 }, | |
| 213 Expr::Alias(_, _) => Type::Bottom, | |
|
4
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
214 Expr::Attribute(lhs, rhs) => { |
|
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
215 let type_left = self.visit_expr(*lhs); |
|
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
216 println!("coucou {:?}", type_left); |
|
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
217 Type::Bottom |
|
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
218 }, |
| 0 | 219 Expr::Name(id) => { |
| 220 let env = match self.environment.pop() { | |
| 221 Some(env) => env, | |
| 222 None => return Type::Bottom | |
| 223 }; | |
| 224 if env.contains_key(&id) { | |
| 225 let value = env.get(&id).unwrap().clone(); | |
| 226 self.environment.push(env); | |
| 227 value | |
| 228 } else { | |
| 229 self.environment.push(env); | |
| 230 self.next_id += 1; | |
| 231 Type::Top(self.next_id) | |
| 232 } | |
| 233 }, | |
| 234 Expr::NameConstant(value) => { | |
| 235 if value == "True" || value == "False" { | |
| 236 Type::Bool | |
| 237 } else if value == "None" { | |
| 238 Type::Unit | |
| 239 } else { | |
| 240 Type::Bottom | |
| 241 } | |
| 242 }, | |
| 243 Expr::Str(_) => Type::Str, | |
| 244 Expr::Num(_) => Type::Int, | |
|
7
680d15073f55
Add ast.List literal.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
6
diff
changeset
|
245 Expr::List(_) => Type::List(Box::new(Type::Bottom)), |
| 0 | 246 Expr::Error => { |
| 247 println!("Expr::Error"); | |
| 248 panic!() | |
| 249 } | |
| 250 }; | |
| 251 println!("{} => {:?}", expr_str, type_); | |
| 252 type_ | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 #[allow(dead_code)] | |
| 257 pub fn type_ast(ast: Module) { | |
| 258 let mut environment = HashMap::new(); | |
| 259 environment.insert("int".to_string(), Type::Int); | |
| 260 environment.insert("__name__".to_string(), Type::Str); | |
| 261 environment.insert("print".to_string(), Type::Unit); | |
| 262 let mut typing = Typing{environment: vec!(environment), next_id: 0}; | |
| 263 typing.visit_module(ast); | |
| 264 } |
