parent
47cf8520ad
commit
201a3c121a
|
@ -123,7 +123,7 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
|
|||
|
||||
PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
|
||||
|
||||
SuffixOpExpression = option("inline") PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
|
||||
FieldAccessExpression = "." Symbol
|
||||
|
||||
|
@ -141,11 +141,13 @@ StructLiteralField = "." Symbol "=" Expression
|
|||
|
||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
|
||||
|
||||
PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
|
||||
PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | CompTimeExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
|
||||
|
||||
ArrayType = "[" option(Expression) "]" option("const") TypeExpr
|
||||
|
||||
GotoExpression = option("inline") "goto" Symbol
|
||||
GotoExpression = "goto" Symbol
|
||||
|
||||
CompTimeExpression = option("comptime") Expression
|
||||
|
||||
GroupedExpression = "(" Expression ")"
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
71
src/ir.cpp
71
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue