remove ability to mark if and switch as inline
if and switch are implicitly inline if the condition/target expression is known at compile time. instead of: ``` inline if (condition) ... inline switch (target) ... ``` one can use: ``` if (comptime condition) ... switch (comptime target) ... ```
This commit is contained in:
parent
cd08c1f3be
commit
b78c91951a
@ -73,7 +73,7 @@ BlockExpression = IfExpression | Block | WhileExpression | ForExpression | Switc
|
|||||||
|
|
||||||
CompTimeExpression = option("comptime") Expression
|
CompTimeExpression = option("comptime") Expression
|
||||||
|
|
||||||
SwitchExpression = option("inline") "switch" "(" Expression ")" "{" many(SwitchProng) "}"
|
SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"
|
||||||
|
|
||||||
SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
|
SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
|
||||||
|
|
||||||
@ -91,9 +91,9 @@ Defer = option("%" | "?") "defer" Expression
|
|||||||
|
|
||||||
IfExpression = IfVarExpression | IfBoolExpression
|
IfExpression = IfVarExpression | IfBoolExpression
|
||||||
|
|
||||||
IfBoolExpression = option("inline") "if" "(" Expression ")" Expression option(Else)
|
IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
|
||||||
|
|
||||||
IfVarExpression = option("inline") "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
|
IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
|
||||||
|
|
||||||
Else = "else" Expression
|
Else = "else" Expression
|
||||||
|
|
||||||
|
@ -509,7 +509,6 @@ struct AstNodeIfBoolExpr {
|
|||||||
AstNode *condition;
|
AstNode *condition;
|
||||||
AstNode *then_block;
|
AstNode *then_block;
|
||||||
AstNode *else_node; // null, block node, or other if expr node
|
AstNode *else_node; // null, block node, or other if expr node
|
||||||
bool is_inline;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeIfVarExpr {
|
struct AstNodeIfVarExpr {
|
||||||
@ -517,7 +516,6 @@ struct AstNodeIfVarExpr {
|
|||||||
AstNode *then_block;
|
AstNode *then_block;
|
||||||
AstNode *else_node; // null, block node, or other if expr node
|
AstNode *else_node; // null, block node, or other if expr node
|
||||||
bool var_is_ptr;
|
bool var_is_ptr;
|
||||||
bool is_inline;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeWhileExpr {
|
struct AstNodeWhileExpr {
|
||||||
@ -539,7 +537,6 @@ struct AstNodeForExpr {
|
|||||||
struct AstNodeSwitchExpr {
|
struct AstNodeSwitchExpr {
|
||||||
AstNode *expr;
|
AstNode *expr;
|
||||||
ZigList<AstNode *> prongs;
|
ZigList<AstNode *> prongs;
|
||||||
bool is_inline;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeSwitchProng {
|
struct AstNodeSwitchProng {
|
||||||
@ -677,11 +674,9 @@ struct AstNodeBoolLiteral {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeBreakExpr {
|
struct AstNodeBreakExpr {
|
||||||
bool is_inline; // TODO
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeContinueExpr {
|
struct AstNodeContinueExpr {
|
||||||
bool is_inline; // TODO
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeArrayType {
|
struct AstNodeArrayType {
|
||||||
|
@ -844,14 +844,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||||||
}
|
}
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
{
|
{
|
||||||
const char *inline_str = node->data.break_expr.is_inline ? "inline " : "";
|
fprintf(ar->f, "break");
|
||||||
fprintf(ar->f, "%sbreak", inline_str);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeTypeContinue:
|
case NodeTypeContinue:
|
||||||
{
|
{
|
||||||
const char *inline_str = node->data.continue_expr.is_inline ? "inline " : "";
|
fprintf(ar->f, "continue");
|
||||||
fprintf(ar->f, "%scontinue", inline_str);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeTypeSliceExpr:
|
case NodeTypeSliceExpr:
|
||||||
|
10
src/ir.cpp
10
src/ir.cpp
@ -4148,7 +4148,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
|
|||||||
return condition;
|
return condition;
|
||||||
|
|
||||||
IrInstruction *is_comptime;
|
IrInstruction *is_comptime;
|
||||||
if (ir_should_inline(irb->exec, scope) || node->data.if_bool_expr.is_inline) {
|
if (ir_should_inline(irb->exec, scope)) {
|
||||||
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
||||||
} else {
|
} else {
|
||||||
is_comptime = ir_build_test_comptime(irb, scope, node, condition);
|
is_comptime = ir_build_test_comptime(irb, scope, node, condition);
|
||||||
@ -4695,7 +4695,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
|
|||||||
IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "MaybeEndIf");
|
IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "MaybeEndIf");
|
||||||
|
|
||||||
IrInstruction *is_comptime;
|
IrInstruction *is_comptime;
|
||||||
if (ir_should_inline(irb->exec, scope) || node->data.if_var_expr.is_inline) {
|
if (ir_should_inline(irb->exec, scope)) {
|
||||||
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
||||||
} else {
|
} else {
|
||||||
is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
|
is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
|
||||||
@ -4807,7 +4807,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
|
|||||||
ZigList<IrInstructionSwitchBrCase> cases = {0};
|
ZigList<IrInstructionSwitchBrCase> cases = {0};
|
||||||
|
|
||||||
IrInstruction *is_comptime;
|
IrInstruction *is_comptime;
|
||||||
if (ir_should_inline(irb->exec, scope) || node->data.switch_expr.is_inline) {
|
if (ir_should_inline(irb->exec, scope)) {
|
||||||
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
||||||
} else {
|
} else {
|
||||||
is_comptime = ir_build_test_comptime(irb, scope, node, target_value);
|
is_comptime = ir_build_test_comptime(irb, scope, node, target_value);
|
||||||
@ -5002,7 +5002,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node)
|
|||||||
LoopStackItem *loop_stack_item = &irb->loop_stack.last();
|
LoopStackItem *loop_stack_item = &irb->loop_stack.last();
|
||||||
|
|
||||||
IrInstruction *is_comptime;
|
IrInstruction *is_comptime;
|
||||||
if (ir_should_inline(irb->exec, scope) || node->data.break_expr.is_inline) {
|
if (ir_should_inline(irb->exec, scope)) {
|
||||||
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
||||||
} else {
|
} else {
|
||||||
is_comptime = loop_stack_item->is_comptime;
|
is_comptime = loop_stack_item->is_comptime;
|
||||||
@ -5025,7 +5025,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod
|
|||||||
LoopStackItem *loop_stack_item = &irb->loop_stack.last();
|
LoopStackItem *loop_stack_item = &irb->loop_stack.last();
|
||||||
|
|
||||||
IrInstruction *is_comptime;
|
IrInstruction *is_comptime;
|
||||||
if (ir_should_inline(irb->exec, scope) || node->data.continue_expr.is_inline) {
|
if (ir_should_inline(irb->exec, scope)) {
|
||||||
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
||||||
} else {
|
} else {
|
||||||
is_comptime = loop_stack_item->is_comptime;
|
is_comptime = loop_stack_item->is_comptime;
|
||||||
|
@ -1313,30 +1313,17 @@ static AstNode *ast_parse_else(ParseContext *pc, size_t *token_index, bool manda
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
IfExpression : IfVarExpression | IfBoolExpression
|
IfExpression : IfVarExpression | IfBoolExpression
|
||||||
IfBoolExpression = option("inline") "if" "(" Expression ")" Expression option(Else)
|
IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
|
||||||
IfVarExpression = option("inline") "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
|
IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
Token *first_token = &pc->tokens->at(*token_index);
|
Token *if_token = &pc->tokens->at(*token_index);
|
||||||
Token *if_tok;
|
|
||||||
|
|
||||||
bool is_inline;
|
if (if_token->id == TokenIdKeywordIf) {
|
||||||
if (first_token->id == TokenIdKeywordInline) {
|
|
||||||
if_tok = &pc->tokens->at(*token_index + 1);
|
|
||||||
if (if_tok->id == TokenIdKeywordIf) {
|
|
||||||
is_inline = true;
|
|
||||||
*token_index += 2;
|
|
||||||
} else if (mandatory) {
|
|
||||||
ast_expect_token(pc, if_tok, TokenIdKeywordIf);
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else if (first_token->id == TokenIdKeywordIf) {
|
|
||||||
if_tok = first_token;
|
|
||||||
is_inline = false;
|
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
} else if (mandatory) {
|
} else if (mandatory) {
|
||||||
ast_expect_token(pc, first_token, TokenIdKeywordIf);
|
ast_expect_token(pc, if_token, TokenIdKeywordIf);
|
||||||
|
zig_unreachable();
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1345,8 +1332,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
|
|||||||
|
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {
|
if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_tok);
|
AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_token);
|
||||||
node->data.if_var_expr.is_inline = is_inline;
|
|
||||||
node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);
|
node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
|
|
||||||
@ -1383,8 +1369,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
|
|||||||
|
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok);
|
AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_token);
|
||||||
node->data.if_bool_expr.is_inline = is_inline;
|
|
||||||
node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);
|
node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);
|
||||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||||
node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);
|
node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);
|
||||||
@ -1700,38 +1685,22 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SwitchExpression = option("inline") "switch" "(" Expression ")" "{" many(SwitchProng) "}"
|
SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"
|
||||||
SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
|
SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbol "|") Expression ","
|
||||||
SwitchItem : Expression | (Expression "..." Expression)
|
SwitchItem : Expression | (Expression "..." Expression)
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
Token *first_token = &pc->tokens->at(*token_index);
|
Token *switch_token = &pc->tokens->at(*token_index);
|
||||||
Token *switch_token;
|
if (switch_token->id == TokenIdKeywordSwitch) {
|
||||||
bool is_inline;
|
|
||||||
if (first_token->id == TokenIdKeywordInline) {
|
|
||||||
is_inline = true;
|
|
||||||
switch_token = &pc->tokens->at(*token_index + 1);
|
|
||||||
if (switch_token->id == TokenIdKeywordSwitch) {
|
|
||||||
*token_index += 2;
|
|
||||||
} else if (mandatory) {
|
|
||||||
ast_expect_token(pc, first_token, TokenIdKeywordSwitch);
|
|
||||||
zig_unreachable();
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else if (first_token->id == TokenIdKeywordSwitch) {
|
|
||||||
is_inline = false;
|
|
||||||
switch_token = first_token;
|
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
} else if (mandatory) {
|
} else if (mandatory) {
|
||||||
ast_expect_token(pc, first_token, TokenIdKeywordSwitch);
|
ast_expect_token(pc, switch_token, TokenIdKeywordSwitch);
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeSwitchExpr, switch_token);
|
AstNode *node = ast_create_node(pc, NodeTypeSwitchExpr, switch_token);
|
||||||
node->data.switch_expr.is_inline = is_inline;
|
|
||||||
|
|
||||||
ast_eat_token(pc, token_index, TokenIdLParen);
|
ast_eat_token(pc, token_index, TokenIdLParen);
|
||||||
node->data.switch_expr.expr = ast_parse_expression(pc, token_index, true);
|
node->data.switch_expr.expr = ast_parse_expression(pc, token_index, true);
|
||||||
|
@ -150,7 +150,7 @@ pub const OutStream = struct {
|
|||||||
@compileError("Incomplete format string: " ++ format);
|
@compileError("Incomplete format string: " ++ format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline if (start_index < format.len) {
|
if (start_index < format.len) {
|
||||||
%return self.write(format[start_index...format.len]);
|
%return self.write(format[start_index...format.len]);
|
||||||
}
|
}
|
||||||
%return self.flush();
|
%return self.flush();
|
||||||
|
@ -33,18 +33,21 @@ fn testSwitchWithAllRanges(x: u32, y: u32) -> u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inlineSwitch() {
|
fn implicitComptimeSwitch() {
|
||||||
@setFnTest(this);
|
@setFnTest(this);
|
||||||
|
|
||||||
const x = 3 + 4;
|
const x = 3 + 4;
|
||||||
const result = inline switch (x) {
|
const result = switch (x) {
|
||||||
3 => 10,
|
3 => 10,
|
||||||
4 => 11,
|
4 => 11,
|
||||||
5, 6 => 12,
|
5, 6 => 12,
|
||||||
7, 8 => 13,
|
7, 8 => 13,
|
||||||
else => 14,
|
else => 14,
|
||||||
};
|
};
|
||||||
assert(result + 1 == 14);
|
|
||||||
|
comptime {
|
||||||
|
assert(result + 1 == 14);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn switchOnEnum() {
|
fn switchOnEnum() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user