mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
translate-c: better way to translate switch
previously `continue` would be handled incorrectly
This commit is contained in:
parent
1b0e90f70b
commit
aa2ca3f02c
@ -82,6 +82,7 @@ struct TransScopeSwitch {
|
||||
AstNode *switch_node;
|
||||
uint32_t case_index;
|
||||
bool found_default;
|
||||
Buf *end_label_name;
|
||||
};
|
||||
|
||||
struct TransScopeVar {
|
||||
@ -248,6 +249,18 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_node_goto(Context *c, Buf *label_name) {
|
||||
AstNode *goto_node = trans_create_node(c, NodeTypeGoto);
|
||||
goto_node->data.goto_expr.name = label_name;
|
||||
return goto_node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_node_label(Context *c, Buf *label_name) {
|
||||
AstNode *label_node = trans_create_node(c, NodeTypeLabel);
|
||||
label_node->data.label.name = label_name;
|
||||
return label_node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_node_bool(Context *c, bool value) {
|
||||
AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral);
|
||||
bool_node->data.bool_literal.value = value;
|
||||
@ -2283,11 +2296,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt
|
||||
}
|
||||
|
||||
static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {
|
||||
TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope);
|
||||
while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
|
||||
|
||||
TransScopeBlock *block_scope = trans_scope_block_create(c, &while_scope->base);
|
||||
while_scope->node->data.while_expr.body = block_scope->node;
|
||||
TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope);
|
||||
|
||||
TransScopeSwitch *switch_scope;
|
||||
|
||||
@ -2305,6 +2314,10 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw
|
||||
}
|
||||
block_scope->node->data.block.statements.append(switch_scope->switch_node);
|
||||
|
||||
// TODO avoid name collisions
|
||||
Buf *end_label_name = buf_create_from_str("end");
|
||||
switch_scope->end_label_name = end_label_name;
|
||||
|
||||
const Expr *cond_expr = stmt->getCond();
|
||||
assert(cond_expr != nullptr);
|
||||
|
||||
@ -2336,9 +2349,11 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw
|
||||
}
|
||||
|
||||
// This is necessary if the last switch case "falls through" the end of the switch block
|
||||
block_scope->node->data.block.statements.append(trans_create_node(c, NodeTypeBreak));
|
||||
block_scope->node->data.block.statements.append(trans_create_node_goto(c, end_label_name));
|
||||
|
||||
return while_scope->node;
|
||||
block_scope->node->data.block.statements.append(trans_create_node_label(c, end_label_name));
|
||||
|
||||
return block_scope->node;
|
||||
}
|
||||
|
||||
static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,
|
||||
@ -2365,18 +2380,13 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStm
|
||||
return ErrorUnexpected;
|
||||
prong_node->data.switch_prong.items.append(item_node);
|
||||
|
||||
AstNode *goto_node = trans_create_node(c, NodeTypeGoto);
|
||||
goto_node->data.goto_expr.name = label_name;
|
||||
prong_node->data.switch_prong.expr = goto_node;
|
||||
prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name);
|
||||
|
||||
switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
|
||||
}
|
||||
|
||||
AstNode *label_node = trans_create_node(c, NodeTypeLabel);
|
||||
label_node->data.label.name = label_name;
|
||||
|
||||
TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
|
||||
scope_block->node->data.block.statements.append(label_node);
|
||||
scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name));
|
||||
|
||||
AstNode *sub_stmt_node;
|
||||
TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
|
||||
@ -2399,23 +2409,19 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const Defa
|
||||
|
||||
Buf *label_name = buf_sprintf("default");
|
||||
|
||||
AstNode *label_node = trans_create_node(c, NodeTypeLabel);
|
||||
label_node->data.label.name = label_name;
|
||||
|
||||
{
|
||||
// Add the prong
|
||||
AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
|
||||
|
||||
AstNode *goto_node = trans_create_node(c, NodeTypeGoto);
|
||||
goto_node->data.goto_expr.name = label_name;
|
||||
prong_node->data.switch_prong.expr = goto_node;
|
||||
prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name);
|
||||
|
||||
switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
|
||||
switch_scope->found_default = true;
|
||||
}
|
||||
|
||||
TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
|
||||
scope_block->node->data.block.statements.append(label_node);
|
||||
scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name));
|
||||
|
||||
|
||||
AstNode *sub_stmt_node;
|
||||
TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
|
||||
@ -2500,7 +2506,17 @@ static AstNode *trans_string_literal(Context *c, TransScope *scope, const String
|
||||
}
|
||||
|
||||
static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) {
|
||||
return trans_create_node(c, NodeTypeBreak);
|
||||
TransScope *cur_scope = scope;
|
||||
while (cur_scope != nullptr) {
|
||||
if (cur_scope->id == TransScopeIdWhile) {
|
||||
return trans_create_node(c, NodeTypeBreak);
|
||||
} else if (cur_scope->id == TransScopeIdSwitch) {
|
||||
TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope;
|
||||
return trans_create_node_goto(c, switch_scope->end_label_name);
|
||||
}
|
||||
cur_scope = cur_scope->parent;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) {
|
||||
|
||||
@ -1019,7 +1019,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
|
||||
,
|
||||
\\fn foo(_arg_x: c_int) -> c_int {
|
||||
\\ var x = _arg_x;
|
||||
\\ while (true) {
|
||||
\\ {
|
||||
\\ switch (x) {
|
||||
\\ 1 => goto case_0,
|
||||
\\ 2 => goto case_1,
|
||||
@ -1030,13 +1030,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {
|
||||
\\ case_0:
|
||||
\\ x += 1;
|
||||
\\ case_1:
|
||||
\\ break;
|
||||
\\ goto end;
|
||||
\\ case_2:
|
||||
\\ case_3:
|
||||
\\ return x + 1;
|
||||
\\ default:
|
||||
\\ return 10;
|
||||
\\ break;
|
||||
\\ goto end;
|
||||
\\ end:
|
||||
\\ };
|
||||
\\ return x + 13;
|
||||
\\}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user