| ... | @@ -104,6 +104,7 @@ static TransScopeRoot *trans_scope_root_create(Context *c); | ... | @@ -104,6 +104,7 @@ static TransScopeRoot *trans_scope_root_create(Context *c); |
| 104 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); | 104 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); |
| 105 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); | 105 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); |
| 106 | static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); | 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 | static TransScopeBlock *trans_scope_block_find(TransScope *scope); | 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,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 | } |
| 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 | static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) { | 2680 | static 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 | } |
| 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 | static TransScopeBlock *trans_scope_block_find(TransScope *scope) { | 3988 | static 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) { |