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.expr.name_use;
5 
6 import vox.all;
7 
8 enum NameUseFlags : ushort
9 {
10 	isSymResolved = AstFlags.userFlag << 0,
11 	// used to prevent parentheses-free call when:
12 	// - function address is taken
13 	// - alias is taken
14 	forbidParenthesesFreeCall = AstFlags.userFlag << 1,
15 }
16 
17 enum NameUseSubType : ubyte {
18 	referTo,
19 	takeAddressOf,
20 	takeAliasOf,
21 }
22 
23 @(AstType.expr_name_use)
24 struct NameUseExprNode {
25 	mixin ExpressionNodeData!(AstType.expr_name_use);
26 	ScopeIndex parentScope;
27 	union
28 	{
29 		private AstIndex _entity; // used when resolved, node contains Identifier internally
30 		private Identifier _id; // used when not yet resolved
31 	}
32 
33 	bool isSymResolved() { return cast(bool)(flags & NameUseFlags.isSymResolved); }
34 	bool forbidParenthesesFreeCall() { return cast(bool)(flags & NameUseFlags.forbidParenthesesFreeCall); }
35 
36 	this(TokenIndex loc, ScopeIndex parentScope, Identifier id, AstIndex type = AstIndex.init)
37 	{
38 		this.loc = loc;
39 		this.astType = AstType.expr_name_use;
40 		this.state = AstNodeState.name_register_nested_done;
41 		this.parentScope = parentScope;
42 		this._id = id;
43 		this.type = type;
44 	}
45 
46 	void resolve(AstIndex n, CompilationContext* c) {
47 		_entity = n;
48 		assert(_entity);
49 		this.flags |= NameUseFlags.isSymResolved;
50 	}
51 	AstIndex entity() { return isSymResolved ? _entity : AstIndex(); }
52 	ref Identifier id(CompilationContext* context) return {
53 		return isSymResolved ? _entity.get_node_id(context) : _id;
54 	}
55 
56 	T* tryGet(T, AstType _astType)(CompilationContext* context) {
57 		assert(isSymResolved);
58 		AstNode* entityNode = context.getAstNode(_entity);
59 		if (entityNode.astType != _astType) return null;
60 		return cast(T*)entityNode;
61 	}
62 
63 	T* get(T, AstType _astType)(CompilationContext* context) {
64 		assert(isSymResolved);
65 		AstNode* entityNode = context.getAstNode(_entity);
66 		assert(entityNode.astType == _astType, format("%s used on %s", _astType, entityNode.astType));
67 		return cast(T*)entityNode;
68 	}
69 
70 	alias varDecl = get!(VariableDeclNode, AstType.decl_var);
71 	alias funcDecl = get!(FunctionDeclNode, AstType.decl_function);
72 	alias structDecl = get!(StructDeclNode, AstType.decl_struct);
73 	alias enumDecl = get!(EnumDeclaration, AstType.decl_enum);
74 	alias enumMember = get!(EnumMemberDecl, AstType.decl_enum_member);
75 
76 	alias tryVarDecl = tryGet!(VariableDeclNode, AstType.decl_var);
77 	alias tryFuncDecl = tryGet!(FunctionDeclNode, AstType.decl_function);
78 	alias tryStructDecl = tryGet!(StructDeclNode, AstType.decl_struct);
79 	alias tryEnumDecl = tryGet!(EnumDeclaration, AstType.decl_enum);
80 	alias tryEnumMember = tryGet!(EnumMemberDecl, AstType.decl_enum_member);
81 }
82 
83 void print_name_use(NameUseExprNode* node, ref AstPrintState state)
84 {
85 	state.print("NAME_USE ", node.type.printer(state.context), " ", state.context.idString(node.id(state.context)));
86 }
87 
88 void post_clone_name_use(NameUseExprNode* node, ref CloneState state)
89 {
90 	CompilationContext* c = state.context;
91 	state.fixScope(node.parentScope);
92 	if (node.isSymResolved)
93 		state.fixAstIndex(node._entity);
94 	// _entity is resolved in template args
95 }
96 
97 void name_resolve_name_use(ref AstIndex nodeIndex, NameUseExprNode* node, ref NameResolveState state) {
98 	CompilationContext* c = state.context;
99 	node.state = AstNodeState.name_resolve;
100 	scope(exit) node.state = AstNodeState.name_resolve_done;
101 
102 	Identifier id = node.id(c);
103 
104 	Scope* currentScope = node.parentScope.get_scope(c);
105 
106 	AstIndex entity = lookupScopeIdRecursive(currentScope, id, node.loc, c);
107 
108 	if (entity == CommonAstNodes.node_error)
109 	{
110 		c.error(node.loc, "undefined identifier `%s`", c.idString(id));
111 		node.resolve(CommonAstNodes.node_error, c);
112 		return;
113 	}
114 
115 	node.resolve(entity, c);
116 	AstNode* entityNode = entity.get_node(c);
117 
118 	switch(entityNode.astType) with(AstType) {
119 		case decl_var:
120 			auto var = entityNode.as!VariableDeclNode(c);
121 			if (var.isMember) lowerToMember(nodeIndex, entity, node, var.scopeIndex, MemberSubType.struct_member, state);
122 			break;
123 		case decl_function:
124 			auto func = entityNode.as!FunctionDeclNode(c);
125 			if (func.isMember) lowerToMember(nodeIndex, entity, node, 0, MemberSubType.struct_method, state);
126 			break;
127 		case decl_enum_member, error:
128 			// valid expr
129 			break;
130 		case decl_struct, decl_enum:
131 			node.flags |= AstFlags.isType;
132 			break;
133 		case decl_alias:
134 			require_name_resolve(entity, state);
135 			if (entityNode.isType) node.flags |= AstFlags.isType;
136 			// replace current node with aliased entity
137 			// this will only replace node index of the current owner, other references will remain
138 			// happens for enum type for example: it is referenced from enum type and from enum members
139 			nodeIndex = entity.get!AliasDeclNode(c).initializer;
140 			break;
141 		case type_ptr:
142 		case type_static_array:
143 		case type_slice:
144 		case expr_name_use:
145 		case type_basic:
146 		case literal_array:
147 		case decl_alias_array:
148 			// Happens after template arg replacement. Similar to alias
149 			nodeIndex = entity;
150 			break;
151 		case decl_template:
152 			break;
153 		default:
154 			c.internal_error(entityNode.loc, "Unknown entity %s", entityNode.astType);
155 	}
156 }
157 
158 private void lowerToMember(ref AstIndex nodeIndex, AstIndex entity, NameUseExprNode* node, uint scopeIndex, MemberSubType subType, ref NameResolveState state)
159 {
160 	CompilationContext* c = state.context;
161 	// rewrite as this.entity
162 	// let member_access handle everything else
163 	AstIndex thisName = c.appendAst!NameUseExprNode(node.loc, node.parentScope, CommonIds.id_this);
164 	require_name_resolve(thisName, state);
165 	AstIndex member = c.appendAst!MemberExprNode(node.loc, node.parentScope, thisName, entity, scopeIndex, subType);
166 	if (node.isLvalue)
167 		member.flags(c) |= AstFlags.isLvalue;
168 	nodeIndex = member;
169 	auto memberNode = member.get!MemberExprNode(c);
170 	memberNode.flags |= MemberExprFlags.needsDeref;
171 	memberNode.state = AstNodeState.name_resolve_done;
172 }
173 
174 // Get type from variable declaration
175 void type_check_name_use(ref AstIndex nodeIndex, NameUseExprNode* node, ref TypeCheckState state)
176 {
177 	type_calc_name_use(nodeIndex, node, state);
178 }
179 
180 void type_calc_name_use(ref AstIndex nodeIndex, NameUseExprNode* node, ref TypeCheckState state)
181 {
182 	CompilationContext* c = state.context;
183 
184 	final switch(node.getPropertyState(NodeProperty.type)) {
185 		case PropertyState.not_calculated: break;
186 		case PropertyState.calculating: c.circular_dependency;
187 		case PropertyState.calculated: return;
188 	}
189 
190 	c.begin_node_property_calculation(node, NodeProperty.type);
191 	scope(exit) c.end_node_property_calculation(node, NodeProperty.type);
192 
193 	AstIndex parentType;
194 	if (state.parentType.isDefined)
195 	{
196 		parentType = state.parentType.get_effective_node(c);
197 		if (parentType == CommonAstNodes.type_alias)
198 			node.flags |= NameUseFlags.forbidParenthesesFreeCall;
199 	}
200 
201 	c.assertf(node.entity.isDefined, node.loc, "name null %s %s", node.isSymResolved, node.state);
202 	switch(node.entity.astType(c))
203 	{
204 		case AstType.decl_template:
205 			node.state = AstNodeState.type_check_done;
206 
207 			auto templ = node.entity.get!TemplateDeclNode(c);
208 			if (templ.body.astType(c) != AstType.decl_function) break;
209 
210 			if (!node.forbidParenthesesFreeCall)
211 			{
212 				// Call without parenthesis
213 				// rewrite as call
214 				nodeIndex = c.appendAst!CallExprNode(node.loc, AstIndex(), node.parentScope, nodeIndex);
215 				nodeIndex.setState(c, AstNodeState.name_resolve_done);
216 				require_type_check(nodeIndex, state);
217 				break;
218 			}
219 			break;
220 
221 		case AstType.decl_function:
222 			// check forbidParenthesesFreeCall to prevent call on func address take
223 			if (!node.forbidParenthesesFreeCall)
224 			{
225 				// Call without parenthesis
226 				// rewrite as call
227 				nodeIndex = c.appendAst!CallExprNode(node.loc, AstIndex(), node.parentScope, nodeIndex);
228 				nodeIndex.setState(c, AstNodeState.name_resolve_done);
229 				require_type_check(nodeIndex, state);
230 				break;
231 			}
232 			goto default;
233 
234 		case AstType.decl_var:
235 			if (parentType == CommonAstNodes.type_alias) {
236 				node.type = CommonAstNodes.type_alias;
237 				node.state = AstNodeState.type_check_done;
238 				//node.subType = NameUseSubType.takeAliasOf;
239 				break;
240 			}
241 			goto default;
242 
243 		case AstType.decl_enum_member:
244 			require_type_check(node._entity, state, IsNested.no);
245 			goto default;
246 
247 		default:
248 			node.state = AstNodeState.type_check;
249 			c.assertf(node.isSymResolved, node.loc, "not resolved");
250 			node.type = node.entity.get_expr_type(state.context);
251 			assert(node.type.isDefined);
252 			node.state = AstNodeState.type_check_done;
253 			break;
254 	}
255 }
256 
257 ExprValue ir_gen_name_use(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, NameUseExprNode* node)
258 {
259 	CompilationContext* c = gen.context;
260 
261 	c.assertf(node.entity.isDefined, node.loc, "name null %s %s", node.isSymResolved, node.state);
262 
263 	if (node.type == CommonAstNodes.type_alias) {
264 		return ExprValue(c.constants.add(makeIrType(IrBasicType.i32), node.entity.storageIndex));
265 	} else {
266 		return ir_gen_expr(gen, node.entity, currentBlock, nextStmt);
267 	}
268 }