diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-01-22 22:59:52 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-01-22 22:59:52 -0500 |
| commit | 201a3c121a5c28273138b1160c5aac4e24d619bd (patch) | |
| tree | 68480040ae3c4cedce7d8bf953cd69359b6749f1 /src | |
| parent | 47cf8520adb245dbd34ad60fc9206b7eaab5e0be (diff) | |
| download | zig-201a3c121a5c28273138b1160c5aac4e24d619bd.tar.gz zig-201a3c121a5c28273138b1160c5aac4e24d619bd.zip | |
introduce comptime expression
closes #221
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 15 | ||||
| -rw-r--r-- | src/analyze.cpp | 70 | ||||
| -rw-r--r-- | src/analyze.hpp | 3 | ||||
| -rw-r--r-- | src/ast_render.cpp | 11 | ||||
| -rw-r--r-- | src/codegen.cpp | 3 | ||||
| -rw-r--r-- | src/ir.cpp | 71 | ||||
| -rw-r--r-- | src/parser.cpp | 73 |
7 files changed, 113 insertions, 133 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 60e22f49f1..61f7d7cc8b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -280,6 +280,7 @@ enum NodeType { NodeTypeSwitchRange, NodeTypeLabel, NodeTypeGoto, + NodeTypeCompTime, NodeTypeBreak, NodeTypeContinue, NodeTypeAsmExpr, @@ -449,7 +450,6 @@ struct AstNodeFnCallExpr { AstNode *fn_ref_expr; ZigList<AstNode *> params; bool is_builtin; - bool is_comptime; }; struct AstNodeArrayAccessExpr { @@ -556,6 +556,10 @@ struct AstNodeGoto { bool is_inline; }; +struct AstNodeCompTime { + AstNode *expr; +}; + struct AsmOutput { Buf *asm_symbolic_name; Buf *constraint; @@ -721,6 +725,7 @@ struct AstNode { AstNodeSwitchRange switch_range; AstNodeLabel label; AstNodeGoto goto_expr; + AstNodeCompTime comptime_expr; AstNodeAsmExpr asm_expr; AstNodeFieldAccessExpr field_access_expr; AstNodeContainerDecl container_decl; @@ -1289,6 +1294,7 @@ enum ScopeId { ScopeIdCImport, ScopeIdLoop, ScopeIdFnDef, + ScopeIdCompTime, }; struct Scope { @@ -1366,6 +1372,13 @@ struct ScopeLoop { Scope base; }; +// This scope is created for a comptime expression. +// NodeTypeCompTime +struct ScopeCompTime { + Scope base; +}; + + // This scope is created for a function definition. // NodeTypeFnDef struct ScopeFnDef { diff --git a/src/analyze.cpp b/src/analyze.cpp index ed62784ea2..3308901628 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -24,67 +24,6 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type); static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); -AstNode *first_executing_node(AstNode *node) { - switch (node->type) { - case NodeTypeFnCallExpr: - return first_executing_node(node->data.fn_call_expr.fn_ref_expr); - case NodeTypeBinOpExpr: - return first_executing_node(node->data.bin_op_expr.op1); - case NodeTypeUnwrapErrorExpr: - return first_executing_node(node->data.unwrap_err_expr.op1); - case NodeTypeArrayAccessExpr: - return first_executing_node(node->data.array_access_expr.array_ref_expr); - case NodeTypeSliceExpr: - return first_executing_node(node->data.slice_expr.array_ref_expr); - case NodeTypeFieldAccessExpr: - return first_executing_node(node->data.field_access_expr.struct_expr); - case NodeTypeSwitchRange: - return first_executing_node(node->data.switch_range.start); - case NodeTypeRoot: - case NodeTypeFnProto: - case NodeTypeFnDef: - case NodeTypeFnDecl: - case NodeTypeParamDecl: - case NodeTypeBlock: - case NodeTypeReturnExpr: - case NodeTypeDefer: - case NodeTypeVariableDeclaration: - case NodeTypeTypeDecl: - case NodeTypeErrorValueDecl: - case NodeTypeNumberLiteral: - case NodeTypeStringLiteral: - case NodeTypeCharLiteral: - case NodeTypeSymbol: - case NodeTypePrefixOpExpr: - case NodeTypeUse: - case NodeTypeBoolLiteral: - case NodeTypeNullLiteral: - case NodeTypeUndefinedLiteral: - case NodeTypeThisLiteral: - case NodeTypeIfBoolExpr: - case NodeTypeIfVarExpr: - case NodeTypeLabel: - case NodeTypeGoto: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeAsmExpr: - case NodeTypeContainerDecl: - case NodeTypeStructField: - case NodeTypeStructValueField: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeSwitchExpr: - case NodeTypeSwitchProng: - case NodeTypeArrayType: - case NodeTypeErrorType: - case NodeTypeTypeLiteral: - case NodeTypeContainerInitExpr: - case NodeTypeVarLiteral: - return node; - } - zig_unreachable(); -} - ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { // if this assert fails, then parseh generated code that // failed semantic analysis, which isn't supposed to happen @@ -199,6 +138,13 @@ ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_en return scope; } +Scope *create_comptime_scope(AstNode *node, Scope *parent) { + assert(node->type == NodeTypeCompTime); + ScopeCompTime *scope = allocate<ScopeCompTime>(1); + init_scope(&scope->base, ScopeIdCompTime, node, parent); + return &scope->base; +} + ImportTableEntry *get_scope_import(Scope *scope) { while (scope) { if (scope->id == ScopeIdDecls) { @@ -1804,6 +1750,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeSwitchRange: case NodeTypeLabel: case NodeTypeGoto: + case NodeTypeCompTime: case NodeTypeBreak: case NodeTypeContinue: case NodeTypeAsmExpr: @@ -2199,6 +2146,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { case ScopeIdVarDecl: case ScopeIdCImport: case ScopeIdLoop: + case ScopeIdCompTime: scope = scope->parent; continue; case ScopeIdFnDef: diff --git a/src/analyze.hpp b/src/analyze.hpp index 50b16e67b1..ad51caa2b4 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -42,8 +42,6 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code); -AstNode *first_executing_node(AstNode *node); - // TODO move these over, these used to be static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type); @@ -95,6 +93,7 @@ ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent); Scope *create_loop_scope(AstNode *node, Scope *parent); ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); +Scope *create_comptime_scope(AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 655570716e..20fcf955cf 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -197,6 +197,8 @@ static const char *node_type_str(NodeType node_type) { return "Label"; case NodeTypeGoto: return "Goto"; + case NodeTypeCompTime: + return "CompTime"; case NodeTypeBreak: return "Break"; case NodeTypeContinue: @@ -810,8 +812,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } case NodeTypeGoto: { - const char *inline_str = node->data.goto_expr.is_inline ? "inline " : ""; - fprintf(ar->f, "%sgoto %s", inline_str, buf_ptr(node->data.goto_expr.name)); + fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name)); + break; + } + case NodeTypeCompTime: + { + fprintf(ar->f, "comptime "); + render_node_grouped(ar, node->data.comptime_expr.expr); break; } case NodeTypeForExpr: diff --git a/src/codegen.cpp b/src/codegen.cpp index b068042ced..5d1f52fb0f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -316,7 +316,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { case ScopeIdBlock: case ScopeIdDefer: case ScopeIdVarDecl: - case ScopeIdLoop: { assert(scope->parent); ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, @@ -328,6 +327,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { return scope->di_scope; } case ScopeIdDeferExpr: + case ScopeIdLoop: + case ScopeIdCompTime: return get_di_scope(g, scope->parent); } zig_unreachable(); diff --git a/src/ir.cpp b/src/ir.cpp index e422545473..9842d2f3ad 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -64,8 +64,16 @@ ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) { } } -static bool ir_should_inline(IrBuilder *irb) { - return irb->exec->is_inline; +static bool ir_should_inline(IrExecutable *exec, Scope *scope) { + if (exec->is_inline) + return true; + + while (scope != nullptr) { + if (scope->id == ScopeIdCompTime) + return true; + scope = scope->parent; + } + return false; } static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { @@ -2904,7 +2912,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); IrInstruction *is_comptime; - if (ir_should_inline(irb)) { + if (ir_should_inline(irb->exec, scope)) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, is_err); @@ -2926,7 +2934,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, return_value); IrInstruction *is_comptime; - if (ir_should_inline(irb)) { + if (ir_should_inline(irb->exec, scope)) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); @@ -2958,7 +2966,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn"); IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "ErrRetContinue"); - IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb)); + IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb->exec, scope)); ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime)); ir_set_cursor_at_end(irb, return_block); @@ -2984,7 +2992,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn"); IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue"); - IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb)); + IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb->exec, scope)); ir_mark_gen(ir_build_cond_br(irb, scope, node, is_non_null, continue_block, return_block, is_comptime)); ir_set_cursor_at_end(irb, return_block); @@ -3128,7 +3136,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode if (!return_value || !instr_is_unreachable(return_value)) { IrInstruction *is_comptime = ir_mark_gen(ir_build_const_bool(irb, child_scope, statement_node, - ir_should_inline(irb))); + ir_should_inline(irb->exec, child_scope))); ir_mark_gen(ir_build_br(irb, child_scope, statement_node, label_block, is_comptime)); } ir_set_cursor_at_end(irb, label_block); @@ -3207,7 +3215,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node IrBasicBlock *post_val1_block = irb->current_basic_block; IrInstruction *is_comptime; - if (ir_should_inline(irb)) { + if (ir_should_inline(irb->exec, scope)) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, val1); @@ -3249,7 +3257,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod IrBasicBlock *post_val1_block = irb->current_basic_block; IrInstruction *is_comptime; - if (ir_should_inline(irb)) { + if (ir_should_inline(irb->exec, scope)) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, val1); @@ -3296,7 +3304,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val); IrInstruction *is_comptime; - if (ir_should_inline(irb)) { + if (ir_should_inline(irb->exec, parent_scope)) { is_comptime = ir_build_const_bool(irb, parent_scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null); @@ -4042,8 +4050,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node return args[i]; } - bool is_comptime = node->data.fn_call_expr.is_comptime; - return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, is_comptime); + return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false); } static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -4054,7 +4061,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode return condition; IrInstruction *is_comptime; - if (ir_should_inline(irb) || node->data.if_bool_expr.is_inline) { + if (ir_should_inline(irb->exec, scope) || node->data.if_bool_expr.is_inline) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, condition); @@ -4281,7 +4288,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod bool is_const = variable_declaration->is_const; bool is_extern = variable_declaration->is_extern; IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, - ir_should_inline(irb) || variable_declaration->is_inline); + ir_should_inline(irb->exec, scope) || variable_declaration->is_inline); VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol, is_const, is_const, is_shadowable, is_comptime); // we detect IrInstructionIdDeclVar in gen_block to make sure the next node @@ -4312,7 +4319,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd"); IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, - ir_should_inline(irb) || node->data.while_expr.is_inline); + ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); ir_build_br(irb, scope, node, cond_block, is_comptime); if (continue_expr_node) { @@ -4381,7 +4388,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, - ir_should_inline(irb) || node->data.for_expr.is_inline); + ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); Scope *child_scope = create_loop_scope(node, parent_scope); @@ -4602,7 +4609,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "MaybeEndIf"); IrInstruction *is_comptime; - if (ir_should_inline(irb) || node->data.if_var_expr.is_inline) { + if (ir_should_inline(irb->exec, scope) || node->data.if_var_expr.is_inline) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); @@ -4714,7 +4721,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * ZigList<IrInstructionSwitchBrCase> cases = {0}; IrInstruction *is_comptime; - if (ir_should_inline(irb) || node->data.switch_expr.is_inline) { + if (ir_should_inline(irb->exec, scope) || node->data.switch_expr.is_inline) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, scope, node, target_value); @@ -4892,6 +4899,13 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { return ir_build_unreachable(irb, scope, node); } +static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LValPurpose lval) { + assert(node->type == NodeTypeCompTime); + + Scope *child_scope = create_comptime_scope(node, parent_scope); + return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); +} + static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeBreak); @@ -4904,7 +4918,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) LoopStackItem *loop_stack_item = &irb->loop_stack.last(); IrInstruction *is_comptime; - if (ir_should_inline(irb) || node->data.break_expr.is_inline) { + if (ir_should_inline(irb->exec, scope) || node->data.break_expr.is_inline) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = loop_stack_item->is_comptime; @@ -4927,7 +4941,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod LoopStackItem *loop_stack_item = &irb->loop_stack.last(); IrInstruction *is_comptime; - if (ir_should_inline(irb) || node->data.continue_expr.is_inline) { + if (ir_should_inline(irb->exec, scope) || node->data.continue_expr.is_inline) { is_comptime = ir_build_const_bool(irb, scope, node, true); } else { is_comptime = loop_stack_item->is_comptime; @@ -5003,7 +5017,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val); IrInstruction *is_comptime; - if (ir_should_inline(irb)) { + if (ir_should_inline(irb->exec, parent_scope)) { is_comptime = ir_build_const_bool(irb, parent_scope, node, true); } else { is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err); @@ -5197,6 +5211,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); case NodeTypeGoto: return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval); + case NodeTypeCompTime: + return ir_gen_comptime(irb, scope, node, lval); case NodeTypeTypeLiteral: return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval); case NodeTypeErrorType: @@ -5259,7 +5275,7 @@ static bool ir_goto_pass2(IrBuilder *irb) { label->used = true; IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node, - ir_should_inline(irb) || source_node->data.goto_expr.is_inline); + ir_should_inline(irb->exec, goto_item->scope) || source_node->data.goto_expr.is_inline); if (!ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false, false)) { add_node_error(irb->codegen, source_node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); @@ -5379,7 +5395,7 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) } static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { - if (ir_should_inline(&ira->new_irb)) { + if (ir_should_inline(ira->new_irb.exec, source_instruction->scope)) { ir_add_error(ira, source_instruction, buf_sprintf("unable to evaluate constant expression")); return false; } @@ -7841,7 +7857,8 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction if (fn_ref->value.type->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; - bool is_inline = call_instruction->is_comptime || ir_should_inline(&ira->new_irb); + bool is_inline = call_instruction->is_comptime || + ir_should_inline(ira->new_irb.exec, call_instruction->base.scope); if (is_inline || instr_is_comptime(fn_ref)) { if (fn_ref->value.type->id == TypeTableEntryIdMetaType) { @@ -8146,7 +8163,7 @@ static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstruct return ir_unreach_error(ira); if (!cond_br_instruction->base.is_gen && !condition->value.depends_on_compile_var && - !ir_should_inline(&ira->new_irb)) + !ir_should_inline(ira->new_irb.exec, cond_br_instruction->base.scope)) { const char *true_or_false = cond_is_true ? "true" : "false"; ir_add_error(ira, &cond_br_instruction->base, @@ -9814,7 +9831,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count); - bool is_comptime = ir_should_inline(&ira->new_irb); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); ConstExprValue const_val = {}; const_val.special = ConstValSpecialStatic; @@ -9931,7 +9948,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count); const_val.data.x_array.size = elem_count; - bool is_comptime = ir_should_inline(&ira->new_irb); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); IrInstruction **new_items = allocate<IrInstruction *>(elem_count); diff --git a/src/parser.cpp b/src/parser.cpp index 569a23d130..dbb6836e60 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -585,29 +585,14 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m } /* -GotoExpression = option("inline") "goto" Symbol +GotoExpression = "goto" Symbol */ static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool mandatory) { - Token *first_token = &pc->tokens->at(*token_index); - Token *goto_token; - bool is_inline; - if (first_token->id == TokenIdKeywordInline) { - is_inline = true; - goto_token = &pc->tokens->at(*token_index + 1); - if (goto_token->id == TokenIdKeywordGoto) { - *token_index += 2; - } else if (mandatory) { - ast_expect_token(pc, first_token, TokenIdKeywordGoto); - zig_unreachable(); - } else { - return nullptr; - } - } else if (first_token->id == TokenIdKeywordGoto) { - goto_token = first_token; - is_inline = false; + Token *goto_token = &pc->tokens->at(*token_index); + if (goto_token->id == TokenIdKeywordGoto) { *token_index += 1; } else if (mandatory) { - ast_expect_token(pc, first_token, TokenIdKeywordGoto); + ast_expect_token(pc, goto_token, TokenIdKeywordGoto); zig_unreachable(); } else { return nullptr; @@ -617,11 +602,30 @@ static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool Token *dest_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); node->data.goto_expr.name = token_buf(dest_symbol); - node->data.goto_expr.is_inline = is_inline; return node; } + /* -PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl +CompTimeExpression = "comptime" Expression +*/ +static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, bool mandatory) { + Token *comptime_token = &pc->tokens->at(*token_index); + if (comptime_token->id == TokenIdKeywordCompTime) { + *token_index += 1; + } else if (mandatory) { + ast_expect_token(pc, comptime_token, TokenIdKeywordCompTime); + zig_unreachable(); + } else { + return nullptr; + } + + AstNode *node = ast_create_node(pc, NodeTypeCompTime, comptime_token); + node->data.comptime_expr.expr = ast_parse_expression(pc, token_index, true); + return node; +} + +/* +PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | CompTimeExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" */ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -706,6 +710,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo if (goto_node) return goto_node; + AstNode *comptime_node = ast_parse_comptime_expr(pc, token_index, false); + if (comptime_node) + return comptime_node; + AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); if (grouped_expr_node) { return grouped_expr_node; @@ -835,7 +843,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde } /* -SuffixOpExpression = option("inline") PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) +SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) ArrayAccessExpression : token(LBracket) Expression token(RBracket) SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) @@ -843,24 +851,9 @@ FieldAccessExpression : token(Dot) token(Symbol) StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression */ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { - Token *inline_token = &pc->tokens->at(*token_index); - bool is_comptime; - if (inline_token->id == TokenIdKeywordInline) { - // TODO make it an error if something other than function call has the comptime keyword - is_comptime = true; - *token_index += 1; - } else { - is_comptime = false; - } - - AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); - if (!primary_expr) { - if (is_comptime) { - *token_index -= 1; - } + if (!primary_expr) return nullptr; - } while (true) { Token *first_token = &pc->tokens->at(*token_index); @@ -869,7 +862,6 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token); node->data.fn_call_expr.fn_ref_expr = primary_expr; - node->data.fn_call_expr.is_comptime = is_comptime; ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); primary_expr = node; @@ -2624,6 +2616,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeGoto: // none break; + case NodeTypeCompTime: + visit_field(&node->data.comptime_expr.expr, visit, context); + break; case NodeTypeBreak: // none break; |
