Mercurial > python-compiler.rs
annotate src/ast_type.rs @ 7:680d15073f55
Add ast.List literal.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Tue, 31 May 2016 04:26:58 +0100 |
parents | 6f2bf13f4cb5 |
children | 94ff501bf336 |
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 }, | |
128 Statement::Return(expr) => { | |
129 self.visit_expr(expr) | |
130 }, | |
131 Statement::ImportFrom(module, names) => { | |
132 for alias in names { | |
133 self.visit_expr(alias); | |
134 } | |
135 Type::Bottom | |
136 }, | |
137 Statement::Expr(expr) => { | |
138 self.visit_expr(expr) | |
139 }, | |
6
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
140 Statement::Break => { |
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
141 Type::Bottom |
6f2bf13f4cb5
Add ast.While and ast.Break.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
5
diff
changeset
|
142 }, |
0 | 143 Statement::Error => { |
144 println!("Statement::Error"); | |
145 panic!() | |
146 }, | |
147 } | |
148 } | |
149 | |
150 fn visit_expr(&mut self, expr: Expr) -> Type { | |
151 let expr_str = format!("{:?}", expr); | |
152 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
|
153 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
|
154 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
|
155 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
|
156 }, |
0 | 157 Expr::BinOp(left, op, right) => { |
158 let type_left = self.visit_expr(*left); | |
159 let type_right = self.visit_expr(*right); | |
160 | |
161 if op == BinOp::BinMult && type_left == Type::Str && type_right == Type::Int { | |
162 return Type::Str; | |
163 } | |
164 | |
165 if type_left != type_right { | |
166 return Type::Bottom; | |
167 } | |
168 if op == BinOp::BinAdd || op == BinOp::BinMult { | |
169 if type_left == Type::Int { | |
170 Type::Int | |
171 } else if type_left == Type::Str { | |
172 Type::Str | |
173 } else { | |
174 Type::Bottom | |
175 } | |
176 } else if op == BinOp::BinEq || op == BinOp::BinLt { | |
177 Type::Bool | |
178 } else { | |
179 Type::Bottom | |
180 } | |
181 }, | |
182 Expr::Compare(_, _, _) => Type::Bool, | |
183 Expr::Call(func, args) => { | |
184 let func = *func; | |
185 let func = match func { | |
186 Expr::Name(arg) => arg, | |
187 _ => panic!() | |
188 }; | |
189 let mut types = vec!(); | |
190 for expr in args { | |
191 let type_ = self.visit_expr(expr); | |
192 types.push(type_); | |
193 } | |
194 println!("types: {:?}", types); | |
195 let env = match self.environment.pop() { | |
196 Some(env) => env, | |
197 None => return Type::Bottom | |
198 }; | |
199 if env.contains_key(&func) { | |
200 let value = env.get(&func).unwrap().clone(); | |
201 self.environment.push(env); | |
202 value | |
203 } else { | |
204 self.environment.push(env); | |
205 Type::Bottom | |
206 } | |
207 }, | |
208 Expr::Alias(_, _) => Type::Bottom, | |
4
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
209 Expr::Attribute(lhs, rhs) => { |
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
210 let type_left = self.visit_expr(*lhs); |
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
211 println!("coucou {:?}", type_left); |
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
212 Type::Bottom |
f27a4aee9dfa
Add ast.Attribute.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
213 }, |
0 | 214 Expr::Name(id) => { |
215 let env = match self.environment.pop() { | |
216 Some(env) => env, | |
217 None => return Type::Bottom | |
218 }; | |
219 if env.contains_key(&id) { | |
220 let value = env.get(&id).unwrap().clone(); | |
221 self.environment.push(env); | |
222 value | |
223 } else { | |
224 self.environment.push(env); | |
225 self.next_id += 1; | |
226 Type::Top(self.next_id) | |
227 } | |
228 }, | |
229 Expr::NameConstant(value) => { | |
230 if value == "True" || value == "False" { | |
231 Type::Bool | |
232 } else if value == "None" { | |
233 Type::Unit | |
234 } else { | |
235 Type::Bottom | |
236 } | |
237 }, | |
238 Expr::Str(_) => Type::Str, | |
239 Expr::Num(_) => Type::Int, | |
7
680d15073f55
Add ast.List literal.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
6
diff
changeset
|
240 Expr::List(_) => Type::List(Box::new(Type::Bottom)), |
0 | 241 Expr::Error => { |
242 println!("Expr::Error"); | |
243 panic!() | |
244 } | |
245 }; | |
246 println!("{} => {:?}", expr_str, type_); | |
247 type_ | |
248 } | |
249 } | |
250 | |
251 #[allow(dead_code)] | |
252 pub fn type_ast(ast: Module) { | |
253 let mut environment = HashMap::new(); | |
254 environment.insert("int".to_string(), Type::Int); | |
255 environment.insert("__name__".to_string(), Type::Str); | |
256 environment.insert("print".to_string(), Type::Unit); | |
257 let mut typing = Typing{environment: vec!(environment), next_id: 0}; | |
258 typing.visit_module(ast); | |
259 } |