authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2018-03-08 10:29:29+01:00
committergravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2018-03-08 10:29:29+01:00
log51b2f1b80b9bc43dc389044565cc3a72c174311e
tree8a84a558384843c59319d253a7dda5124e4a8c86
parentbb80daf509b7afd84fe3076347e69e8f39f586d6

Translate C can now translate switch statements again


2 files changed, 206 insertions(+), 7 deletions(-)

src/translate_c.cpp+164-7
...@@ -104,6 +104,7 @@ static TransScopeRoot *trans_scope_root_create(Context *c);...@@ -104,6 +104,7 @@ static TransScopeRoot *trans_scope_root_create(Context *c);
104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
106static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);106static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);
107static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope);
107108
108static TransScopeBlock *trans_scope_block_find(TransScope *scope);109static TransScopeBlock *trans_scope_block_find(TransScope *scope);
109110
...@@ -2527,6 +2528,155 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt...@@ -2527,6 +2528,155 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
2527 return loop_block_node;2528 return loop_block_node;
2528}2529}
25292530
2531static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {
2532 TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope);
2533
2534 TransScopeSwitch *switch_scope;
2535
2536 const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt();
2537 if (var_decl_stmt == nullptr) {
2538 switch_scope = trans_scope_switch_create(c, &block_scope->base);
2539 } else {
2540 AstNode *vars_node;
2541 TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node);
2542 if (var_scope == nullptr)
2543 return nullptr;
2544 if (vars_node != nullptr)
2545 block_scope->node->data.block.statements.append(vars_node);
2546 switch_scope = trans_scope_switch_create(c, var_scope);
2547 }
2548 block_scope->node->data.block.statements.append(switch_scope->switch_node);
2549
2550 // TODO avoid name collisions
2551 Buf *end_label_name = buf_create_from_str("__switch");
2552 switch_scope->end_label_name = end_label_name;
2553 block_scope->node->data.block.name = end_label_name;
2554
2555 const Expr *cond_expr = stmt->getCond();
2556 assert(cond_expr != nullptr);
2557
2558 AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue);
2559 if (expr_node == nullptr)
2560 return nullptr;
2561 switch_scope->switch_node->data.switch_expr.expr = expr_node;
2562
2563 AstNode *body_node;
2564 const Stmt *body_stmt = stmt->getBody();
2565 if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) {
2566 if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt,
2567 block_scope->node, nullptr))
2568 {
2569 return nullptr;
2570 }
2571 } else {
2572 TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node);
2573 if (body_scope == nullptr)
2574 return nullptr;
2575 if (body_node != nullptr)
2576 block_scope->node->data.block.statements.append(body_node);
2577 }
2578
2579 if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) {
2580 AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
2581 prong_node->data.switch_prong.expr = trans_create_node_break(c, end_label_name, nullptr);
2582 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
2583 }
2584
2585 return block_scope->node;
2586}
2587
2588static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) {
2589 while (scope != nullptr) {
2590 if (scope->id == TransScopeIdSwitch) {
2591 return (TransScopeSwitch *)scope;
2592 }
2593 scope = scope->parent;
2594 }
2595 return nullptr;
2596}
2597
2598static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,
2599 TransScope **out_scope) {
2600 *out_node = nullptr;
2601
2602 if (stmt->getRHS() != nullptr) {
2603 emit_warning(c, stmt->getLocStart(), "TODO support GNU switch case a ... b extension");
2604 return ErrorUnexpected;
2605 }
2606
2607 TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope);
2608 assert(switch_scope != nullptr);
2609
2610 Buf *label_name = buf_sprintf("__case_%" PRIu32, switch_scope->case_index);
2611 switch_scope->case_index += 1;
2612
2613 {
2614 // Add the prong
2615 AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
2616 AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue);
2617 if (item_node == nullptr)
2618 return ErrorUnexpected;
2619 prong_node->data.switch_prong.items.append(item_node);
2620 prong_node->data.switch_prong.expr = trans_create_node_break(c, label_name, nullptr);
2621 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
2622 }
2623
2624 TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
2625
2626 AstNode *case_block = trans_create_node(c, NodeTypeBlock);
2627 case_block->data.block.name = label_name;
2628 case_block->data.block.statements = scope_block->node->data.block.statements;
2629 scope_block->node->data.block.statements = {0};
2630 scope_block->node->data.block.statements.append(case_block);
2631
2632 AstNode *sub_stmt_node;
2633 TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
2634 if (new_scope == nullptr)
2635 return ErrorUnexpected;
2636 if (sub_stmt_node != nullptr)
2637 scope_block->node->data.block.statements.append(sub_stmt_node);
2638
2639 *out_scope = new_scope;
2640 return ErrorNone;
2641}
2642
2643static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node,
2644 TransScope **out_scope)
2645{
2646 *out_node = nullptr;
2647
2648 TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope);
2649 assert(switch_scope != nullptr);
2650
2651 Buf *label_name = buf_sprintf("__default");
2652
2653 {
2654 // Add the prong
2655 AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
2656 prong_node->data.switch_prong.expr = trans_create_node_break(c, label_name, nullptr);
2657 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
2658 switch_scope->found_default = true;
2659 }
2660
2661 TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
2662
2663 AstNode *case_block = trans_create_node(c, NodeTypeBlock);
2664 case_block->data.block.name = label_name;
2665 case_block->data.block.statements = scope_block->node->data.block.statements;
2666 scope_block->node->data.block.statements = {0};
2667 scope_block->node->data.block.statements.append(case_block);
2668
2669 AstNode *sub_stmt_node;
2670 TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
2671 if (new_scope == nullptr)
2672 return ErrorUnexpected;
2673 if (sub_stmt_node != nullptr)
2674 scope_block->node->data.block.statements.append(sub_stmt_node);
2675
2676 *out_scope = new_scope;
2677 return ErrorNone;
2678}
2679
2530static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) {2680static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) {
2531 switch (stmt->getKind()) {2681 switch (stmt->getKind()) {
2532 case StringLiteral::Ascii:2682 case StringLiteral::Ascii:
...@@ -2551,7 +2701,8 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt...@@ -2551,7 +2701,8 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt
2551 if (cur_scope->id == TransScopeIdWhile) {2701 if (cur_scope->id == TransScopeIdWhile) {
2552 return trans_create_node(c, NodeTypeBreak);2702 return trans_create_node(c, NodeTypeBreak);
2553 } else if (cur_scope->id == TransScopeIdSwitch) {2703 } else if (cur_scope->id == TransScopeIdSwitch) {
2554 zig_panic("TODO");2704 TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope;
2705 return trans_create_node_break(c, switch_scope->end_label_name, nullptr);
2555 }2706 }
2556 cur_scope = cur_scope->parent;2707 cur_scope = cur_scope->parent;
2557 }2708 }
...@@ -2651,14 +2802,12 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,...@@ -2651,14 +2802,12 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
2651 return wrap_stmt(out_node, out_child_scope, scope,2802 return wrap_stmt(out_node, out_child_scope, scope,
2652 trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));2803 trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));
2653 case Stmt::SwitchStmtClass:2804 case Stmt::SwitchStmtClass:
2654 emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass");2805 return wrap_stmt(out_node, out_child_scope, scope,
2655 return ErrorUnexpected;2806 trans_switch_stmt(c, scope, (const SwitchStmt *)stmt));
2656 case Stmt::CaseStmtClass:2807 case Stmt::CaseStmtClass:
2657 emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");2808 return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope);
2658 return ErrorUnexpected;
2659 case Stmt::DefaultStmtClass:2809 case Stmt::DefaultStmtClass:
2660 emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass");2810 return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope);
2661 return ErrorUnexpected;
2662 case Stmt::NoStmtClass:2811 case Stmt::NoStmtClass:
2663 emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");2812 emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");
2664 return ErrorUnexpected;2813 return ErrorUnexpected;
...@@ -3828,6 +3977,14 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop...@@ -3828,6 +3977,14 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop
3828 return result;3977 return result;
3829}3978}
38303979
3980static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) {
3981 TransScopeSwitch *result = allocate<TransScopeSwitch>(1);
3982 result->base.id = TransScopeIdSwitch;
3983 result->base.parent = parent_scope;
3984 result->switch_node = trans_create_node(c, NodeTypeSwitchExpr);
3985 return result;
3986}
3987
3831static TransScopeBlock *trans_scope_block_find(TransScope *scope) {3988static TransScopeBlock *trans_scope_block_find(TransScope *scope) {
3832 while (scope != nullptr) {3989 while (scope != nullptr) {
3833 if (scope->id == TransScopeIdBlock) {3990 if (scope->id == TransScopeIdBlock) {
test/translate_c.zig+42
...@@ -1197,4 +1197,46 @@ pub fn addCases(cases: &tests.TranslateCContext) void {...@@ -1197,4 +1197,46 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
1197 \\ }1197 \\ }
1198 \\}1198 \\}
1199 );1199 );
1200
1201 cases.add("for on int",
1202 \\int switch_fn(int i) {
1203 \\ int res = 0;
1204 \\ switch (i) {
1205 \\ case 0:
1206 \\ res = 1;
1207 \\ case 1:
1208 \\ res = 2;
1209 \\ default:
1210 \\ res = 3 * i;
1211 \\ break;
1212 \\ case 2:
1213 \\ res = 5;
1214 \\ }
1215 \\}
1216 ,
1217 \\pub fn switch_fn(i: c_int) c_int {
1218 \\ var res: c_int = 0;
1219 \\ __switch: {
1220 \\ __case_2: {
1221 \\ __default: {
1222 \\ __case_1: {
1223 \\ __case_0: {
1224 \\ switch (i) {
1225 \\ 0 => break :__case_0,
1226 \\ 1 => break :__case_1,
1227 \\ else => break :__default,
1228 \\ 2 => break :__case_2,
1229 \\ }
1230 \\ }
1231 \\ res = 1;
1232 \\ }
1233 \\ res = 2;
1234 \\ }
1235 \\ res = (3 * i);
1236 \\ break :__switch;
1237 \\ }
1238 \\ res = 5;
1239 \\ }
1240 \\}
1241 );
1200}1242}