| ... | @@ -327,6 +327,13 @@ static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue * | ... | @@ -327,6 +327,13 @@ static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue * |
| 327 | } | 327 | } |
| 328 | } else if (container_type->id == TypeTableEntryIdVoid) { | 328 | } else if (container_type->id == TypeTableEntryIdVoid) { |
| 329 | return false; | 329 | return false; |
| | 330 | } else if (container_type->id == TypeTableEntryIdUnreachable) { |
| | 331 | ef->root->abort = true; |
| | 332 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, |
| | 333 | buf_sprintf("function evaluation reached unreachable expression")); |
| | 334 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); |
| | 335 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here")); |
| | 336 | return true; |
| 330 | } else { | 337 | } else { |
| 331 | zig_panic("TODO"); | 338 | zig_panic("TODO"); |
| 332 | } | 339 | } |
| ... | @@ -472,6 +479,194 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val | ... | @@ -472,6 +479,194 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val |
| 472 | return false; | 479 | return false; |
| 473 | } | 480 | } |
| 474 | | 481 | |
| | 482 | static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { |
| | 483 | assert(node->type == NodeTypeFieldAccessExpr); |
| | 484 | |
| | 485 | AstNode *struct_expr = node->data.field_access_expr.struct_expr; |
| | 486 | TypeTableEntry *struct_type = get_resolved_expr(struct_expr)->type_entry; |
| | 487 | |
| | 488 | if (struct_type->id == TypeTableEntryIdArray) { |
| | 489 | Buf *name = &node->data.field_access_expr.field_name; |
| | 490 | assert(buf_eql_str(name, "len")); |
| | 491 | zig_panic("TODO"); |
| | 492 | } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && |
| | 493 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) |
| | 494 | { |
| | 495 | TypeStructField *tsf = node->data.field_access_expr.type_struct_field; |
| | 496 | assert(tsf); |
| | 497 | if (struct_type->id == TypeTableEntryIdStruct) { |
| | 498 | ConstExprValue struct_val = {0}; |
| | 499 | if (eval_expr(ef, struct_expr, &struct_val)) return true; |
| | 500 | ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; |
| | 501 | *out_val = *field_value; |
| | 502 | } else { |
| | 503 | zig_panic("TODO"); |
| | 504 | } |
| | 505 | } else if (struct_type->id == TypeTableEntryIdMetaType) { |
| | 506 | zig_panic("TODO"); |
| | 507 | } else if (struct_type->id == TypeTableEntryIdNamespace) { |
| | 508 | zig_panic("TODO"); |
| | 509 | } else { |
| | 510 | zig_unreachable(); |
| | 511 | } |
| | 512 | |
| | 513 | return false; |
| | 514 | } |
| | 515 | |
| | 516 | static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { |
| | 517 | assert(node->type == NodeTypeForExpr); |
| | 518 | |
| | 519 | AstNode *array_node = node->data.for_expr.array_expr; |
| | 520 | AstNode *elem_node = node->data.for_expr.elem_node; |
| | 521 | AstNode *index_node = node->data.for_expr.index_node; |
| | 522 | AstNode *body_node = node->data.for_expr.body; |
| | 523 | |
| | 524 | TypeTableEntry *array_type = get_resolved_expr(array_node)->type_entry; |
| | 525 | |
| | 526 | ConstExprValue array_val = {0}; |
| | 527 | if (eval_expr(ef, array_node, &array_val)) return true; |
| | 528 | |
| | 529 | assert(elem_node->type == NodeTypeSymbol); |
| | 530 | Buf *elem_var_name = &elem_node->data.symbol_expr.symbol; |
| | 531 | |
| | 532 | Buf *index_var_name = nullptr; |
| | 533 | if (index_node) { |
| | 534 | assert(index_node->type == NodeTypeSymbol); |
| | 535 | index_var_name = &index_node->data.symbol_expr.symbol; |
| | 536 | } |
| | 537 | |
| | 538 | uint64_t it_index = 0; |
| | 539 | uint64_t array_len; |
| | 540 | ConstExprValue **array_ptr_val; |
| | 541 | if (array_type->id == TypeTableEntryIdArray) { |
| | 542 | array_len = array_type->data.array.len; |
| | 543 | array_ptr_val = array_val.data.x_array.fields; |
| | 544 | } else if (array_type->id == TypeTableEntryIdStruct) { |
| | 545 | ConstExprValue *len_field_val = array_val.data.x_struct.fields[1]; |
| | 546 | array_len = len_field_val->data.x_bignum.data.x_uint; |
| | 547 | array_ptr_val = array_val.data.x_struct.fields[0]->data.x_ptr.ptr; |
| | 548 | } else { |
| | 549 | zig_unreachable(); |
| | 550 | } |
| | 551 | |
| | 552 | EvalScope *my_scope = allocate<EvalScope>(1); |
| | 553 | my_scope->block_context = body_node->block_context; |
| | 554 | ef->scope_stack.append(my_scope); |
| | 555 | |
| | 556 | for (; it_index < array_len; it_index += 1) { |
| | 557 | my_scope->vars.resize(0); |
| | 558 | |
| | 559 | if (index_var_name) { |
| | 560 | my_scope->vars.add_one(); |
| | 561 | EvalVar *index_var = &my_scope->vars.last(); |
| | 562 | index_var->name = index_var_name; |
| | 563 | memset(&index_var->value, 0, sizeof(ConstExprValue)); |
| | 564 | index_var->value.ok = true; |
| | 565 | bignum_init_unsigned(&index_var->value.data.x_bignum, it_index); |
| | 566 | } |
| | 567 | { |
| | 568 | my_scope->vars.add_one(); |
| | 569 | EvalVar *elem_var = &my_scope->vars.last(); |
| | 570 | elem_var->name = elem_var_name; |
| | 571 | elem_var->value = *array_ptr_val[it_index]; |
| | 572 | } |
| | 573 | |
| | 574 | ConstExprValue body_val = {0}; |
| | 575 | if (eval_expr(ef, body_node, &body_val)) return true; |
| | 576 | |
| | 577 | ef->root->branches_used += 1; |
| | 578 | } |
| | 579 | |
| | 580 | ef->scope_stack.pop(); |
| | 581 | |
| | 582 | return false; |
| | 583 | } |
| | 584 | |
| | 585 | static bool eval_array_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { |
| | 586 | assert(node->type == NodeTypeArrayAccessExpr); |
| | 587 | |
| | 588 | AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; |
| | 589 | AstNode *index_node = node->data.array_access_expr.subscript; |
| | 590 | |
| | 591 | TypeTableEntry *array_type = get_resolved_expr(array_ref_node)->type_entry; |
| | 592 | |
| | 593 | ConstExprValue array_val = {0}; |
| | 594 | if (eval_expr(ef, array_ref_node, &array_val)) return true; |
| | 595 | |
| | 596 | ConstExprValue index_val = {0}; |
| | 597 | if (eval_expr(ef, index_node, &index_val)) return true; |
| | 598 | uint64_t index_int = index_val.data.x_bignum.data.x_uint; |
| | 599 | |
| | 600 | if (array_type->id == TypeTableEntryIdPointer) { |
| | 601 | if (index_int >= array_val.data.x_ptr.len) { |
| | 602 | zig_panic("TODO"); |
| | 603 | } |
| | 604 | *out_val = *array_val.data.x_ptr.ptr[index_int]; |
| | 605 | } else if (array_type->id == TypeTableEntryIdStruct) { |
| | 606 | assert(array_type->data.structure.is_unknown_size_array); |
| | 607 | |
| | 608 | ConstExprValue *len_value = array_val.data.x_struct.fields[1]; |
| | 609 | uint64_t len_int = len_value->data.x_bignum.data.x_uint; |
| | 610 | if (index_int >= len_int) { |
| | 611 | zig_panic("TODO"); |
| | 612 | } |
| | 613 | |
| | 614 | ConstExprValue *ptr_value = array_val.data.x_struct.fields[0]; |
| | 615 | *out_val = *ptr_value->data.x_ptr.ptr[index_int]; |
| | 616 | } else if (array_type->id == TypeTableEntryIdArray) { |
| | 617 | uint64_t array_len = array_type->data.array.len; |
| | 618 | if (index_int >= array_len) { |
| | 619 | zig_panic("TODO"); |
| | 620 | } |
| | 621 | *out_val = *array_val.data.x_array.fields[index_int]; |
| | 622 | } else { |
| | 623 | zig_unreachable(); |
| | 624 | } |
| | 625 | |
| | 626 | return false; |
| | 627 | } |
| | 628 | |
| | 629 | static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { |
| | 630 | assert(node->type == NodeTypeBoolLiteral); |
| | 631 | |
| | 632 | out_val->ok = true; |
| | 633 | out_val->deep_const = true; |
| | 634 | out_val->data.x_bool = node->data.bool_literal.value; |
| | 635 | |
| | 636 | return false; |
| | 637 | } |
| | 638 | |
| | 639 | static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { |
| | 640 | assert(node->type == NodeTypePrefixOpExpr); |
| | 641 | |
| | 642 | PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; |
| | 643 | |
| | 644 | ConstExprValue expr_val = {0}; |
| | 645 | if (eval_expr(ef, node->data.prefix_op_expr.primary_expr, &expr_val)) return true; |
| | 646 | |
| | 647 | switch (prefix_op) { |
| | 648 | case PrefixOpBoolNot: |
| | 649 | *out_val = expr_val; |
| | 650 | out_val->data.x_bool = !out_val->data.x_bool; |
| | 651 | break; |
| | 652 | case PrefixOpBinNot: |
| | 653 | case PrefixOpNegation: |
| | 654 | case PrefixOpAddressOf: |
| | 655 | case PrefixOpConstAddressOf: |
| | 656 | case PrefixOpDereference: |
| | 657 | case PrefixOpMaybe: |
| | 658 | case PrefixOpError: |
| | 659 | case PrefixOpUnwrapError: |
| | 660 | case PrefixOpUnwrapMaybe: |
| | 661 | zig_panic("TODO"); |
| | 662 | case PrefixOpInvalid: |
| | 663 | zig_unreachable(); |
| | 664 | } |
| | 665 | |
| | 666 | return false; |
| | 667 | } |
| | 668 | |
| | 669 | |
| 475 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | 670 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 476 | if (ef->root->branches_used > ef->root->branch_quota) { | 671 | if (ef->root->branches_used > ef->root->branch_quota) { |
| 477 | ef->root->exceeded_quota_node = node; | 672 | ef->root->exceeded_quota_node = node; |
| ... | @@ -492,6 +687,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ... | @@ -492,6 +687,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 492 | return eval_if_bool_expr(ef, node, out); | 687 | return eval_if_bool_expr(ef, node, out); |
| 493 | case NodeTypeFnCallExpr: | 688 | case NodeTypeFnCallExpr: |
| 494 | return eval_fn_call_expr(ef, node, out); | 689 | return eval_fn_call_expr(ef, node, out); |
| | 690 | case NodeTypeFieldAccessExpr: |
| | 691 | return eval_field_access_expr(ef, node, out); |
| | 692 | case NodeTypeForExpr: |
| | 693 | return eval_for_expr(ef, node, out); |
| | 694 | case NodeTypeArrayAccessExpr: |
| | 695 | return eval_array_access_expr(ef, node, out); |
| | 696 | case NodeTypeBoolLiteral: |
| | 697 | return eval_bool_literal_expr(ef, node, out); |
| | 698 | case NodeTypePrefixOpExpr: |
| | 699 | return eval_prefix_op_expr(ef, node, out); |
| 495 | case NodeTypeRoot: | 700 | case NodeTypeRoot: |
| 496 | case NodeTypeFnProto: | 701 | case NodeTypeFnProto: |
| 497 | case NodeTypeFnDef: | 702 | case NodeTypeFnDef: |
| ... | @@ -506,17 +711,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ... | @@ -506,17 +711,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 506 | case NodeTypeNumberLiteral: | 711 | case NodeTypeNumberLiteral: |
| 507 | case NodeTypeStringLiteral: | 712 | case NodeTypeStringLiteral: |
| 508 | case NodeTypeCharLiteral: | 713 | case NodeTypeCharLiteral: |
| 509 | case NodeTypePrefixOpExpr: | | |
| 510 | case NodeTypeArrayAccessExpr: | | |
| 511 | case NodeTypeSliceExpr: | 714 | case NodeTypeSliceExpr: |
| 512 | case NodeTypeFieldAccessExpr: | | |
| 513 | case NodeTypeUse: | 715 | case NodeTypeUse: |
| 514 | case NodeTypeBoolLiteral: | | |
| 515 | case NodeTypeNullLiteral: | 716 | case NodeTypeNullLiteral: |
| 516 | case NodeTypeUndefinedLiteral: | 717 | case NodeTypeUndefinedLiteral: |
| 517 | case NodeTypeIfVarExpr: | 718 | case NodeTypeIfVarExpr: |
| 518 | case NodeTypeWhileExpr: | 719 | case NodeTypeWhileExpr: |
| 519 | case NodeTypeForExpr: | | |
| 520 | case NodeTypeSwitchExpr: | 720 | case NodeTypeSwitchExpr: |
| 521 | case NodeTypeSwitchProng: | 721 | case NodeTypeSwitchProng: |
| 522 | case NodeTypeSwitchRange: | 722 | case NodeTypeSwitchRange: |
| ... | @@ -602,6 +802,6 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va | ... | @@ -602,6 +802,6 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va |
| 602 | return true; | 802 | return true; |
| 603 | } | 803 | } |
| 604 | | 804 | |
| 605 | return false; | 805 | return efr.abort; |
| 606 | } | 806 | } |
| 607 | | 807 | |