1 /// Copyright: Copyright (c) 2017-2020 Andrey Penechko. 2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 3 /// Authors: Andrey Penechko. 4 module vox.fe.ast.stmt.switch_stmt; 5 6 import vox.all; 7 8 9 @(AstType.stmt_switch) 10 struct SwitchStmtNode 11 { 12 mixin AstNodeData!(AstType.stmt_switch, 0, AstNodeState.name_register_self_done); 13 AstIndex condition; 14 AstIndex elseStmt; // else block stmt, nullable 15 Array!SwitchCase cases; 16 IrIndex[] argsValues; 17 } 18 19 struct SwitchCase 20 { 21 AstIndex expr; // case constant expr 22 AstIndex stmt; // block stmt 23 } 24 25 void print_switch(SwitchStmtNode* node, ref AstPrintState state) 26 { 27 state.print("SWITCH"); 28 print_ast(node.condition, state); 29 foreach (SwitchCase c; node.cases) 30 { 31 state.print("CASE"); 32 print_ast(c.expr, state); 33 print_ast(c.stmt, state); 34 } 35 if (node.elseStmt) 36 { 37 state.print("ELSE"); 38 print_ast(node.elseStmt, state); 39 } 40 } 41 42 void post_clone_switch(SwitchStmtNode* node, ref CloneState state) 43 { 44 state.fixAstIndex(node.condition); 45 state.fixAstIndex(node.elseStmt); 46 node.cases = node.cases.dup(state.context.arrayArena); 47 foreach(ref SwitchCase c; node.cases) { 48 state.fixAstIndex(c.expr); 49 state.fixAstIndex(c.stmt); 50 } 51 } 52 53 void name_register_nested_switch(SwitchStmtNode* node, ref NameRegisterState state) 54 { 55 node.state = AstNodeState.name_register_nested; 56 require_name_register(node.condition, state); 57 if (node.elseStmt.isDefined) require_name_register(node.elseStmt, state); 58 foreach(ref SwitchCase c; node.cases) { 59 require_name_register(c.expr, state); 60 require_name_register(c.stmt, state); 61 } 62 node.state = AstNodeState.name_register_nested_done; 63 } 64 65 void name_resolve_switch(SwitchStmtNode* node, ref NameResolveState state) 66 { 67 require_name_resolve(node.condition, state); 68 if (node.elseStmt.isDefined) require_name_resolve(node.elseStmt, state); 69 foreach(ref SwitchCase c; node.cases) { 70 require_name_resolve(c.expr, state); 71 require_name_resolve(c.stmt, state); 72 } 73 } 74 75 void type_check_switch(SwitchStmtNode* node, ref TypeCheckState state) 76 { 77 CompilationContext* c = state.context; 78 require_type_check(node.condition, state); 79 if (node.elseStmt.isDefined) require_type_check(node.elseStmt, state); 80 // Args: value + N integer constants 81 node.argsValues = c.allocateTempArray!IrIndex(node.cases.length + 1); 82 foreach(i, ref SwitchCase caseNode; node.cases) { 83 require_type_check(caseNode.expr, state); 84 require_type_check(caseNode.stmt, state); 85 node.argsValues[i+1] = eval_static_expr(caseNode.expr, c); 86 } 87 } 88 89 bool isSwitchableType(CompilationContext* c, AstIndex type) 90 { 91 return false; 92 } 93 94 void ir_gen_switch(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, SwitchStmtNode* node) 95 { 96 CompilationContext* c = gen.context; 97 98 IrLabel afterExpr = IrLabel(currentBlock); 99 ExprValue lval = ir_gen_expr(gen, node.condition, currentBlock, afterExpr); 100 currentBlock = afterExpr.blockIndex; 101 IrIndex rval = lval.rvalue(gen, node.loc, currentBlock); 102 103 node.argsValues[0] = rval; 104 gen.builder.emitInstr!(IrOpcode.branch_switch)(currentBlock, node.argsValues); 105 106 IrBasicBlock* block = gen.ir.getBlock(currentBlock); 107 assert(!block.isFinished); 108 block.isFinished = true; 109 110 // default case 111 IrIndex defaultBlock = gen.builder.addBasicBlock; 112 gen.builder.addBlockTarget(currentBlock, defaultBlock); 113 gen.builder.sealBlock(defaultBlock); 114 if (node.elseStmt.isDefined) { 115 ir_gen_stmt(gen, node.elseStmt, defaultBlock, nextStmt); 116 } else { 117 gen.builder.addUnreachable(defaultBlock); 118 } 119 120 // cases 121 foreach(i, ref SwitchCase switchCase; node.cases) { 122 IrIndex caseBlock = gen.builder.addBasicBlock; 123 gen.builder.addBlockTarget(currentBlock, caseBlock); 124 gen.builder.sealBlock(caseBlock); 125 ir_gen_stmt(gen, switchCase.stmt, caseBlock, nextStmt); 126 } 127 }