eval: support more node types
This commit is contained in:
parent
a177e30534
commit
fa605485ea
@ -497,8 +497,8 @@ struct AstNodeWhileExpr {
|
||||
};
|
||||
|
||||
struct AstNodeForExpr {
|
||||
AstNode *elem_node; // always a symbol
|
||||
AstNode *array_expr;
|
||||
AstNode *elem_node; // always a symbol
|
||||
AstNode *index_node; // always a symbol, might be null
|
||||
AstNode *body;
|
||||
|
||||
@ -1054,6 +1054,7 @@ struct EvalFnRoot {
|
||||
int branch_quota;
|
||||
int branches_used;
|
||||
AstNode *exceeded_quota_node;
|
||||
bool abort;
|
||||
};
|
||||
|
||||
struct EvalFn {
|
||||
|
@ -1074,15 +1074,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
|
||||
|
||||
AstNode *struct_expr = node->data.field_access_expr.struct_expr;
|
||||
TypeTableEntry *struct_type = get_expr_type(struct_expr);
|
||||
Buf *name = &node->data.field_access_expr.field_name;
|
||||
|
||||
if (struct_type->id == TypeTableEntryIdArray) {
|
||||
if (buf_eql_str(name, "len")) {
|
||||
return LLVMConstInt(g->builtin_types.entry_isize->type_ref,
|
||||
struct_type->data.array.len, false);
|
||||
} else {
|
||||
zig_panic("gen_field_access_expr bad array field");
|
||||
}
|
||||
Buf *name = &node->data.field_access_expr.field_name;
|
||||
assert(buf_eql_str(name, "len"));
|
||||
return LLVMConstInt(g->builtin_types.entry_isize->type_ref,
|
||||
struct_type->data.array.len, false);
|
||||
} else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
|
||||
struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
|
||||
{
|
||||
|
212
src/eval.cpp
212
src/eval.cpp
@ -327,6 +327,13 @@ static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *
|
||||
}
|
||||
} else if (container_type->id == TypeTableEntryIdVoid) {
|
||||
return false;
|
||||
} else if (container_type->id == TypeTableEntryIdUnreachable) {
|
||||
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;
|
||||
} else {
|
||||
zig_panic("TODO");
|
||||
}
|
||||
@ -472,6 +479,194 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *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");
|
||||
} 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;
|
||||
} else {
|
||||
zig_panic("TODO");
|
||||
}
|
||||
} else if (struct_type->id == TypeTableEntryIdMetaType) {
|
||||
zig_panic("TODO");
|
||||
} else if (struct_type->id == TypeTableEntryIdNamespace) {
|
||||
zig_panic("TODO");
|
||||
} 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;
|
||||
|
||||
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");
|
||||
}
|
||||
*out_val = *array_val.data.x_ptr.ptr[index_int];
|
||||
} else if (array_type->id == TypeTableEntryIdStruct) {
|
||||
assert(array_type->data.structure.is_unknown_size_array);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
*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->deep_const = 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;
|
||||
|
||||
ConstExprValue expr_val = {0};
|
||||
if (eval_expr(ef, node->data.prefix_op_expr.primary_expr, &expr_val)) return true;
|
||||
|
||||
switch (prefix_op) {
|
||||
case PrefixOpBoolNot:
|
||||
*out_val = expr_val;
|
||||
out_val->data.x_bool = !out_val->data.x_bool;
|
||||
break;
|
||||
case PrefixOpBinNot:
|
||||
case PrefixOpNegation:
|
||||
case PrefixOpAddressOf:
|
||||
case PrefixOpConstAddressOf:
|
||||
case PrefixOpDereference:
|
||||
case PrefixOpMaybe:
|
||||
case PrefixOpError:
|
||||
case PrefixOpUnwrapError:
|
||||
case PrefixOpUnwrapMaybe:
|
||||
zig_panic("TODO");
|
||||
case PrefixOpInvalid:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
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;
|
||||
@ -492,6 +687,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
||||
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 NodeTypeRoot:
|
||||
case NodeTypeFnProto:
|
||||
case NodeTypeFnDef:
|
||||
@ -506,17 +711,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
case NodeTypeFieldAccessExpr:
|
||||
case NodeTypeUse:
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeIfVarExpr:
|
||||
case NodeTypeWhileExpr:
|
||||
case NodeTypeForExpr:
|
||||
case NodeTypeSwitchExpr:
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
@ -602,6 +802,6 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return efr.abort;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user