| 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 |