Line | Branch | Exec | Source |
---|---|---|---|
1 | |||
2 | #include "../dtypes.h" | ||
3 | #include "ast/values/exception.h" | ||
4 | #include "ast/values/generator.h" | ||
5 | #include "ast/values/object.h" | ||
6 | #include "logging/logging.h" | ||
7 | #include "parser/parsing_error.h" | ||
8 | #include "utilities/guard.h" | ||
9 | |||
10 | #include "vm/tree.h" | ||
11 | |||
12 | #define EXEC_BODY(body) \ | ||
13 | for (StmtNode * stmt: (body)) { \ | ||
14 | exec(stmt, depth); \ | ||
15 | \ | ||
16 | if (has_exceptions()) { \ | ||
17 | return None(); \ | ||
18 | } \ | ||
19 | \ | ||
20 | if (return_value != nullptr) { \ | ||
21 | return return_value; \ | ||
22 | } \ | ||
23 | } | ||
24 | |||
25 | namespace lython { | ||
26 | |||
27 | void TreeEvaluator::raise_exception(PartialResult* exception, PartialResult* cause) { | ||
28 | // Create the exception object | ||
29 | |||
30 | // Constant* cause_value = cast<Constant>(cause); | ||
31 | // // cause should be an exception | ||
32 | // NativeObject* cause_except = cause_value->value.get<NativeObject*>(); | ||
33 | |||
34 | // if (cause != nullptr && cause_except) { | ||
35 | // // TODO: | ||
36 | // } | ||
37 | |||
38 |
1/1✓ Branch 1 taken 3 times.
|
3 | lyException* except = root.new_object<lyException>(traces); |
39 | // Constant* except_value = root.new_object<Constant>(except); | ||
40 | |||
41 |
1/1✓ Branch 1 taken 3 times.
|
3 | exceptions.push_back(except); |
42 | 3 | } | |
43 | |||
44 | PartialResult* TreeEvaluator::compare(Compare_t* n, int depth) { | ||
45 | |||
46 | // a and b and c and d | ||
47 | // | ||
48 |
1/1✓ Branch 1 taken 52 times.
|
52 | PartialResult* left = exec(n->left, depth); |
49 |
1/1✓ Branch 1 taken 52 times.
|
52 | Constant* left_const = cast<Constant>(left); |
50 | |||
51 | 52 | Array<PartialResult*> partials; | |
52 |
1/1✓ Branch 2 taken 52 times.
|
52 | partials.reserve(n->comparators.size()); |
53 | |||
54 | 52 | bool bnative = !n->native_operator.empty(); | |
55 | 52 | bool full_eval = true; | |
56 | 52 | bool result = true; | |
57 | |||
58 |
2/2✓ Branch 1 taken 55 times.
✓ Branch 2 taken 22 times.
|
77 | for (int i = 0; i < n->comparators.size(); i++) { |
59 |
1/1✓ Branch 2 taken 55 times.
|
55 | PartialResult* right = exec(n->comparators[i], depth); |
60 |
1/1✓ Branch 1 taken 55 times.
|
55 | partials.push_back(right); |
61 | |||
62 |
1/1✓ Branch 1 taken 55 times.
|
55 | Constant* right_const = cast<Constant>(right); |
63 | |||
64 |
2/4✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
|
55 | if (left_const != nullptr && right_const != nullptr) { |
65 | 55 | Constant* value = nullptr; | |
66 | |||
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (!bnative) { |
68 | ✗ | Scope scope(bindings); | |
69 | |||
70 | ✗ | bindings.add(StringRef(), left_const, nullptr); | |
71 | ✗ | bindings.add(StringRef(), right_const, nullptr); | |
72 | |||
73 | ✗ | value = cast<Constant>(exec(n->resolved_operator[i], depth)); | |
74 | |||
75 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
55 | } else if (bnative) { |
76 | 55 | auto native = n->native_operator[i]; | |
77 | assert(native, "Operator needs to be set"); | ||
78 | |||
79 |
1/1✓ Branch 1 taken 55 times.
|
55 | ConstantValue v = native(left_const->value, right_const->value); |
80 |
3/4✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 30 times.
|
55 | result = result && v.get<bool>(); |
81 | 55 | } | |
82 | |||
83 | // One comparison is false so the entire thing does not work | ||
84 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 25 times.
|
55 | if (!result) { |
85 |
1/1✓ Branch 1 taken 30 times.
|
30 | return False(); |
86 | } | ||
87 | |||
88 | 25 | left = right; | |
89 | 25 | left_const = right_const; | |
90 | |||
91 | 25 | } else { | |
92 | ✗ | full_eval = false; | |
93 | } | ||
94 | } | ||
95 | |||
96 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | if (full_eval) { |
97 |
1/1✓ Branch 1 taken 22 times.
|
22 | return True(); |
98 | } | ||
99 | |||
100 | ✗ | Compare* comp = root.new_object<Compare>(); | |
101 | ✗ | comp->left = n->left; | |
102 | ✗ | comp->ops = n->ops; | |
103 | ✗ | comp->comparators.reserve(partials.size()); | |
104 | |||
105 | ✗ | comp->resolved_operator = n->resolved_operator; | |
106 | ✗ | comp->native_operator = n->native_operator; | |
107 | |||
108 | ✗ | for (auto* p: partials) { | |
109 | ✗ | comp->comparators.push_back((ExprNode*)p); | |
110 | } | ||
111 | ✗ | return comp; | |
112 | 52 | } | |
113 | |||
114 | PartialResult* TreeEvaluator::boolop(BoolOp_t* n, int depth) { | ||
115 | // a and b or c and d | ||
116 | // | ||
117 |
1/1✓ Branch 2 taken 2 times.
|
2 | PartialResult* first_value = exec(n->values[0], depth); |
118 |
1/1✓ Branch 1 taken 2 times.
|
2 | Constant* first = cast<Constant>(first_value); |
119 | |||
120 | 2 | Array<PartialResult*> partials; | |
121 |
1/1✓ Branch 2 taken 2 times.
|
2 | partials.reserve(n->values.size()); |
122 |
1/1✓ Branch 1 taken 2 times.
|
2 | partials.push_back(first_value); |
123 | |||
124 | 2 | bool full_eval = true; | |
125 | 2 | bool result = false; | |
126 | std::function<bool(bool, bool)> reduce = [](bool a, bool b) -> bool { return a || b; }; | ||
127 | |||
128 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (n->op == BoolOperator::And) { |
129 | 2 | result = true; | |
130 | reduce = [](bool a, bool b) -> bool { return a && b; }; | ||
131 | } | ||
132 | |||
133 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
|
3 | for (int i = 1; i < n->values.size(); i++) { |
134 |
1/1✓ Branch 2 taken 2 times.
|
2 | PartialResult* second_value = exec(n->values[i], depth); |
135 |
1/1✓ Branch 1 taken 2 times.
|
2 | partials.push_back(second_value); |
136 | |||
137 |
1/1✓ Branch 1 taken 2 times.
|
2 | Constant* second = cast<Constant>(second_value); |
138 | |||
139 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (first != nullptr && second != nullptr) { |
140 | 2 | Constant* value = nullptr; | |
141 | |||
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (n->resolved_operator != nullptr) { |
143 | ✗ | Scope scope(bindings); | |
144 | |||
145 | ✗ | bindings.add(StringRef(), first_value, nullptr); | |
146 | ✗ | bindings.add(StringRef(), second_value, nullptr); | |
147 | |||
148 | ✗ | value = cast<Constant>(exec(n->resolved_operator, depth)); | |
149 | |||
150 | ✗ | result = reduce(result, value->value.get<bool>()); | |
151 | |||
152 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | } else if (n->native_operator != nullptr) { |
153 |
1/1✓ Branch 1 taken 2 times.
|
2 | ConstantValue v = n->native_operator(first->value, second->value); |
154 |
1/1✓ Branch 2 taken 2 times.
|
2 | result = reduce(result, v.get<bool>()); |
155 | 2 | } | |
156 | |||
157 | // Shortcut | ||
158 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
2 | if (n->op == BoolOperator::And && !result) { |
159 |
1/1✓ Branch 1 taken 1 times.
|
1 | return False(); |
160 | } | ||
161 | |||
162 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (n->op == BoolOperator::Or && result) { |
163 | ✗ | return True(); | |
164 | } | ||
165 | |||
166 | 1 | first = second; | |
167 | 1 | first_value = second_value; | |
168 | |||
169 | 1 | } else { | |
170 | ✗ | full_eval = false; | |
171 | } | ||
172 | } | ||
173 | |||
174 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (result) { |
175 |
1/1✓ Branch 1 taken 1 times.
|
1 | return True(); |
176 | } else { | ||
177 | ✗ | return False(); | |
178 | } | ||
179 | |||
180 | BoolOp* boolop = root.new_object<BoolOp>(); | ||
181 | boolop->op = n->op; | ||
182 | boolop->values.reserve(partials.size()); | ||
183 | boolop->resolved_operator = n->resolved_operator; | ||
184 | boolop->native_operator = n->native_operator; | ||
185 | |||
186 | for (auto* p: partials) { | ||
187 | boolop->values.push_back((ExprNode*)p); | ||
188 | } | ||
189 | return boolop; | ||
190 | 2 | } | |
191 | |||
192 | PartialResult* TreeEvaluator::binop(BinOp_t* n, int depth) { | ||
193 | |||
194 | 61 | auto* lhs = exec(n->left, depth); | |
195 | 61 | auto* rhs = exec(n->right, depth); | |
196 | |||
197 | // TODO: if they evaluate to constant that belong to the value root | ||
198 | // we can free them as soon as we finish combining the values | ||
199 | |||
200 | // We can execute the function because both arguments got resolved | ||
201 |
4/8✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 61 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 61 times.
✗ Branch 8 not taken.
|
122 | if (lhs != nullptr && lhs->is_instance<Constant>() && rhs != nullptr && |
202 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | rhs->is_instance<Constant>()) { |
203 | 61 | PartialResult* result = nullptr; | |
204 | |||
205 | // Execute function | ||
206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | if (n->resolved_operator != nullptr) { |
207 | ✗ | Scope scope(bindings); | |
208 | |||
209 | ✗ | bindings.add(StringRef(), lhs, nullptr); | |
210 | ✗ | bindings.add(StringRef(), rhs, nullptr); | |
211 | |||
212 | ✗ | result = exec(n->resolved_operator, depth); | |
213 | ✗ | } | |
214 | |||
215 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | else if (n->native_operator != nullptr) { |
216 | 61 | Constant* lhsc = static_cast<Constant*>(lhs); | |
217 | 61 | Constant* rhsc = static_cast<Constant*>(rhs); | |
218 | |||
219 |
2/2✓ Branch 1 taken 61 times.
✓ Branch 4 taken 61 times.
|
61 | result = root.new_object<Constant>(n->native_operator(lhsc->value, rhsc->value)); |
220 | } | ||
221 | |||
222 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | if (result != nullptr) { |
223 | // Free the temporary values because we were able to combine them into a result | ||
224 | // lhs/rhs could be constant created by the parser, in that case their parent are not | ||
225 | // the root node and they should not be destroyed | ||
226 | |||
227 | // This is not valid, the constant could have been allocated by a function call | ||
228 | // they need to be freed when the call ends | ||
229 | // root.remove_child_if_parent(lhs, true); | ||
230 | // root.remove_child_if_parent(rhs, true); | ||
231 | |||
232 | 61 | return result; | |
233 | } | ||
234 | } | ||
235 | |||
236 | // We could not execute, just return what we could execute so far | ||
237 | ✗ | BinOp* binary = root.new_object<BinOp>(); | |
238 | |||
239 | ✗ | binary->op = n->op; | |
240 | ✗ | binary->left = (ExprNode*)lhs; | |
241 | ✗ | binary->right = (ExprNode*)rhs; | |
242 | |||
243 | ✗ | binary->resolved_operator = n->resolved_operator; | |
244 | ✗ | binary->native_operator = n->native_operator; | |
245 | |||
246 | // The partial operator becomes the owner of the partial results | ||
247 | ✗ | lhs->move(binary); | |
248 | ✗ | rhs->move(binary); | |
249 | |||
250 | ✗ | return binary; | |
251 | } | ||
252 | |||
253 | PartialResult* TreeEvaluator::unaryop(UnaryOp_t* n, int depth) { | ||
254 | 3 | auto* operand = exec(n->operand, depth); | |
255 | |||
256 | // We can execute the function because both arguments got resolved | ||
257 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
3 | if (operand != nullptr && operand->is_instance<Constant>()) { |
258 | |||
259 | // Execute function | ||
260 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (n->resolved_operator != nullptr) { |
261 | ✗ | Scope scope(bindings); | |
262 | ✗ | bindings.add(StringRef(), operand, nullptr); | |
263 | ✗ | return exec(n->resolved_operator, depth); | |
264 | ✗ | } | |
265 | |||
266 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (n->native_operator != nullptr) { |
267 | 3 | Constant* operandc = static_cast<Constant*>(operand); | |
268 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
|
3 | return root.new_object<Constant>(n->native_operator(operandc->value)); |
269 | } | ||
270 | } | ||
271 | |||
272 | // We could not execute, just return what we could execute so far | ||
273 | ✗ | UnaryOp* unary = root.new_object<UnaryOp>(); | |
274 | ✗ | unary->op = n->op; | |
275 | ✗ | unary->operand = (ExprNode*)operand; | |
276 | ✗ | unary->resolved_operator = n->resolved_operator; | |
277 | ✗ | unary->native_operator = n->native_operator; | |
278 | ✗ | return unary; | |
279 | } | ||
280 | |||
281 | PartialResult* TreeEvaluator::namedexpr(NamedExpr_t* n, int depth) { | ||
282 | 1 | PartialResult* value = exec(n->value, depth); | |
283 | |||
284 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (value->is_instance<Constant>()) { |
285 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
1 | bindings.add(StringRef(), value, nullptr); |
286 | 1 | return value; | |
287 | } | ||
288 | |||
289 | // TODO: do i put the evaluated expression or the partial expression ? | ||
290 | ✗ | NamedExpr* expr = root.new_object<NamedExpr>(); | |
291 | ✗ | expr->target = n->target; | |
292 | ✗ | expr->value = (ExprNode*)value; | |
293 | ✗ | bindings.add(StringRef(), value, nullptr); | |
294 | ✗ | return expr; | |
295 | } | ||
296 | |||
297 | PartialResult* TreeEvaluator::lambda(Lambda_t* n, int depth) { | ||
298 | ✗ | auto* result = exec(n->body, depth); | |
299 | |||
300 | ✗ | if (result != nullptr && result->is_instance<Constant>()) | |
301 | ✗ | return result; | |
302 | |||
303 | // Here we should build a new lambda | ||
304 | // but we have to know which args were defined and which were not | ||
305 | // we can check n->args vardid and fetch them from the context | ||
306 | // if they are undefined we need to forward them | ||
307 | ✗ | return None(); | |
308 | } | ||
309 | |||
310 | PartialResult* TreeEvaluator::ifexp(IfExp_t* n, int depth) { | ||
311 | 2 | Constant* value = cast<Constant>(exec(n->test, depth)); | |
312 | |||
313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (value == nullptr) { |
314 | // Could not evaluate the if test | ||
315 | // the entire expression cannot be evaluated | ||
316 | ✗ | return n; | |
317 | } | ||
318 | |||
319 | 2 | bool btrue = value->value.get<bool>(); | |
320 | |||
321 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (btrue) { |
322 | 1 | return exec(n->body, depth); | |
323 | } | ||
324 | |||
325 | 1 | return exec(n->orelse, depth); | |
326 | } | ||
327 | |||
328 | PartialResult* TreeEvaluator::call_native(Call_t* call, BuiltinType_t* function, int depth) { | ||
329 | ✗ | Array<PartialResult*> args; | |
330 | ✗ | Array<Constant*> value_args; | |
331 | ✗ | args.reserve(call->args.size()); | |
332 | ✗ | value_args.reserve(call->args.size()); | |
333 | |||
334 | ✗ | bool compile_time = true; | |
335 | |||
336 | ✗ | for (int i = 0; i < call->args.size(); i++) { | |
337 | ✗ | PartialResult* arg = exec(call->args[i], depth); | |
338 | ✗ | args.push_back(arg); | |
339 | |||
340 | ✗ | Constant* value = cast<Constant>(arg); | |
341 | ✗ | if (value != nullptr) { | |
342 | ✗ | value_args.push_back(value); | |
343 | } | ||
344 | ✗ | compile_time = compile_time && value != nullptr; | |
345 | } | ||
346 | |||
347 | ✗ | PartialResult* ret_result = nullptr; | |
348 | |||
349 | ✗ | if (compile_time) { | |
350 | ✗ | ConstantValue result = function->native_function(value_args); | |
351 | ✗ | ret_result = root.new_object<Constant>(result); | |
352 | ✗ | } else { | |
353 | // FIXME: we probably need the context here | ||
354 | ✗ | ret_result = function->native_macro(args); | |
355 | } | ||
356 | |||
357 | ✗ | for (PartialResult* arg: args) { | |
358 | ✗ | root.remove_child_if_parent(arg, true); | |
359 | } | ||
360 | |||
361 | ✗ | return ret_result; | |
362 | ✗ | } | |
363 | PartialResult* TreeEvaluator::call_script(Call_t* call, FunctionDef_t* function, int depth) { | ||
364 | 50 | Scope scope(bindings); | |
365 | |||
366 | // TODO: free the references held by the binding to save sapce | ||
367 | 50 | Array<PartialResult*> to_be_freed; | |
368 |
1/1✓ Branch 2 taken 50 times.
|
50 | to_be_freed.reserve(call->args.size()); |
369 | |||
370 | // insert arguments to the context | ||
371 |
2/2✓ Branch 1 taken 46 times.
✓ Branch 2 taken 50 times.
|
96 | for (int i = 0; i < call->args.size(); i++) { |
372 |
1/1✓ Branch 2 taken 46 times.
|
46 | PartialResult* arg = exec(call->args[i], depth); |
373 |
1/1✓ Branch 1 taken 46 times.
|
46 | to_be_freed.push_back(arg); |
374 |
2/2✓ Branch 1 taken 46 times.
✓ Branch 4 taken 46 times.
|
46 | bindings.add(StringRef(), arg, nullptr); |
375 | } | ||
376 | |||
377 |
7/8✓ Branch 4 taken 98 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 93 times.
✓ Branch 10 taken 5 times.
✓ Branch 12 taken 45 times.
✓ Branch 13 taken 48 times.
✓ Branch 16 taken 98 times.
✗ Branch 17 not taken.
|
98 | EXEC_BODY(function->body); |
378 | |||
379 | // TODO: check if the execution was partial or full | ||
380 | // Actually; if we take ownership of the arguments | ||
381 | // when we generate partial nodes then we can always try to free regardless | ||
382 | ✗ | for (PartialResult* arg: to_be_freed) { | |
383 | ✗ | root.remove_child_if_parent(arg, true); | |
384 | } | ||
385 | |||
386 | ✗ | return return_value; | |
387 | 50 | } | |
388 | |||
389 | Constant* object__new__(GCObject* parent, ClassDef* class_t) { | ||
390 | 2 | Constant* value = parent->new_object<Constant>(); | |
391 | |||
392 | 2 | Object* obj = value->new_object<Object>(); | |
393 | 2 | obj->attributes.resize(class_t->attributes.size()); | |
394 | |||
395 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
|
6 | for (int i = 0; i < class_t->attributes.size(); i++) { |
396 | 4 | obj->attributes[i] = obj->new_object<Constant>(); | |
397 | } | ||
398 | |||
399 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
|
2 | value->value = ConstantValue(obj); |
400 | 2 | return value; | |
401 | } | ||
402 | |||
403 | PartialResult* TreeEvaluator::call_constructor(Call_t* call, ClassDef_t* cls, int depth) { | ||
404 | // Create the object | ||
405 |
1/1✓ Branch 1 taken 2 times.
|
2 | Constant* obj = object__new__(&root, cls); |
406 | |||
407 | // Fetch construtor | ||
408 | // TODO: this lookup should not exist | ||
409 |
3/3✓ Branch 2 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 2 times.
|
2 | String ctor_name = String(cls->name) + String(".__init__"); |
410 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
|
2 | int ctorvarid = bindings.get_varid(ctor_name); |
411 |
1/1✓ Branch 2 taken 2 times.
|
2 | FunctionDef* ctor = cast<FunctionDef>(bindings.get_value(ctorvarid)); |
412 | |||
413 | 2 | Scope scope(bindings); | |
414 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (ctor != nullptr) { |
415 |
3/3✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
|
2 | bindings.add(StringRef("self"), obj, nullptr); |
416 | |||
417 |
2/2✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
|
6 | for (auto& arg: call->args) { |
418 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
|
4 | bindings.add(StringRef(), arg, nullptr); |
419 | } | ||
420 | |||
421 |
2/2✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
|
6 | for (auto& stmt: ctor->body) { |
422 |
1/1✓ Branch 1 taken 4 times.
|
4 | exec(stmt, depth); |
423 | |||
424 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (has_exceptions()) { |
425 | ✗ | break; | |
426 | } | ||
427 | } | ||
428 | } | ||
429 | |||
430 | 2 | return obj; | |
431 | 2 | } | |
432 | |||
433 | Constant* TreeEvaluator::make(ClassDef* class_t, Array<Constant*> args, int depth) { | ||
434 | // TODO: this should be generated inside the SEMA | ||
435 | // | ||
436 | ✗ | String __new__ = class_t->cls_namespace + "." + "__new__"; | |
437 | ✗ | String __init__ = class_t->cls_namespace + "." + "__init__"; | |
438 | |||
439 | ✗ | int varid_new_fun = bindings.get_varid(__new__); | |
440 | ✗ | int varid_init_fun = bindings.get_varid(__init__); | |
441 | |||
442 | ✗ | FunctionDef* new_fun = cast<FunctionDef>(bindings.get_value(varid_new_fun)); | |
443 | ✗ | FunctionDef* init_fun = cast<FunctionDef>(bindings.get_value(varid_init_fun)); | |
444 | |||
445 | ✗ | Constant* self = nullptr; | |
446 | |||
447 | ✗ | if (new_fun != nullptr) { | |
448 | ✗ | Scope _(bindings); | |
449 | ✗ | bindings.add(StringRef(), class_t, nullptr); | |
450 | ✗ | for (auto& arg: args) { | |
451 | ✗ | bindings.add(StringRef(), arg, nullptr); | |
452 | } | ||
453 | |||
454 | ✗ | for (auto& stmt: new_fun->body) { | |
455 | ✗ | exec(stmt, depth); | |
456 | |||
457 | ✗ | if (return_value != nullptr) { | |
458 | ✗ | self = cast<Constant>(return_value); | |
459 | ✗ | break; | |
460 | } | ||
461 | |||
462 | ✗ | if (has_exceptions()) { | |
463 | ✗ | break; | |
464 | } | ||
465 | } | ||
466 | ✗ | } | |
467 | |||
468 | ✗ | if (init_fun != nullptr) { | |
469 | ✗ | Scope _(bindings); | |
470 | |||
471 | ✗ | bindings.add(StringRef(), self, nullptr); | |
472 | ✗ | for (auto& arg: args) { | |
473 | ✗ | bindings.add(StringRef(), arg, nullptr); | |
474 | } | ||
475 | |||
476 | ✗ | for (auto& stmt: init_fun->body) { | |
477 | ✗ | exec(stmt, depth); | |
478 | |||
479 | ✗ | if (has_exceptions()) { | |
480 | ✗ | break; | |
481 | } | ||
482 | } | ||
483 | ✗ | } | |
484 | |||
485 | ✗ | return self; | |
486 | ✗ | } | |
487 | |||
488 | PartialResult* TreeEvaluator::make_generator(Call_t* call, FunctionDef_t* n, int depth) { | ||
489 | |||
490 | ✗ | Generator* gen = root.new_object<Generator>(); | |
491 | ✗ | gen->scope = bindings; | |
492 | |||
493 | ✗ | for (int i = 0; i < call->args.size(); i++) { | |
494 | ✗ | PartialResult* arg = exec(call->args[i], depth); | |
495 | ✗ | gen->scope.add(StringRef(), arg, nullptr); | |
496 | } | ||
497 | |||
498 | ✗ | Constant* val = root.new_object<Constant>(); | |
499 | ✗ | val->value = ConstantValue(gen); | |
500 | |||
501 | ✗ | return val; | |
502 | } | ||
503 | |||
504 | PartialResult* TreeEvaluator::call(Call_t* n, int depth) { | ||
505 | |||
506 | using TraceGuard = PopGuard<Array<StackTrace>, StackTrace>; | ||
507 | |||
508 | // Populate current stack with the expression that will branch out | ||
509 | 52 | get_kwtrace().expr = n; | |
510 | |||
511 | 52 | TraceGuard _(traces); | |
512 |
1/1✓ Branch 1 taken 52 times.
|
52 | StackTrace& trace = traces.emplace_back(); |
513 | |||
514 | // fetch the function we need to call | ||
515 |
1/1✓ Branch 1 taken 52 times.
|
52 | auto* function = exec(n->func, depth); |
516 | assert(function, "Function should be found"); | ||
517 | |||
518 |
3/3✓ Branch 1 taken 52 times.
✓ Branch 3 taken 50 times.
✓ Branch 4 taken 2 times.
|
52 | if (FunctionDef_t* fun = cast<FunctionDef>(function)) { |
519 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (fun->generator) { |
520 | ✗ | return make_generator(n, fun, depth); | |
521 | } | ||
522 |
1/1✓ Branch 1 taken 50 times.
|
50 | return call_script(n, fun, depth); |
523 | } | ||
524 | |||
525 |
2/3✓ Branch 1 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | if (ClassDef_t* cls = cast<ClassDef_t>(function)) { |
526 |
1/1✓ Branch 1 taken 2 times.
|
2 | return call_constructor(n, cls, depth); |
527 | } | ||
528 | |||
529 | ✗ | if (BuiltinType_t* fun = cast<BuiltinType>(function)) { | |
530 | ✗ | return call_native(n, fun, depth); | |
531 | } | ||
532 | |||
533 | /* | ||
534 | if (Coroutine_t* fun = cast<Coroutine>(function)) { | ||
535 | return call_coroutine(n, fun, depth); | ||
536 | } | ||
537 | */ | ||
538 | |||
539 | // function could not be resolved at compile time | ||
540 | // return self ? | ||
541 | ✗ | return nullptr; | |
542 | 52 | } | |
543 | |||
544 | PartialResult* TreeEvaluator::constant(Constant_t* n, int depth) { | ||
545 | 188 | Constant* cpy = root.copy(n); | |
546 | 188 | return cpy; | |
547 | } | ||
548 | |||
549 | PartialResult* TreeEvaluator::comment(Comment_t* n, int depth) { return nullptr; } | ||
550 | |||
551 | PartialResult* TreeEvaluator::name(Name_t* n, int depth) { | ||
552 | |||
553 | 203 | Node* result = nullptr; | |
554 | 203 | int varid = -1; | |
555 | |||
556 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 186 times.
|
203 | if (n->ctx == ExprContext::Store) { |
557 |
1/1✓ Branch 1 taken 17 times.
|
17 | Constant* variable = root.new_object<Constant>(); |
558 |
1/1✓ Branch 1 taken 17 times.
|
17 | bindings.add(n->id, variable, nullptr); |
559 | 17 | return variable; | |
560 | } | ||
561 | |||
562 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 52 times.
|
186 | if (n->dynamic) { |
563 | // Local variables | Arguments | ||
564 | kwassert(n->offset != -1, "Reference should have a reverse lookup offset"); | ||
565 | 134 | varid = int(bindings.bindings.size()) - n->offset; | |
566 | 134 | result = bindings.get_value(varid); | |
567 | } else { | ||
568 | // Global variables | ||
569 | 52 | result = bindings.get_value(n->varid); | |
570 | } | ||
571 | |||
572 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 186 times.
|
186 | if (result == nullptr) { |
573 | ✗ | bindings.dump(std::cout); | |
574 | } | ||
575 | kwassert(result != nullptr, "Could not find variable"); | ||
576 | |||
577 | 186 | String kindstr; | |
578 |
1/2✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
|
186 | if (result != nullptr) { |
579 |
1/1✓ Branch 1 taken 186 times.
|
186 | kindstr = str(result->kind); |
580 | } | ||
581 | |||
582 | 186 | String strresult; | |
583 |
3/4✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 52 times.
|
186 | if (result != nullptr && result->kind == NodeKind::Constant) { |
584 |
1/1✓ Branch 1 taken 134 times.
|
134 | strresult = str(result); |
585 | } | ||
586 | kwdebug("Name (varid: {}), (size: {}) (offset: {}) resolved: {}", | ||
587 | n->varid, | ||
588 | n->size, | ||
589 | n->offset, | ||
590 | varid); | ||
591 | kwdebug("Looked for {} (id: {}) found {}: {}", n->id, n->varid, kindstr, strresult); | ||
592 | 186 | return result; | |
593 | 186 | } | |
594 | |||
595 | PartialResult* TreeEvaluator::functiondef(FunctionDef_t* n, int depth) { | ||
596 | // this should not be called | ||
597 | ✗ | return_value = nullptr; | |
598 | ✗ | EXEC_BODY(n->body); | |
599 | ✗ | return return_value; | |
600 | } | ||
601 | |||
602 | PartialResult* TreeEvaluator::invalidstmt(InvalidStatement_t* n, int depth) { | ||
603 | // FIXME: raise exception here | ||
604 | ✗ | raise_exception(nullptr, nullptr); | |
605 | ✗ | return nullptr; | |
606 | } | ||
607 | |||
608 | PartialResult* TreeEvaluator::returnstmt(Return_t* n, int depth) { | ||
609 | kwdebug("Compute return {}", str(n)); | ||
610 | |||
611 |
1/2✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
|
47 | if (n->value.has_value()) { |
612 | 47 | set_return_value(exec(n->value.value(), depth)); | |
613 | kwdebug("Returning {}", str(return_value)); | ||
614 | 47 | return return_value; | |
615 | } | ||
616 | |||
617 | ✗ | set_return_value(None()); | |
618 | ✗ | return return_value; | |
619 | } | ||
620 | |||
621 | PartialResult* TreeEvaluator::assign(Assign_t* n, int depth) { | ||
622 | 21 | PartialResult* value = exec(n->value, depth); | |
623 | |||
624 | // Unpacking | ||
625 | 21 | TupleExpr* targets = cast<TupleExpr>(n->targets[0]); | |
626 | 21 | TupleExpr* values = cast<TupleExpr>(value); | |
627 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
21 | if (values != nullptr && targets != nullptr) { |
628 | assert(values->elts.size() == targets->elts.size(), "Size must match"); | ||
629 | |||
630 | // this probably does not work quite right in some cases | ||
631 | ✗ | for (int i = 0; i < values->elts.size(); i++) { | |
632 | ✗ | bindings.add(StringRef(), values->elts[i], nullptr); | |
633 | } | ||
634 | ✗ | return None(); | |
635 | } | ||
636 | |||
637 | 21 | Constant* new_value = cast<Constant>(value); | |
638 | |||
639 |
3/6✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
|
21 | if (!n->targets.empty() && new_value != nullptr) { |
640 | |||
641 | // resolve the target | ||
642 | // the target should always be a reference to a constant/value | ||
643 | 21 | auto* gtarg = exec(n->targets[0], depth); | |
644 | 21 | auto* target = cast<Constant>(gtarg); | |
645 | |||
646 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | if (target != nullptr) { |
647 | 21 | target->value = new_value->value; | |
648 | } | ||
649 | 21 | return None(); | |
650 | } | ||
651 | |||
652 | ✗ | bindings.add(StringRef(), value, nullptr); | |
653 | ✗ | return None(); | |
654 | } | ||
655 | PartialResult* TreeEvaluator::augassign(AugAssign_t* n, int depth) { | ||
656 | |||
657 | // This should a Name | ||
658 | 28 | auto* name = cast<Name>(n->target); | |
659 | |||
660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (name == nullptr) { |
661 | kwerror("Assign to {}", str(n->target->kind)); | ||
662 | ✗ | return None(); | |
663 | } | ||
664 | |||
665 | 28 | auto* left = exec(n->target, depth); // load a | |
666 | 28 | auto* right = exec(n->value, depth); // load b | |
667 | |||
668 | 28 | auto* left_v = cast<Constant>(left); | |
669 | 28 | auto* right_v = cast<Constant>(right); | |
670 | |||
671 |
2/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | if (left_v != nullptr && right_v != nullptr) { |
672 | 28 | PartialResult* value = nullptr; | |
673 | |||
674 | // Execute function | ||
675 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (n->resolved_operator != nullptr) { |
676 | ✗ | Scope scope(bindings); | |
677 | |||
678 | ✗ | bindings.add(StringRef(), left_v, nullptr); | |
679 | ✗ | bindings.add(StringRef(), right_v, nullptr); | |
680 | |||
681 | ✗ | value = exec(n->resolved_operator, depth); | |
682 | ✗ | } | |
683 | |||
684 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | else if (n->native_operator != nullptr) { |
685 |
1/1✓ Branch 1 taken 28 times.
|
28 | auto result = n->native_operator(left_v->value, right_v->value); |
686 |
1/1✓ Branch 1 taken 28 times.
|
28 | value = root.new_object<Constant>(result); |
687 | 28 | } else { | |
688 | kwerror("Operator does not have implementation!"); | ||
689 | } | ||
690 | |||
691 | 28 | bindings.set_value(name->varid, value); // store a | |
692 | 28 | return None(); | |
693 | } | ||
694 | |||
695 | ✗ | AugAssign* expr = root.new_object<AugAssign>(); | |
696 | // Do not use the evaluted target here | ||
697 | ✗ | expr->target = n->target; | |
698 | ✗ | expr->op = n->op; | |
699 | ✗ | expr->value = (ExprNode*)right; | |
700 | ✗ | return expr; | |
701 | } | ||
702 | |||
703 | PartialResult* TreeEvaluator::annassign(AnnAssign_t* n, int depth) { | ||
704 | 2 | PartialResult* value = None(); | |
705 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (n->value.has_value()) { |
706 | 2 | value = exec(n->value.value(), depth); | |
707 | } | ||
708 | |||
709 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
|
2 | bindings.add(StringRef(), value, nullptr); |
710 | 2 | return None(); | |
711 | } | ||
712 | |||
713 | PartialResult* TreeEvaluator::forstmt(For_t* n, int depth) { | ||
714 | |||
715 | // insert target into the context | ||
716 | // exec(n->target, depth); | ||
717 | ✗ | int targetid = bindings.add(StringRef(), None(), nullptr); | |
718 | |||
719 | ✗ | PartialResult* iterator = exec(n->iter, depth); | |
720 | |||
721 | ✗ | bool broke = false; | |
722 | ✗ | loop_break = false; | |
723 | ✗ | loop_continue = false; | |
724 | |||
725 | while (true) { | ||
726 | // Python does not create a new scope for `for` | ||
727 | // Scope scope(bindings); | ||
728 | |||
729 | // Get the value of the iterator | ||
730 | ✗ | PartialResult* value = get_next(iterator, depth); | |
731 | |||
732 | // or value == StopIteration | ||
733 | ✗ | if (value == nullptr) { | |
734 | ✗ | break; | |
735 | } | ||
736 | |||
737 | ✗ | bindings.set_value(targetid, value); | |
738 | |||
739 | ✗ | for (StmtNode* stmt: n->body) { | |
740 | ✗ | exec(stmt, depth); | |
741 | |||
742 | ✗ | if (has_exceptions()) { | |
743 | ✗ | return None(); | |
744 | } | ||
745 | |||
746 | ✗ | if (return_value != nullptr) { | |
747 | ✗ | return return_value; | |
748 | } | ||
749 | |||
750 | ✗ | if (loop_break) { | |
751 | ✗ | broke = true; | |
752 | ✗ | break; | |
753 | } | ||
754 | |||
755 | ✗ | if (loop_continue) { | |
756 | ✗ | break; | |
757 | } | ||
758 | } | ||
759 | |||
760 | ✗ | loop_break = false; | |
761 | ✗ | loop_continue = false; | |
762 | |||
763 | ✗ | if (broke) { | |
764 | ✗ | break; | |
765 | } | ||
766 | ✗ | } | |
767 | |||
768 | ✗ | EXEC_BODY(n->orelse); | |
769 | ✗ | return None(); | |
770 | } | ||
771 | PartialResult* TreeEvaluator::whilestmt(While_t* n, int depth) { | ||
772 | |||
773 | 5 | bool broke = false; | |
774 | 5 | loop_break = false; | |
775 | 5 | loop_continue = false; | |
776 | |||
777 | while (true) { | ||
778 | 17 | Constant* value = cast<Constant>(exec(n->test, depth)); | |
779 | // TODO if it is not a value that means we could not evaluate it so we should return the | ||
780 | // node itself | ||
781 | assert(value, "While test should return a boolean"); | ||
782 | |||
783 |
3/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 3 times.
|
17 | bool bcontinue = value != nullptr && value->value.get<bool>(); |
784 | |||
785 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
17 | if (!bcontinue || broke) { |
786 | break; | ||
787 | } | ||
788 | |||
789 |
2/2✓ Branch 5 taken 38 times.
✓ Branch 6 taken 2 times.
|
40 | for (StmtNode* stmt: n->body) { |
790 |
1/1✓ Branch 1 taken 38 times.
|
38 | exec(stmt, depth); |
791 | |||
792 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 37 times.
|
38 | if (has_exceptions()) { |
793 |
1/1✓ Branch 1 taken 1 times.
|
1 | return None(); |
794 | } | ||
795 | |||
796 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (return_value != nullptr) { |
797 | ✗ | return return_value; | |
798 | } | ||
799 | |||
800 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 36 times.
|
37 | if (loop_break) { |
801 | 1 | broke = true; | |
802 | 1 | break; | |
803 | } | ||
804 | |||
805 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
|
36 | if (loop_continue) { |
806 | 10 | break; | |
807 | } | ||
808 | } | ||
809 | |||
810 | // reset | ||
811 | 13 | loop_break = false; | |
812 | 13 | loop_continue = false; | |
813 | |||
814 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | if (broke) { |
815 | 1 | break; | |
816 | } | ||
817 | 12 | } | |
818 | |||
819 |
1/10✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 4 times.
|
4 | EXEC_BODY(n->orelse); |
820 | 4 | return None(); | |
821 | } | ||
822 | |||
823 | PartialResult* TreeEvaluator::ifstmt(If_t* n, int depth) { | ||
824 | |||
825 | 29 | Array<StmtNode*>& body = n->orelse; | |
826 | // Chained | ||
827 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | if (!n->tests.empty()) { |
828 | ✗ | for (int i = 0; i < n->tests.size(); i++) { | |
829 | ✗ | Constant* value = cast<Constant>(exec(n->test, depth)); | |
830 | assert(value, "If test should return a boolean"); | ||
831 | |||
832 | ✗ | bool btrue = value->value.get<bool>(); | |
833 | ✗ | if (btrue) { | |
834 | ✗ | body = n->bodies[i]; | |
835 | ✗ | break; | |
836 | } | ||
837 | } | ||
838 | |||
839 | ✗ | EXEC_BODY(body); | |
840 | |||
841 | ✗ | return None(); | |
842 | } | ||
843 | |||
844 | // Simple | ||
845 | 29 | PartialResult* test = exec(n->test, depth); | |
846 | 29 | Constant* value = cast<Constant>(test); | |
847 | assert(value, "If test should return a boolean"); | ||
848 | |||
849 | 29 | bool btrue = value->value.get<bool>(); | |
850 | |||
851 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 24 times.
|
29 | if (btrue) { |
852 | 5 | body = n->body; | |
853 | } | ||
854 | |||
855 |
7/8✓ Branch 4 taken 6 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 5 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 6 times.
✓ Branch 17 taken 23 times.
|
29 | EXEC_BODY(body); |
856 | 23 | return None(); | |
857 | } | ||
858 | |||
859 | PartialResult* TreeEvaluator::assertstmt(Assert_t* n, int depth) { | ||
860 | 4 | PartialResult* btest = exec(n->test, depth); | |
861 | 4 | Constant* value = cast<Constant>(btest); | |
862 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (value != nullptr) { |
863 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
|
4 | if (!value->value.get<bool>()) { |
864 | // make_ref(n, "AssertionError") n->msg | ||
865 | 3 | raise_exception(nullptr, nullptr); | |
866 | 3 | return None(); | |
867 | } | ||
868 | |||
869 | // All Good | ||
870 | 1 | return None(); | |
871 | } | ||
872 | |||
873 | ✗ | Assert* expr = root.new_object<Assert>(); | |
874 | ✗ | expr->test = (ExprNode*)btest; | |
875 | ✗ | expr->msg = n->msg; | |
876 | ✗ | return expr; | |
877 | } | ||
878 | |||
879 | PartialResult* TreeEvaluator::exprstmt(Expr_t* n, int depth) { return exec(n->value, depth); } | ||
880 | PartialResult* TreeEvaluator::pass(Pass_t* n, int depth) { | ||
881 | // return itself in case the pass is required for correctness | ||
882 | ✗ | return n; | |
883 | } | ||
884 | PartialResult* TreeEvaluator::breakstmt(Break_t* n, int depth) { | ||
885 | 1 | loop_break = true; | |
886 | 1 | return n; | |
887 | } | ||
888 | PartialResult* TreeEvaluator::continuestmt(Continue_t* n, int depth) { | ||
889 | 10 | loop_continue = true; | |
890 | 10 | return n; | |
891 | } | ||
892 | |||
893 | PartialResult* TreeEvaluator::inlinestmt(Inline_t* n, int depth) { | ||
894 | |||
895 |
5/9✓ Branch 4 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
|
2 | EXEC_BODY(n->body); |
896 | |||
897 | ✗ | return None(); | |
898 | } | ||
899 | |||
900 | PartialResult* TreeEvaluator::raise(Raise_t* n, int depth) { | ||
901 | |||
902 | ✗ | if (n->exc.has_value()) { | |
903 | // create a new exceptins | ||
904 | ✗ | auto* obj = exec(n->exc.value(), depth); | |
905 | |||
906 | ✗ | if (n->cause.has_value()) { | |
907 | ✗ | cause = exec(n->cause.value(), depth); | |
908 | } | ||
909 | |||
910 | ✗ | raise_exception(obj, cause); | |
911 | } | ||
912 | |||
913 | // FIXME: this re-reraise current exception | ||
914 | // check what happens if no exception exists | ||
915 | ✗ | exceptions.push_back(nullptr); | |
916 | ✗ | return nullptr; | |
917 | } | ||
918 | |||
919 | PartialResult* TreeEvaluator::trystmt(Try_t* n, int depth) { | ||
920 | |||
921 | ✗ | EXEC_BODY(n->body); | |
922 | |||
923 | ✗ | if (has_exceptions()) { | |
924 | // start handling all the exceptions we received | ||
925 | ✗ | auto _ = HandleException(this); | |
926 | |||
927 | ✗ | ExceptHandler const* matched = nullptr; | |
928 | ✗ | lyException* latest_exception = exceptions[exceptions.size() - 1]; | |
929 | |||
930 | ✗ | for (ExceptHandler const& handler: n->handlers) { | |
931 | // match the exception type to the one we received | ||
932 | |||
933 | ✗ | bool found_matcher = false; | |
934 | |||
935 | // catch all | ||
936 | ✗ | if (!handler.type.has_value()) { | |
937 | ✗ | matched = &handler; | |
938 | ✗ | found_matcher = true; | |
939 | } | ||
940 | |||
941 | // FIXME: we do not have the type at runtime!!! | ||
942 | ✗ | else if (equal(handler.type.value(), latest_exception->type)) { | |
943 | ✗ | matched = &handler; | |
944 | ✗ | found_matcher = true; | |
945 | } | ||
946 | |||
947 | ✗ | if (found_matcher) { | |
948 | ✗ | break; | |
949 | } | ||
950 | } | ||
951 | |||
952 | ✗ | if (matched != nullptr) { | |
953 | ✗ | Scope _(bindings); | |
954 | ✗ | Constant exception; | |
955 | |||
956 | // Execute Handler | ||
957 | ✗ | if (matched->name.has_value()) { | |
958 | ✗ | exception.value = latest_exception->custom; | |
959 | ✗ | bindings.add(matched->name.value(), &exception, nullptr); | |
960 | } | ||
961 | |||
962 | ✗ | EXEC_BODY(matched->body); | |
963 | |||
964 | // Exception was handled! | ||
965 | ✗ | exceptions.pop_back(); | |
966 | ✗ | cause = nullptr; | |
967 | ✗ | } | |
968 | // Exception was NOT handled | ||
969 | // leave the exception as is so we continue moving back | ||
970 | |||
971 | ✗ | } else { | |
972 | ✗ | EXEC_BODY(n->orelse); | |
973 | } | ||
974 | |||
975 | ✗ | auto _ = HandleException(this); | |
976 | |||
977 | ✗ | EXEC_BODY(n->finalbody); | |
978 | |||
979 | // we are not handling exception anymore | ||
980 | ✗ | handling_exceptions = 0; | |
981 | |||
982 | ✗ | return None(); | |
983 | ✗ | } | |
984 | |||
985 | /* | ||
986 | https://stackoverflow.com/questions/60926323/can-i-raise-an-exception-in-exit | ||
987 | |||
988 | manager = (EXPRESSION) | ||
989 | enter = type(manager).__enter__ | ||
990 | exit = type(manager).__exit__ | ||
991 | value = enter(manager) | ||
992 | hit_except = False | ||
993 | |||
994 | try: | ||
995 | TARGET = value | ||
996 | SUITE | ||
997 | except: | ||
998 | hit_except = True | ||
999 | if not exit(manager, *sys.exc_kwinfo()): | ||
1000 | raise | ||
1001 | finally: | ||
1002 | if not hit_except: | ||
1003 | exit(manager, None, None, None) | ||
1004 | |||
1005 | */ | ||
1006 | PartialResult* TreeEvaluator::with(With_t* n, int depth) { | ||
1007 | // Call enter | ||
1008 | ✗ | for (auto& item: n->items) { | |
1009 | ✗ | auto* ctx = exec(item.context_expr, depth); | |
1010 | ✗ | auto* result = call_enter(ctx, depth); | |
1011 | |||
1012 | ✗ | if (item.optional_vars.has_value()) { | |
1013 | ✗ | bindings.add(StringRef(""), result, nullptr); | |
1014 | } | ||
1015 | } | ||
1016 | |||
1017 | ✗ | EXEC_BODY(n->body); | |
1018 | |||
1019 | // Call exit regardless of exception status | ||
1020 | ✗ | auto _ = HandleException(this); | |
1021 | |||
1022 | ✗ | for (auto& item: n->items) { | |
1023 | ✗ | auto* ctx = exec(item.context_expr, depth); | |
1024 | ✗ | call_exit(ctx, depth); | |
1025 | } | ||
1026 | |||
1027 | ✗ | return nullptr; | |
1028 | ✗ | } | |
1029 | |||
1030 | PartialResult* TreeEvaluator::match(Match_t* n, int depth) { return nullptr; } | ||
1031 | PartialResult* TreeEvaluator::import(Import_t* n, int depth) { return nullptr; } | ||
1032 | PartialResult* TreeEvaluator::importfrom(ImportFrom_t* n, int depth) { return nullptr; } | ||
1033 | |||
1034 | PartialResult* TreeEvaluator::dictexpr(DictExpr_t* n, int depth) { return nullptr; } | ||
1035 | PartialResult* TreeEvaluator::setexpr(SetExpr_t* n, int depth) { return nullptr; } | ||
1036 | PartialResult* TreeEvaluator::listcomp(ListComp_t* n, int depth) { return nullptr; } | ||
1037 | PartialResult* TreeEvaluator::generateexpr(GeneratorExp_t* n, int depth) { return nullptr; } | ||
1038 | PartialResult* TreeEvaluator::setcomp(SetComp_t* n, int depth) { return nullptr; } | ||
1039 | PartialResult* TreeEvaluator::dictcomp(DictComp_t* n, int depth) { return nullptr; } | ||
1040 | |||
1041 | PartialResult* TreeEvaluator::yield(Yield_t* n, int depth) { | ||
1042 | ✗ | if (n->value.has_value()) { | |
1043 | ✗ | auto* value = exec(n->value.value(), depth); | |
1044 | // Get the top level functions and create a lambda | ||
1045 | ✗ | yielding = true; | |
1046 | ✗ | return_value = value; | |
1047 | ✗ | return value; | |
1048 | } | ||
1049 | ✗ | return None(); | |
1050 | } | ||
1051 | PartialResult* TreeEvaluator::yieldfrom(YieldFrom_t* n, int depth) { return nullptr; } | ||
1052 | PartialResult* TreeEvaluator::joinedstr(JoinedStr_t* n, int depth) { return nullptr; } | ||
1053 | PartialResult* TreeEvaluator::formattedvalue(FormattedValue_t* n, int depth) { return nullptr; } | ||
1054 | |||
1055 | PartialResult* TreeEvaluator::starred(Starred_t* n, int depth) { return nullptr; } | ||
1056 | PartialResult* TreeEvaluator::listexpr(ListExpr_t* n, int depth) { return nullptr; } | ||
1057 | PartialResult* TreeEvaluator::tupleexpr(TupleExpr_t* n, int depth) { return nullptr; } | ||
1058 | PartialResult* TreeEvaluator::deletestmt(Delete_t* n, int depth) { return nullptr; } | ||
1059 | |||
1060 | PartialResult* TreeEvaluator::await(Await_t* n, int depth) { return nullptr; } | ||
1061 | |||
1062 | // Objects | ||
1063 | PartialResult* TreeEvaluator::slice(Slice_t* n, int depth) { return nullptr; } | ||
1064 | PartialResult* TreeEvaluator::attribute(Attribute_t* n, int depth) { | ||
1065 | // a.b | ||
1066 | 6 | Constant* obj = cast<Constant>(exec(n->value, depth)); | |
1067 | |||
1068 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (obj != nullptr) { |
1069 | 6 | NativeObject* nv = obj->value.get<NativeObject*>(); | |
1070 | |||
1071 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | if (nv->class_id == meta::type_id<Object>()) { |
1072 | 6 | Object* nvobj = reinterpret_cast<Object*>(nv); | |
1073 | |||
1074 | // If Object held ConstantValue | ||
1075 | // we would pass down a copy of the attribute not a reference to them | ||
1076 | // return root.new_object<Constant>(nvobj->attributes[n->attrid]); | ||
1077 | |||
1078 | // Object is holding a Constant Node | ||
1079 | // we pass a reference to it not a copy | ||
1080 | 6 | return nvobj->attributes[n->attrid]; | |
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | ✗ | return nullptr; | |
1085 | } | ||
1086 | PartialResult* TreeEvaluator::subscript(Subscript_t* n, int depth) { return nullptr; } | ||
1087 | |||
1088 | // Call __next__ for a given object | ||
1089 | PartialResult* TreeEvaluator::get_next(Node* iterator, int depth) { | ||
1090 | // FIXME: implement me | ||
1091 | ✗ | return nullptr; | |
1092 | } | ||
1093 | |||
1094 | PartialResult* TreeEvaluator::call_enter(Node* ctx, int depth) { | ||
1095 | // Call __enter__ | ||
1096 | ✗ | return nullptr; | |
1097 | } | ||
1098 | PartialResult* TreeEvaluator::call_exit(Node* ctx, int depth) { | ||
1099 | // Call __exit__ | ||
1100 | ✗ | return nullptr; | |
1101 | } | ||
1102 | |||
1103 | // Types | ||
1104 | // ----- | ||
1105 | PartialResult* TreeEvaluator::classdef(ClassDef_t* n, int depth) { return nullptr; } | ||
1106 | |||
1107 | PartialResult* TreeEvaluator::dicttype(DictType_t* n, int depth) { return nullptr; } | ||
1108 | PartialResult* TreeEvaluator::arraytype(ArrayType_t* n, int depth) { return nullptr; } | ||
1109 | PartialResult* TreeEvaluator::tupletype(TupleType_t* n, int depth) { return nullptr; } | ||
1110 | PartialResult* TreeEvaluator::arrow(Arrow_t* n, int depth) { return nullptr; } | ||
1111 | PartialResult* TreeEvaluator::classtype(ClassType_t* n, int depth) { return nullptr; } | ||
1112 | PartialResult* TreeEvaluator::settype(SetType_t* n, int depth) { return nullptr; } | ||
1113 | PartialResult* TreeEvaluator::builtintype(BuiltinType_t* n, int depth) { | ||
1114 | // return self because it also holds the native function to use | ||
1115 | ✗ | return n; | |
1116 | } | ||
1117 | |||
1118 | // Match | ||
1119 | // ----- | ||
1120 | PartialResult* TreeEvaluator::matchvalue(MatchValue_t* n, int depth) { return nullptr; } | ||
1121 | PartialResult* TreeEvaluator::matchsingleton(MatchSingleton_t* n, int depth) { return nullptr; } | ||
1122 | PartialResult* TreeEvaluator::matchsequence(MatchSequence_t* n, int depth) { return nullptr; } | ||
1123 | PartialResult* TreeEvaluator::matchmapping(MatchMapping_t* n, int depth) { return nullptr; } | ||
1124 | PartialResult* TreeEvaluator::matchclass(MatchClass_t* n, int depth) { return nullptr; } | ||
1125 | PartialResult* TreeEvaluator::matchstar(MatchStar_t* n, int depth) { return nullptr; } | ||
1126 | PartialResult* TreeEvaluator::matchas(MatchAs_t* n, int depth) { return nullptr; } | ||
1127 | PartialResult* TreeEvaluator::matchor(MatchOr_t* n, int depth) { return nullptr; } | ||
1128 | |||
1129 | PartialResult* TreeEvaluator::global(Global_t* n, int depth) { | ||
1130 | // we don't really need it right now, we are not enforcing this | ||
1131 | // might be sema business anyway | ||
1132 | ✗ | return nullptr; | |
1133 | } | ||
1134 | PartialResult* TreeEvaluator::nonlocal(Nonlocal_t* n, int depth) { | ||
1135 | // we don't really need it right now, we are not enforcing this | ||
1136 | // might be sema business anyway | ||
1137 | ✗ | return nullptr; | |
1138 | } | ||
1139 | |||
1140 | #define PRINT(msg) std::cout << (msg) << "\n"; | ||
1141 | |||
1142 | void printkwtrace(StackTrace& trace) { | ||
1143 |
1/1✓ Branch 2 taken 8 times.
|
8 | String file = "<input>"; |
1144 | 8 | int line = -1; | |
1145 |
1/1✓ Branch 2 taken 8 times.
|
8 | String parent = "<module>"; |
1146 | 8 | String expr; | |
1147 | |||
1148 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (trace.stmt != nullptr) { |
1149 | 8 | line = trace.stmt->lineno; | |
1150 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
|
8 | parent = shortprint(get_parent(trace.stmt)); |
1151 |
1/1✓ Branch 1 taken 8 times.
|
8 | expr = shortprint(trace.stmt); |
1152 | ✗ | } else if (trace.expr != nullptr) { | |
1153 | ✗ | line = trace.expr->lineno; | |
1154 | ✗ | parent = shortprint(trace.stmt); | |
1155 | ✗ | expr = shortprint(trace.stmt); | |
1156 | } | ||
1157 | |||
1158 |
1/1✓ Branch 1 taken 8 times.
|
8 | fmt::print(" File \"{}\", line {}, in {}\n", file, line, parent); |
1159 |
1/1✓ Branch 1 taken 8 times.
|
8 | fmt::print(" {}\n", expr); |
1160 | 8 | } | |
1161 | |||
1162 | PartialResult* TreeEvaluator::eval(StmtNode_t* stmt) { | ||
1163 | 28 | auto* result = exec(stmt, 0); | |
1164 | |||
1165 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 25 times.
|
28 | if (has_exceptions()) { |
1166 | 3 | lyException* except = exceptions[exceptions.size() - 1]; | |
1167 | |||
1168 | assert(except != nullptr, "Exception is null"); | ||
1169 | |||
1170 |
1/1✓ Branch 1 taken 3 times.
|
3 | fmt::print("Traceback (most recent call last):\n"); |
1171 |
2/2✓ Branch 5 taken 8 times.
✓ Branch 6 taken 3 times.
|
11 | for (StackTrace& st: except->traces) { |
1172 |
1/1✓ Branch 1 taken 8 times.
|
8 | printkwtrace(st); |
1173 | } | ||
1174 | |||
1175 |
1/1✓ Branch 2 taken 3 times.
|
3 | String exception_type = "AssertionError"; |
1176 |
1/1✓ Branch 2 taken 3 times.
|
3 | String exception_msg = "Very bad"; |
1177 |
1/1✓ Branch 1 taken 3 times.
|
3 | fmt::print("{}: {}\n", exception_type, exception_msg); |
1178 | 3 | } | |
1179 | |||
1180 | 28 | return result; | |
1181 | } | ||
1182 | |||
1183 | } // namespace lython | ||
1184 |