Mercurial > python-compiler.rs
annotate src/ast_type.rs @ 81:dc82a0d8f144
Add ast.Dict.
author | Bastien Orivel <eijebong@bananium.fr> |
---|---|
date | Mon, 13 Jun 2016 20:45:19 +0200 |
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 } |