| ... | ... | @@ -327,6 +327,13 @@ static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue * |
| 327 | 327 | } |
| 328 | 328 | } else if (container_type->id == TypeTableEntryIdVoid) { |
| 329 | 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 | 337 | } else { |
| 331 | 338 | zig_panic("TODO"); |
| 332 | 339 | } |
| ... | ... | @@ -472,6 +479,194 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val |
| 472 | 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 | 670 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 476 | 671 | if (ef->root->branches_used > ef->root->branch_quota) { |
| 477 | 672 | ef->root->exceeded_quota_node = node; |
| ... | ... | @@ -492,6 +687,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 492 | 687 | return eval_if_bool_expr(ef, node, out); |
| 493 | 688 | case NodeTypeFnCallExpr: |
| 494 | 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 | 700 | case NodeTypeRoot: |
| 496 | 701 | case NodeTypeFnProto: |
| 497 | 702 | case NodeTypeFnDef: |
| ... | ... | @@ -506,17 +711,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 506 | 711 | case NodeTypeNumberLiteral: |
| 507 | 712 | case NodeTypeStringLiteral: |
| 508 | 713 | case NodeTypeCharLiteral: |
| 509 | | case NodeTypePrefixOpExpr: |
| 510 | | case NodeTypeArrayAccessExpr: |
| 511 | 714 | case NodeTypeSliceExpr: |
| 512 | | case NodeTypeFieldAccessExpr: |
| 513 | 715 | case NodeTypeUse: |
| 514 | | case NodeTypeBoolLiteral: |
| 515 | 716 | case NodeTypeNullLiteral: |
| 516 | 717 | case NodeTypeUndefinedLiteral: |
| 517 | 718 | case NodeTypeIfVarExpr: |
| 518 | 719 | case NodeTypeWhileExpr: |
| 519 | | case NodeTypeForExpr: |
| 520 | 720 | case NodeTypeSwitchExpr: |
| 521 | 721 | case NodeTypeSwitchProng: |
| 522 | 722 | case NodeTypeSwitchRange: |
| ... | ... | @@ -602,6 +802,6 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va |
| 602 | 802 | return true; |
| 603 | 803 | } |
| 604 | 804 | |
| 605 | | return false; |
| 805 | return efr.abort; |
| 606 | 806 | } |
| 607 | 807 | |