Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ziglang/zig
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1b0e90f70b4d
Choose a base ref
...
head repository: ziglang/zig
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9a8545d5903f
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Nov 26, 2017

  1. translate-c: better way to translate switch

    previously `continue` would be handled incorrectly
    andrewrk committed Nov 26, 2017
    Copy the full SHA
    aa2ca3f View commit details
  2. Copy the full SHA
    9a8545d View commit details
Showing with 81 additions and 26 deletions.
  1. +39 −23 src/translate_c.cpp
  2. +42 −3 test/translate_c.zig
62 changes: 39 additions & 23 deletions src/translate_c.cpp
Original file line number Diff line number Diff line change
@@ -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);

@@ -2331,14 +2344,16 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw

if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) {
AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
prong_node->data.switch_prong.expr = trans_create_node(c, NodeTypeBreak);
prong_node->data.switch_prong.expr = trans_create_node_goto(c, end_label_name);
switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
}

// 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) {
45 changes: 42 additions & 3 deletions test/translate_c.zig
Original file line number Diff line number Diff line change
@@ -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,52 @@ 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;
\\}
);

cases.add("switch statement with no default",
\\int foo(int x) {
\\ switch (x) {
\\ case 1:
\\ x += 1;
\\ case 2:
\\ break;
\\ case 3:
\\ case 4:
\\ return x + 1;
\\ }
\\ return x + 13;
\\}
,
\\fn foo(_arg_x: c_int) -> c_int {
\\ var x = _arg_x;
\\ {
\\ switch (x) {
\\ 1 => goto case_0,
\\ 2 => goto case_1,
\\ 3 => goto case_2,
\\ 4 => goto case_3,
\\ else => goto end,
\\ };
\\ case_0:
\\ x += 1;
\\ case_1:
\\ goto end;
\\ case_2:
\\ case_3:
\\ return x + 1;
\\ goto end;
\\ end:
\\ };
\\ return x + 13;
\\}