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.for_stmt; 5 6 import vox.all; 7 8 9 @(AstType.stmt_for) 10 struct ForStmtNode { 11 mixin AstNodeData!(AstType.stmt_for, 0, AstNodeState.name_register_self_done); 12 AstNodes init_statements; 13 AstIndex condition; // Nullable 14 AstNodes increment_statements; 15 AstNodes body_statements; 16 } 17 18 void print_for(ForStmtNode* node, ref AstPrintState state) 19 { 20 state.print("FOR"); 21 print_ast(node.init_statements, state); 22 state.print("COND"); 23 if (node.condition) 24 print_ast(node.condition, state); 25 state.print("INC"); 26 print_ast(node.increment_statements, state); 27 print_ast(node.body_statements, state); 28 } 29 30 void post_clone_for(ForStmtNode* node, ref CloneState state) 31 { 32 state.fixAstIndex(node.condition); 33 state.fixAstNodes(node.init_statements); 34 state.fixAstNodes(node.increment_statements); 35 state.fixAstNodes(node.body_statements); 36 } 37 38 void name_register_nested_for(ForStmtNode* node, ref NameRegisterState state) { 39 node.state = AstNodeState.name_register_nested; 40 require_name_register(node.init_statements, state); 41 if (node.condition) require_name_register(node.condition, state); 42 require_name_register(node.increment_statements, state); 43 require_name_register(node.body_statements, state); 44 node.state = AstNodeState.name_register_nested_done; 45 } 46 47 void name_resolve_for(ForStmtNode* node, ref NameResolveState state) { 48 node.state = AstNodeState.name_resolve; 49 require_name_resolve(node.init_statements, state); 50 if (node.condition) require_name_resolve(node.condition, state); 51 require_name_resolve(node.increment_statements, state); 52 require_name_resolve(node.body_statements, state); 53 node.state = AstNodeState.name_resolve_done; 54 } 55 56 void type_check_for(ForStmtNode* node, ref TypeCheckState state) 57 { 58 node.state = AstNodeState.type_check; 59 require_type_check(node.init_statements, state); 60 if (node.condition) { 61 require_type_check(node.condition, state); 62 autoconvToBool(node.condition, state.context); 63 } 64 require_type_check(node.increment_statements, state); 65 require_type_check(node.body_statements, state); 66 node.state = AstNodeState.type_check_done; 67 } 68 69 void ir_gen_for(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, ForStmtNode* n) 70 { 71 CompilationContext* c = gen.context; 72 // init statements 73 IrLabel afterInitLabel = IrLabel(currentBlock); 74 genBlock(gen, n.as!AstNode(c), n.init_statements, currentBlock, afterInitLabel); 75 currentBlock = afterInitLabel.blockIndex; 76 77 // loop header 78 IrLabel loopHeaderLabel = IrLabel(currentBlock); 79 // increment section of body 80 IrLabel incrementLabel = IrLabel(currentBlock); 81 82 // continue label 83 IrLabel* prevLoopHeader = gen.currentLoopHeader; // save continue label 84 gen.currentLoopHeader = &incrementLabel; 85 scope(exit) gen.currentLoopHeader = prevLoopHeader; // restore continue label 86 87 // break label 88 IrLabel* prevLoopEnd = gen.currentLoopEnd; // save break label 89 gen.currentLoopEnd = &nextStmt; 90 scope(exit) gen.currentLoopEnd = prevLoopEnd; // restore break label 91 92 gen.builder.addJumpToLabel(currentBlock, loopHeaderLabel); 93 94 // we need loop header in a separate block because it will 95 // have 2 predecessors: currentBlock and loop body 96 gen.builder.forceAllocLabelBlock(loopHeaderLabel); 97 IrIndex loopHeaderBlock = loopHeaderLabel.blockIndex; 98 gen.ir.getBlock(loopHeaderBlock).preventSeal = true; 99 currentBlock = loopHeaderBlock; 100 101 IrLabel bodyLabel = IrLabel(currentBlock); 102 103 // will force allocate body block 104 if (n.condition) 105 ir_gen_branch(gen, n.condition, loopHeaderBlock, bodyLabel, nextStmt); 106 else 107 gen.builder.addJumpToLabel(loopHeaderBlock, bodyLabel); 108 109 // body 110 if (bodyLabel.numPredecessors > 0) 111 { 112 currentBlock = bodyLabel.blockIndex; 113 gen.builder.sealBlock(currentBlock); 114 115 IrBasicBlock* block = gen.ir.getBlock(currentBlock); 116 assert(!block.isFinished); 117 genBlock(gen, n.as!AstNode(c), n.body_statements, currentBlock, incrementLabel); 118 119 if (incrementLabel.numPredecessors > 0) 120 { 121 gen.builder.sealBlock(incrementLabel.blockIndex); 122 genBlock(gen, n.as!AstNode(c), n.increment_statements, incrementLabel.blockIndex, loopHeaderLabel); 123 } 124 } 125 126 if (loopHeaderLabel.numPredecessors > 1) 127 gen.ir.getBlock(loopHeaderBlock).isLoopHeader = true; 128 129 assert(!gen.ir.getBlock(loopHeaderBlock).isSealed); 130 gen.builder.sealBlock(loopHeaderBlock, true); 131 }