mirror of
https://github.com/ziglang/zig.git
synced 2025-12-20 13:13:16 +00:00
passing all tests
This commit is contained in:
parent
aa89fd3b3e
commit
be4df96e4b
@ -35,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
|
|||||||
static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
|
static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
|
||||||
TypeTableEntry *expected_type, uint64_t x);
|
TypeTableEntry *expected_type, uint64_t x);
|
||||||
static AstNode *find_decl(BlockContext *context, Buf *name);
|
static AstNode *find_decl(BlockContext *context, Buf *name);
|
||||||
static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, bool pointer_only);
|
static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
|
||||||
|
bool pointer_only, BlockContext *block_context);
|
||||||
static TopLevelDecl *get_as_top_level_decl(AstNode *node);
|
static TopLevelDecl *get_as_top_level_decl(AstNode *node);
|
||||||
static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
|
static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
|
||||||
BlockContext *context, AstNode *source_node,
|
BlockContext *context, AstNode *source_node,
|
||||||
@ -957,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||||||
add_node_error(g, directive_node,
|
add_node_error(g, directive_node,
|
||||||
buf_sprintf("#condition valid only on exported symbols"));
|
buf_sprintf("#condition valid only on exported symbols"));
|
||||||
}
|
}
|
||||||
|
} else if (buf_eql_str(name, "static_eval_enable")) {
|
||||||
|
if (fn_table_entry->is_extern) {
|
||||||
|
add_node_error(g, directive_node,
|
||||||
|
buf_sprintf("#static_val_enable invalid on extern functions"));
|
||||||
|
} else {
|
||||||
|
bool enable;
|
||||||
|
bool ok = resolve_const_expr_bool(g, import, import->block_context,
|
||||||
|
&directive_node->data.directive.expr, &enable);
|
||||||
|
if (!enable || !ok) {
|
||||||
|
fn_table_entry->is_pure = false;
|
||||||
|
}
|
||||||
|
// TODO cause compile error if enable is true and impure fn
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, directive_node,
|
add_node_error(g, directive_node,
|
||||||
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
||||||
@ -2227,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
|
|||||||
const_val->ok = false;
|
const_val->ok = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!const_val->ok) {
|
}
|
||||||
context->fn_entry->struct_val_expr_alloca_list.append(codegen);
|
if (!const_val->ok) {
|
||||||
}
|
context->fn_entry->struct_val_expr_alloca_list.append(codegen);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < actual_field_count; i += 1) {
|
for (int i = 0; i < actual_field_count; i += 1) {
|
||||||
@ -2381,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
|
|||||||
AstNode *decl_node = entry ? entry->value : nullptr;
|
AstNode *decl_node = entry ? entry->value : nullptr;
|
||||||
if (decl_node) {
|
if (decl_node) {
|
||||||
bool pointer_only = false;
|
bool pointer_only = false;
|
||||||
return analyze_decl_ref(g, node, decl_node, pointer_only);
|
return analyze_decl_ref(g, node, decl_node, pointer_only, context);
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, node,
|
add_node_error(g, node,
|
||||||
buf_sprintf("container '%s' has no member called '%s'",
|
buf_sprintf("container '%s' has no member called '%s'",
|
||||||
@ -2408,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
|
|||||||
add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
|
add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
|
||||||
}
|
}
|
||||||
bool pointer_only = false;
|
bool pointer_only = false;
|
||||||
return analyze_decl_ref(g, node, decl_node, pointer_only);
|
return analyze_decl_ref(g, node, decl_node, pointer_only, context);
|
||||||
} else {
|
} else {
|
||||||
const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
|
const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
|
||||||
add_node_error(g, node,
|
add_node_error(g, node,
|
||||||
@ -2674,8 +2688,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
|
|||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) {
|
static bool var_is_pure(VariableTableEntry *var, BlockContext *context) {
|
||||||
|
if (var->block_context->fn_entry == context->fn_entry) {
|
||||||
|
// variable was declared in the current function, so it's OK.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return var->is_const && var->type->deep_const;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var,
|
||||||
|
BlockContext *context)
|
||||||
|
{
|
||||||
get_resolved_expr(source_node)->variable = var;
|
get_resolved_expr(source_node)->variable = var;
|
||||||
|
if (!var_is_pure(var, context)) {
|
||||||
|
mark_impure_fn(context);
|
||||||
|
}
|
||||||
if (var->is_const && var->val_node) {
|
if (var->is_const && var->val_node) {
|
||||||
ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
|
ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val;
|
||||||
if (other_const_val->ok) {
|
if (other_const_val->ok) {
|
||||||
@ -2686,7 +2713,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
|
static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
|
||||||
bool pointer_only)
|
bool pointer_only, BlockContext *block_context)
|
||||||
{
|
{
|
||||||
resolve_top_level_decl(g, decl_node, pointer_only);
|
resolve_top_level_decl(g, decl_node, pointer_only);
|
||||||
TopLevelDecl *tld = get_as_top_level_decl(decl_node);
|
TopLevelDecl *tld = get_as_top_level_decl(decl_node);
|
||||||
@ -2696,7 +2723,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
|
|||||||
|
|
||||||
if (decl_node->type == NodeTypeVariableDeclaration) {
|
if (decl_node->type == NodeTypeVariableDeclaration) {
|
||||||
VariableTableEntry *var = decl_node->data.variable_declaration.variable;
|
VariableTableEntry *var = decl_node->data.variable_declaration.variable;
|
||||||
return analyze_var_ref(g, source_node, var);
|
return analyze_var_ref(g, source_node, var, block_context);
|
||||||
} else if (decl_node->type == NodeTypeFnProto) {
|
} else if (decl_node->type == NodeTypeFnProto) {
|
||||||
if (decl_node->data.fn_proto.generic_params.length > 0) {
|
if (decl_node->data.fn_proto.generic_params.length > 0) {
|
||||||
TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
|
TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type;
|
||||||
@ -2716,14 +2743,6 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, BlockContext *context) {
|
|
||||||
if (var->block_context->fn_entry == context->fn_entry) {
|
|
||||||
// variable was declared in the current function, so it's OK.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return var->is_const && var->type->deep_const;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||||
TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
|
TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
|
||||||
{
|
{
|
||||||
@ -2740,16 +2759,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
|
|
||||||
VariableTableEntry *var = find_variable(g, context, variable_name);
|
VariableTableEntry *var = find_variable(g, context, variable_name);
|
||||||
if (var) {
|
if (var) {
|
||||||
TypeTableEntry *var_type = analyze_var_ref(g, node, var);
|
TypeTableEntry *var_type = analyze_var_ref(g, node, var, context);
|
||||||
if (!var_is_pure(var, var_type, context)) {
|
|
||||||
mark_impure_fn(context);
|
|
||||||
}
|
|
||||||
return var_type;
|
return var_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *decl_node = find_decl(context, variable_name);
|
AstNode *decl_node = find_decl(context, variable_name);
|
||||||
if (decl_node) {
|
if (decl_node) {
|
||||||
return analyze_decl_ref(g, node, decl_node, pointer_only);
|
return analyze_decl_ref(g, node, decl_node, pointer_only, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (import->any_imports_failed) {
|
if (import->any_imports_failed) {
|
||||||
@ -2992,7 +3008,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
}
|
}
|
||||||
|
|
||||||
analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
|
analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
|
||||||
return resolve_expr_const_val_as_void(g, node);
|
// not const ok because expression has side effects
|
||||||
|
return g->builtin_types.entry_void;
|
||||||
}
|
}
|
||||||
case BinOpTypeBoolOr:
|
case BinOpTypeBoolOr:
|
||||||
case BinOpTypeBoolAnd:
|
case BinOpTypeBoolAnd:
|
||||||
@ -4473,12 +4490,16 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
|
|||||||
actual_param_count += 1;
|
actual_param_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ok_invocation = true;
|
||||||
|
|
||||||
if (fn_type->data.fn.fn_type_id.is_var_args) {
|
if (fn_type->data.fn.fn_type_id.is_var_args) {
|
||||||
if (actual_param_count < src_param_count) {
|
if (actual_param_count < src_param_count) {
|
||||||
|
ok_invocation = false;
|
||||||
add_node_error(g, node,
|
add_node_error(g, node,
|
||||||
buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));
|
buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));
|
||||||
}
|
}
|
||||||
} else if (src_param_count != actual_param_count) {
|
} else if (src_param_count != actual_param_count) {
|
||||||
|
ok_invocation = false;
|
||||||
add_node_error(g, node,
|
add_node_error(g, node,
|
||||||
buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));
|
buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));
|
||||||
}
|
}
|
||||||
@ -4517,7 +4538,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
|
FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
|
||||||
if (fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) {
|
if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) {
|
||||||
if (fn_table_entry->anal_state == FnAnalStateReady) {
|
if (fn_table_entry->anal_state == FnAnalStateReady) {
|
||||||
analyze_fn_body(g, fn_table_entry);
|
analyze_fn_body(g, fn_table_entry);
|
||||||
} else if (fn_table_entry->anal_state == FnAnalStateProbing) {
|
} else if (fn_table_entry->anal_state == FnAnalStateProbing) {
|
||||||
@ -4726,7 +4747,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
|
|||||||
if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
|
if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
|
||||||
fn_ref_expr->data.field_access_expr.is_member_fn)
|
fn_ref_expr->data.field_access_expr.is_member_fn)
|
||||||
{
|
{
|
||||||
struct_node = fn_ref_expr;
|
struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
|
||||||
} else {
|
} else {
|
||||||
struct_node = nullptr;
|
struct_node = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
105
src/eval.cpp
105
src/eval.cpp
@ -70,6 +70,7 @@ static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
|||||||
|
|
||||||
for (int i = 0; i < node->data.block.statements.length; i += 1) {
|
for (int i = 0; i < node->data.block.statements.length; i += 1) {
|
||||||
AstNode *child = node->data.block.statements.at(i);
|
AstNode *child = node->data.block.statements.at(i);
|
||||||
|
memset(out, 0, sizeof(ConstExprValue));
|
||||||
if (eval_expr(ef, child, out)) return true;
|
if (eval_expr(ef, child, out)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +110,6 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
|||||||
{
|
{
|
||||||
assert(op1_val->ok);
|
assert(op1_val->ok);
|
||||||
assert(op2_val->ok);
|
assert(op2_val->ok);
|
||||||
assert(op1_type == op2_type);
|
|
||||||
|
|
||||||
switch (bin_op) {
|
switch (bin_op) {
|
||||||
case BinOpTypeAssign:
|
case BinOpTypeAssign:
|
||||||
@ -275,6 +275,7 @@ static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
|
|||||||
|
|
||||||
Buf *name = &node->data.symbol_expr.symbol;
|
Buf *name = &node->data.symbol_expr.symbol;
|
||||||
EvalVar *var = find_var(ef, name);
|
EvalVar *var = find_var(ef, name);
|
||||||
|
assert(var);
|
||||||
|
|
||||||
*out_val = var->value;
|
*out_val = var->value;
|
||||||
|
|
||||||
@ -374,6 +375,8 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
|||||||
*const_val = *other_val;
|
*const_val = *other_val;
|
||||||
break;
|
break;
|
||||||
case CastOpPointerReinterpret:
|
case CastOpPointerReinterpret:
|
||||||
|
if (other_type->id == TypeTableEntryIdPointer &&
|
||||||
|
new_type->id == TypeTableEntryIdPointer)
|
||||||
{
|
{
|
||||||
TypeTableEntry *other_child_type = other_type->data.pointer.child_type;
|
TypeTableEntry *other_child_type = other_type->data.pointer.child_type;
|
||||||
TypeTableEntry *new_child_type = new_type->data.pointer.child_type;
|
TypeTableEntry *new_child_type = new_type->data.pointer.child_type;
|
||||||
@ -393,8 +396,47 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
|||||||
} else {
|
} else {
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
}
|
}
|
||||||
break;
|
} else if (other_type->id == TypeTableEntryIdMaybe &&
|
||||||
|
new_type->id == TypeTableEntryIdMaybe)
|
||||||
|
{
|
||||||
|
if (!other_val->data.x_maybe) {
|
||||||
|
*const_val = *other_val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTableEntry *other_ptr_type = other_type->data.maybe.child_type;
|
||||||
|
TypeTableEntry *new_ptr_type = new_type->data.maybe.child_type;
|
||||||
|
|
||||||
|
if (other_ptr_type->id == TypeTableEntryIdPointer &&
|
||||||
|
new_ptr_type->id == TypeTableEntryIdPointer)
|
||||||
|
{
|
||||||
|
TypeTableEntry *other_child_type = other_ptr_type->data.pointer.child_type;
|
||||||
|
TypeTableEntry *new_child_type = new_ptr_type->data.pointer.child_type;
|
||||||
|
|
||||||
|
if ((other_child_type->id == TypeTableEntryIdInt ||
|
||||||
|
other_child_type->id == TypeTableEntryIdFloat) &&
|
||||||
|
(new_child_type->id == TypeTableEntryIdInt ||
|
||||||
|
new_child_type->id == TypeTableEntryIdFloat))
|
||||||
|
{
|
||||||
|
ConstExprValue *ptr_parent = allocate<ConstExprValue>(1);
|
||||||
|
ConstExprValue **ptr_val = allocate<ConstExprValue*>(1);
|
||||||
|
*ptr_val = other_val->data.x_maybe->data.x_ptr.ptr[0];
|
||||||
|
ptr_parent->data.x_ptr.ptr = ptr_val;
|
||||||
|
ptr_parent->data.x_ptr.len = 1;
|
||||||
|
ptr_parent->ok = true;
|
||||||
|
|
||||||
|
const_val->data.x_maybe = ptr_parent;
|
||||||
|
const_val->ok = true;
|
||||||
|
const_val->undef = other_val->undef;
|
||||||
|
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
|
||||||
|
} else {
|
||||||
|
zig_panic("TODO");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zig_panic("TODO");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case CastOpPtrToInt:
|
case CastOpPtrToInt:
|
||||||
case CastOpIntToPtr:
|
case CastOpIntToPtr:
|
||||||
// can't do it
|
// can't do it
|
||||||
@ -684,6 +726,7 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
|
|||||||
if (eval_expr(ef, struct_expr, &struct_val)) return true;
|
if (eval_expr(ef, struct_expr, &struct_val)) return true;
|
||||||
ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index];
|
ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index];
|
||||||
*out_val = *field_value;
|
*out_val = *field_value;
|
||||||
|
assert(out_val->ok);
|
||||||
} else {
|
} else {
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
}
|
}
|
||||||
@ -916,11 +959,45 @@ static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
|
|||||||
return false;
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
ef->root->branches_used += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ef->scope_stack.pop();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
||||||
if (ef->root->branches_used > ef->root->branch_quota) {
|
if (ef->root->branches_used > ef->root->branch_quota) {
|
||||||
ef->root->exceeded_quota_node = node;
|
ef->root->exceeded_quota_node = node;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||||
|
if (const_val->ok) {
|
||||||
|
*out = *const_val;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case NodeTypeBlock:
|
case NodeTypeBlock:
|
||||||
return eval_block(ef, node, out);
|
return eval_block(ef, node, out);
|
||||||
@ -952,23 +1029,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
|||||||
return eval_number_literal_expr(ef, node, out);
|
return eval_number_literal_expr(ef, node, out);
|
||||||
case NodeTypeCharLiteral:
|
case NodeTypeCharLiteral:
|
||||||
return eval_char_literal_expr(ef, node, out);
|
return eval_char_literal_expr(ef, node, out);
|
||||||
case NodeTypeRoot:
|
case NodeTypeWhileExpr:
|
||||||
case NodeTypeFnProto:
|
return eval_while_expr(ef, node, out);
|
||||||
case NodeTypeFnDef:
|
|
||||||
case NodeTypeFnDecl:
|
|
||||||
case NodeTypeParamDecl:
|
|
||||||
case NodeTypeDirective:
|
|
||||||
case NodeTypeDefer:
|
case NodeTypeDefer:
|
||||||
case NodeTypeTypeDecl:
|
|
||||||
case NodeTypeErrorValueDecl:
|
case NodeTypeErrorValueDecl:
|
||||||
case NodeTypeUnwrapErrorExpr:
|
case NodeTypeUnwrapErrorExpr:
|
||||||
case NodeTypeStringLiteral:
|
case NodeTypeStringLiteral:
|
||||||
case NodeTypeSliceExpr:
|
case NodeTypeSliceExpr:
|
||||||
case NodeTypeUse:
|
|
||||||
case NodeTypeNullLiteral:
|
case NodeTypeNullLiteral:
|
||||||
case NodeTypeUndefinedLiteral:
|
case NodeTypeUndefinedLiteral:
|
||||||
case NodeTypeIfVarExpr:
|
case NodeTypeIfVarExpr:
|
||||||
case NodeTypeWhileExpr:
|
|
||||||
case NodeTypeSwitchExpr:
|
case NodeTypeSwitchExpr:
|
||||||
case NodeTypeSwitchProng:
|
case NodeTypeSwitchProng:
|
||||||
case NodeTypeSwitchRange:
|
case NodeTypeSwitchRange:
|
||||||
@ -976,13 +1046,22 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
|||||||
case NodeTypeGoto:
|
case NodeTypeGoto:
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
case NodeTypeContinue:
|
case NodeTypeContinue:
|
||||||
case NodeTypeAsmExpr:
|
|
||||||
case NodeTypeStructDecl:
|
case NodeTypeStructDecl:
|
||||||
case NodeTypeStructField:
|
case NodeTypeStructField:
|
||||||
case NodeTypeStructValueField:
|
case NodeTypeStructValueField:
|
||||||
case NodeTypeArrayType:
|
case NodeTypeArrayType:
|
||||||
case NodeTypeErrorType:
|
case NodeTypeErrorType:
|
||||||
case NodeTypeTypeLiteral:
|
case NodeTypeTypeLiteral:
|
||||||
|
zig_panic("TODO");
|
||||||
|
case NodeTypeRoot:
|
||||||
|
case NodeTypeFnProto:
|
||||||
|
case NodeTypeFnDef:
|
||||||
|
case NodeTypeFnDecl:
|
||||||
|
case NodeTypeUse:
|
||||||
|
case NodeTypeAsmExpr:
|
||||||
|
case NodeTypeParamDecl:
|
||||||
|
case NodeTypeDirective:
|
||||||
|
case NodeTypeTypeDecl:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1054,6 +1133,8 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(out_val->ok);
|
||||||
|
|
||||||
return efr.abort;
|
return efr.abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub struct Rand {
|
|||||||
index: isize,
|
index: isize,
|
||||||
|
|
||||||
/// Initialize random state with the given seed.
|
/// Initialize random state with the given seed.
|
||||||
|
#static_eval_enable(false)
|
||||||
pub fn init(seed: u32) -> Rand {
|
pub fn init(seed: u32) -> Rand {
|
||||||
var r: Rand = undefined;
|
var r: Rand = undefined;
|
||||||
r.index = 0;
|
r.index = 0;
|
||||||
|
|||||||
@ -218,6 +218,7 @@ pub fn bar_function() {
|
|||||||
)SOURCE");
|
)SOURCE");
|
||||||
|
|
||||||
add_source_file(tc, "other.zig", R"SOURCE(
|
add_source_file(tc, "other.zig", R"SOURCE(
|
||||||
|
#static_eval_enable(false)
|
||||||
pub fn foo_function() -> bool {
|
pub fn foo_function() -> bool {
|
||||||
// this one conflicts with the one from foo
|
// this one conflicts with the one from foo
|
||||||
return true;
|
return true;
|
||||||
@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void {
|
|||||||
}
|
}
|
||||||
)SOURCE", "loop\nloop\nloop\nloop\n");
|
)SOURCE", "loop\nloop\nloop\nloop\n");
|
||||||
|
|
||||||
add_simple_case("implicit cast after unreachable", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
const x = outer();
|
|
||||||
if (x == 1234) {
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn inner() -> i32 { 1234 }
|
|
||||||
fn outer() -> isize {
|
|
||||||
return inner();
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("@sizeof() and @typeof()", R"SOURCE(
|
add_simple_case("@sizeof() and @typeof()", R"SOURCE(
|
||||||
const io = @import("std").io;
|
const io = @import("std").io;
|
||||||
const x: u16 = 13;
|
const x: u16 = 13;
|
||||||
@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void {
|
|||||||
}
|
}
|
||||||
)SOURCE", "2\n");
|
)SOURCE", "2\n");
|
||||||
|
|
||||||
add_simple_case("member functions", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
struct Rand {
|
|
||||||
seed: u32,
|
|
||||||
pub fn get_seed(r: Rand) -> u32 {
|
|
||||||
r.seed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
const r = Rand {.seed = 1234};
|
|
||||||
if (r.get_seed() != 1234) {
|
|
||||||
%%io.stdout.printf("BAD seed\n");
|
|
||||||
}
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("pointer dereferencing", R"SOURCE(
|
add_simple_case("pointer dereferencing", R"SOURCE(
|
||||||
const io = @import("std").io;
|
const io = @import("std").io;
|
||||||
|
|
||||||
@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void {
|
|||||||
"min i64: -9223372036854775808\n");
|
"min i64: -9223372036854775808\n");
|
||||||
|
|
||||||
|
|
||||||
add_simple_case("else if expression", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
if (f(1) == 1) {
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn f(c: u8) -> u8 {
|
|
||||||
if (c == 0) {
|
|
||||||
0
|
|
||||||
} else if (c == 1) {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("overflow intrinsics", R"SOURCE(
|
add_simple_case("overflow intrinsics", R"SOURCE(
|
||||||
const io = @import("std").io;
|
const io = @import("std").io;
|
||||||
pub fn main(args: [][]u8) -> %void {
|
pub fn main(args: [][]u8) -> %void {
|
||||||
@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void {
|
|||||||
}
|
}
|
||||||
)SOURCE", "OK\n");
|
)SOURCE", "OK\n");
|
||||||
|
|
||||||
add_simple_case("%% binary operator", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
error ItBroke;
|
|
||||||
fn g(x: bool) -> %isize {
|
|
||||||
if (x) {
|
|
||||||
error.ItBroke
|
|
||||||
} else {
|
|
||||||
10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
const a = g(true) %% 3;
|
|
||||||
const b = g(false) %% 3;
|
|
||||||
if (a != 3) {
|
|
||||||
%%io.stdout.printf("BAD\n");
|
|
||||||
}
|
|
||||||
if (b != 10) {
|
|
||||||
%%io.stdout.printf("BAD\n");
|
|
||||||
}
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("string concatenation", R"SOURCE(
|
add_simple_case("string concatenation", R"SOURCE(
|
||||||
const io = @import("std").io;
|
const io = @import("std").io;
|
||||||
pub fn main(args: [][]u8) -> %void {
|
pub fn main(args: [][]u8) -> %void {
|
||||||
@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void {
|
|||||||
}
|
}
|
||||||
)SOURCE", "OK\n");
|
)SOURCE", "OK\n");
|
||||||
|
|
||||||
add_simple_case("unwrap simple value from error", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
fn do() -> %isize {
|
|
||||||
13
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
const i = %%do();
|
|
||||||
if (i != 13) {
|
|
||||||
%%io.stdout.printf("BAD\n");
|
|
||||||
}
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("store member function in variable", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
struct Foo {
|
|
||||||
x: i32,
|
|
||||||
fn member(foo: Foo) -> i32 { foo.x }
|
|
||||||
}
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
const instance = Foo { .x = 1234, };
|
|
||||||
const member_fn = Foo.member;
|
|
||||||
const result = member_fn(instance);
|
|
||||||
if (result != 1234) {
|
|
||||||
%%io.stdout.printf("BAD\n");
|
|
||||||
}
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("call member function directly", R"SOURCE(
|
|
||||||
const io = @import("std").io;
|
|
||||||
struct Foo {
|
|
||||||
x: i32,
|
|
||||||
fn member(foo: Foo) -> i32 { foo.x }
|
|
||||||
}
|
|
||||||
pub fn main(args: [][]u8) -> %void {
|
|
||||||
const instance = Foo { .x = 1234, };
|
|
||||||
const result = Foo.member(instance);
|
|
||||||
if (result != 1234) {
|
|
||||||
%%io.stdout.printf("BAD\n");
|
|
||||||
}
|
|
||||||
%%io.stdout.printf("OK\n");
|
|
||||||
}
|
|
||||||
)SOURCE", "OK\n");
|
|
||||||
|
|
||||||
add_simple_case("call result of if else expression", R"SOURCE(
|
add_simple_case("call result of if else expression", R"SOURCE(
|
||||||
const io = @import("std").io;
|
const io = @import("std").io;
|
||||||
fn a() -> []u8 { "a\n" }
|
fn a() -> []u8 { "a\n" }
|
||||||
@ -1496,7 +1377,8 @@ fn a(x: i32) {
|
|||||||
struct Foo {
|
struct Foo {
|
||||||
y: [get()]u8,
|
y: [get()]u8,
|
||||||
}
|
}
|
||||||
fn get() -> isize { 1 }
|
var global_var: isize = 1;
|
||||||
|
fn get() -> isize { global_var }
|
||||||
)SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression");
|
)SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -123,18 +123,18 @@ fn short_circuit() {
|
|||||||
var hit_3 = false;
|
var hit_3 = false;
|
||||||
var hit_4 = false;
|
var hit_4 = false;
|
||||||
|
|
||||||
if (true || { assert(false); false }) {
|
if (true || {assert_runtime(false); false}) {
|
||||||
hit_1 = true;
|
hit_1 = true;
|
||||||
}
|
}
|
||||||
if (false || { hit_2 = true; false }) {
|
if (false || { hit_2 = true; false }) {
|
||||||
assert(false);
|
assert_runtime(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true && { hit_3 = true; false }) {
|
if (true && { hit_3 = true; false }) {
|
||||||
%%io.stdout.printf("BAD 3\n");
|
assert_runtime(false);
|
||||||
}
|
}
|
||||||
if (false && { assert(false); false }) {
|
if (false && {assert_runtime(false); false}) {
|
||||||
assert(false);
|
assert_runtime(false);
|
||||||
} else {
|
} else {
|
||||||
hit_4 = true;
|
hit_4 = true;
|
||||||
}
|
}
|
||||||
@ -144,6 +144,11 @@ fn short_circuit() {
|
|||||||
assert(hit_4);
|
assert(hit_4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#static_eval_enable(false)
|
||||||
|
fn assert_runtime(b: bool) {
|
||||||
|
if (!b) unreachable{}
|
||||||
|
}
|
||||||
|
|
||||||
#attribute("test")
|
#attribute("test")
|
||||||
fn modify_operators() {
|
fn modify_operators() {
|
||||||
var i : i32 = 0;
|
var i : i32 = 0;
|
||||||
@ -509,6 +514,7 @@ enum Fruit {
|
|||||||
Orange,
|
Orange,
|
||||||
Banana,
|
Banana,
|
||||||
}
|
}
|
||||||
|
#static_eval_enable(false)
|
||||||
fn non_const_switch_on_enum(fruit: Fruit) {
|
fn non_const_switch_on_enum(fruit: Fruit) {
|
||||||
switch (fruit) {
|
switch (fruit) {
|
||||||
Apple => unreachable{},
|
Apple => unreachable{},
|
||||||
@ -521,6 +527,7 @@ fn non_const_switch_on_enum(fruit: Fruit) {
|
|||||||
fn switch_statement() {
|
fn switch_statement() {
|
||||||
non_const_switch(SwitchStatmentFoo.C);
|
non_const_switch(SwitchStatmentFoo.C);
|
||||||
}
|
}
|
||||||
|
#static_eval_enable(false)
|
||||||
fn non_const_switch(foo: SwitchStatmentFoo) {
|
fn non_const_switch(foo: SwitchStatmentFoo) {
|
||||||
const val: i32 = switch (foo) {
|
const val: i32 = switch (foo) {
|
||||||
A => 1,
|
A => 1,
|
||||||
@ -549,6 +556,7 @@ enum SwitchProngWithVarEnum {
|
|||||||
Two: f32,
|
Two: f32,
|
||||||
Meh,
|
Meh,
|
||||||
}
|
}
|
||||||
|
#static_eval_enable(false)
|
||||||
fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) {
|
fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) {
|
||||||
switch(a) {
|
switch(a) {
|
||||||
One => |x| {
|
One => |x| {
|
||||||
@ -569,6 +577,7 @@ fn err_return_in_assignment() {
|
|||||||
%%do_err_return_in_assignment();
|
%%do_err_return_in_assignment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#static_eval_enable(false)
|
||||||
fn do_err_return_in_assignment() -> %void {
|
fn do_err_return_in_assignment() -> %void {
|
||||||
var x : i32 = undefined;
|
var x : i32 = undefined;
|
||||||
x = %return make_a_non_err();
|
x = %return make_a_non_err();
|
||||||
@ -608,7 +617,7 @@ fn explicit_cast_maybe_pointers() {
|
|||||||
|
|
||||||
#attribute("test")
|
#attribute("test")
|
||||||
fn const_expr_eval_on_single_expr_blocks() {
|
fn const_expr_eval_on_single_expr_blocks() {
|
||||||
if (const_expr_eval_on_single_expr_blocks_fn(1, true) != 3) unreachable{}
|
assert(const_expr_eval_on_single_expr_blocks_fn(1, true) == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {
|
fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {
|
||||||
@ -736,6 +745,7 @@ fn generic_malloc_free() {
|
|||||||
mem_free(u8)(a);
|
mem_free(u8)(a);
|
||||||
}
|
}
|
||||||
const some_mem : [100]u8 = undefined;
|
const some_mem : [100]u8 = undefined;
|
||||||
|
#static_eval_enable(false)
|
||||||
fn mem_alloc(T: type)(n: isize) -> %[]T {
|
fn mem_alloc(T: type)(n: isize) -> %[]T {
|
||||||
return (&T)(&some_mem[0])[0...n];
|
return (&T)(&some_mem[0])[0...n];
|
||||||
}
|
}
|
||||||
@ -789,6 +799,7 @@ var goto_counter: i32 = 0;
|
|||||||
fn goto_leave_defer_scope() {
|
fn goto_leave_defer_scope() {
|
||||||
test_goto_leave_defer_scope(true);
|
test_goto_leave_defer_scope(true);
|
||||||
}
|
}
|
||||||
|
#static_eval_enable(false)
|
||||||
fn test_goto_leave_defer_scope(b: bool) {
|
fn test_goto_leave_defer_scope(b: bool) {
|
||||||
var it_worked = false;
|
var it_worked = false;
|
||||||
|
|
||||||
@ -820,3 +831,83 @@ fn cast_small_unsigned_to_larger_signed() {
|
|||||||
}
|
}
|
||||||
fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x }
|
fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x }
|
||||||
fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x }
|
fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x }
|
||||||
|
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn implicit_cast_after_unreachable() {
|
||||||
|
assert(outer() == 1234);
|
||||||
|
}
|
||||||
|
fn inner() -> i32 { 1234 }
|
||||||
|
fn outer() -> isize {
|
||||||
|
return inner();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn else_if_expression() {
|
||||||
|
assert(else_if_expression_f(1) == 1);
|
||||||
|
}
|
||||||
|
fn else_if_expression_f(c: u8) -> u8 {
|
||||||
|
if (c == 0) {
|
||||||
|
0
|
||||||
|
} else if (c == 1) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn err_binary_operator() {
|
||||||
|
const a = err_binary_operator_g(true) %% 3;
|
||||||
|
const b = err_binary_operator_g(false) %% 3;
|
||||||
|
assert(a == 3);
|
||||||
|
assert(b == 10);
|
||||||
|
}
|
||||||
|
error ItBroke;
|
||||||
|
fn err_binary_operator_g(x: bool) -> %isize {
|
||||||
|
if (x) {
|
||||||
|
error.ItBroke
|
||||||
|
} else {
|
||||||
|
10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn unwrap_simple_value_from_error() {
|
||||||
|
const i = %%unwrap_simple_value_from_error_do();
|
||||||
|
assert(i == 13);
|
||||||
|
}
|
||||||
|
fn unwrap_simple_value_from_error_do() -> %isize { 13 }
|
||||||
|
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn store_member_function_in_variable() {
|
||||||
|
const instance = MemberFnTestFoo { .x = 1234, };
|
||||||
|
const member_fn = MemberFnTestFoo.member;
|
||||||
|
const result = member_fn(instance);
|
||||||
|
assert(result == 1234);
|
||||||
|
}
|
||||||
|
struct MemberFnTestFoo {
|
||||||
|
x: i32,
|
||||||
|
fn member(foo: MemberFnTestFoo) -> i32 { foo.x }
|
||||||
|
}
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn call_member_function_directly() {
|
||||||
|
const instance = MemberFnTestFoo { .x = 1234, };
|
||||||
|
const result = MemberFnTestFoo.member(instance);
|
||||||
|
assert(result == 1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
#attribute("test")
|
||||||
|
fn member_functions() {
|
||||||
|
const r = MemberFnRand {.seed = 1234};
|
||||||
|
assert(r.get_seed() == 1234);
|
||||||
|
}
|
||||||
|
struct MemberFnRand {
|
||||||
|
seed: u32,
|
||||||
|
pub fn get_seed(r: MemberFnRand) -> u32 {
|
||||||
|
r.seed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user