| ... | ... | @@ -104,6 +104,7 @@ static TransScopeRoot *trans_scope_root_create(Context *c); |
| 104 | 104 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); |
| 105 | 105 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); |
| 106 | 106 | static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); |
| 107 | static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope); |
| 107 | 108 | |
| 108 | 109 | static TransScopeBlock *trans_scope_block_find(TransScope *scope); |
| 109 | 110 | |
| ... | ... | @@ -2527,6 +2528,155 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt |
| 2527 | 2528 | return loop_block_node; |
| 2528 | 2529 | } |
| 2529 | 2530 | |
| 2531 | static 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 | |
| 2588 | static 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 | |
| 2598 | static 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 | |
| 2643 | static 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 | |
| 2530 | 2680 | static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) { |
| 2531 | 2681 | switch (stmt->getKind()) { |
| 2532 | 2682 | case StringLiteral::Ascii: |
| ... | ... | @@ -2551,7 +2701,8 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt |
| 2551 | 2701 | if (cur_scope->id == TransScopeIdWhile) { |
| 2552 | 2702 | return trans_create_node(c, NodeTypeBreak); |
| 2553 | 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 | 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 | 2802 | return wrap_stmt(out_node, out_child_scope, scope, |
| 2652 | 2803 | trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue)); |
| 2653 | 2804 | 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)); |
| 2656 | 2807 | 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); |
| 2659 | 2809 | 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); |
| 2662 | 2811 | case Stmt::NoStmtClass: |
| 2663 | 2812 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); |
| 2664 | 2813 | return ErrorUnexpected; |
| ... | ... | @@ -3828,6 +3977,14 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop |
| 3828 | 3977 | return result; |
| 3829 | 3978 | } |
| 3830 | 3979 | |
| 3980 | static 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 | |
| 3831 | 3988 | static TransScopeBlock *trans_scope_block_find(TransScope *scope) { |
| 3832 | 3989 | while (scope != nullptr) { |
| 3833 | 3990 | if (scope->id == TransScopeIdBlock) { |