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 
5 /// Register identifiers in scope tree
6 module vox.fe.passes.names_register;
7 
8 import std.stdio;
9 import std.string : format;
10 import vox.all;
11 
12 
13 void pass_names_register(ref CompilationContext context, CompilePassPerModule[] subPasses)
14 {
15 	auto state = NameRegisterState(&context);
16 
17 	foreach (ref SourceFileInfo file; context.files.data) {
18 		AstIndex modIndex = file.mod.get_ast_index(&context);
19 		require_name_register(modIndex, state);
20 		assert(context.analisysStack.length == 0);
21 	}
22 }
23 
24 void require_name_register(ref AstIndex nodeIndex, CompilationContext* context)
25 {
26 	auto state = NameRegisterState(context);
27 	require_name_register(nodeIndex, state);
28 }
29 
30 // solves conditional compilation
31 // must be called inside name_register_nested state
32 void require_name_register(ref AstNodes items, ref NameRegisterState state)
33 {
34 	require_name_register_self_sub_array(items, 0, items.length, state);
35 	foreach(ref AstIndex item; items) require_name_register(item, state);
36 }
37 
38 // returns `items` size delta
39 // walk all items in from..to range.
40 // gather all static ifs into linked list, while doing `require_name_register_self`
41 // for each static if in linked list
42 //   eval condition
43 //   in array replace static if node with correct branch
44 //   call this recursively for inserted subrange
45 private long require_name_register_self_sub_array(ref AstNodes items, uint from, uint to, ref NameRegisterState state)
46 {
47 	CompilationContext* c = state.context;
48 	state.firstCondDecl = AstIndex();
49 	state.lastCondDecl = AstIndex();
50 	size_t i = from;
51 	foreach(ref AstIndex item; items[from..to]) {
52 		require_name_register_self(cast(uint)(i++), item, state);
53 	}
54 
55 	if (state.firstCondDecl.isUndefined) return 0; // no static ifs
56 
57 	long sizeDelta;
58 
59 	AstIndex condDecl = state.firstCondDecl;
60 	while (condDecl)
61 	{
62 		AstNode* decl = condDecl.get_node(c);
63 		if(decl.astType == AstType.decl_static_foreach)
64 		{
65 			auto staticForeachNode = decl.as!StaticForeachDeclNode(c);
66 			require_name_register(staticForeachNode.iterableExpr, state);
67 			require_name_resolve(staticForeachNode.iterableExpr, c);
68 
69 			auto iter = staticForeachNode.iterableExpr.get_node(c);
70 
71 			if (iter.astType == AstType.decl_alias_array)
72 			{
73 				auto aliasArray = iter.as!AliasArrayDeclNode(c);
74 
75 				size_t bodySize = staticForeachNode.body.length;
76 				uint numItemsToInsert = cast(uint)(aliasArray.items.length * bodySize);
77 
78 				uint insertPoint = cast(uint)(staticForeachNode.arrayIndex + sizeDelta);
79 				items.replaceAtVoid(c.arrayArena, insertPoint, 1, numItemsToInsert);
80 
81 				foreach(idx, AstIndex item; aliasArray.items)
82 				{
83 					// Create scope for key/value vars
84 					ScopeIndex instance_scope = c.appendScope;
85 					Scope* newScope = c.getAstScope(instance_scope);
86 					newScope.parentScope = staticForeachNode.parentScope;
87 					newScope.debugName = "#foreach instance";
88 					newScope.kind = newScope.parentScope.get_scope(c).kind;
89 
90 					CloneState cloneState = clone_node(staticForeachNode.body_start, staticForeachNode.after_body, instance_scope, c);
91 
92 					if (staticForeachNode.keyId.isDefined) {
93 						AstIndex keyNode = c.appendAst!EnumMemberDecl(staticForeachNode.loc);
94 						auto enumMemberNode = keyNode.get!EnumMemberDecl(c);
95 						enumMemberNode.initValue = c.constants.add(makeIrType(IrBasicType.i64), idx);
96 						enumMemberNode.id = staticForeachNode.keyId;
97 						enumMemberNode.type = CommonAstNodes.type_u64;
98 						enumMemberNode.state = AstNodeState.type_check_done;
99 						newScope.insert(staticForeachNode.keyId, keyNode, c);
100 					}
101 					newScope.insert(staticForeachNode.valueId, item, c);
102 
103 					size_t insertAt = insertPoint + idx * bodySize;
104 					foreach(j, AstIndex node; staticForeachNode.body)
105 					{
106 						cloneState.fixAstIndex(node);
107 						items[insertAt+j] = node;
108 					}
109 				}
110 
111 				// we replace #foreach with its children
112 				//   #foreach is removed from the list (-1)
113 				//   children are inserted (numItemsToInsert)
114 				sizeDelta += numItemsToInsert - 1;
115 				sizeDelta += require_name_register_self_sub_array(items, insertPoint, insertPoint+numItemsToInsert, state);
116 			}
117 			else
118 			{
119 				c.error(iter.loc, "#foreach cannot iterate over %s", iter.astType);
120 			}
121 
122 			condDecl = staticForeachNode.next;
123 		}
124 		else
125 		{
126 			auto condNode = decl.as!ConditionalDeclNode(c);
127 			AstNodes itemsToInsert;
128 
129 			if (decl.astType == AstType.decl_static_if)
130 			{
131 				auto staticIfNode = condNode.as!StaticIfDeclNode(c);
132 				require_name_register(staticIfNode.condition, state);
133 				IrIndex val = eval_static_expr(staticIfNode.condition, c);
134 				itemsToInsert = c.constants.get(val).i64 ? staticIfNode.thenItems : staticIfNode.elseItems;
135 			}
136 			else
137 			{
138 				assert(decl.astType == AstType.decl_static_version);
139 				auto versionNode = condNode.as!StaticVersionDeclNode(c);
140 				Identifier versionId = versionNode.versionId;
141 				bool isEnabled = false;
142 
143 				// Is built-in version identifier
144 				if (versionId.index >= commonId_version_id_first && versionId.index <= commonId_version_id_last)
145 				{
146 					uint versionIndex = versionId.index - commonId_version_id_first;
147 					isEnabled = (c.enabledVersionIdentifiers & (1 << versionIndex)) != 0;
148 				}
149 				else
150 				{
151 					c.error(decl.loc, "Only built-in versions are supported, not %s", c.idString(versionId));
152 				}
153 
154 				itemsToInsert = isEnabled ? versionNode.thenItems : versionNode.elseItems;
155 			}
156 
157 			uint insertPoint = cast(uint)(condNode.arrayIndex + sizeDelta);
158 			items.replaceAt(c.arrayArena, insertPoint, 1, itemsToInsert[]);
159 
160 			// we replace #if with its children
161 			//   #if is removed from the list (-1)
162 			//   children are inserted (itemsToInsert.length)
163 			sizeDelta += itemsToInsert.length - 1;
164 			sizeDelta += require_name_register_self_sub_array(items, insertPoint, insertPoint+itemsToInsert.length, state);
165 
166 			condDecl = condNode.next;
167 		}
168 	}
169 
170 	return sizeDelta;
171 }
172 
173 // register own identifier in parent scope
174 void require_name_register_self(uint arrayIndex, ref AstIndex nodeIndex, ref NameRegisterState state)
175 {
176 	CompilationContext* c = state.context;
177 	AstNode* node = c.getAstNode(nodeIndex);
178 
179 	switch(node.state) with(AstNodeState)
180 	{
181 		case name_register_self, name_register_nested, name_resolve, type_check:
182 			state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.name_register_self));
183 			c.circular_dependency;
184 		case parse_done:
185 			// all requirement are done
186 			break;
187 		case name_register_self_done, name_register_nested_done, name_resolve_done, type_check_done:
188 			// already name registered
189 			return;
190 		default:
191 			c.internal_error(node.loc, "Node %s in %s state", node.astType, node.state);
192 	}
193 
194 	state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.name_register_self));
195 	scope(success) state.context.pop_analized_node;
196 
197 	switch(node.astType) with(AstType)
198 	{
199 		case error: c.internal_error(node.loc, "Visiting error node");
200 		case abstract_node: c.internal_error(node.loc, "Visiting abstract node");
201 
202 		case decl_alias: name_register_self_alias(nodeIndex, cast(AliasDeclNode*)node, state); break;
203 		case decl_import: name_register_self_import(cast(ImportDeclNode*)node, state); break;
204 		case decl_function: name_register_self_func(nodeIndex, cast(FunctionDeclNode*)node, state); break;
205 		case decl_var: name_register_self_var(nodeIndex, cast(VariableDeclNode*)node, state); break;
206 		case decl_struct: name_register_self_struct(nodeIndex, cast(StructDeclNode*)node, state); break;
207 		case decl_enum: name_register_self_enum(nodeIndex, cast(EnumDeclaration*)node, state); break;
208 		case decl_enum_member: name_register_self_enum_member(nodeIndex, cast(EnumMemberDecl*)node, state); break;
209 		case decl_static_if, decl_static_version, decl_static_foreach:
210 			auto condDecl = node.as!ConditionalDeclNode(c);
211 			if (state.lastCondDecl)
212 				state.lastCondDecl.get!ConditionalDeclNode(c).next = nodeIndex;
213 			else
214 				state.firstCondDecl = nodeIndex;
215 			condDecl.prev = state.lastCondDecl;
216 			condDecl.arrayIndex = arrayIndex;
217 			state.lastCondDecl = nodeIndex;
218 			break;
219 		case decl_template: name_register_self_template(nodeIndex, cast(TemplateDeclNode*)node, state); break;
220 
221 		default: c.internal_error(node.loc, "Visiting %s node %s", node.astType, node.state);
222 	}
223 }
224 
225 // register identifiers of nested nodes
226 void require_name_register(ref AstIndex nodeIndex, ref NameRegisterState state)
227 {
228 	AstNode* node = state.context.getAstNode(nodeIndex);
229 
230 	switch(node.state) with(AstNodeState)
231 	{
232 		case name_register_self, name_register_nested, name_resolve, type_check:
233 			state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.name_register_nested));
234 			state.context.circular_dependency;
235 		case parse_done:
236 			auto name_state = NameRegisterState(state.context);
237 			require_name_register_self(0, nodeIndex, name_state);
238 			state.context.throwOnErrors;
239 			goto case;
240 		case name_register_self_done: break; // all requirement are done
241 		case name_register_nested_done, name_resolve_done, type_check_done, ir_gen_done: return; // already name registered
242 		default: state.context.internal_error(node.loc, "Node %s in %s state", node.astType, node.state);
243 	}
244 
245 	state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.name_register_nested));
246 	scope(success) state.context.pop_analized_node;
247 
248 	if (node.hasAttributes) {
249 		name_register_nested_attributes(node.attributeInfo, state);
250 	}
251 
252 	switch(node.astType) with(AstType)
253 	{
254 		case error: state.context.internal_error(node.loc, "Visiting error node");
255 		case abstract_node: state.context.internal_error(node.loc, "Visiting abstract node");
256 
257 		case decl_alias: assert(false);
258 		case decl_module: name_register_nested_module(cast(ModuleDeclNode*)node, state); break;
259 		case decl_import: assert(false);
260 		case decl_function: name_register_nested_func(nodeIndex, cast(FunctionDeclNode*)node, state); break;
261 		case decl_var: name_register_nested_var(nodeIndex, cast(VariableDeclNode*)node, state); break;
262 		case decl_struct: name_register_nested_struct(nodeIndex, cast(StructDeclNode*)node, state); break;
263 		case decl_enum: name_register_nested_enum(nodeIndex, cast(EnumDeclaration*)node, state); break;
264 		case decl_enum_member: name_register_nested_enum_member(nodeIndex, cast(EnumMemberDecl*)node, state); break;
265 		case decl_static_assert: name_register_nested_static_assert(cast(StaticAssertDeclNode*)node, state); break;
266 		case decl_static_if: assert(false);
267 		case decl_static_version: assert(false);
268 
269 		case stmt_block: name_register_nested_block(cast(BlockStmtNode*)node, state); break;
270 		case stmt_if: name_register_nested_if(cast(IfStmtNode*)node, state); break;
271 		case stmt_while: name_register_nested_while(cast(WhileStmtNode*)node, state); break;
272 		case stmt_do_while: name_register_nested_do(cast(DoWhileStmtNode*)node, state); break;
273 		case stmt_for: name_register_nested_for(cast(ForStmtNode*)node, state); break;
274 		case stmt_switch: name_register_nested_switch(cast(SwitchStmtNode*)node, state); break;
275 		case stmt_return: assert(false);
276 		case stmt_break: assert(false);
277 		case stmt_continue: assert(false);
278 
279 		case expr_name_use: assert(false);
280 		case expr_member: name_register_nested_member(cast(MemberExprNode*)node, state); break;
281 		case expr_bin_op: name_register_nested_binary_op(cast(BinaryExprNode*)node, state); break;
282 		case expr_un_op: name_register_nested_unary_op(cast(UnaryExprNode*)node, state); break;
283 		case expr_call: name_register_nested_call(cast(CallExprNode*)node, state); break;
284 		case expr_named_argument: name_register_nested_named_argument(cast(NamedArgumenExprNode*)node, state); break;
285 		case expr_index: name_register_nested_index(cast(IndexExprNode*)node, state); break;
286 		case expr_slice: name_register_nested_expr_slice(cast(SliceExprNode*)node, state); break;
287 		case expr_type_conv: name_register_nested_type_conv(cast(TypeConvExprNode*)node, state); break;
288 
289 		case literal_int: assert(false);
290 		case literal_float: assert(false);
291 		case literal_string: assert(false);
292 		case literal_null: assert(false);
293 		case literal_bool: assert(false);
294 		case literal_array: assert(false);
295 
296 		case type_basic: assert(false);
297 		case type_func_sig: name_register_nested_func_sig(cast(FunctionSignatureNode*)node, state); break;
298 		case type_ptr: name_register_nested_ptr(cast(PtrTypeNode*)node, state); break;
299 		case type_static_array: name_register_nested_static_array(cast(StaticArrayTypeNode*)node, state); break;
300 		case type_slice: name_register_nested_slice(cast(SliceTypeNode*)node, state); break;
301 
302 		default: state.context.internal_error(node.loc, "Visiting %s node", node.astType);
303 	}
304 }
305 
306 struct NameRegisterState
307 {
308 	CompilationContext* context;
309 
310 	// first #if or #foreach in a block
311 	AstIndex firstCondDecl;
312 	// last #if or #foreach in a block
313 	AstIndex lastCondDecl;
314 }