1 /**
2 Copyright: Copyright (c) 2017-2019 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 /// Resolve all symbol references (variable/type/function/enum name uses)
8 /// using information collected on previous pass
9 module vox.fe.passes.names_resolve;
10 
11 import std.stdio;
12 import std.string : format;
13 import vox.all;
14 
15 void pass_names_resolve(ref CompilationContext context, CompilePassPerModule[] subPasses)
16 {
17 	auto state = NameResolveState(&context);
18 
19 	foreach (ref SourceFileInfo file; context.files.data) {
20 		AstIndex modIndex = file.mod.get_ast_index(&context);
21 		require_name_resolve(modIndex, state);
22 		assert(context.analisysStack.length == 0);
23 	}
24 }
25 
26 struct NameResolveState
27 {
28 	CompilationContext* context;
29 }
30 
31 void require_name_resolve(ref AstIndex nodeIndex, CompilationContext* context)
32 {
33 	auto state = NameResolveState(context);
34 	require_name_resolve(nodeIndex, state);
35 }
36 
37 void require_name_resolve(ref AstNodes items, ref NameResolveState state)
38 {
39 	foreach(ref AstIndex item; items) require_name_resolve(item, state);
40 }
41 
42 void require_name_resolve(ref AstIndex nodeIndex, ref NameResolveState state)
43 {
44 	AstNode* node = state.context.getAstNode(nodeIndex);
45 
46 	switch(node.state) with(AstNodeState)
47 	{
48 		case name_register_self, name_register_nested, name_resolve, type_check:
49 			state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.name_resolve));
50 			state.context.circular_dependency;
51 		case parse_done:
52 			auto name_state = NameRegisterState(state.context);
53 			require_name_register_self(0, nodeIndex, name_state);
54 			state.context.throwOnErrors;
55 			goto case;
56 		case name_register_self_done:
57 			require_name_register(nodeIndex, state.context);
58 			state.context.throwOnErrors;
59 			break;
60 		case name_register_nested_done: break; // all requirement are done
61 		case name_resolve_done, type_check_done, ir_gen_done: return; // already name resolved
62 		default: state.context.internal_error(node.loc, "Node %s in %s state", node.astType, node.state);
63 	}
64 
65 	state.context.push_analized_node(AnalysedNode(nodeIndex, NodeProperty.name_resolve));
66 	scope(success) state.context.pop_analized_node;
67 
68 	if (node.hasAttributes) {
69 		name_resolve_attributes(node.attributeInfo, state);
70 	}
71 
72 	final switch(node.astType) with(AstType)
73 	{
74 		case error: state.context.internal_error(node.loc, "Visiting error node");
75 		case abstract_node: state.context.internal_error(node.loc, "Visiting abstract node");
76 
77 		case decl_alias: name_resolve_alias(cast(AliasDeclNode*)node, state); break;
78 		case decl_alias_array: assert(false);
79 		case decl_builtin: assert(false);
80 		case decl_builtin_attribute: assert(false);
81 		case decl_module: name_resolve_module(cast(ModuleDeclNode*)node, state); break;
82 		case decl_package: assert(false);
83 		case decl_import: assert(false);
84 		case decl_function: name_resolve_func(cast(FunctionDeclNode*)node, state); break;
85 		case decl_var: name_resolve_var(cast(VariableDeclNode*)node, state); break;
86 		case decl_struct: name_resolve_struct(cast(StructDeclNode*)node, state); break;
87 		case decl_enum: name_resolve_enum(cast(EnumDeclaration*)node, state); break;
88 		case decl_enum_member: name_resolve_enum_member(cast(EnumMemberDecl*)node, state); break;
89 		case decl_static_assert: name_resolve_static_assert(cast(StaticAssertDeclNode*)node, state); break;
90 		case decl_static_foreach: assert(false);
91 		case decl_static_if: assert(false);
92 		case decl_static_version: assert(false);
93 		case decl_template: assert(false);
94 		case decl_template_param: assert(false);
95 
96 		case stmt_block: name_resolve_block(cast(BlockStmtNode*)node, state); break;
97 		case stmt_if: name_resolve_if(cast(IfStmtNode*)node, state); break;
98 		case stmt_while: name_resolve_while(cast(WhileStmtNode*)node, state); break;
99 		case stmt_do_while: name_resolve_do(cast(DoWhileStmtNode*)node, state); break;
100 		case stmt_for: name_resolve_for(cast(ForStmtNode*)node, state); break;
101 		case stmt_switch: name_resolve_switch(cast(SwitchStmtNode*)node, state); break;
102 		case stmt_return: name_resolve_return(cast(ReturnStmtNode*)node, state); break;
103 		case stmt_break: assert(false);
104 		case stmt_continue: assert(false);
105 
106 		case expr_name_use: name_resolve_name_use(nodeIndex, cast(NameUseExprNode*)node, state); break;
107 		case expr_member: name_resolve_member(cast(MemberExprNode*)node, state); break;
108 		case expr_bin_op: name_resolve_binary_op(cast(BinaryExprNode*)node, state); break;
109 		case expr_un_op: name_resolve_unary_op(cast(UnaryExprNode*)node, state); break;
110 		case expr_call: name_resolve_call(cast(CallExprNode*)node, state); break;
111 		case expr_named_argument: name_resolve_named_argument(cast(NamedArgumenExprNode*)node, state); break;
112 		case expr_index: name_resolve_index(nodeIndex, cast(IndexExprNode*)node, state); break;
113 		case expr_slice: name_resolve_expr_slice(cast(SliceExprNode*)node, state); break;
114 		case expr_type_conv: name_resolve_type_conv(cast(TypeConvExprNode*)node, state); break;
115 
116 		case literal_int: assert(false);
117 		case literal_float: assert(false);
118 		case literal_string: assert(false);
119 		case literal_null: assert(false);
120 		case literal_bool: assert(false);
121 		case literal_array: assert(false);
122 		case literal_special: assert(false);
123 
124 		case type_basic: assert(false);
125 		case type_func_sig: name_resolve_func_sig(cast(FunctionSignatureNode*)node, state); break;
126 		case type_ptr: name_resolve_ptr(cast(PtrTypeNode*)node, state); break;
127 		case type_static_array: name_resolve_static_array(cast(StaticArrayTypeNode*)node, state); break;
128 		case type_slice: name_resolve_slice(cast(SliceTypeNode*)node, state); break;
129 	}
130 }
131 
132 /// Error means that lookup failed due to earlier failure or error, so no new error should be produced
133 enum LookupResult : ubyte {
134 	success,
135 	failure,
136 	error
137 }
138 
139 /// Look up symbol by Identifier. Searches the stack of scopes.
140 // Returns errorNode if not found or error occured
141 AstIndex lookupScopeIdRecursive(Scope* scop, const Identifier id, TokenIndex from, CompilationContext* context)
142 {
143 	Scope* sc = scop;
144 
145 	//writefln("lookup %s", context.idString(id));
146 	// first phase
147 	while(sc)
148 	{
149 		AstIndex symIndex = sc.symbols.get(id, AstIndex.init);
150 		//writefln("  scope %s %s %s", context.getAstNodeIndex(sc), sc.debugName, symIndex);
151 
152 		if (symIndex)
153 		{
154 			AstNode* symNode = context.getAstNode(symIndex);
155 			if (sc.kind == ScopeKind.local)
156 			{
157 				// we need to skip forward references in function scope
158 				uint fromStart = context.tokenLocationBuffer[from].start;
159 				uint toStart = context.tokenLocationBuffer[symNode.loc].start;
160 				//writefln("    local %s %s", fromStart, toStart);
161 				// backward reference
162 				if (fromStart > toStart) {
163 					return symIndex;
164 				}
165 			}
166 			else
167 			{
168 				// forward reference allowed in global and member scopes
169 				return symIndex;
170 			}
171 		}
172 
173 		sc = sc.parentScope.get_scope(context);
174 	}
175 
176 	// second phase
177 	return lookupImports(scop, id, from, context);
178 }
179 
180 // Returns errorNode if not found or error occured
181 AstIndex lookupImports(Scope* scop, const Identifier id, TokenIndex from, CompilationContext* c)
182 {
183 	while (scop)
184 	{
185 		AstIndex symIndex;
186 		ModuleDeclNode* symMod;
187 
188 		foreach (AstIndex impIndex; scop.imports)
189 		{
190 			ModuleDeclNode* imp = c.getAst!ModuleDeclNode(impIndex);
191 			// TODO: check that import is higher in ordered scopes
192 			AstIndex scopeSym = imp.memberScope.lookup_scope(id, c);
193 			if (!scopeSym) continue;
194 
195 			if (scopeSym && symIndex && scopeSym != symIndex)
196 			{
197 				c.error(from,
198 					"`%s` at %s conflicts with `%s` at %s",
199 					symIndex.get_node_id(c).pr(c), FmtSrcLoc(c.getAstNode(symIndex).loc, c),
200 					scopeSym.get_node_id(c).pr(c), FmtSrcLoc(c.getAstNode(scopeSym).loc, c));
201 				return CommonAstNodes.node_error;
202 			}
203 
204 			symIndex = scopeSym;
205 			symMod = imp;
206 		}
207 
208 		if (symIndex) return symIndex;
209 
210 		scop = scop.parentScope.get_scope(c);
211 	}
212 
213 	return CommonAstNodes.node_error;
214 }
215