| ... | @@ -2,36 +2,6 @@ | ... | @@ -2,36 +2,6 @@ |
| 2 | #include "analyze.hpp" | 2 | #include "analyze.hpp" |
| 3 | #include "error.hpp" | 3 | #include "error.hpp" |
| 4 | | 4 | |
| 5 | struct EvalVar { | | |
| 6 | Buf *name; | | |
| 7 | ConstExprValue value; | | |
| 8 | }; | | |
| 9 | | | |
| 10 | struct EvalScope { | | |
| 11 | BlockContext *block_context; | | |
| 12 | ZigList<EvalVar> vars; | | |
| 13 | }; | | |
| 14 | | | |
| 15 | struct EvalFnRoot { | | |
| 16 | CodeGen *codegen; | | |
| 17 | FnTableEntry *fn; | | |
| 18 | AstNode *call_node; | | |
| 19 | size_t branch_quota; | | |
| 20 | size_t branches_used; | | |
| 21 | AstNode *exceeded_quota_node; | | |
| 22 | bool abort; | | |
| 23 | }; | | |
| 24 | | | |
| 25 | struct EvalFn { | | |
| 26 | EvalFnRoot *root; | | |
| 27 | FnTableEntry *fn; | | |
| 28 | ConstExprValue *return_expr; | | |
| 29 | ZigList<EvalScope*> scope_stack; | | |
| 30 | }; | | |
| 31 | | | |
| 32 | | | |
| 33 | static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val); | | |
| 34 | | | |
| 35 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { | 5 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { |
| 36 | switch (type_entry->id) { | 6 | switch (type_entry->id) { |
| 37 | case TypeTableEntryIdEnum: | 7 | case TypeTableEntryIdEnum: |
| ... | @@ -95,33 +65,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty | ... | @@ -95,33 +65,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty |
| 95 | } | 65 | } |
| 96 | | 66 | |
| 97 | | 67 | |
| 98 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out); | | |
| 99 | | | |
| 100 | static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) { | | |
| 101 | assert(node->type == NodeTypeBlock); | | |
| 102 | | | |
| 103 | EvalScope *my_scope = allocate<EvalScope>(1); | | |
| 104 | my_scope->block_context = node->block_context; | | |
| 105 | ef->scope_stack.append(my_scope); | | |
| 106 | | | |
| 107 | for (size_t i = 0; i < node->data.block.statements.length; i += 1) { | | |
| 108 | AstNode *child = node->data.block.statements.at(i); | | |
| 109 | memset(out, 0, sizeof(ConstExprValue)); | | |
| 110 | if (eval_expr(ef, child, out)) return true; | | |
| 111 | } | | |
| 112 | | | |
| 113 | ef->scope_stack.pop(); | | |
| 114 | | | |
| 115 | return false; | | |
| 116 | } | | |
| 117 | | | |
| 118 | static bool eval_return(EvalFn *ef, AstNode *node, ConstExprValue *out) { | | |
| 119 | assert(node->type == NodeTypeReturnExpr); | | |
| 120 | | | |
| 121 | eval_expr(ef, node->data.return_expr.expr, ef->return_expr); | | |
| 122 | return true; | | |
| 123 | } | | |
| 124 | | | |
| 125 | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { | 68 | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { |
| 126 | if (bin_op == BinOpTypeBoolOr || bin_op == BinOpTypeAssignBoolOr) { | 69 | if (bin_op == BinOpTypeBoolOr || bin_op == BinOpTypeAssignBoolOr) { |
| 127 | return a || b; | 70 | return a || b; |
| ... | @@ -209,31 +152,6 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue | ... | @@ -209,31 +152,6 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue |
| 209 | return 0; | 152 | return 0; |
| 210 | } | 153 | } |
| 211 | | 154 | |
| 212 | bool eval_const_expr_bin_op_handle_errors(EvalFn *ef, AstNode *node, | | |
| 213 | ConstExprValue *op1_val, TypeTableEntry *op1_type, | | |
| 214 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) | | |
| 215 | { | | |
| 216 | int err; | | |
| 217 | if ((err = eval_const_expr_bin_op(op1_val, op1_type, bin_op, op2_val, op2_type, out_val))) { | | |
| 218 | ef->root->abort = true; | | |
| 219 | if (err == ErrorDivByZero) { | | |
| 220 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | | |
| 221 | buf_sprintf("function evaluation caused division by zero")); | | |
| 222 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | | |
| 223 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here")); | | |
| 224 | } else if (err == ErrorOverflow) { | | |
| 225 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | | |
| 226 | buf_sprintf("function evaluation caused overflow")); | | |
| 227 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | | |
| 228 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); | | |
| 229 | } else { | | |
| 230 | zig_unreachable(); | | |
| 231 | } | | |
| 232 | return true; | | |
| 233 | } | | |
| 234 | return false; | | |
| 235 | } | | |
| 236 | | | |
| 237 | int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | 155 | int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 238 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) | 156 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) |
| 239 | { | 157 | { |
| ... | @@ -375,249 +293,6 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ... | @@ -375,249 +293,6 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 375 | zig_unreachable(); | 293 | zig_unreachable(); |
| 376 | } | 294 | } |
| 377 | | 295 | |
| 378 | static EvalVar *find_var(EvalFn *ef, Buf *name) { | | |
| 379 | size_t scope_index = ef->scope_stack.length - 1; | | |
| 380 | while (scope_index != SIZE_MAX) { | | |
| 381 | EvalScope *scope = ef->scope_stack.at(scope_index); | | |
| 382 | for (size_t var_i = 0; var_i < scope->vars.length; var_i += 1) { | | |
| 383 | EvalVar *var = &scope->vars.at(var_i); | | |
| 384 | if (buf_eql_buf(var->name, name)) { | | |
| 385 | return var; | | |
| 386 | } | | |
| 387 | } | | |
| 388 | scope_index -= 1; | | |
| 389 | } | | |
| 390 | | | |
| 391 | return nullptr; | | |
| 392 | } | | |
| 393 | | | |
| 394 | static bool eval_get_lvalue(EvalFn *ef, AstNode *node, ConstExprValue **lvalue) { | | |
| 395 | if (node->type == NodeTypeSymbol) { | | |
| 396 | Buf *name = node->data.symbol_expr.symbol; | | |
| 397 | EvalVar *var = find_var(ef, name); | | |
| 398 | assert(var); | | |
| 399 | *lvalue = &var->value; | | |
| 400 | } else { | | |
| 401 | zig_panic("TODO eval other lvalue types"); | | |
| 402 | } | | |
| 403 | return false; | | |
| 404 | } | | |
| 405 | | | |
| 406 | static bool eval_bin_op_assign(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 407 | AstNode *op1 = node->data.bin_op_expr.op1; | | |
| 408 | AstNode *op2 = node->data.bin_op_expr.op2; | | |
| 409 | BinOpType bin_op = node->data.bin_op_expr.bin_op; | | |
| 410 | | | |
| 411 | TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; | | |
| 412 | assert(op2_type); | | |
| 413 | | | |
| 414 | ConstExprValue *assign_result_val; | | |
| 415 | if (eval_get_lvalue(ef, op1, &assign_result_val)) return true; | | |
| 416 | | | |
| 417 | ConstExprValue op1_val = *assign_result_val; | | |
| 418 | | | |
| 419 | ConstExprValue op2_val = {0}; | | |
| 420 | if (eval_expr(ef, op2, &op2_val)) return true; | | |
| 421 | | | |
| 422 | if (eval_const_expr_bin_op_handle_errors(ef, node, &op1_val, op2_type, bin_op, &op2_val, op2_type, | | |
| 423 | assign_result_val)) | | |
| 424 | { | | |
| 425 | return true; | | |
| 426 | } | | |
| 427 | | | |
| 428 | out_val->ok = true; | | |
| 429 | out_val->depends_on_compile_var = false; | | |
| 430 | return false; | | |
| 431 | } | | |
| 432 | | | |
| 433 | static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 434 | assert(node->type == NodeTypeBinOpExpr); | | |
| 435 | | | |
| 436 | BinOpType bin_op = node->data.bin_op_expr.bin_op; | | |
| 437 | | | |
| 438 | switch (bin_op) { | | |
| 439 | case BinOpTypeAssign: | | |
| 440 | case BinOpTypeAssignTimes: | | |
| 441 | case BinOpTypeAssignTimesWrap: | | |
| 442 | case BinOpTypeAssignDiv: | | |
| 443 | case BinOpTypeAssignMod: | | |
| 444 | case BinOpTypeAssignPlus: | | |
| 445 | case BinOpTypeAssignPlusWrap: | | |
| 446 | case BinOpTypeAssignMinus: | | |
| 447 | case BinOpTypeAssignMinusWrap: | | |
| 448 | case BinOpTypeAssignBitShiftLeft: | | |
| 449 | case BinOpTypeAssignBitShiftLeftWrap: | | |
| 450 | case BinOpTypeAssignBitShiftRight: | | |
| 451 | case BinOpTypeAssignBitAnd: | | |
| 452 | case BinOpTypeAssignBitXor: | | |
| 453 | case BinOpTypeAssignBitOr: | | |
| 454 | case BinOpTypeAssignBoolAnd: | | |
| 455 | case BinOpTypeAssignBoolOr: | | |
| 456 | return eval_bin_op_assign(ef, node, out_val); | | |
| 457 | case BinOpTypeBoolOr: | | |
| 458 | case BinOpTypeBoolAnd: | | |
| 459 | case BinOpTypeCmpEq: | | |
| 460 | case BinOpTypeCmpNotEq: | | |
| 461 | case BinOpTypeCmpLessThan: | | |
| 462 | case BinOpTypeCmpGreaterThan: | | |
| 463 | case BinOpTypeCmpLessOrEq: | | |
| 464 | case BinOpTypeCmpGreaterOrEq: | | |
| 465 | case BinOpTypeBinOr: | | |
| 466 | case BinOpTypeBinXor: | | |
| 467 | case BinOpTypeBinAnd: | | |
| 468 | case BinOpTypeBitShiftLeft: | | |
| 469 | case BinOpTypeBitShiftLeftWrap: | | |
| 470 | case BinOpTypeBitShiftRight: | | |
| 471 | case BinOpTypeAdd: | | |
| 472 | case BinOpTypeAddWrap: | | |
| 473 | case BinOpTypeSub: | | |
| 474 | case BinOpTypeSubWrap: | | |
| 475 | case BinOpTypeMult: | | |
| 476 | case BinOpTypeMultWrap: | | |
| 477 | case BinOpTypeDiv: | | |
| 478 | case BinOpTypeMod: | | |
| 479 | case BinOpTypeUnwrapMaybe: | | |
| 480 | case BinOpTypeArrayCat: | | |
| 481 | case BinOpTypeArrayMult: | | |
| 482 | break; | | |
| 483 | case BinOpTypeInvalid: | | |
| 484 | zig_unreachable(); | | |
| 485 | } | | |
| 486 | | | |
| 487 | AstNode *op1 = node->data.bin_op_expr.op1; | | |
| 488 | AstNode *op2 = node->data.bin_op_expr.op2; | | |
| 489 | | | |
| 490 | | | |
| 491 | TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry; | | |
| 492 | TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; | | |
| 493 | | | |
| 494 | assert(op1_type); | | |
| 495 | assert(op2_type); | | |
| 496 | | | |
| 497 | ConstExprValue op1_val = {0}; | | |
| 498 | if (eval_expr(ef, op1, &op1_val)) return true; | | |
| 499 | | | |
| 500 | ConstExprValue op2_val = {0}; | | |
| 501 | if (eval_expr(ef, op2, &op2_val)) return true; | | |
| 502 | | | |
| 503 | if (eval_const_expr_bin_op_handle_errors(ef, node, &op1_val, op1_type, bin_op, &op2_val, op2_type, out_val)) { | | |
| 504 | return true; | | |
| 505 | } | | |
| 506 | | | |
| 507 | assert(out_val->ok); | | |
| 508 | | | |
| 509 | return false; | | |
| 510 | } | | |
| 511 | | | |
| 512 | static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 513 | assert(node->type == NodeTypeSymbol); | | |
| 514 | | | |
| 515 | Buf *name = node->data.symbol_expr.symbol; | | |
| 516 | EvalVar *var = find_var(ef, name); | | |
| 517 | assert(var); | | |
| 518 | | | |
| 519 | *out_val = var->value; | | |
| 520 | | | |
| 521 | return false; | | |
| 522 | } | | |
| 523 | | | |
| 524 | static TypeTableEntry *resolve_expr_type(AstNode *node) { | | |
| 525 | Expr *expr = get_resolved_expr(node); | | |
| 526 | TypeTableEntry *type_entry = expr->type_entry; | | |
| 527 | assert(type_entry->id == TypeTableEntryIdMetaType); | | |
| 528 | ConstExprValue *const_val = &expr->const_val; | | |
| 529 | assert(const_val->ok); | | |
| 530 | return const_val->data.x_type; | | |
| 531 | } | | |
| 532 | | | |
| 533 | static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 534 | assert(node->type == NodeTypeContainerInitExpr); | | |
| 535 | | | |
| 536 | AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; | | |
| 537 | ContainerInitKind kind = container_init_expr->kind; | | |
| 538 | | | |
| 539 | if (container_init_expr->enum_type) { | | |
| 540 | zig_panic("TODO eval enum init"); | | |
| 541 | } | | |
| 542 | | | |
| 543 | TypeTableEntry *container_type = resolve_expr_type(container_init_expr->type); | | |
| 544 | out_val->ok = true; | | |
| 545 | | | |
| 546 | if (container_type->id == TypeTableEntryIdStruct && | | |
| 547 | !container_type->data.structure.is_slice && | | |
| 548 | kind == ContainerInitKindStruct) | | |
| 549 | { | | |
| 550 | size_t expr_field_count = container_init_expr->entries.length; | | |
| 551 | size_t actual_field_count = container_type->data.structure.src_field_count; | | |
| 552 | assert(expr_field_count == actual_field_count); | | |
| 553 | | | |
| 554 | out_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count); | | |
| 555 | | | |
| 556 | for (size_t i = 0; i < expr_field_count; i += 1) { | | |
| 557 | AstNode *val_field_node = container_init_expr->entries.at(i); | | |
| 558 | assert(val_field_node->type == NodeTypeStructValueField); | | |
| 559 | | | |
| 560 | TypeStructField *type_field = val_field_node->data.struct_val_field.type_struct_field; | | |
| 561 | size_t field_index = type_field->src_index; | | |
| 562 | | | |
| 563 | ConstExprValue src_field_val = {0}; | | |
| 564 | if (eval_expr(ef, val_field_node->data.struct_val_field.expr, &src_field_val)) return true; | | |
| 565 | | | |
| 566 | ConstExprValue *dest_field_val = allocate<ConstExprValue>(1); | | |
| 567 | *dest_field_val = src_field_val; | | |
| 568 | | | |
| 569 | out_val->data.x_struct.fields[field_index] = dest_field_val; | | |
| 570 | out_val->depends_on_compile_var = out_val->depends_on_compile_var || | | |
| 571 | src_field_val.depends_on_compile_var; | | |
| 572 | } | | |
| 573 | } else if (container_type->id == TypeTableEntryIdVoid) { | | |
| 574 | return false; | | |
| 575 | } else if (container_type->id == TypeTableEntryIdStruct && | | |
| 576 | container_type->data.structure.is_slice && | | |
| 577 | kind == ContainerInitKindArray) | | |
| 578 | { | | |
| 579 | | | |
| 580 | size_t elem_count = container_init_expr->entries.length; | | |
| 581 | | | |
| 582 | out_val->ok = true; | | |
| 583 | out_val->data.x_array.fields = allocate<ConstExprValue*>(elem_count); | | |
| 584 | | | |
| 585 | for (size_t i = 0; i < elem_count; i += 1) { | | |
| 586 | AstNode *elem_node = container_init_expr->entries.at(i); | | |
| 587 | | | |
| 588 | ConstExprValue *elem_val = allocate<ConstExprValue>(1); | | |
| 589 | if (eval_expr(ef, elem_node, elem_val)) return true; | | |
| 590 | | | |
| 591 | assert(elem_val->ok); | | |
| 592 | | | |
| 593 | out_val->data.x_array.fields[i] = elem_val; | | |
| 594 | out_val->depends_on_compile_var = out_val->depends_on_compile_var || | | |
| 595 | elem_val->depends_on_compile_var; | | |
| 596 | } | | |
| 597 | } else { | | |
| 598 | zig_panic("TODO init more container kinds"); | | |
| 599 | } | | |
| 600 | | | |
| 601 | | | |
| 602 | return false; | | |
| 603 | } | | |
| 604 | | | |
| 605 | static bool eval_if_bool_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 606 | assert(node->type == NodeTypeIfBoolExpr); | | |
| 607 | | | |
| 608 | ConstExprValue cond_val = {0}; | | |
| 609 | if (eval_expr(ef, node->data.if_bool_expr.condition, &cond_val)) return true; | | |
| 610 | | | |
| 611 | AstNode *exec_node = cond_val.data.x_bool ? | | |
| 612 | node->data.if_bool_expr.then_block : node->data.if_bool_expr.else_node; | | |
| 613 | | | |
| 614 | if (exec_node) { | | |
| 615 | if (eval_expr(ef, exec_node, out_val)) return true; | | |
| 616 | } | | |
| 617 | out_val->ok = true; | | |
| 618 | return false; | | |
| 619 | } | | |
| 620 | | | |
| 621 | void eval_const_expr_implicit_cast(CastOp cast_op, | 296 | void eval_const_expr_implicit_cast(CastOp cast_op, |
| 622 | ConstExprValue *other_val, TypeTableEntry *other_type, | 297 | ConstExprValue *other_val, TypeTableEntry *other_type, |
| 623 | ConstExprValue *const_val, TypeTableEntry *new_type) | 298 | ConstExprValue *const_val, TypeTableEntry *new_type) |
| ... | @@ -817,685 +492,3 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * | ... | @@ -817,685 +492,3 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * |
| 817 | zig_unreachable(); | 492 | zig_unreachable(); |
| 818 | } | 493 | } |
| 819 | } | 494 | } |
| 820 | | | |
| 821 | static bool eval_min_max(EvalFn *ef, AstNode *node, ConstExprValue *out_val, bool is_max) { | | |
| 822 | assert(node->type == NodeTypeFnCallExpr); | | |
| 823 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | | |
| 824 | TypeTableEntry *type_entry = resolve_expr_type(type_node); | | |
| 825 | eval_min_max_value(ef->root->codegen, type_entry, out_val, is_max); | | |
| 826 | return false; | | |
| 827 | } | | |
| 828 | | | |
| 829 | static bool eval_div_exact(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 830 | assert(node->type == NodeTypeFnCallExpr); | | |
| 831 | AstNode *op1_node = node->data.fn_call_expr.params.at(0); | | |
| 832 | AstNode *op2_node = node->data.fn_call_expr.params.at(1); | | |
| 833 | | | |
| 834 | TypeTableEntry *type_entry = get_resolved_expr(op1_node)->type_entry; | | |
| 835 | assert(type_entry->id == TypeTableEntryIdInt); | | |
| 836 | | | |
| 837 | ConstExprValue op1_val = {0}; | | |
| 838 | if (eval_expr(ef, op1_node, &op1_val)) return true; | | |
| 839 | | | |
| 840 | ConstExprValue op2_val = {0}; | | |
| 841 | if (eval_expr(ef, op2_node, &op2_val)) return true; | | |
| 842 | | | |
| 843 | if (op2_val.data.x_bignum.data.x_uint == 0) { | | |
| 844 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | | |
| 845 | buf_sprintf("function evaluation caused division by zero")); | | |
| 846 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | | |
| 847 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here")); | | |
| 848 | return true; | | |
| 849 | } | | |
| 850 | | | |
| 851 | bignum_div(&out_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum); | | |
| 852 | | | |
| 853 | BigNum orig_bn; | | |
| 854 | bignum_mul(&orig_bn, &out_val->data.x_bignum, &op2_val.data.x_bignum); | | |
| 855 | | | |
| 856 | if (bignum_cmp_neq(&orig_bn, &op1_val.data.x_bignum)) { | | |
| 857 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | | |
| 858 | buf_sprintf("function evaluation violated exact division")); | | |
| 859 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | | |
| 860 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("exact division violation here")); | | |
| 861 | return true; | | |
| 862 | } | | |
| 863 | | | |
| 864 | out_val->ok = true; | | |
| 865 | out_val->depends_on_compile_var = op1_val.depends_on_compile_var || op2_val.depends_on_compile_var; | | |
| 866 | return false; | | |
| 867 | } | | |
| 868 | | | |
| 869 | static bool eval_unreachable(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 870 | ef->root->abort = true; | | |
| 871 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | | |
| 872 | buf_sprintf("function evaluation reached unreachable expression")); | | |
| 873 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | | |
| 874 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here")); | | |
| 875 | return true; | | |
| 876 | } | | |
| 877 | | | |
| 878 | static bool eval_fn_with_overflow(EvalFn *ef, AstNode *node, ConstExprValue *out_val, | | |
| 879 | bool (*bignum_fn)(BigNum *dest, BigNum *op1, BigNum *op2)) | | |
| 880 | { | | |
| 881 | assert(node->type == NodeTypeFnCallExpr); | | |
| 882 | | | |
| 883 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | | |
| 884 | TypeTableEntry *int_type = resolve_expr_type(type_node); | | |
| 885 | assert(int_type->id == TypeTableEntryIdInt); | | |
| 886 | | | |
| 887 | AstNode *op1_node = node->data.fn_call_expr.params.at(1); | | |
| 888 | AstNode *op2_node = node->data.fn_call_expr.params.at(2); | | |
| 889 | AstNode *result_node = node->data.fn_call_expr.params.at(3); | | |
| 890 | | | |
| 891 | ConstExprValue op1_val = {0}; | | |
| 892 | if (eval_expr(ef, op1_node, &op1_val)) return true; | | |
| 893 | | | |
| 894 | ConstExprValue op2_val = {0}; | | |
| 895 | if (eval_expr(ef, op2_node, &op2_val)) return true; | | |
| 896 | | | |
| 897 | ConstExprValue result_ptr_val = {0}; | | |
| 898 | if (eval_expr(ef, result_node, &result_ptr_val)) return true; | | |
| 899 | | | |
| 900 | ConstExprValue *result_val = result_ptr_val.data.x_ptr.ptr[0]; | | |
| 901 | | | |
| 902 | out_val->ok = true; | | |
| 903 | bool overflow = bignum_fn(&result_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum); | | |
| 904 | | | |
| 905 | overflow = overflow || !bignum_fits_in_bits(&result_val->data.x_bignum, | | |
| 906 | int_type->data.integral.bit_count, int_type->data.integral.is_signed); | | |
| 907 | | | |
| 908 | out_val->data.x_bool = overflow; | | |
| 909 | | | |
| 910 | if (overflow) { | | |
| 911 | bignum_truncate(&result_val->data.x_bignum, int_type->data.integral.bit_count); | | |
| 912 | } | | |
| 913 | | | |
| 914 | return false; | | |
| 915 | } | | |
| 916 | | | |
| 917 | static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 918 | assert(node->type == NodeTypeFnCallExpr); | | |
| 919 | | | |
| 920 | BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; | | |
| 921 | switch (builtin_fn->id) { | | |
| 922 | case BuiltinFnIdMaxValue: | | |
| 923 | return eval_min_max(ef, node, out_val, true); | | |
| 924 | case BuiltinFnIdMinValue: | | |
| 925 | return eval_min_max(ef, node, out_val, false); | | |
| 926 | case BuiltinFnIdMulWithOverflow: | | |
| 927 | return eval_fn_with_overflow(ef, node, out_val, bignum_mul); | | |
| 928 | case BuiltinFnIdAddWithOverflow: | | |
| 929 | return eval_fn_with_overflow(ef, node, out_val, bignum_add); | | |
| 930 | case BuiltinFnIdSubWithOverflow: | | |
| 931 | return eval_fn_with_overflow(ef, node, out_val, bignum_sub); | | |
| 932 | case BuiltinFnIdShlWithOverflow: | | |
| 933 | return eval_fn_with_overflow(ef, node, out_val, bignum_shl); | | |
| 934 | case BuiltinFnIdFence: | | |
| 935 | return false; | | |
| 936 | case BuiltinFnIdDivExact: | | |
| 937 | return eval_div_exact(ef, node, out_val); | | |
| 938 | case BuiltinFnIdUnreachable: | | |
| 939 | return eval_unreachable(ef, node, out_val); | | |
| 940 | case BuiltinFnIdMemcpy: | | |
| 941 | case BuiltinFnIdMemset: | | |
| 942 | case BuiltinFnIdSizeof: | | |
| 943 | case BuiltinFnIdAlignof: | | |
| 944 | case BuiltinFnIdMemberCount: | | |
| 945 | case BuiltinFnIdTypeof: | | |
| 946 | case BuiltinFnIdCInclude: | | |
| 947 | case BuiltinFnIdCDefine: | | |
| 948 | case BuiltinFnIdCUndef: | | |
| 949 | case BuiltinFnIdCompileVar: | | |
| 950 | case BuiltinFnIdConstEval: | | |
| 951 | case BuiltinFnIdCtz: | | |
| 952 | case BuiltinFnIdClz: | | |
| 953 | case BuiltinFnIdImport: | | |
| 954 | case BuiltinFnIdCImport: | | |
| 955 | case BuiltinFnIdErrName: | | |
| 956 | case BuiltinFnIdEmbedFile: | | |
| 957 | case BuiltinFnIdCmpExchange: | | |
| 958 | case BuiltinFnIdTruncate: | | |
| 959 | zig_panic("TODO builtin function"); | | |
| 960 | case BuiltinFnIdBreakpoint: | | |
| 961 | case BuiltinFnIdInvalid: | | |
| 962 | case BuiltinFnIdFrameAddress: | | |
| 963 | case BuiltinFnIdReturnAddress: | | |
| 964 | case BuiltinFnIdCompileErr: | | |
| 965 | case BuiltinFnIdIntType: | | |
| 966 | zig_unreachable(); | | |
| 967 | case BuiltinFnIdSetFnTest: | | |
| 968 | case BuiltinFnIdSetFnVisible: | | |
| 969 | case BuiltinFnIdSetFnStaticEval: | | |
| 970 | case BuiltinFnIdSetFnNoInline: | | |
| 971 | case BuiltinFnIdSetDebugSafety: | | |
| 972 | return false; | | |
| 973 | } | | |
| 974 | | | |
| 975 | return false; | | |
| 976 | } | | |
| 977 | | | |
| 978 | static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 979 | assert(node->type == NodeTypeFnCallExpr); | | |
| 980 | | | |
| 981 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | | |
| 982 | CastOp cast_op = node->data.fn_call_expr.cast_op; | | |
| 983 | if (node->data.fn_call_expr.is_builtin) { | | |
| 984 | return eval_fn_call_builtin(ef, node, out_val); | | |
| 985 | } else if (cast_op != CastOpNoCast) { | | |
| 986 | TypeTableEntry *new_type = resolve_expr_type(fn_ref_expr); | | |
| 987 | AstNode *param_node = node->data.fn_call_expr.params.at(0); | | |
| 988 | TypeTableEntry *old_type = get_resolved_expr(param_node)->type_entry; | | |
| 989 | ConstExprValue param_val = {0}; | | |
| 990 | if (eval_expr(ef, param_node, &param_val)) return true; | | |
| 991 | eval_const_expr_implicit_cast(cast_op, &param_val, old_type, out_val, new_type); | | |
| 992 | return false; | | |
| 993 | } | | |
| 994 | | | |
| 995 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; | | |
| 996 | | | |
| 997 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && | | |
| 998 | fn_ref_expr->data.field_access_expr.is_member_fn) | | |
| 999 | { | | |
| 1000 | zig_panic("TODO field access member fn"); | | |
| 1001 | } | | |
| 1002 | | | |
| 1003 | if (!fn_table_entry) { | | |
| 1004 | ConstExprValue fn_val = {0}; | | |
| 1005 | if (eval_expr(ef, fn_ref_expr, &fn_val)) return true; | | |
| 1006 | fn_table_entry = fn_val.data.x_fn; | | |
| 1007 | } | | |
| 1008 | | | |
| 1009 | size_t param_count = node->data.fn_call_expr.params.length; | | |
| 1010 | ConstExprValue *args = allocate<ConstExprValue>(param_count); | | |
| 1011 | for (size_t call_i = 0; call_i < param_count; call_i += 1) { | | |
| 1012 | AstNode *param_expr_node = node->data.fn_call_expr.params.at(call_i); | | |
| 1013 | ConstExprValue *param_val = &args[call_i]; | | |
| 1014 | if (eval_expr(ef, param_expr_node, param_val)) return true; | | |
| 1015 | } | | |
| 1016 | | | |
| 1017 | ef->root->branches_used += 1; | | |
| 1018 | | | |
| 1019 | eval_fn_args(ef->root, fn_table_entry, args, out_val); | | |
| 1020 | return false; | | |
| 1021 | } | | |
| 1022 | | | |
| 1023 | static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1024 | assert(node->type == NodeTypeFieldAccessExpr); | | |
| 1025 | | | |
| 1026 | AstNode *struct_expr = node->data.field_access_expr.struct_expr; | | |
| 1027 | TypeTableEntry *struct_type = get_resolved_expr(struct_expr)->type_entry; | | |
| 1028 | | | |
| 1029 | if (struct_type->id == TypeTableEntryIdArray) { | | |
| 1030 | Buf *name = node->data.field_access_expr.field_name; | | |
| 1031 | assert(buf_eql_str(name, "len")); | | |
| 1032 | zig_panic("TODO field access array"); | | |
| 1033 | } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && | | |
| 1034 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) | | |
| 1035 | { | | |
| 1036 | TypeStructField *tsf = node->data.field_access_expr.type_struct_field; | | |
| 1037 | assert(tsf); | | |
| 1038 | if (struct_type->id == TypeTableEntryIdStruct) { | | |
| 1039 | ConstExprValue struct_val = {0}; | | |
| 1040 | if (eval_expr(ef, struct_expr, &struct_val)) return true; | | |
| 1041 | ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; | | |
| 1042 | *out_val = *field_value; | | |
| 1043 | assert(out_val->ok); | | |
| 1044 | } else { | | |
| 1045 | zig_panic("TODO field access struct"); | | |
| 1046 | } | | |
| 1047 | } else if (struct_type->id == TypeTableEntryIdMetaType) { | | |
| 1048 | TypeTableEntry *child_type = resolve_expr_type(struct_expr); | | |
| 1049 | if (child_type->id == TypeTableEntryIdPureError) { | | |
| 1050 | *out_val = get_resolved_expr(node)->const_val; | | |
| 1051 | } else { | | |
| 1052 | zig_panic("TODO field access meta type"); | | |
| 1053 | } | | |
| 1054 | } else if (struct_type->id == TypeTableEntryIdNamespace) { | | |
| 1055 | zig_panic("TODO field access namespace"); | | |
| 1056 | } else { | | |
| 1057 | zig_unreachable(); | | |
| 1058 | } | | |
| 1059 | | | |
| 1060 | return false; | | |
| 1061 | } | | |
| 1062 | | | |
| 1063 | static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1064 | assert(node->type == NodeTypeForExpr); | | |
| 1065 | | | |
| 1066 | AstNode *array_node = node->data.for_expr.array_expr; | | |
| 1067 | AstNode *elem_node = node->data.for_expr.elem_node; | | |
| 1068 | AstNode *index_node = node->data.for_expr.index_node; | | |
| 1069 | AstNode *body_node = node->data.for_expr.body; | | |
| 1070 | | | |
| 1071 | TypeTableEntry *array_type = get_resolved_expr(array_node)->type_entry; | | |
| 1072 | | | |
| 1073 | ConstExprValue array_val = {0}; | | |
| 1074 | if (eval_expr(ef, array_node, &array_val)) return true; | | |
| 1075 | | | |
| 1076 | assert(elem_node->type == NodeTypeSymbol); | | |
| 1077 | Buf *elem_var_name = elem_node->data.symbol_expr.symbol; | | |
| 1078 | | | |
| 1079 | if (node->data.for_expr.elem_is_ptr) { | | |
| 1080 | zig_panic("TODO for elem is ptr"); | | |
| 1081 | } | | |
| 1082 | | | |
| 1083 | Buf *index_var_name = nullptr; | | |
| 1084 | if (index_node) { | | |
| 1085 | assert(index_node->type == NodeTypeSymbol); | | |
| 1086 | index_var_name = index_node->data.symbol_expr.symbol; | | |
| 1087 | } | | |
| 1088 | | | |
| 1089 | uint64_t it_index = 0; | | |
| 1090 | uint64_t array_len; | | |
| 1091 | ConstExprValue **array_ptr_val; | | |
| 1092 | if (array_type->id == TypeTableEntryIdArray) { | | |
| 1093 | array_len = array_type->data.array.len; | | |
| 1094 | array_ptr_val = array_val.data.x_array.fields; | | |
| 1095 | } else if (array_type->id == TypeTableEntryIdStruct) { | | |
| 1096 | ConstExprValue *len_field_val = array_val.data.x_struct.fields[1]; | | |
| 1097 | array_len = len_field_val->data.x_bignum.data.x_uint; | | |
| 1098 | array_ptr_val = array_val.data.x_struct.fields[0]->data.x_ptr.ptr; | | |
| 1099 | } else { | | |
| 1100 | zig_unreachable(); | | |
| 1101 | } | | |
| 1102 | | | |
| 1103 | EvalScope *my_scope = allocate<EvalScope>(1); | | |
| 1104 | my_scope->block_context = body_node->block_context; | | |
| 1105 | ef->scope_stack.append(my_scope); | | |
| 1106 | | | |
| 1107 | for (; it_index < array_len; it_index += 1) { | | |
| 1108 | my_scope->vars.resize(0); | | |
| 1109 | | | |
| 1110 | if (index_var_name) { | | |
| 1111 | my_scope->vars.add_one(); | | |
| 1112 | EvalVar *index_var = &my_scope->vars.last(); | | |
| 1113 | index_var->name = index_var_name; | | |
| 1114 | memset(&index_var->value, 0, sizeof(ConstExprValue)); | | |
| 1115 | index_var->value.ok = true; | | |
| 1116 | bignum_init_unsigned(&index_var->value.data.x_bignum, it_index); | | |
| 1117 | } | | |
| 1118 | { | | |
| 1119 | my_scope->vars.add_one(); | | |
| 1120 | EvalVar *elem_var = &my_scope->vars.last(); | | |
| 1121 | elem_var->name = elem_var_name; | | |
| 1122 | elem_var->value = *array_ptr_val[it_index]; | | |
| 1123 | } | | |
| 1124 | | | |
| 1125 | ConstExprValue body_val = {0}; | | |
| 1126 | if (eval_expr(ef, body_node, &body_val)) return true; | | |
| 1127 | | | |
| 1128 | ef->root->branches_used += 1; | | |
| 1129 | } | | |
| 1130 | | | |
| 1131 | ef->scope_stack.pop(); | | |
| 1132 | | | |
| 1133 | return false; | | |
| 1134 | } | | |
| 1135 | | | |
| 1136 | static bool eval_array_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1137 | assert(node->type == NodeTypeArrayAccessExpr); | | |
| 1138 | | | |
| 1139 | AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; | | |
| 1140 | AstNode *index_node = node->data.array_access_expr.subscript; | | |
| 1141 | | | |
| 1142 | TypeTableEntry *array_type = get_resolved_expr(array_ref_node)->type_entry; | | |
| 1143 | | | |
| 1144 | ConstExprValue array_val = {0}; | | |
| 1145 | if (eval_expr(ef, array_ref_node, &array_val)) return true; | | |
| 1146 | | | |
| 1147 | ConstExprValue index_val = {0}; | | |
| 1148 | if (eval_expr(ef, index_node, &index_val)) return true; | | |
| 1149 | uint64_t index_int = index_val.data.x_bignum.data.x_uint; | | |
| 1150 | | | |
| 1151 | if (array_type->id == TypeTableEntryIdPointer) { | | |
| 1152 | if (index_int >= array_val.data.x_ptr.len) { | | |
| 1153 | zig_panic("TODO array access pointer"); | | |
| 1154 | } | | |
| 1155 | *out_val = *array_val.data.x_ptr.ptr[index_int]; | | |
| 1156 | } else if (array_type->id == TypeTableEntryIdStruct) { | | |
| 1157 | assert(array_type->data.structure.is_slice); | | |
| 1158 | | | |
| 1159 | ConstExprValue *len_value = array_val.data.x_struct.fields[1]; | | |
| 1160 | uint64_t len_int = len_value->data.x_bignum.data.x_uint; | | |
| 1161 | if (index_int >= len_int) { | | |
| 1162 | zig_panic("TODO array access slice"); | | |
| 1163 | } | | |
| 1164 | | | |
| 1165 | ConstExprValue *ptr_value = array_val.data.x_struct.fields[0]; | | |
| 1166 | *out_val = *ptr_value->data.x_ptr.ptr[index_int]; | | |
| 1167 | } else if (array_type->id == TypeTableEntryIdArray) { | | |
| 1168 | uint64_t array_len = array_type->data.array.len; | | |
| 1169 | if (index_int >= array_len) { | | |
| 1170 | zig_panic("TODO array access array"); | | |
| 1171 | } | | |
| 1172 | *out_val = *array_val.data.x_array.fields[index_int]; | | |
| 1173 | } else { | | |
| 1174 | zig_unreachable(); | | |
| 1175 | } | | |
| 1176 | | | |
| 1177 | return false; | | |
| 1178 | } | | |
| 1179 | | | |
| 1180 | static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1181 | assert(node->type == NodeTypeBoolLiteral); | | |
| 1182 | | | |
| 1183 | out_val->ok = true; | | |
| 1184 | out_val->data.x_bool = node->data.bool_literal.value; | | |
| 1185 | | | |
| 1186 | return false; | | |
| 1187 | } | | |
| 1188 | | | |
| 1189 | static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1190 | assert(node->type == NodeTypePrefixOpExpr); | | |
| 1191 | | | |
| 1192 | PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; | | |
| 1193 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; | | |
| 1194 | | | |
| 1195 | ConstExprValue expr_val = {0}; | | |
| 1196 | if (eval_expr(ef, expr_node, &expr_val)) return true; | | |
| 1197 | | | |
| 1198 | TypeTableEntry *expr_type = get_resolved_expr(expr_node)->type_entry; | | |
| 1199 | | | |
| 1200 | switch (prefix_op) { | | |
| 1201 | case PrefixOpBoolNot: | | |
| 1202 | *out_val = expr_val; | | |
| 1203 | out_val->data.x_bool = !out_val->data.x_bool; | | |
| 1204 | break; | | |
| 1205 | case PrefixOpDereference: | | |
| 1206 | assert(expr_type->id == TypeTableEntryIdPointer); | | |
| 1207 | *out_val = *expr_val.data.x_ptr.ptr[0]; | | |
| 1208 | break; | | |
| 1209 | case PrefixOpAddressOf: | | |
| 1210 | case PrefixOpConstAddressOf: | | |
| 1211 | { | | |
| 1212 | ConstExprValue *child_val = allocate<ConstExprValue>(1); | | |
| 1213 | *child_val = expr_val; | | |
| 1214 | | | |
| 1215 | ConstExprValue **ptr_val = allocate<ConstExprValue*>(1); | | |
| 1216 | *ptr_val = child_val; | | |
| 1217 | | | |
| 1218 | out_val->data.x_ptr.ptr = ptr_val; | | |
| 1219 | out_val->data.x_ptr.len = 1; | | |
| 1220 | out_val->ok = true; | | |
| 1221 | break; | | |
| 1222 | } | | |
| 1223 | case PrefixOpNegation: | | |
| 1224 | case PrefixOpNegationWrap: | | |
| 1225 | if (expr_type->id == TypeTableEntryIdInt) { | | |
| 1226 | assert(expr_type->data.integral.is_signed); | | |
| 1227 | bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum); | | |
| 1228 | out_val->ok = true; | | |
| 1229 | bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, | | |
| 1230 | expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); | | |
| 1231 | if (prefix_op == PrefixOpNegationWrap) { | | |
| 1232 | if (overflow) { | | |
| 1233 | out_val->data.x_bignum.is_negative = true; | | |
| 1234 | } | | |
| 1235 | } else if (overflow) { | | |
| 1236 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | | |
| 1237 | buf_sprintf("function evaluation caused overflow")); | | |
| 1238 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | | |
| 1239 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); | | |
| 1240 | return true; | | |
| 1241 | } | | |
| 1242 | } else if (expr_type->id == TypeTableEntryIdFloat) { | | |
| 1243 | zig_panic("TODO prefix op on floats"); | | |
| 1244 | } else { | | |
| 1245 | zig_unreachable(); | | |
| 1246 | } | | |
| 1247 | break; | | |
| 1248 | case PrefixOpBinNot: | | |
| 1249 | case PrefixOpMaybe: | | |
| 1250 | case PrefixOpError: | | |
| 1251 | case PrefixOpUnwrapError: | | |
| 1252 | case PrefixOpUnwrapMaybe: | | |
| 1253 | zig_panic("TODO more prefix operations"); | | |
| 1254 | case PrefixOpInvalid: | | |
| 1255 | zig_unreachable(); | | |
| 1256 | } | | |
| 1257 | | | |
| 1258 | return false; | | |
| 1259 | } | | |
| 1260 | | | |
| 1261 | static bool eval_var_decl_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1262 | assert(node->type == NodeTypeVariableDeclaration); | | |
| 1263 | | | |
| 1264 | assert(node->data.variable_declaration.expr); | | |
| 1265 | | | |
| 1266 | EvalScope *my_scope = ef->scope_stack.at(ef->scope_stack.length - 1); | | |
| 1267 | | | |
| 1268 | my_scope->vars.add_one(); | | |
| 1269 | EvalVar *var = &my_scope->vars.last(); | | |
| 1270 | var->name = node->data.variable_declaration.symbol; | | |
| 1271 | | | |
| 1272 | if (eval_expr(ef, node->data.variable_declaration.expr, &var->value)) return true; | | |
| 1273 | | | |
| 1274 | out_val->ok = true; | | |
| 1275 | | | |
| 1276 | return false; | | |
| 1277 | } | | |
| 1278 | | | |
| 1279 | static bool eval_number_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1280 | assert(node->type == NodeTypeNumberLiteral); | | |
| 1281 | assert(!node->data.number_literal.overflow); | | |
| 1282 | | | |
| 1283 | out_val->ok = true; | | |
| 1284 | bignum_init_bignum(&out_val->data.x_bignum, node->data.number_literal.bignum); | | |
| 1285 | | | |
| 1286 | return false; | | |
| 1287 | } | | |
| 1288 | | | |
| 1289 | static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1290 | assert(node->type == NodeTypeCharLiteral); | | |
| 1291 | | | |
| 1292 | out_val->ok = true; | | |
| 1293 | bignum_init_unsigned(&out_val->data.x_bignum, node->data.char_literal.value); | | |
| 1294 | | | |
| 1295 | return false; | | |
| 1296 | } | | |
| 1297 | | | |
| 1298 | static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | | |
| 1299 | assert(node->type == NodeTypeWhileExpr); | | |
| 1300 | | | |
| 1301 | AstNode *cond_node = node->data.while_expr.condition; | | |
| 1302 | AstNode *body_node = node->data.while_expr.body; | | |
| 1303 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; | | |
| 1304 | | | |
| 1305 | EvalScope *my_scope = allocate<EvalScope>(1); | | |
| 1306 | my_scope->block_context = body_node->block_context; | | |
| 1307 | ef->scope_stack.append(my_scope); | | |
| 1308 | | | |
| 1309 | for (;;) { | | |
| 1310 | my_scope->vars.resize(0); | | |
| 1311 | | | |
| 1312 | ConstExprValue cond_val = {0}; | | |
| 1313 | if (eval_expr(ef, cond_node, &cond_val)) return true; | | |
| 1314 | | | |
| 1315 | if (!cond_val.data.x_bool) break; | | |
| 1316 | | | |
| 1317 | ConstExprValue body_val = {0}; | | |
| 1318 | if (eval_expr(ef, body_node, &body_val)) return true; | | |
| 1319 | | | |
| 1320 | if (continue_expr_node) { | | |
| 1321 | ConstExprValue continue_expr_val = {0}; | | |
| 1322 | if (eval_expr(ef, continue_expr_node, &continue_expr_val)) return true; | | |
| 1323 | } | | |
| 1324 | | | |
| 1325 | ef->root->branches_used += 1; | | |
| 1326 | } | | |
| 1327 | | | |
| 1328 | ef->scope_stack.pop(); | | |
| 1329 | | | |
| 1330 | return false; | | |
| 1331 | } | | |
| 1332 | | | |
| 1333 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | | |
| 1334 | if (ef->root->branches_used > ef->root->branch_quota) { | | |
| 1335 | ef->root->exceeded_quota_node = node; | | |
| 1336 | return true; | | |
| 1337 | } | | |
| 1338 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | | |
| 1339 | if (const_val->ok) { | | |
| 1340 | *out = *const_val; | | |
| 1341 | return false; | | |
| 1342 | } | | |
| 1343 | switch (node->type) { | | |
| 1344 | case NodeTypeBlock: | | |
| 1345 | return eval_block(ef, node, out); | | |
| 1346 | case NodeTypeReturnExpr: | | |
| 1347 | return eval_return(ef, node, out); | | |
| 1348 | case NodeTypeBinOpExpr: | | |
| 1349 | return eval_bin_op_expr(ef, node, out); | | |
| 1350 | case NodeTypeSymbol: | | |
| 1351 | return eval_symbol_expr(ef, node, out); | | |
| 1352 | case NodeTypeContainerInitExpr: | | |
| 1353 | return eval_container_init_expr(ef, node, out); | | |
| 1354 | case NodeTypeIfBoolExpr: | | |
| 1355 | return eval_if_bool_expr(ef, node, out); | | |
| 1356 | case NodeTypeFnCallExpr: | | |
| 1357 | return eval_fn_call_expr(ef, node, out); | | |
| 1358 | case NodeTypeFieldAccessExpr: | | |
| 1359 | return eval_field_access_expr(ef, node, out); | | |
| 1360 | case NodeTypeForExpr: | | |
| 1361 | return eval_for_expr(ef, node, out); | | |
| 1362 | case NodeTypeArrayAccessExpr: | | |
| 1363 | return eval_array_access_expr(ef, node, out); | | |
| 1364 | case NodeTypeBoolLiteral: | | |
| 1365 | return eval_bool_literal_expr(ef, node, out); | | |
| 1366 | case NodeTypePrefixOpExpr: | | |
| 1367 | return eval_prefix_op_expr(ef, node, out); | | |
| 1368 | case NodeTypeVariableDeclaration: | | |
| 1369 | return eval_var_decl_expr(ef, node, out); | | |
| 1370 | case NodeTypeNumberLiteral: | | |
| 1371 | return eval_number_literal_expr(ef, node, out); | | |
| 1372 | case NodeTypeCharLiteral: | | |
| 1373 | return eval_char_literal_expr(ef, node, out); | | |
| 1374 | case NodeTypeWhileExpr: | | |
| 1375 | return eval_while_expr(ef, node, out); | | |
| 1376 | case NodeTypeDefer: | | |
| 1377 | case NodeTypeErrorValueDecl: | | |
| 1378 | case NodeTypeUnwrapErrorExpr: | | |
| 1379 | case NodeTypeStringLiteral: | | |
| 1380 | case NodeTypeSliceExpr: | | |
| 1381 | case NodeTypeNullLiteral: | | |
| 1382 | case NodeTypeUndefinedLiteral: | | |
| 1383 | case NodeTypeZeroesLiteral: | | |
| 1384 | case NodeTypeThisLiteral: | | |
| 1385 | case NodeTypeIfVarExpr: | | |
| 1386 | case NodeTypeSwitchExpr: | | |
| 1387 | case NodeTypeSwitchProng: | | |
| 1388 | case NodeTypeSwitchRange: | | |
| 1389 | case NodeTypeLabel: | | |
| 1390 | case NodeTypeGoto: | | |
| 1391 | case NodeTypeBreak: | | |
| 1392 | case NodeTypeContinue: | | |
| 1393 | case NodeTypeContainerDecl: | | |
| 1394 | case NodeTypeStructField: | | |
| 1395 | case NodeTypeStructValueField: | | |
| 1396 | case NodeTypeArrayType: | | |
| 1397 | case NodeTypeErrorType: | | |
| 1398 | case NodeTypeTypeLiteral: | | |
| 1399 | case NodeTypeVarLiteral: | | |
| 1400 | zig_panic("TODO expr node"); | | |
| 1401 | case NodeTypeRoot: | | |
| 1402 | case NodeTypeFnProto: | | |
| 1403 | case NodeTypeFnDef: | | |
| 1404 | case NodeTypeFnDecl: | | |
| 1405 | case NodeTypeUse: | | |
| 1406 | case NodeTypeAsmExpr: | | |
| 1407 | case NodeTypeParamDecl: | | |
| 1408 | case NodeTypeTypeDecl: | | |
| 1409 | zig_unreachable(); | | |
| 1410 | } | | |
| 1411 | zig_unreachable(); | | |
| 1412 | } | | |
| 1413 | | | |
| 1414 | static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) { | | |
| 1415 | AstNode *acting_proto_node; | | |
| 1416 | if (fn->proto_node->data.fn_proto.generic_proto_node) { | | |
| 1417 | acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node; | | |
| 1418 | } else { | | |
| 1419 | acting_proto_node = fn->proto_node; | | |
| 1420 | } | | |
| 1421 | | | |
| 1422 | EvalFn ef = {0}; | | |
| 1423 | ef.root = efr; | | |
| 1424 | ef.fn = fn; | | |
| 1425 | ef.return_expr = out_val; | | |
| 1426 | | | |
| 1427 | EvalScope *root_scope = allocate<EvalScope>(1); | | |
| 1428 | root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context; | | |
| 1429 | ef.scope_stack.append(root_scope); | | |
| 1430 | | | |
| 1431 | size_t param_count = acting_proto_node->data.fn_proto.params.length; | | |
| 1432 | for (size_t proto_i = 0; proto_i < param_count; proto_i += 1) { | | |
| 1433 | AstNode *decl_param_node = acting_proto_node->data.fn_proto.params.at(proto_i); | | |
| 1434 | assert(decl_param_node->type == NodeTypeParamDecl); | | |
| 1435 | | | |
| 1436 | ConstExprValue *src_const_val = &args[proto_i]; | | |
| 1437 | assert(src_const_val->ok); | | |
| 1438 | | | |
| 1439 | root_scope->vars.add_one(); | | |
| 1440 | EvalVar *eval_var = &root_scope->vars.last(); | | |
| 1441 | eval_var->name = decl_param_node->data.param_decl.name; | | |
| 1442 | eval_var->value = *src_const_val; | | |
| 1443 | } | | |
| 1444 | | | |
| 1445 | return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val); | | |
| 1446 | } | | |
| 1447 | | | |
| 1448 | bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val, | | |
| 1449 | size_t branch_quota, AstNode *struct_node) | | |
| 1450 | { | | |
| 1451 | assert(node->type == NodeTypeFnCallExpr); | | |
| 1452 | | | |
| 1453 | EvalFnRoot efr = {0}; | | |
| 1454 | efr.codegen = g; | | |
| 1455 | efr.fn = fn; | | |
| 1456 | efr.call_node = node; | | |
| 1457 | efr.branch_quota = branch_quota; | | |
| 1458 | | | |
| 1459 | AstNode *acting_proto_node; | | |
| 1460 | if (fn->proto_node->data.fn_proto.generic_proto_node) { | | |
| 1461 | acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node; | | |
| 1462 | } else { | | |
| 1463 | acting_proto_node = fn->proto_node; | | |
| 1464 | } | | |
| 1465 | | | |
| 1466 | size_t call_param_count = node->data.fn_call_expr.params.length; | | |
| 1467 | size_t proto_param_count = acting_proto_node->data.fn_proto.params.length; | | |
| 1468 | ConstExprValue *args = allocate<ConstExprValue>(proto_param_count); | | |
| 1469 | size_t next_arg_index = 0; | | |
| 1470 | if (struct_node) { | | |
| 1471 | ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val; | | |
| 1472 | assert(struct_val->ok); | | |
| 1473 | args[next_arg_index] = *struct_val; | | |
| 1474 | next_arg_index += 1; | | |
| 1475 | } | | |
| 1476 | for (size_t call_index = 0; call_index < call_param_count; call_index += 1) { | | |
| 1477 | AstNode *call_param_node = node->data.fn_call_expr.params.at(call_index); | | |
| 1478 | ConstExprValue *src_const_val = &get_resolved_expr(call_param_node)->const_val; | | |
| 1479 | assert(src_const_val->ok); | | |
| 1480 | args[next_arg_index] = *src_const_val; | | |
| 1481 | next_arg_index += 1; | | |
| 1482 | } | | |
| 1483 | eval_fn_args(&efr, fn, args, out_val); | | |
| 1484 | | | |
| 1485 | if (efr.exceeded_quota_node) { | | |
| 1486 | ErrorMsg *msg = add_node_error(g, fn->fn_def_node, | | |
| 1487 | buf_sprintf("function evaluation exceeded %zu branches", efr.branch_quota)); | | |
| 1488 | | | |
| 1489 | add_error_note(g, msg, efr.call_node, buf_sprintf("called from here")); | | |
| 1490 | add_error_note(g, msg, efr.exceeded_quota_node, buf_sprintf("quota exceeded here")); | | |
| 1491 | return true; | | |
| 1492 | } | | |
| 1493 | | | |
| 1494 | if (efr.abort) { | | |
| 1495 | return true; | | |
| 1496 | } | | |
| 1497 | | | |
| 1498 | assert(out_val->ok); | | |
| 1499 | return false; | | |
| 1500 | } | | |
| 1501 | | | |