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.decl.scope_;
5 
6 import vox.all;
7 
8 enum ScopeKind : ubyte {
9 	no_scope, // scope created by @attr{} or by #version or #if or #foreach
10 	local,  // function
11 	member, // struct, enum
12 	global, // module
13 }
14 
15 struct ScopeIndex
16 {
17 	uint storageIndex;
18 	bool isDefined() const { return storageIndex != 0; }
19 	bool isUndefined() const { return storageIndex == 0; }
20 
21 	bool opCast(T : bool)() const {
22 		return storageIndex != 0;
23 	}
24 
25 	Scope* get_scope(CompilationContext* c) { return c.getAstScope(this); }
26 
27 	// null scope index is treated as empty scope and results in null AstIndex
28 	AstIndex lookup_scope(Identifier id, CompilationContext* c) {
29 		if (isUndefined) return AstIndex.init;
30 		Scope* sc = c.getAstScope(this);
31 		return sc.symbols.get(id, AstIndex.init);
32 	}
33 	void insert_scope(Identifier id, AstIndex nodeIndex, CompilationContext* c) {
34 		assert(isDefined, "scope is undefined");
35 		Scope* sc = c.getAstScope(this);
36 		sc.insert(id, nodeIndex, c);
37 	}
38 }
39 
40 ///
41 struct Scope
42 {
43 	///
44 	AstNodeMap symbols;
45 	/// Imported modules
46 	AstNodes imports;
47 	///
48 	ScopeIndex parentScope;
49 	/// This node is owner of all the definitions inside of this scope
50 	AstIndex owner;
51 	///
52 	ScopeKind kind;
53 	///
54 	string debugName;
55 
56 	/// Constructs and inserts symbol with id
57 	void insert(Identifier id, AstIndex nodeIndex, CompilationContext* c)
58 	{
59 		AstNode* node = nodeIndex.get_node(c);
60 		if (auto s = symbols.get(id, AstIndex.init))
61 		{
62 			c.error(node.loc,
63 				"declaration `%s` is already defined at %s",
64 				c.idString(id), FmtSrcLoc(s.get_node(c).loc, c));
65 		}
66 		symbols.put(c.arrayArena, id, nodeIndex);
67 	}
68 }
69 
70 void post_clone_scope(Scope* node, ref CloneState state)
71 {
72 	// Scope.symbols/imports dont need fixing, because no symbols are registered at this point
73 	state.fixScope(node.parentScope);
74 	state.fixAstIndex(node.owner);
75 }
76 
77 mixin template ScopeDeclNodeData(AstType _astType, int default_flags = 0, AstNodeState _init_state = AstNodeState.parse_done) {
78 	mixin AstNodeData!(_astType, default_flags, _init_state);
79 	/// Each node can be struct, function or variable
80 	AstNodes declarations;
81 }