Commit a55555c99e
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<EvalVar> 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<EvalScope*> 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<EvalScope>(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<ConstExprValue*>(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<ConstExprValue>(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<ConstExprValue*>(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<ConstExprValue>(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<ConstExprValue>(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<EvalScope>(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<ConstExprValue>(1);
- *child_val = expr_val;
-
- ConstExprValue **ptr_val = allocate<ConstExprValue*>(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<EvalScope>(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<EvalScope>(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<ConstExprValue>(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;
-}
-
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);