1 /// Copyright: Copyright (c) 2017-2019 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.while_stmt; 5 6 import vox.all; 7 8 9 @(AstType.stmt_while) 10 struct WhileStmtNode { 11 mixin AstNodeData!(AstType.stmt_while, 0, AstNodeState.name_register_self_done); 12 AstIndex condition; 13 AstNodes statements; 14 } 15 16 void print_while(WhileStmtNode* node, ref AstPrintState state) 17 { 18 state.print("WHILE"); 19 print_ast(node.condition, state); 20 print_ast(node.statements, state); 21 } 22 23 void post_clone_while(WhileStmtNode* node, ref CloneState state) 24 { 25 state.fixAstIndex(node.condition); 26 state.fixAstNodes(node.statements); 27 } 28 29 void name_register_nested_while(WhileStmtNode* node, ref NameRegisterState state) { 30 node.state = AstNodeState.name_register_nested; 31 require_name_register(node.condition, state); 32 require_name_register(node.statements, state); 33 node.state = AstNodeState.name_register_nested_done; 34 } 35 36 void name_resolve_while(WhileStmtNode* node, ref NameResolveState state) { 37 node.state = AstNodeState.name_resolve; 38 require_name_resolve(node.condition, state); 39 require_name_resolve(node.statements, state); 40 node.state = AstNodeState.name_resolve_done; 41 } 42 43 void type_check_while(WhileStmtNode* node, ref TypeCheckState state) 44 { 45 node.state = AstNodeState.type_check; 46 require_type_check(node.condition, state); 47 autoconvToBool(node.condition, state.context); 48 require_type_check(node.statements, state); 49 node.state = AstNodeState.type_check_done; 50 } 51 52 void ir_gen_while(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, WhileStmtNode* n) 53 { 54 // loop header 55 IrLabel loopHeaderLabel = IrLabel(currentBlock); 56 57 IrLabel* prevLoopHeader = gen.currentLoopHeader; // save continue label 58 gen.currentLoopHeader = &loopHeaderLabel; 59 scope(exit) gen.currentLoopHeader = prevLoopHeader; // restore continue label 60 61 IrLabel* prevLoopEnd = gen.currentLoopEnd; // save break label 62 gen.currentLoopEnd = &nextStmt; 63 scope(exit) gen.currentLoopEnd = prevLoopEnd; // restore break label 64 65 gen.builder.addJumpToLabel(currentBlock, loopHeaderLabel); 66 67 // we need loop header in a separate block because it will 68 // have 2 predecessors: currentBlock and loop body 69 gen.builder.forceAllocLabelBlock(loopHeaderLabel); 70 IrIndex loopHeaderBlock = loopHeaderLabel.blockIndex; 71 gen.ir.getBlock(loopHeaderBlock).preventSeal = true; 72 currentBlock = loopHeaderBlock; 73 74 IrLabel bodyLabel = IrLabel(currentBlock); 75 76 // will force allocate body block 77 ir_gen_branch(gen, n.condition, loopHeaderBlock, bodyLabel, nextStmt); 78 79 // body 80 if (bodyLabel.numPredecessors > 0) 81 { 82 currentBlock = bodyLabel.blockIndex; 83 gen.builder.sealBlock(currentBlock); 84 85 IrBasicBlock* block = gen.ir.getBlock(currentBlock); 86 assert(!block.isFinished); 87 genBlock(gen, n.as!AstNode(gen.context), n.statements, currentBlock, loopHeaderLabel); 88 } 89 90 if (loopHeaderLabel.numPredecessors > 1) 91 gen.ir.getBlock(loopHeaderBlock).isLoopHeader = true; 92 93 assert(!gen.ir.getBlock(loopHeaderBlock).isSealed); 94 gen.builder.sealBlock(loopHeaderBlock, true); 95 }