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