1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sngcpp/symbols/Scope.hpp>
  7 #include <sngcpp/symbols/ContainerSymbol.hpp>
  8 #include <sngcpp/ast/Visitor.hpp>
  9 #include <sngcpp/ast/Expression.hpp>
 10 #include <unordered_set>
 11 
 12 namespace sngcpp { namespace symbols {
 13 
 14 class NameResolver public Visitor
 15 {
 16 public:
 17     void Visit(IdentifierNode& identifierNode) override;
 18     void Visit(NestedIdNode& nestedIdNode) override;
 19     const std::std::vector<std::u32string>&NameSequence() const{returnnameSequence;}
 20 private:
 21     std::vector<std::u32string> nameSequence;
 22 };
 23 
 24 void NameResolver::Visit(IdentifierNode& identifierNode)
 25 {
 26     nameSequence.push_back(identifierNode.Identifier());
 27 }
 28 
 29 void NameResolver::Visit(NestedIdNode& nestedIdNode)
 30 {
 31     if (nestedIdNode.Left())
 32     {
 33         nestedIdNode.Left()->Accept(*this);
 34     }
 35     else
 36     {
 37         nameSequence.push_back(std::u32string());
 38     }
 39     nestedIdNode.Right()->Accept(*this);
 40 }
 41 
 42 Scope::Scope()
 43 {
 44 }
 45 
 46 Scope::~Scope()
 47 {
 48 }
 49 
 50 Symbol* Scope::Lookup(Node* nameNode)
 51 {
 52     return Lookup(nameNodeScopeLookup::this_);
 53 }
 54 
 55 Symbol* Scope::Lookup(Node* nameNodeScopeLookup scopeLookup)
 56 {
 57     NameResolver nameResolver;
 58     nameNode->Accept(nameResolver);
 59     if (nameResolver.NameSequence().empty())
 60     {
 61         return nullptr;
 62     }
 63     else if (nameResolver.NameSequence().size() == 1)
 64     {
 65         return Lookup(nameResolver.NameSequence().front()scopeLookup);
 66     }
 67     else
 68     {
 69         return Lookup(nameResolver.NameSequence()scopeLookup);
 70     }
 71 }
 72 
 73 ContainerScope::ContainerScope() : container()
 74 {
 75 }
 76 
 77 ContainerScope::ContainerScope(ContainerSymbol* container_) : container(container_)
 78 {
 79 }
 80 
 81 ContainerSymbol* ContainerScope::GlobalNs()
 82 {
 83     ContainerSymbol* globalNs = container;
 84     while (globalNs->Parent())
 85     {
 86         globalNs = globalNs->Parent();
 87     }
 88     return globalNs;
 89 }
 90 
 91 void ContainerScope::Install(Symbol* symbol)
 92 {
 93     symbolMap[symbol->Name()] = symbol;
 94 }
 95 
 96 Symbol* ContainerScope::Lookup(const std::u32string& name)
 97 {
 98     return Lookup(nameScopeLookup::this_);
 99 }
100 
101 Symbol* ContainerScope::Lookup(const std::u32string& nameScopeLookup scopeLookup)
102 {
103     auto it = symbolMap.find(name);
104     if (it != symbolMap.cend())
105     {
106         return it->second;
107     }
108     if ((scopeLookup & ScopeLookup::bases) != ScopeLookup::none)
109     {
110         int n = container->NumBases();
111         for (int i = 0; i < n; ++i)
112         {
113             ContainerSymbol* baseSymbol = container->GetBase(i);
114             ContainerScope* baseScope = baseSymbol->GetContainerScope();
115             Symbol* s = baseScope->Lookup(namescopeLookup);
116             if (s)
117             {
118                 return s;
119             }
120         }
121     }
122     if ((scopeLookup & ScopeLookup::parent) != ScopeLookup::none)
123     {
124         ContainerSymbol* parent = container->Parent();
125         if (parent)
126         {
127             ContainerScope* parentScope = parent->GetContainerScope();
128             Symbol* s = parentScope->Lookup(namescopeLookup);
129             if (s)
130             {
131                 return s;
132             }
133         }
134     }
135     return nullptr;
136 }
137 
138 Symbol* ContainerScope::Lookup(const std::std::vector<std::u32string>&nameSequenceScopeLookupscopeLoookup)
139 {
140     ContainerScope* scope = this;
141     Symbol* s = nullptr;
142     int n = nameSequence.size();
143     bool allComponentsMatched = true;
144     for (int i = 0; i < n; ++i)
145     {
146         const std::u32string& name = nameSequence[i];
147         if (name.empty())
148         {
149             scope = GlobalNs()->GetContainerScope();
150         }
151         else if (scope)
152         {
153             s = scope->Lookup(nameScopeLookup::this_);
154             if (s)
155             {
156                 scope = s->GetContainerScope();
157             }
158             else
159             {
160                 allComponentsMatched = false;
161             }
162         }
163     }
164     if (!s || !allComponentsMatched)
165     {
166         if ((scopeLoookup & ScopeLookup::parent) != ScopeLookup::none)
167         {
168             ContainerSymbol* parent = container->Parent();
169             if (parent)
170             {
171                 return parent->GetContainerScope()->Lookup(nameSequencescopeLoookup);
172             }
173             else
174             {
175                 return nullptr;
176             }
177         }
178     }
179     return s;
180 }
181 
182 void FileScope::Install(ContainerScope* containerScopeUsingDirectiveNode& usingDirectiveNode)
183 {
184     Symbol* symbol = static_cast<Scope*>(containerScope)->Lookup(usingDirectiveNode.NamespaceName()ScopeLookup::this_and_parent);
185     if (symbol)
186     {
187         if (symbol->IsNamespaceSymbol())
188         {
189             ContainerScope* containerScope = symbol->GetContainerScope();
190             if (containerScope)
191             {
192                 for (ContainerScope* scope : containerScopes)
193                 {
194                     if (scope == containerScope) return;
195                 }
196                 containerScopes.push_back(containerScope);
197             }
198             else
199             {
200                 throw std::runtime_error("container scope expected");
201             }
202         }
203         else
204         {
205             throw std::runtime_error("namespace symbol expected");
206         }
207     }
208 }
209 
210 void FileScope::Install(ContainerScope* containerScopeUsingDeclarationNode& usingDeclarationNode)
211 {
212     Symbol* symbol = static_cast<Scope*>(containerScope)->Lookup(usingDeclarationNode.QualifiedId()ScopeLookup::this_and_parent);
213     if (symbol)
214     {
215         aliasSymbolMap[symbol->Name()] = symbol;
216     }
217 }
218 
219 Symbol* FileScope::Lookup(const std::u32string& name)
220 {
221     return Lookup(nameScopeLookup::this_);
222 }
223 
224 Symbol* FileScope::Lookup(const std::u32string& nameScopeLookup scopeLookup)
225 {
226     if (scopeLookup != ScopeLookup::this_)
227     {
228         throw std::runtime_error("file scope supports only this scope lookup");
229     }
230     std::unordered_set<Symbol*> foundSymbols;
231     auto it = aliasSymbolMap.find(name);
232     if (it != aliasSymbolMap.cend())
233     {
234         Symbol* symbol = it->second;
235         foundSymbols.insert(symbol);
236     }
237     else
238     {
239         for (ContainerScope* containerScope : containerScopes)
240         {
241             Symbol* symbol = containerScope->Lookup(nameScopeLookup::this_);
242             if (symbol)
243             {
244                 foundSymbols.insert(symbol);
245             }
246         }
247     }
248     if (foundSymbols.empty())
249     {
250         return nullptr;
251     }
252     else if (foundSymbols.size() > 1)
253     {
254         return nullptr;
255     }
256     else
257     {
258         return *foundSymbols.begin();
259     }
260 }
261 
262 Symbol* FileScope::Lookup(const std::std::vector<std::u32string>&nameSequenceScopeLookupscopeLoookup)
263 {
264     std::unordered_set<Symbol*> foundSymbols;
265     for (ContainerScope* containerScope : containerScopes)
266     {
267         Symbol* symbol = containerScope->Lookup(nameSequenceScopeLookup::this_);
268         if (symbol)
269         {
270             foundSymbols.insert(symbol);
271         }
272     }
273     if (foundSymbols.empty())
274     {
275         return nullptr;
276     }
277     else if (foundSymbols.size() > 1)
278     {
279         return nullptr;
280     }
281     else
282     {
283         return *foundSymbols.begin();
284     }
285 }
286 
287 } } // namespace sngcpp::symbols