diff --git a/src/eval.cpp b/src/eval.cpp index 414bdfffb5..930b50d93a 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -2,36 +2,6 @@ #include "analyze.hpp" #include "error.hpp" -struct EvalVar { - Buf *name; - ConstExprValue value; -}; - -struct EvalScope { - BlockContext *block_context; - ZigList vars; -}; - -struct EvalFnRoot { - CodeGen *codegen; - FnTableEntry *fn; - AstNode *call_node; - size_t branch_quota; - size_t branches_used; - AstNode *exceeded_quota_node; - bool abort; -}; - -struct EvalFn { - EvalFnRoot *root; - FnTableEntry *fn; - ConstExprValue *return_expr; - ZigList scope_stack; -}; - - -static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val); - bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { switch (type_entry->id) { case TypeTableEntryIdEnum: @@ -95,33 +65,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty } -static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out); - -static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) { - assert(node->type == NodeTypeBlock); - - EvalScope *my_scope = allocate(1); - my_scope->block_context = node->block_context; - ef->scope_stack.append(my_scope); - - for (size_t i = 0; i < node->data.block.statements.length; i += 1) { - AstNode *child = node->data.block.statements.at(i); - memset(out, 0, sizeof(ConstExprValue)); - if (eval_expr(ef, child, out)) return true; - } - - ef->scope_stack.pop(); - - return false; -} - -static bool eval_return(EvalFn *ef, AstNode *node, ConstExprValue *out) { - assert(node->type == NodeTypeReturnExpr); - - eval_expr(ef, node->data.return_expr.expr, ef->return_expr); - return true; -} - static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { if (bin_op == BinOpTypeBoolOr || bin_op == BinOpTypeAssignBoolOr) { return a || b; @@ -209,31 +152,6 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue return 0; } -bool eval_const_expr_bin_op_handle_errors(EvalFn *ef, AstNode *node, - ConstExprValue *op1_val, TypeTableEntry *op1_type, - BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) -{ - int err; - if ((err = eval_const_expr_bin_op(op1_val, op1_type, bin_op, op2_val, op2_type, out_val))) { - ef->root->abort = true; - if (err == ErrorDivByZero) { - ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, - buf_sprintf("function evaluation caused division by zero")); - add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); - add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here")); - } else if (err == ErrorOverflow) { - ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, - buf_sprintf("function evaluation caused overflow")); - add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); - add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); - } else { - zig_unreachable(); - } - return true; - } - return false; -} - int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) { @@ -375,249 +293,6 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, zig_unreachable(); } -static EvalVar *find_var(EvalFn *ef, Buf *name) { - size_t scope_index = ef->scope_stack.length - 1; - while (scope_index != SIZE_MAX) { - EvalScope *scope = ef->scope_stack.at(scope_index); - for (size_t var_i = 0; var_i < scope->vars.length; var_i += 1) { - EvalVar *var = &scope->vars.at(var_i); - if (buf_eql_buf(var->name, name)) { - return var; - } - } - scope_index -= 1; - } - - return nullptr; -} - -static bool eval_get_lvalue(EvalFn *ef, AstNode *node, ConstExprValue **lvalue) { - if (node->type == NodeTypeSymbol) { - Buf *name = node->data.symbol_expr.symbol; - EvalVar *var = find_var(ef, name); - assert(var); - *lvalue = &var->value; - } else { - zig_panic("TODO eval other lvalue types"); - } - return false; -} - -static bool eval_bin_op_assign(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - AstNode *op1 = node->data.bin_op_expr.op1; - AstNode *op2 = node->data.bin_op_expr.op2; - BinOpType bin_op = node->data.bin_op_expr.bin_op; - - TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; - assert(op2_type); - - ConstExprValue *assign_result_val; - if (eval_get_lvalue(ef, op1, &assign_result_val)) return true; - - ConstExprValue op1_val = *assign_result_val; - - ConstExprValue op2_val = {0}; - if (eval_expr(ef, op2, &op2_val)) return true; - - if (eval_const_expr_bin_op_handle_errors(ef, node, &op1_val, op2_type, bin_op, &op2_val, op2_type, - assign_result_val)) - { - return true; - } - - out_val->ok = true; - out_val->depends_on_compile_var = false; - return false; -} - -static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeBinOpExpr); - - BinOpType bin_op = node->data.bin_op_expr.bin_op; - - switch (bin_op) { - case BinOpTypeAssign: - case BinOpTypeAssignTimes: - case BinOpTypeAssignTimesWrap: - case BinOpTypeAssignDiv: - case BinOpTypeAssignMod: - case BinOpTypeAssignPlus: - case BinOpTypeAssignPlusWrap: - case BinOpTypeAssignMinus: - case BinOpTypeAssignMinusWrap: - case BinOpTypeAssignBitShiftLeft: - case BinOpTypeAssignBitShiftLeftWrap: - case BinOpTypeAssignBitShiftRight: - case BinOpTypeAssignBitAnd: - case BinOpTypeAssignBitXor: - case BinOpTypeAssignBitOr: - case BinOpTypeAssignBoolAnd: - case BinOpTypeAssignBoolOr: - return eval_bin_op_assign(ef, node, out_val); - case BinOpTypeBoolOr: - case BinOpTypeBoolAnd: - case BinOpTypeCmpEq: - case BinOpTypeCmpNotEq: - case BinOpTypeCmpLessThan: - case BinOpTypeCmpGreaterThan: - case BinOpTypeCmpLessOrEq: - case BinOpTypeCmpGreaterOrEq: - case BinOpTypeBinOr: - case BinOpTypeBinXor: - case BinOpTypeBinAnd: - case BinOpTypeBitShiftLeft: - case BinOpTypeBitShiftLeftWrap: - case BinOpTypeBitShiftRight: - case BinOpTypeAdd: - case BinOpTypeAddWrap: - case BinOpTypeSub: - case BinOpTypeSubWrap: - case BinOpTypeMult: - case BinOpTypeMultWrap: - case BinOpTypeDiv: - case BinOpTypeMod: - case BinOpTypeUnwrapMaybe: - case BinOpTypeArrayCat: - case BinOpTypeArrayMult: - break; - case BinOpTypeInvalid: - zig_unreachable(); - } - - AstNode *op1 = node->data.bin_op_expr.op1; - AstNode *op2 = node->data.bin_op_expr.op2; - - - TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry; - TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; - - assert(op1_type); - assert(op2_type); - - ConstExprValue op1_val = {0}; - if (eval_expr(ef, op1, &op1_val)) return true; - - ConstExprValue op2_val = {0}; - if (eval_expr(ef, op2, &op2_val)) return true; - - if (eval_const_expr_bin_op_handle_errors(ef, node, &op1_val, op1_type, bin_op, &op2_val, op2_type, out_val)) { - return true; - } - - assert(out_val->ok); - - return false; -} - -static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeSymbol); - - Buf *name = node->data.symbol_expr.symbol; - EvalVar *var = find_var(ef, name); - assert(var); - - *out_val = var->value; - - return false; -} - -static TypeTableEntry *resolve_expr_type(AstNode *node) { - Expr *expr = get_resolved_expr(node); - TypeTableEntry *type_entry = expr->type_entry; - assert(type_entry->id == TypeTableEntryIdMetaType); - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); - return const_val->data.x_type; -} - -static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeContainerInitExpr); - - AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; - ContainerInitKind kind = container_init_expr->kind; - - if (container_init_expr->enum_type) { - zig_panic("TODO eval enum init"); - } - - TypeTableEntry *container_type = resolve_expr_type(container_init_expr->type); - out_val->ok = true; - - if (container_type->id == TypeTableEntryIdStruct && - !container_type->data.structure.is_slice && - kind == ContainerInitKindStruct) - { - size_t expr_field_count = container_init_expr->entries.length; - size_t actual_field_count = container_type->data.structure.src_field_count; - assert(expr_field_count == actual_field_count); - - out_val->data.x_struct.fields = allocate(actual_field_count); - - for (size_t i = 0; i < expr_field_count; i += 1) { - AstNode *val_field_node = container_init_expr->entries.at(i); - assert(val_field_node->type == NodeTypeStructValueField); - - TypeStructField *type_field = val_field_node->data.struct_val_field.type_struct_field; - size_t field_index = type_field->src_index; - - ConstExprValue src_field_val = {0}; - if (eval_expr(ef, val_field_node->data.struct_val_field.expr, &src_field_val)) return true; - - ConstExprValue *dest_field_val = allocate(1); - *dest_field_val = src_field_val; - - out_val->data.x_struct.fields[field_index] = dest_field_val; - out_val->depends_on_compile_var = out_val->depends_on_compile_var || - src_field_val.depends_on_compile_var; - } - } else if (container_type->id == TypeTableEntryIdVoid) { - return false; - } else if (container_type->id == TypeTableEntryIdStruct && - container_type->data.structure.is_slice && - kind == ContainerInitKindArray) - { - - size_t elem_count = container_init_expr->entries.length; - - out_val->ok = true; - out_val->data.x_array.fields = allocate(elem_count); - - for (size_t i = 0; i < elem_count; i += 1) { - AstNode *elem_node = container_init_expr->entries.at(i); - - ConstExprValue *elem_val = allocate(1); - if (eval_expr(ef, elem_node, elem_val)) return true; - - assert(elem_val->ok); - - out_val->data.x_array.fields[i] = elem_val; - out_val->depends_on_compile_var = out_val->depends_on_compile_var || - elem_val->depends_on_compile_var; - } - } else { - zig_panic("TODO init more container kinds"); - } - - - return false; -} - -static bool eval_if_bool_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeIfBoolExpr); - - ConstExprValue cond_val = {0}; - if (eval_expr(ef, node->data.if_bool_expr.condition, &cond_val)) return true; - - AstNode *exec_node = cond_val.data.x_bool ? - node->data.if_bool_expr.then_block : node->data.if_bool_expr.else_node; - - if (exec_node) { - if (eval_expr(ef, exec_node, out_val)) return true; - } - out_val->ok = true; - return false; -} - void eval_const_expr_implicit_cast(CastOp cast_op, ConstExprValue *other_val, TypeTableEntry *other_type, ConstExprValue *const_val, TypeTableEntry *new_type) @@ -817,685 +492,3 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * zig_unreachable(); } } - -static bool eval_min_max(EvalFn *ef, AstNode *node, ConstExprValue *out_val, bool is_max) { - assert(node->type == NodeTypeFnCallExpr); - AstNode *type_node = node->data.fn_call_expr.params.at(0); - TypeTableEntry *type_entry = resolve_expr_type(type_node); - eval_min_max_value(ef->root->codegen, type_entry, out_val, is_max); - return false; -} - -static bool eval_div_exact(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeFnCallExpr); - AstNode *op1_node = node->data.fn_call_expr.params.at(0); - AstNode *op2_node = node->data.fn_call_expr.params.at(1); - - TypeTableEntry *type_entry = get_resolved_expr(op1_node)->type_entry; - assert(type_entry->id == TypeTableEntryIdInt); - - ConstExprValue op1_val = {0}; - if (eval_expr(ef, op1_node, &op1_val)) return true; - - ConstExprValue op2_val = {0}; - if (eval_expr(ef, op2_node, &op2_val)) return true; - - if (op2_val.data.x_bignum.data.x_uint == 0) { - ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, - buf_sprintf("function evaluation caused division by zero")); - add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); - add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here")); - return true; - } - - bignum_div(&out_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum); - - BigNum orig_bn; - bignum_mul(&orig_bn, &out_val->data.x_bignum, &op2_val.data.x_bignum); - - if (bignum_cmp_neq(&orig_bn, &op1_val.data.x_bignum)) { - ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, - buf_sprintf("function evaluation violated exact division")); - add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); - add_error_note(ef->root->codegen, msg, node, buf_sprintf("exact division violation here")); - return true; - } - - out_val->ok = true; - out_val->depends_on_compile_var = op1_val.depends_on_compile_var || op2_val.depends_on_compile_var; - return false; -} - -static bool eval_unreachable(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - ef->root->abort = true; - ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, - buf_sprintf("function evaluation reached unreachable expression")); - add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); - add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here")); - return true; -} - -static bool eval_fn_with_overflow(EvalFn *ef, AstNode *node, ConstExprValue *out_val, - bool (*bignum_fn)(BigNum *dest, BigNum *op1, BigNum *op2)) -{ - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - TypeTableEntry *int_type = resolve_expr_type(type_node); - assert(int_type->id == TypeTableEntryIdInt); - - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *result_node = node->data.fn_call_expr.params.at(3); - - ConstExprValue op1_val = {0}; - if (eval_expr(ef, op1_node, &op1_val)) return true; - - ConstExprValue op2_val = {0}; - if (eval_expr(ef, op2_node, &op2_val)) return true; - - ConstExprValue result_ptr_val = {0}; - if (eval_expr(ef, result_node, &result_ptr_val)) return true; - - ConstExprValue *result_val = result_ptr_val.data.x_ptr.ptr[0]; - - out_val->ok = true; - bool overflow = bignum_fn(&result_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum); - - overflow = overflow || !bignum_fits_in_bits(&result_val->data.x_bignum, - int_type->data.integral.bit_count, int_type->data.integral.is_signed); - - out_val->data.x_bool = overflow; - - if (overflow) { - bignum_truncate(&result_val->data.x_bignum, int_type->data.integral.bit_count); - } - - return false; -} - -static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeFnCallExpr); - - BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; - switch (builtin_fn->id) { - case BuiltinFnIdMaxValue: - return eval_min_max(ef, node, out_val, true); - case BuiltinFnIdMinValue: - return eval_min_max(ef, node, out_val, false); - case BuiltinFnIdMulWithOverflow: - return eval_fn_with_overflow(ef, node, out_val, bignum_mul); - case BuiltinFnIdAddWithOverflow: - return eval_fn_with_overflow(ef, node, out_val, bignum_add); - case BuiltinFnIdSubWithOverflow: - return eval_fn_with_overflow(ef, node, out_val, bignum_sub); - case BuiltinFnIdShlWithOverflow: - return eval_fn_with_overflow(ef, node, out_val, bignum_shl); - case BuiltinFnIdFence: - return false; - case BuiltinFnIdDivExact: - return eval_div_exact(ef, node, out_val); - case BuiltinFnIdUnreachable: - return eval_unreachable(ef, node, out_val); - case BuiltinFnIdMemcpy: - case BuiltinFnIdMemset: - case BuiltinFnIdSizeof: - case BuiltinFnIdAlignof: - case BuiltinFnIdMemberCount: - case BuiltinFnIdTypeof: - case BuiltinFnIdCInclude: - case BuiltinFnIdCDefine: - case BuiltinFnIdCUndef: - case BuiltinFnIdCompileVar: - case BuiltinFnIdConstEval: - case BuiltinFnIdCtz: - case BuiltinFnIdClz: - case BuiltinFnIdImport: - case BuiltinFnIdCImport: - case BuiltinFnIdErrName: - case BuiltinFnIdEmbedFile: - case BuiltinFnIdCmpExchange: - case BuiltinFnIdTruncate: - zig_panic("TODO builtin function"); - case BuiltinFnIdBreakpoint: - case BuiltinFnIdInvalid: - case BuiltinFnIdFrameAddress: - case BuiltinFnIdReturnAddress: - case BuiltinFnIdCompileErr: - case BuiltinFnIdIntType: - zig_unreachable(); - case BuiltinFnIdSetFnTest: - case BuiltinFnIdSetFnVisible: - case BuiltinFnIdSetFnStaticEval: - case BuiltinFnIdSetFnNoInline: - case BuiltinFnIdSetDebugSafety: - return false; - } - - return false; -} - -static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - CastOp cast_op = node->data.fn_call_expr.cast_op; - if (node->data.fn_call_expr.is_builtin) { - return eval_fn_call_builtin(ef, node, out_val); - } else if (cast_op != CastOpNoCast) { - TypeTableEntry *new_type = resolve_expr_type(fn_ref_expr); - AstNode *param_node = node->data.fn_call_expr.params.at(0); - TypeTableEntry *old_type = get_resolved_expr(param_node)->type_entry; - ConstExprValue param_val = {0}; - if (eval_expr(ef, param_node, ¶m_val)) return true; - eval_const_expr_implicit_cast(cast_op, ¶m_val, old_type, out_val, new_type); - return false; - } - - FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; - - if (fn_ref_expr->type == NodeTypeFieldAccessExpr && - fn_ref_expr->data.field_access_expr.is_member_fn) - { - zig_panic("TODO field access member fn"); - } - - if (!fn_table_entry) { - ConstExprValue fn_val = {0}; - if (eval_expr(ef, fn_ref_expr, &fn_val)) return true; - fn_table_entry = fn_val.data.x_fn; - } - - size_t param_count = node->data.fn_call_expr.params.length; - ConstExprValue *args = allocate(param_count); - for (size_t call_i = 0; call_i < param_count; call_i += 1) { - AstNode *param_expr_node = node->data.fn_call_expr.params.at(call_i); - ConstExprValue *param_val = &args[call_i]; - if (eval_expr(ef, param_expr_node, param_val)) return true; - } - - ef->root->branches_used += 1; - - eval_fn_args(ef->root, fn_table_entry, args, out_val); - return false; -} - -static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeFieldAccessExpr); - - AstNode *struct_expr = node->data.field_access_expr.struct_expr; - TypeTableEntry *struct_type = get_resolved_expr(struct_expr)->type_entry; - - if (struct_type->id == TypeTableEntryIdArray) { - Buf *name = node->data.field_access_expr.field_name; - assert(buf_eql_str(name, "len")); - zig_panic("TODO field access array"); - } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && - struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) - { - TypeStructField *tsf = node->data.field_access_expr.type_struct_field; - assert(tsf); - if (struct_type->id == TypeTableEntryIdStruct) { - ConstExprValue struct_val = {0}; - if (eval_expr(ef, struct_expr, &struct_val)) return true; - ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; - *out_val = *field_value; - assert(out_val->ok); - } else { - zig_panic("TODO field access struct"); - } - } else if (struct_type->id == TypeTableEntryIdMetaType) { - TypeTableEntry *child_type = resolve_expr_type(struct_expr); - if (child_type->id == TypeTableEntryIdPureError) { - *out_val = get_resolved_expr(node)->const_val; - } else { - zig_panic("TODO field access meta type"); - } - } else if (struct_type->id == TypeTableEntryIdNamespace) { - zig_panic("TODO field access namespace"); - } else { - zig_unreachable(); - } - - return false; -} - -static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeForExpr); - - AstNode *array_node = node->data.for_expr.array_expr; - AstNode *elem_node = node->data.for_expr.elem_node; - AstNode *index_node = node->data.for_expr.index_node; - AstNode *body_node = node->data.for_expr.body; - - TypeTableEntry *array_type = get_resolved_expr(array_node)->type_entry; - - ConstExprValue array_val = {0}; - if (eval_expr(ef, array_node, &array_val)) return true; - - assert(elem_node->type == NodeTypeSymbol); - Buf *elem_var_name = elem_node->data.symbol_expr.symbol; - - if (node->data.for_expr.elem_is_ptr) { - zig_panic("TODO for elem is ptr"); - } - - Buf *index_var_name = nullptr; - if (index_node) { - assert(index_node->type == NodeTypeSymbol); - index_var_name = index_node->data.symbol_expr.symbol; - } - - uint64_t it_index = 0; - uint64_t array_len; - ConstExprValue **array_ptr_val; - if (array_type->id == TypeTableEntryIdArray) { - array_len = array_type->data.array.len; - array_ptr_val = array_val.data.x_array.fields; - } else if (array_type->id == TypeTableEntryIdStruct) { - ConstExprValue *len_field_val = array_val.data.x_struct.fields[1]; - array_len = len_field_val->data.x_bignum.data.x_uint; - array_ptr_val = array_val.data.x_struct.fields[0]->data.x_ptr.ptr; - } else { - zig_unreachable(); - } - - EvalScope *my_scope = allocate(1); - my_scope->block_context = body_node->block_context; - ef->scope_stack.append(my_scope); - - for (; it_index < array_len; it_index += 1) { - my_scope->vars.resize(0); - - if (index_var_name) { - my_scope->vars.add_one(); - EvalVar *index_var = &my_scope->vars.last(); - index_var->name = index_var_name; - memset(&index_var->value, 0, sizeof(ConstExprValue)); - index_var->value.ok = true; - bignum_init_unsigned(&index_var->value.data.x_bignum, it_index); - } - { - my_scope->vars.add_one(); - EvalVar *elem_var = &my_scope->vars.last(); - elem_var->name = elem_var_name; - elem_var->value = *array_ptr_val[it_index]; - } - - ConstExprValue body_val = {0}; - if (eval_expr(ef, body_node, &body_val)) return true; - - ef->root->branches_used += 1; - } - - ef->scope_stack.pop(); - - return false; -} - -static bool eval_array_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeArrayAccessExpr); - - AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - AstNode *index_node = node->data.array_access_expr.subscript; - - TypeTableEntry *array_type = get_resolved_expr(array_ref_node)->type_entry; - - ConstExprValue array_val = {0}; - if (eval_expr(ef, array_ref_node, &array_val)) return true; - - ConstExprValue index_val = {0}; - if (eval_expr(ef, index_node, &index_val)) return true; - uint64_t index_int = index_val.data.x_bignum.data.x_uint; - - if (array_type->id == TypeTableEntryIdPointer) { - if (index_int >= array_val.data.x_ptr.len) { - zig_panic("TODO array access pointer"); - } - *out_val = *array_val.data.x_ptr.ptr[index_int]; - } else if (array_type->id == TypeTableEntryIdStruct) { - assert(array_type->data.structure.is_slice); - - ConstExprValue *len_value = array_val.data.x_struct.fields[1]; - uint64_t len_int = len_value->data.x_bignum.data.x_uint; - if (index_int >= len_int) { - zig_panic("TODO array access slice"); - } - - ConstExprValue *ptr_value = array_val.data.x_struct.fields[0]; - *out_val = *ptr_value->data.x_ptr.ptr[index_int]; - } else if (array_type->id == TypeTableEntryIdArray) { - uint64_t array_len = array_type->data.array.len; - if (index_int >= array_len) { - zig_panic("TODO array access array"); - } - *out_val = *array_val.data.x_array.fields[index_int]; - } else { - zig_unreachable(); - } - - return false; -} - -static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeBoolLiteral); - - out_val->ok = true; - out_val->data.x_bool = node->data.bool_literal.value; - - return false; -} - -static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypePrefixOpExpr); - - PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - ConstExprValue expr_val = {0}; - if (eval_expr(ef, expr_node, &expr_val)) return true; - - TypeTableEntry *expr_type = get_resolved_expr(expr_node)->type_entry; - - switch (prefix_op) { - case PrefixOpBoolNot: - *out_val = expr_val; - out_val->data.x_bool = !out_val->data.x_bool; - break; - case PrefixOpDereference: - assert(expr_type->id == TypeTableEntryIdPointer); - *out_val = *expr_val.data.x_ptr.ptr[0]; - break; - case PrefixOpAddressOf: - case PrefixOpConstAddressOf: - { - ConstExprValue *child_val = allocate(1); - *child_val = expr_val; - - ConstExprValue **ptr_val = allocate(1); - *ptr_val = child_val; - - out_val->data.x_ptr.ptr = ptr_val; - out_val->data.x_ptr.len = 1; - out_val->ok = true; - break; - } - case PrefixOpNegation: - case PrefixOpNegationWrap: - if (expr_type->id == TypeTableEntryIdInt) { - assert(expr_type->data.integral.is_signed); - bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum); - out_val->ok = true; - bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, - expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); - if (prefix_op == PrefixOpNegationWrap) { - if (overflow) { - out_val->data.x_bignum.is_negative = true; - } - } else if (overflow) { - ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, - buf_sprintf("function evaluation caused overflow")); - add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); - add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); - return true; - } - } else if (expr_type->id == TypeTableEntryIdFloat) { - zig_panic("TODO prefix op on floats"); - } else { - zig_unreachable(); - } - break; - case PrefixOpBinNot: - case PrefixOpMaybe: - case PrefixOpError: - case PrefixOpUnwrapError: - case PrefixOpUnwrapMaybe: - zig_panic("TODO more prefix operations"); - case PrefixOpInvalid: - zig_unreachable(); - } - - return false; -} - -static bool eval_var_decl_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeVariableDeclaration); - - assert(node->data.variable_declaration.expr); - - EvalScope *my_scope = ef->scope_stack.at(ef->scope_stack.length - 1); - - my_scope->vars.add_one(); - EvalVar *var = &my_scope->vars.last(); - var->name = node->data.variable_declaration.symbol; - - if (eval_expr(ef, node->data.variable_declaration.expr, &var->value)) return true; - - out_val->ok = true; - - return false; -} - -static bool eval_number_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeNumberLiteral); - assert(!node->data.number_literal.overflow); - - out_val->ok = true; - bignum_init_bignum(&out_val->data.x_bignum, node->data.number_literal.bignum); - - return false; -} - -static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeCharLiteral); - - out_val->ok = true; - bignum_init_unsigned(&out_val->data.x_bignum, node->data.char_literal.value); - - return false; -} - -static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { - assert(node->type == NodeTypeWhileExpr); - - AstNode *cond_node = node->data.while_expr.condition; - AstNode *body_node = node->data.while_expr.body; - AstNode *continue_expr_node = node->data.while_expr.continue_expr; - - EvalScope *my_scope = allocate(1); - my_scope->block_context = body_node->block_context; - ef->scope_stack.append(my_scope); - - for (;;) { - my_scope->vars.resize(0); - - ConstExprValue cond_val = {0}; - if (eval_expr(ef, cond_node, &cond_val)) return true; - - if (!cond_val.data.x_bool) break; - - ConstExprValue body_val = {0}; - if (eval_expr(ef, body_node, &body_val)) return true; - - if (continue_expr_node) { - ConstExprValue continue_expr_val = {0}; - if (eval_expr(ef, continue_expr_node, &continue_expr_val)) return true; - } - - ef->root->branches_used += 1; - } - - ef->scope_stack.pop(); - - return false; -} - -static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { - if (ef->root->branches_used > ef->root->branch_quota) { - ef->root->exceeded_quota_node = node; - return true; - } - ConstExprValue *const_val = &get_resolved_expr(node)->const_val; - if (const_val->ok) { - *out = *const_val; - return false; - } - switch (node->type) { - case NodeTypeBlock: - return eval_block(ef, node, out); - case NodeTypeReturnExpr: - return eval_return(ef, node, out); - case NodeTypeBinOpExpr: - return eval_bin_op_expr(ef, node, out); - case NodeTypeSymbol: - return eval_symbol_expr(ef, node, out); - case NodeTypeContainerInitExpr: - return eval_container_init_expr(ef, node, out); - case NodeTypeIfBoolExpr: - return eval_if_bool_expr(ef, node, out); - case NodeTypeFnCallExpr: - return eval_fn_call_expr(ef, node, out); - case NodeTypeFieldAccessExpr: - return eval_field_access_expr(ef, node, out); - case NodeTypeForExpr: - return eval_for_expr(ef, node, out); - case NodeTypeArrayAccessExpr: - return eval_array_access_expr(ef, node, out); - case NodeTypeBoolLiteral: - return eval_bool_literal_expr(ef, node, out); - case NodeTypePrefixOpExpr: - return eval_prefix_op_expr(ef, node, out); - case NodeTypeVariableDeclaration: - return eval_var_decl_expr(ef, node, out); - case NodeTypeNumberLiteral: - return eval_number_literal_expr(ef, node, out); - case NodeTypeCharLiteral: - return eval_char_literal_expr(ef, node, out); - case NodeTypeWhileExpr: - return eval_while_expr(ef, node, out); - case NodeTypeDefer: - case NodeTypeErrorValueDecl: - case NodeTypeUnwrapErrorExpr: - case NodeTypeStringLiteral: - case NodeTypeSliceExpr: - case NodeTypeNullLiteral: - case NodeTypeUndefinedLiteral: - case NodeTypeZeroesLiteral: - case NodeTypeThisLiteral: - case NodeTypeIfVarExpr: - case NodeTypeSwitchExpr: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeLabel: - case NodeTypeGoto: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeContainerDecl: - case NodeTypeStructField: - case NodeTypeStructValueField: - case NodeTypeArrayType: - case NodeTypeErrorType: - case NodeTypeTypeLiteral: - case NodeTypeVarLiteral: - zig_panic("TODO expr node"); - case NodeTypeRoot: - case NodeTypeFnProto: - case NodeTypeFnDef: - case NodeTypeFnDecl: - case NodeTypeUse: - case NodeTypeAsmExpr: - case NodeTypeParamDecl: - case NodeTypeTypeDecl: - zig_unreachable(); - } - zig_unreachable(); -} - -static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) { - AstNode *acting_proto_node; - if (fn->proto_node->data.fn_proto.generic_proto_node) { - acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node; - } else { - acting_proto_node = fn->proto_node; - } - - EvalFn ef = {0}; - ef.root = efr; - ef.fn = fn; - ef.return_expr = out_val; - - EvalScope *root_scope = allocate(1); - root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context; - ef.scope_stack.append(root_scope); - - size_t param_count = acting_proto_node->data.fn_proto.params.length; - for (size_t proto_i = 0; proto_i < param_count; proto_i += 1) { - AstNode *decl_param_node = acting_proto_node->data.fn_proto.params.at(proto_i); - assert(decl_param_node->type == NodeTypeParamDecl); - - ConstExprValue *src_const_val = &args[proto_i]; - assert(src_const_val->ok); - - root_scope->vars.add_one(); - EvalVar *eval_var = &root_scope->vars.last(); - eval_var->name = decl_param_node->data.param_decl.name; - eval_var->value = *src_const_val; - } - - return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val); -} - -bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val, - size_t branch_quota, AstNode *struct_node) -{ - assert(node->type == NodeTypeFnCallExpr); - - EvalFnRoot efr = {0}; - efr.codegen = g; - efr.fn = fn; - efr.call_node = node; - efr.branch_quota = branch_quota; - - AstNode *acting_proto_node; - if (fn->proto_node->data.fn_proto.generic_proto_node) { - acting_proto_node = fn->proto_node->data.fn_proto.generic_proto_node; - } else { - acting_proto_node = fn->proto_node; - } - - size_t call_param_count = node->data.fn_call_expr.params.length; - size_t proto_param_count = acting_proto_node->data.fn_proto.params.length; - ConstExprValue *args = allocate(proto_param_count); - size_t next_arg_index = 0; - if (struct_node) { - ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val; - assert(struct_val->ok); - args[next_arg_index] = *struct_val; - next_arg_index += 1; - } - for (size_t call_index = 0; call_index < call_param_count; call_index += 1) { - AstNode *call_param_node = node->data.fn_call_expr.params.at(call_index); - ConstExprValue *src_const_val = &get_resolved_expr(call_param_node)->const_val; - assert(src_const_val->ok); - args[next_arg_index] = *src_const_val; - next_arg_index += 1; - } - eval_fn_args(&efr, fn, args, out_val); - - if (efr.exceeded_quota_node) { - ErrorMsg *msg = add_node_error(g, fn->fn_def_node, - buf_sprintf("function evaluation exceeded %zu branches", efr.branch_quota)); - - add_error_note(g, msg, efr.call_node, buf_sprintf("called from here")); - add_error_note(g, msg, efr.exceeded_quota_node, buf_sprintf("quota exceeded here")); - return true; - } - - if (efr.abort) { - return true; - } - - assert(out_val->ok); - return false; -} - diff --git a/src/eval.hpp b/src/eval.hpp index aa9606bd14..b90aca21ae 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -10,9 +10,6 @@ #include "all_types.hpp" -bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val, size_t branch_quota, - AstNode *struct_node); - bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val);