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 }