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);
104104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
105105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
106106static 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
108109static TransScopeBlock *trans_scope_block_find(TransScope *scope);
109110
......@@ -2527,6 +2528,155 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
25272528 return loop_block_node;
25282529}
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
25302680static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) {
25312681 switch (stmt->getKind()) {
25322682 case StringLiteral::Ascii:
......@@ -2551,7 +2701,8 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt
25512701 if (cur_scope->id == TransScopeIdWhile) {
25522702 return trans_create_node(c, NodeTypeBreak);
25532703 } 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);
25552706 }
25562707 cur_scope = cur_scope->parent;
25572708 }
......@@ -2651,14 +2802,12 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
26512802 return wrap_stmt(out_node, out_child_scope, scope,
26522803 trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));
26532804 case Stmt::SwitchStmtClass:
2654 emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass");
2655 return ErrorUnexpected;
2805 return wrap_stmt(out_node, out_child_scope, scope,
2806 trans_switch_stmt(c, scope, (const SwitchStmt *)stmt));
26562807 case Stmt::CaseStmtClass:
2657 emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");
2658 return ErrorUnexpected;
2808 return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope);
26592809 case Stmt::DefaultStmtClass:
2660 emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass");
2661 return ErrorUnexpected;
2810 return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope);
26622811 case Stmt::NoStmtClass:
26632812 emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");
26642813 return ErrorUnexpected;
......@@ -3828,6 +3977,14 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop
38283977 return result;
38293978}
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
38313988static TransScopeBlock *trans_scope_block_find(TransScope *scope) {
38323989 while (scope != nullptr) {
38333990 if (scope->id == TransScopeIdBlock) {
test/translate_c.zig+42
......@@ -1197,4 +1197,46 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
11971197 \\ }
11981198 \\}
11991199 );
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 );
12001242}