1 /// Copyright: Copyright (c) 2021 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module vox.fe.ast.ast_node;
5 
6 import std.traits : getUDAs;
7 import vox.all;
8 
9 mixin template AstNodeData(AstType _astType = AstType.abstract_node, int default_flags = 0, AstNodeState _init_state = AstNodeState.parse_done)
10 {
11 	import std.bitmanip : bitfields;
12 
13 	// how many fields this mixin template has
14 	private enum NUM_BASE_FIELDS = 5;
15 
16 	this(Args...)(TokenIndex loc, Args args) {
17 		this(loc);
18 		enum len = this.tupleof.length - NUM_BASE_FIELDS;
19 		enum numDefault = len - args.length;
20 		static assert(args.length <= len, "Too many args");
21 		this.tupleof[NUM_BASE_FIELDS..$-numDefault] = args;
22 	}
23 
24 	this(TokenIndex loc) {
25 		this.loc = loc;
26 		this.astType = _astType;
27 		this.flags = cast(ushort)default_flags;
28 		this.state = _init_state;
29 	}
30 
31 	TokenIndex loc;
32 	AstType astType = _astType;
33 
34 	mixin(bitfields!(
35 		AstNodeState,  "state",     4,
36 		uint,          "subType",   4,
37 	));
38 	ushort flags = cast(ushort)default_flags;
39 
40 	// Stores one PropertyState per NodeProperty for up to 16 properties
41 	uint propertyStates;
42 
43 	PropertyState getPropertyState(NodeProperty prop) {
44 		return cast(PropertyState)((propertyStates >> (prop * 2)) & 0b11);
45 	}
46 
47 	void setPropertyState(NodeProperty prop, PropertyState state) {
48 		uint mask = ~(uint(0b11) << (prop * 2));
49 		propertyStates = (propertyStates & mask) | (uint(state) << (prop * 2));
50 	}
51 
52 	T* as(T)(CompilationContext* c) {
53 		static if (hasAstNodeType!T)
54 		{
55 			c.assertf(astType == getAstNodeType!T, "as(%s) got %s", T.stringof, astType);
56 		}
57 		return cast(T*)&this;
58 	}
59 
60 	TypeNode* as_type(CompilationContext* c) return {
61 		c.assertf(isType, loc, "as_type(%s)", astType);
62 		return cast(TypeNode*)&this;
63 	}
64 
65 	// Returns pointer to attributes. Only valid if hasAttributes flag is set
66 	AttributeInfo* attributeInfo() return {
67 		assert(hasAttributes);
68 		return cast(AttributeInfo*)(cast(void*)(&this) - AttributeInfo.sizeof);
69 	}
70 
71 	bool hasExternAttrib() {
72 		if (!hasAttributes) return false;
73 		return attributeInfo.isExternal;
74 	}
75 
76 	// Returns last @extern attribute attached to the node
77 	AstNode* getExternAttrib(CompilationContext* c) {
78 		if (!hasAttributes) return null;
79 		foreach_reverse(AstIndex attrib; attributeInfo.attributes) {
80 			auto attribNode = attrib.get_node(c);
81 			if (attribNode.astType != AstType.decl_builtin_attribute) continue;
82 			if (attribNode.subType == BuiltinAttribSubType.extern_syscall) return attribNode;
83 			if (attribNode.subType == BuiltinAttribSubType.extern_module) return attribNode;
84 		}
85 		return null;
86 	}
87 
88 	bool isError()      { return astType == AstType.error; }
89 	bool isModOrPack()  { return astType == AstType.decl_module || astType == AstType.decl_package; }
90 	bool isType()       { return cast(bool)(flags & AstFlags.isType); }
91 	bool isLvalue()     { return cast(bool)(flags & AstFlags.isLvalue); }
92 	bool hasAttributes(){ return cast(bool)(flags & AstFlags.hasAttributes); }
93 	bool isTemplateInstance() { return cast(bool)(flags & AstFlags.isTemplateInstance); }
94 	bool isGlobal()     { return (flags & AstFlags.scopeKindMask) == AstFlags.isGlobal; }
95 	bool isMember()     { return (flags & AstFlags.scopeKindMask) == AstFlags.isMember; }
96 	bool isLocal()      { return (flags & AstFlags.scopeKindMask) == AstFlags.isLocal;  }
97 }
98 
99 struct AstNode
100 {
101 	mixin AstNodeData;
102 }
103 
104 @(AstType.error)
105 struct ErrorAstNode
106 {
107 	mixin AstNodeData!(AstType.error);
108 }
109 
110 alias AstNodes = Array!AstIndex;
111 alias AstNodeMap = HashMap!(Identifier, AstIndex, Identifier.init);
112 
113 enum hasAstNodeType(T) = getUDAs!(T, AstType).length > 0;
114 enum getAstNodeType(T) = getUDAs!(T, AstType)[0];
115 
116 AstNodePrinter printer(AstIndex nodeIndex, CompilationContext* context)
117 {
118 	return AstNodePrinter(nodeIndex, context);
119 }
120 
121 struct AstNodePrinter
122 {
123 	AstIndex nodeIndex;
124 	CompilationContext* context;
125 
126 	void toString(scope void delegate(const(char)[]) sink) {
127 		if (!nodeIndex) {
128 			sink("<null>");
129 			return;
130 		}
131 		AstNode* node = context.getAstNode(nodeIndex);
132 		if (node.isType) node.as_type(context).printType(sink, context);
133 	}
134 }
135 
136 void print_node_name(ref TextSink sink, AstIndex nodeIndex, CompilationContext* c)
137 {
138 	AstNode* node = c.getAstNode(nodeIndex);
139 	switch(node.astType) with(AstType)
140 	{
141 		case decl_alias: sink.put(c.idString(node.as!AliasDeclNode(c).id)); break;
142 		case decl_builtin: sink.put(c.idString(node.as!BuiltinNode(c).id)); break;
143 		case decl_module: sink.formattedWrite("%s", node.as!ModuleDeclNode(c).fqn.pr(c)); break;
144 		case decl_struct: sink.put(c.idString(node.as!StructDeclNode(c).id)); break;
145 		case decl_function: sink.put(c.idString(node.as!FunctionDeclNode(c).id)); break;
146 		case decl_var: sink.put(c.idString(node.as!VariableDeclNode(c).id)); break;
147 		case decl_enum: sink.put(c.idString(node.as!EnumDeclaration(c).id)); break;
148 		case decl_enum_member: sink.put(c.idString(node.as!EnumMemberDecl(c).id)); break;
149 		case expr_name_use: sink.put(c.idString(node.as!NameUseExprNode(c).id(c))); break;
150 		case expr_member: sink.put(c.idString(node.as!MemberExprNode(c).memberId(c))); break;
151 		case decl_template: sink.put(c.idString(node.as!TemplateDeclNode(c).id)); break;
152 		case type_basic: sink.put(basicTypeNames[node.as!BasicTypeNode(c).basicType]); break;
153 		case type_ptr:
154 			print_node_name(sink, node.as!PtrTypeNode(c).base, c);
155 			sink.put("*");
156 			break;
157 		case type_slice:
158 			print_node_name(sink, node.as!SliceTypeNode(c).base, c);
159 			sink.put("[]");
160 			break;
161 		case type_static_array:
162 			auto arr = node.as!StaticArrayTypeNode(c);
163 			print_node_name(sink, arr.base, c);
164 			sink.putf("[%s]", arr.length);
165 			break;
166 		case type_func_sig:
167 			auto sig = node.as!FunctionSignatureNode(c);
168 			print_node_name(sink, sig.returnType, c);
169 			sink.put(" function(");
170 			foreach(i, AstIndex param; sig.parameters)
171 			{
172 				if (i > 0) sink.put(", ");
173 				print_node_name(sink, param, c);
174 			}
175 			sink.put(")");
176 			break;
177 		case expr_call:
178 			print_node_name(sink, node.as!CallExprNode(c).callee, c);
179 			break;
180 		default: sink.formattedWrite("%s", node.astType);
181 	}
182 }
183 
184 void check_is_type(ref AstIndex nodeIndex, CompilationContext* c)
185 {
186 	AstNode* node = c.getAstNode(nodeIndex);
187 	if (!node.isType) {
188 		c.error(node.loc, "%s is not a type", get_node_kind_name(nodeIndex, c));
189 		nodeIndex = CommonAstNodes.type_error;
190 	}
191 }
192 
193 ref Identifier get_node_id(AstIndex nodeIndex, CompilationContext* c)
194 {
195 	AstNode* node = c.getAstNode(nodeIndex);
196 	switch(node.astType) with(AstType)
197 	{
198 		case decl_alias: return node.as!AliasDeclNode(c).id;
199 		case decl_builtin: return node.as!BuiltinNode(c).id;
200 		case decl_module: return node.as!ModuleDeclNode(c).fqn;
201 		case decl_struct: return node.as!StructDeclNode(c).id;
202 		case decl_function: return node.as!FunctionDeclNode(c).id;
203 		case decl_var: return node.as!VariableDeclNode(c).id;
204 		case decl_enum: return node.as!EnumDeclaration(c).id;
205 		case decl_enum_member: return node.as!EnumMemberDecl(c).id;
206 		case expr_name_use: return node.as!NameUseExprNode(c).id(c);
207 		case expr_member: return node.as!MemberExprNode(c).memberId(c);
208 		case decl_template: return node.as!TemplateDeclNode(c).id;
209 		default: assert(false, format("got %s", node.astType));
210 	}
211 }
212 
213 AstIndex get_node_type(AstIndex nodeIndex, CompilationContext* c)
214 {
215 	if (nodeIndex.isUndefined) return nodeIndex;
216 
217 	AstNode* node = c.getAstNode(nodeIndex);
218 	//c.assertf(node.state >= AstNodeState.type_check_done, "get_node_type on node %s in state %s", node.astType, node.state);
219 
220 	switch(node.astType) with(AstType)
221 	{
222 		case decl_alias: return node.as!AliasDeclNode(c).initializer.get_node_type(c);
223 		case decl_struct: return nodeIndex;
224 		case decl_function: return node.as!FunctionDeclNode(c).signature.get_node_type(c);
225 		case decl_var: return node.as!VariableDeclNode(c).type.get_node_type(c);
226 		case decl_enum: return nodeIndex;
227 		case decl_enum_member: return node.as!EnumMemberDecl(c).type.get_node_type(c);
228 		case type_basic, type_func_sig, type_ptr, type_slice, type_static_array: return nodeIndex;
229 		case expr_name_use: return node.as!NameUseExprNode(c).entity.get_node_type(c);
230 		case error, literal_null, literal_bool, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member:
231 			return node.as!ExpressionNode(c).type.get_node_type(c);
232 
233 		default: assert(false, format("get_node_type used on %s", node.astType));
234 	}
235 }
236 
237 AstIndex get_node_alias(AstIndex nodeIndex, CompilationContext* c)
238 {
239 	if (nodeIndex.isUndefined) return nodeIndex;
240 
241 	AstNode* node = c.getAstNode(nodeIndex);
242 	//c.assertf(node.state >= AstNodeState.type_check_done, "get_node_type on node in state %s", node.state);
243 
244 	switch(node.astType) with(AstType)
245 	{
246 		case decl_alias: return node.as!AliasDeclNode(c).initializer.get_node_alias(c);
247 		case decl_struct: return CommonAstNodes.type_type;
248 		case decl_function: return CommonAstNodes.type_type;
249 		case decl_var: return CommonAstNodes.type_alias;
250 		case decl_enum: return CommonAstNodes.type_type;
251 		case decl_enum_member: return CommonAstNodes.type_alias;
252 		case type_basic, type_func_sig, type_ptr, type_slice, type_static_array: return CommonAstNodes.type_type;
253 		case expr_name_use: return node.as!NameUseExprNode(c).entity.get_node_alias(c);
254 		case error, literal_null, literal_bool, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member:
255 			return CommonAstNodes.type_alias;
256 
257 		default: assert(false, format("get_node_alias used on %s", node.astType));
258 	}
259 }
260 
261 AstIndex get_expr_type(AstIndex nodeIndex, CompilationContext* c)
262 	out(res; res.isDefined, "null result")
263 {
264 	assert(nodeIndex, "get_expr_type nodeIndex is null");
265 
266 	AstNode* node = c.getAstNode(nodeIndex);
267 	//c.assertf(node.state >= AstNodeState.type_check_done, "get_expr_type on node in state %s", node.state);
268 
269 	switch(node.astType) with(AstType)
270 	{
271 		case decl_alias: return node.as!AliasDeclNode(c).initializer.get_expr_type(c);
272 		case decl_struct: return CommonAstNodes.type_type;
273 		case decl_function: return node.as!FunctionDeclNode(c).signature.get_node_type(c);
274 		case decl_var: return node.as!VariableDeclNode(c).type.get_node_type(c);
275 		case decl_enum: return CommonAstNodes.type_type;
276 		case decl_enum_member: return node.as!EnumMemberDecl(c).type.get_node_type(c);
277 		case type_basic, type_func_sig, type_ptr, type_slice, type_static_array: return CommonAstNodes.type_type;
278 		case expr_name_use: return node.as!NameUseExprNode(c).type;
279 		case error, literal_null, literal_bool, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member:
280 			return node.as!ExpressionNode(c).type.get_node_type(c);
281 
282 		default: assert(false, format("get_expr_type used on %s", node.astType));
283 	}
284 }
285 
286 AstIndex get_effective_node(AstIndex nodeIndex, CompilationContext* c)
287 {
288 	if (nodeIndex.isUndefined) return nodeIndex;
289 
290 	AstNode* node = c.getAstNode(nodeIndex);
291 	//c.assertf(node.state >= AstNodeState.type_check_done, "get_effective_node on node in state %s", node.state);
292 
293 	switch(node.astType) with(AstType)
294 	{
295 		case decl_alias: return node.as!AliasDeclNode(c).initializer.get_effective_node(c);
296 		case decl_alias_array: return nodeIndex;
297 		case decl_template: return nodeIndex;
298 		case decl_struct: return nodeIndex;
299 		case decl_builtin: return nodeIndex;
300 		case decl_function: return nodeIndex;
301 		case decl_var: return nodeIndex;
302 		case decl_enum: return nodeIndex;
303 		case decl_enum_member: return nodeIndex;
304 		case type_basic, type_ptr, type_slice, type_static_array: return nodeIndex;
305 		case expr_name_use: return node.as!NameUseExprNode(c).entity.get_effective_node(c);
306 		case error, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member:
307 			return nodeIndex;
308 
309 		default: assert(false, format("get_effective_node used on %s", node.astType));
310 	}
311 }
312 
313 AstIndex get_ast_index(T)(T* node, CompilationContext* context)
314 {
315 	return context.getAstNodeIndex(node);
316 }
317 
318 string get_node_kind_name(AstIndex nodeIndex, CompilationContext* c)
319 {
320 	AstNode* node = c.getAstNode(nodeIndex);
321 
322 	switch(node.astType) with(AstType)
323 	{
324 		case decl_alias: return "alias";
325 		case decl_struct: return "struct";
326 		case decl_function: return "function";
327 		case decl_var: return "variable";
328 		case decl_enum: return "enum";
329 		case decl_enum_member: return "enum member";
330 		case type_basic: return "basic type";
331 		case type_ptr: return "pointer type";
332 		case type_slice: return "slice type";
333 		case type_static_array: return "static array type";
334 		case expr_name_use: return node.as!NameUseExprNode(c).entity.get_node_kind_name(c);
335 		case literal_int: return "int literal";
336 		case literal_float: return "float literal";
337 		case literal_string: return "string literal";
338 		case literal_array: return "array literal";
339 		case literal_special: return "special literal";
340 		case expr_call: return "call expression";
341 		case expr_index: return "index expression";
342 		case expr_slice: return "slice expression";
343 		case expr_bin_op: return "binary expression";
344 		case expr_un_op: return "unary expression";
345 		case expr_type_conv: return "type conversion expression";
346 		case expr_member: return "member access expression";
347 
348 		default: return node.astType.to!string;
349 	}
350 }
351 
352 AstIndex find_innermost_owner(ScopeIndex parentScope, AstType ownerType, CompilationContext* c)
353 {
354 	c.assertf(ownerType == AstType.decl_struct ||
355 		ownerType == AstType.decl_module ||
356 		ownerType == AstType.decl_function,
357 		"Invalid owner type requested (%s)", ownerType);
358 
359 	while(true)
360 	{
361 		c.assertf(parentScope.isDefined, "Undefined scope");
362 		Scope* sc = parentScope.get_scope(c);
363 
364 		c.assertf(sc.owner.isDefined, "Undefined owner");
365 		AstNode* ownerNode = sc.owner.get_node(c);
366 
367 		if (ownerNode.astType == ownerType) return sc.owner;
368 
369 		// module is the top scope
370 		// didn't find the requested owner
371 		if (ownerNode.astType == AstType.decl_module) return AstIndex(0);
372 
373 		parentScope = sc.parentScope;
374 	}
375 }