1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/symbols/Scope.hpp>
  7 #include <cmajor/symbols/ContainerSymbol.hpp>
  8 #include <cmajor/symbols/ClassTypeSymbol.hpp>
  9 #include <cmajor/symbols/NamespaceSymbol.hpp>
 10 #include <cmajor/symbols/FunctionSymbol.hpp>
 11 #include <cmajor/symbols/Exception.hpp>
 12 #include <cmajor/symbols/GlobalFlags.hpp>
 13 #include <cmajor/symbols/Module.hpp>
 14 #include <sngcm/ast/Identifier.hpp>
 15 #include <soulng/util/TextUtils.hpp>
 16 #include <soulng/util/Unicode.hpp>
 17 #include <soulng/util/Util.hpp>
 18 #include <algorithm>
 19 
 20 namespace cmajor { namespace symbols {
 21 
 22 using namespace soulng::unicode;
 23 using namespace soulng::util;
 24 
 25 Scope::~Scope()
 26 {
 27 }
 28 
 29 ContainerScope::ContainerScope() : container(nullptr)parentScope(nullptr)symbolMap()
 30 {
 31 }
 32 
 33 ContainerScope* ContainerScope::BaseScope() const
 34 {
 35     if (container)
 36     {
 37         if (container->GetSymbolType() == SymbolType::classTypeSymbol || container->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
 38         {
 39             ClassTypeSymbol* cls = static_cast<ClassTypeSymbol*>(container);
 40             ClassTypeSymbol* baseClass = cls->BaseClass();
 41             if (baseClass)
 42             {
 43                 return baseClass->GetContainerScope();
 44             }
 45         }
 46     }
 47     return nullptr;
 48 }
 49 
 50 ContainerScope* ContainerScope::ParentScope() const
 51 {
 52     if (parentScope)
 53     {
 54         return parentScope;
 55     }
 56     if (container)
 57     {
 58         Symbol* parent = nullptr;
 59         if (container->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
 60         {
 61             ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(container);
 62             ClassTypeSymbol* classTemplate = specialization->GetClassTemplate();
 63             parent = classTemplate->Parent();
 64         }
 65         else
 66         {
 67             parent = container->Parent();
 68         }
 69         if (parent)
 70         {
 71             if (!parent->GetModule()->IsRootModule() && parent->GetSymbolType() == SymbolType::namespaceSymbol)
 72             {
 73                 NamespaceSymbol* ns = static_cast<NamespaceSymbol*>(parent);
 74                 Module* rootModule = GetRootModuleForCurrentThread();
 75                 NamespaceSymbol* mappedNs = rootModule->GetSymbolTable().GetMappedNs(ns);
 76                 if (mappedNs)
 77                 {
 78                     return mappedNs->GetContainerScope();
 79                 }
 80             }
 81             return parent->GetContainerScope();
 82         }
 83     }
 84     return nullptr;
 85 }
 86 
 87 void ContainerScope::Install(Symbol* symbol)
 88 {
 89     auto it = symbolMap.find(symbol->Name());
 90     if (symbol->GetSymbolType() != SymbolType::namespaceSymbol && 
 91         symbol->GetSymbolType() != SymbolType::declarationBlock && 
 92         it != symbolMap.cend())
 93     {
 94         Symbol* prev = it->second;
 95         if (prev != symbol)
 96         {
 97             throw Exception("symbol '" + ToUtf8(symbol->Name()) + "' already defined"symbol->GetSpan()symbol->SourceModuleId()prev->GetSpan()prev->SourceModuleId());
 98         }
 99     }
100     else
101     {
102         symbolMap[symbol->Name()] = symbol;
103     }
104     symbol->SetInstalled();
105 }
106 
107 void ContainerScope::Uninstall(Symbol* symbol)
108 {
109     symbolMap.erase(symbol->Name());
110     symbol->ResetInstalled();
111 }
112 
113 Symbol* ContainerScope::Lookup(const std::u32string& name) const
114 {
115     return Lookup(nameScopeLookup::this_);
116 }
117 
118 int CountQualifiedNameComponents(const std::u32string& qualifiedName)
119 {
120     int numComponents = 0;
121     int componentSize = 0;
122     int state = 0;
123     int angleBracketCount = 0;
124     for (char32_t c : qualifiedName)
125     {
126         switch (state)
127         {
128             case 0:
129             {
130                 if (c == '.')
131                 {
132                     ++numComponents;
133                     componentSize = 0;
134                 }
135                 else if (c == '<')
136                 {
137                     ++componentSize;
138                     angleBracketCount = 1;
139                     state = 1;
140                 }
141                 else
142                 {
143                     ++componentSize;
144                 }
145                 break;
146             }
147             case 1:
148             {
149                 ++componentSize;
150                 if (c == '<')
151                 {
152                     ++angleBracketCount;
153                 }
154                 else if (c == '>')
155                 {
156                     --angleBracketCount;
157                     if (angleBracketCount == 0)
158                     {
159                         state = 0;
160                     }
161                 }
162                 break;
163             }
164         }
165     }
166     if (componentSize > 0)
167     {
168         ++numComponents;
169     }
170     return numComponents;
171 }
172 
173 std::std::vector<std::u32string>ParseQualifiedName(conststd::u32string&qualifiedName)
174 {
175     std::vector<std::u32string> components;
176     int state = 0;
177     std::u32string component;
178     int angleBracketCount = 0;
179     for (char32_t c : qualifiedName)
180     {
181         switch (state)
182         {
183             case 0:
184             {
185                 if (c == '.')
186                 {
187                     components.push_back(component);
188                     component.clear();
189                 }
190                 else if (c == '<')
191                 {
192                     component.append(1c);
193                     angleBracketCount = 1;
194                     state = 1;
195                 }
196                 else
197                 {
198                     component.append(1c);
199                 }
200                 break;
201             }
202             case 1:
203             {
204                 component.append(1c);
205                 if (c == '<')
206                 {
207                     ++angleBracketCount;
208                 }
209                 else if (c == '>')
210                 {
211                     --angleBracketCount;
212                     if (angleBracketCount == 0)
213                     {
214                         state = 0;
215                     }
216                 }
217                 break;
218             }
219         }
220     }
221     if (!component.empty())
222     {
223         components.push_back(component);
224     }
225     return components;
226 }
227 
228 std::std::vector<CCComponent>ParseCCName(conststd::u32string&qualifiedName)
229 {
230     std::vector<CCComponent> components;
231     int state = 0;
232     std::u32string str;
233     int angleBracketCount = 0;
234     CCComponentSeparator separator = CCComponentSeparator::dot;
235     for (char32_t c : qualifiedName)
236     {
237         switch (state)
238         {
239             case 0:
240             {
241                 if (c == '.')
242                 {
243                     components.push_back(CCComponent(separatorstr));
244                     separator = CCComponentSeparator::dot;
245                     str.clear();
246                 }
247                 else if (c == '-')
248                 {
249                     state = 2;
250                 }
251                 else if (c == '<')
252                 {
253                     str.append(1c);
254                     angleBracketCount = 1;
255                     state = 1;
256                 }
257                 else
258                 {
259                     str.append(1c);
260                 }
261                 break;
262             }
263             case 1:
264             {
265                 str.append(1c);
266                 if (c == '<')
267                 {
268                     ++angleBracketCount;
269                 }
270                 else if (c == '>')
271                 {
272                     --angleBracketCount;
273                     if (angleBracketCount == 0)
274                     {
275                         state = 0;
276                     }
277                 }
278                 break;
279             }
280             case 2:
281             {
282                 if (c == '>')
283                 {
284                     components.push_back(CCComponent(separatorstr));
285                     separator = CCComponentSeparator::arrow;
286                     str.clear();
287                     state = 0;
288                 }
289                 else if (c != '-')
290                 {
291                     state = 0;
292                 }
293                 break;
294             }
295         }
296     }
297     components.push_back(CCComponent(separatorstr));
298     return components;
299 }
300 
301 int CountCCComponents(const std::u32string& qualifiedName)
302 {
303     int numComponents = 0;
304     int state = 0;
305     int angleBracketCount = 0;
306     for (char32_t c : qualifiedName)
307     {
308         switch (state)
309         {
310             case 0:
311             {
312                 if (c == '.')
313                 {
314                     ++numComponents;
315                 }
316                 else if (c == '-')
317                 {
318                     state = 2;
319                 }
320                 else if (c == '<')
321                 {
322                     angleBracketCount = 1;
323                     state = 1;
324                 }
325                 break;
326             }
327             case 1:
328             {
329                 if (c == '<')
330                 {
331                     ++angleBracketCount;
332                 }
333                 else if (c == '>')
334                 {
335                     --angleBracketCount;
336                     if (angleBracketCount == 0)
337                     {
338                         state = 0;
339                     }
340                 }
341                 break;
342             }
343             case 2:
344             {
345                 if (c == '>')
346                 {
347                     ++numComponents;
348                     state = 0;
349                 }
350                 else if (c != '-')
351                 {
352                     state = 0;
353                 }
354                 break;
355             }
356         }
357     }
358     ++numComponents;
359     return numComponents;
360 }
361 
362 std::u32string MakeCCMatch(const std::std::vector<CCComponent>&componentsconststd::u32string&last)
363 {
364     std::u32string ccMatch;
365     int n = components.size();
366     bool first = true;
367     for (int i = 0; i < n - 1; ++i)
368     {
369         const CCComponent& component = components[i];
370         if (first)
371         {
372             first = false;
373         }
374         else
375         {
376             if (component.separator == CCComponentSeparator::dot)
377             {
378                 ccMatch.append(1'.');
379             }
380             else if (component.separator == CCComponentSeparator::arrow)
381             {
382                 ccMatch.append(U"->");
383             }
384         }
385         ccMatch.append(component.str);
386     }
387     const CCComponent& component = components[n - 1];
388     if (first)
389     {
390         first = false;
391     }
392     else
393     {
394         if (component.separator == CCComponentSeparator::dot)
395         {
396             ccMatch.append(1'.');
397         }
398         else if (component.separator == CCComponentSeparator::arrow)
399         {
400             ccMatch.append(U"->");
401         }
402     }
403     ccMatch.append(last);
404     return ccMatch;
405 }
406 
407 std::std::vector<CCSymbolEntry>MakeCCMatches(conststd::std::vector<CCComponent>&componentsconststd::std::vector<CCSymbolEntry>&matches)
408 {
409     std::vector<CCSymbolEntry> ccMatches;
410     for (const CCSymbolEntry& match : matches)
411     {
412         ccMatches.push_back(CCSymbolEntry(match.symbolmatch.ccPrefixLenMakeCCMatch(componentsmatch.replacement)));
413     }
414     return ccMatches;
415 }
416 
417 void AddMatches(std::std::vector<CCSymbolEntry>&matchesstd::std::vector<CCSymbolEntry>&matchesToAdd)
418 {
419     for (CCSymbolEntry& entry : matchesToAdd)
420     {
421         Symbol* s = entry.symbol;
422         bool found = false;
423         for (CCSymbolEntry& m : matches)
424         {
425             if (s == m.symbol)
426             {
427                 found = true;
428                 break;
429             }
430         }
431         if (!found)
432         {
433             matches.push_back(std::move(entry));
434         }
435     }
436 }
437 
438 Symbol* ContainerScope::Lookup(const std::u32string& nameScopeLookup lookup) const
439 {
440     int numQualifiedNameComponents = CountQualifiedNameComponents(name);
441     if (numQualifiedNameComponents > 1)
442     {
443         std::vector<std::u32string> components = ParseQualifiedName(name);
444         return LookupQualified(componentslookup);
445     }
446     else
447     {
448         auto it = symbolMap.find(name);
449         if (it != symbolMap.end())
450         {
451             Symbol* s = it->second;
452             return s;
453         }
454         if ((lookup & ScopeLookup::base) != ScopeLookup::none)
455         {
456             ContainerScope* baseScope = BaseScope();
457             if (baseScope)
458             {
459                 Symbol* s = baseScope->Lookup(namelookup);
460                 if (s)
461                 {
462                     return s;
463                 }
464             }
465         }
466         if ((lookup & ScopeLookup::parent) != ScopeLookup::none)
467         {
468             ContainerScope* parentScope = ParentScope();
469             if (parentScope)
470             {
471                 Symbol* s = parentScope->Lookup(namelookup);
472                 if (s)
473                 {
474                     return s;
475                 }
476             }
477         }
478         return nullptr;
479     }
480 }
481 
482 Symbol* ContainerScope::LookupQualified(const std::std::vector<std::u32string>&componentsScopeLookuplookup) const
483 {
484     const ContainerScope* scope = this;
485     Symbol* s = nullptr;
486     int n = int(components.size());
487     bool allComponentsMatched = true;
488     for (int i = 0; i < n; ++i)
489     {
490         const std::u32string& component = components[i];
491         if (scope)
492         {
493             s = scope->Lookup(componentScopeLookup::this_);
494             if (s)
495             {
496                 scope = s->GetContainerScope();
497             }
498             else
499             {
500                 allComponentsMatched = false;
501             }
502         }
503     }
504     if (!s || !allComponentsMatched)
505     {
506         if ((lookup & ScopeLookup::parent) != ScopeLookup::none)
507         {
508             ContainerScope* parentScope = ParentScope();
509             if (parentScope)
510             {
511                 return parentScope->LookupQualified(componentslookup);
512             }
513             else
514             {
515                 return nullptr;
516             }
517         }
518     }
519     return s;
520 }
521 
522 std::std::vector<CCSymbolEntry>ContainerScope::LookupBeginWith(conststd::u32string&prefix) const
523 {
524     return LookupBeginWith(prefixScopeLookup::this_);
525 }
526 
527 std::std::vector<CCSymbolEntry>ContainerScope::LookupBeginWith(conststd::u32string&prefixScopeLookuplookup) const
528 {
529     int numQualifiedNameComponents = CountCCComponents(prefix);
530     if (numQualifiedNameComponents > 1)
531     {
532         std::vector<CCComponent> components = ParseCCName(prefix);
533         return LookupQualifiedBeginWith(componentslookup);
534     }
535     else
536     {
537         std::vector<CCSymbolEntry> matches;
538         auto it = symbolMap.lower_bound(prefix);
539         while (it != symbolMap.cend() && StartsWith(it->firstprefix))
540         {
541             matches.push_back(CCSymbolEntry(it->secondprefix.length()it->second->Name()));
542             ++it;
543         }
544         if ((lookup & ScopeLookup::base) != ScopeLookup::none)
545         {
546             ContainerScope* baseScope = BaseScope();
547             if (baseScope)
548             {
549                 std::vector<CCSymbolEntry> m = baseScope->LookupBeginWith(prefixlookup);
550                 AddMatches(matchesm);
551             }
552         }
553         if ((lookup & ScopeLookup::parent) != ScopeLookup::none)
554         {
555             ContainerScope* parentScope = ParentScope();
556             if (parentScope)
557             {
558                 std::vector<CCSymbolEntry> m = parentScope->LookupBeginWith(prefixlookup);
559                 AddMatches(matchesm);
560             }
561         }
562         return matches;
563     }
564 }
565 
566 std::std::vector<CCSymbolEntry>ContainerScope::LookupQualifiedBeginWith(conststd::std::vector<CCComponent>&componentsScopeLookuplookup) const
567 {
568     std::vector<CCSymbolEntry> matches;
569     const ContainerScope* scope = this;
570     int n = int(components.size());
571     const Symbol* s = nullptr;
572     for (int i = 0; i < n - 1; ++i)
573     {
574         const CCComponent& component = components[i];
575         if (scope)
576         {
577             if (component.separator == CCComponentSeparator::arrow)
578             {
579                 const ContainerSymbol* containerSymbol = scope->Container();
580                 scope = containerSymbol->GetArrowScope();
581             }
582             if (component.str == U"this")
583             {
584                 const ContainerSymbol* containerSymbol = Container();
585                 const FunctionSymbol* f = containerSymbol->FunctionNoThrow();
586                 if (f && f->GetSymbolType() == SymbolType::memberFunctionSymbol)
587                 {
588                     s = f->Parameters()[0];
589                 }
590                 else
591                 {
592                     s = nullptr;
593                 }
594             }
595             else
596             {
597                 s = scope->Lookup(component.strScopeLookup::this_);
598             }
599             if (s)
600             {
601                 scope = s->GetTypeScope();
602             }
603         }
604         else
605         {
606             s = nullptr;
607         }
608     }
609     if (s && scope)
610     {
611         bool validAccess = true;
612         if (components[n - 1].separator == CCComponentSeparator::dot)
613         {
614             switch (s->GetSymbolType())
615             {
616                 case SymbolType::localVariableSymbol:
617                 case SymbolType::memberVariableSymbol:
618                 case SymbolType::parameterSymbol:
619                 {
620                     const VariableSymbol* variableSymbol = static_cast<const VariableSymbol*>(s);
621                     const TypeSymbol* type = variableSymbol->GetType();
622                     if (type && type->IsPointerType())
623                     {
624                         validAccess = false;
625                     }
626                 }
627             }
628         }
629         else if (components[n - 1].separator == CCComponentSeparator::arrow)
630         {
631             const ContainerSymbol* containerSymbol = scope->Container();
632             scope = containerSymbol->GetArrowScope();
633         }
634         if (validAccess)
635         {
636             std::vector<CCSymbolEntry> m = MakeCCMatches(componentsscope->LookupBeginWith(components[n - 1].str));
637             AddMatches(matchesm);
638             lookup = lookup & ~ScopeLookup::parent;
639         }
640     }
641     if ((lookup & ScopeLookup::base) != ScopeLookup::none)
642     {
643         ContainerScope* baseScope = BaseScope();
644         if (baseScope)
645         {
646             std::vector<CCSymbolEntry> m = baseScope->LookupQualifiedBeginWith(componentsScopeLookup::this_and_base);
647             AddMatches(matchesm);
648         }
649     }
650     if ((lookup & ScopeLookup::parent) != ScopeLookup::none)
651     {
652         ContainerScope* parentScope = ParentScope();
653         if (parentScope)
654         {
655             std::vector<CCSymbolEntry> m = parentScope->LookupQualifiedBeginWith(componentsScopeLookup::this_and_base_and_parent);
656             AddMatches(matchesm);
657         }
658     }
659     return matches;
660 }
661 
662 const NamespaceSymbol* ContainerScope::Ns() const
663 {
664     return container->Ns();
665 }
666 
667 NamespaceSymbol* ContainerScope::Ns()
668 {
669     return container->Ns();
670 }
671 
672 void ContainerScope::Clear()
673 {
674     symbolMap.clear();
675 }
676 
677 NamespaceSymbol* ContainerScope::CreateNamespace(const std::u32string& qualifiedNsNameconst Span& spanconst boost::uuids::uuid& sourceModuleId)
678 {
679     ContainerScope* scope = this;
680     NamespaceSymbol* parentNs = scope->Ns();
681     std::vector<std::u32string> components = Split(qualifiedNsName'.');
682     for (const std::u32string& component : components)
683     {
684         Symbol* s = scope->Lookup(component);
685         if (s)
686         {
687             if (s->GetSymbolType() == SymbolType::namespaceSymbol)
688             {
689                 scope = s->GetContainerScope();
690                 parentNs = scope->Ns();
691             }
692             else
693             {
694                 throw Exception("symbol '" + ToUtf8(s->Name()) + "' does not denote a namespace"s->GetSpan()s->SourceModuleId());
695             }
696         }
697         else
698         {
699             NamespaceSymbol* newNs = new NamespaceSymbol(spansourceModuleIdcomponent);
700             newNs->SetModule(container->GetModule());
701             scope = newNs->GetContainerScope();
702             parentNs->AddMember(newNs);
703             parentNs = newNs;
704         }
705     }
706     return parentNs;
707 }
708 
709 void ContainerScope::CollectViableFunctions(int arityconst std::u32string& groupNamestd::std::unordered_set<ContainerScope*>&scopesLookedUpScopeLookupscopeLookup
710     ViableFunctionSet& viableFunctionsModule* module)
711 {
712     if ((scopeLookup & ScopeLookup::this_) != ScopeLookup::none)
713     {
714         if (scopesLookedUp.find(this) == scopesLookedUp.end())
715         {
716             scopesLookedUp.insert(this);
717             Symbol* symbol = Lookup(groupName);
718             if (symbol)
719             {
720                 if (symbol->GetSymbolType() == SymbolType::functionGroupSymbol)
721                 {
722                     FunctionGroupSymbol* functionGroupSymbol = static_cast<FunctionGroupSymbol*>(symbol);
723                     functionGroupSymbol->CollectViableFunctions(arityviableFunctionsmodule);
724                 }
725             }
726         }
727     }
728     if ((scopeLookup & ScopeLookup::base) != ScopeLookup::none)
729     {
730         ContainerScope* baseScope = BaseScope();
731         if (baseScope)
732         {
733             baseScope->CollectViableFunctions(aritygroupNamescopesLookedUpscopeLookupviableFunctionsmodule);
734         }
735     }
736     if ((scopeLookup & ScopeLookup::parent) != ScopeLookup::none)
737     {
738         ContainerScope* parentScope = ParentScope();
739         if (parentScope)
740         {
741             parentScope->CollectViableFunctions(aritygroupNamescopesLookedUpscopeLookupviableFunctionsmodule);
742         }
743     }
744 }
745 
746 FileScope::FileScope()
747 {
748 }
749 
750 void FileScope::InstallAlias(ContainerScope* containerScopeAliasNode* aliasNode)
751 {
752     Assert(containerScope"container scope is null");
753     std::u32string qualifiedName = aliasNode->Qid()->Str();
754     Symbol* symbol = containerScope->Lookup(qualifiedNameScopeLookup::this_and_parent);
755     if (symbol)
756     {
757         std::u32string aliasName = aliasNode->Id()->Str();
758         aliasSymbolMap[aliasName] = symbol;
759     }
760     else
761     {
762         throw Exception("referred symbol '" + ToUtf8(aliasNode->Qid()->Str()) + "' not found"aliasNode->Qid()->GetSpan()aliasNode->Qid()->ModuleId());
763     }
764 }
765 
766 void FileScope::AddContainerScope(ContainerScope* containerScope)
767 {
768     if (std::find(containerScopes.begin()containerScopes.end()containerScope) == containerScopes.end())
769     {
770         containerScopes.push_back(containerScope);
771     }
772 }
773 
774 void FileScope::InstallNamespaceImport(ContainerScope* containerScopeNamespaceImportNode* namespaceImportNode)
775 {
776     try
777     {
778         Assert(containerScope"container scope is null");
779         std::u32string importedNamespaceName = namespaceImportNode->Ns()->Str();
780         Symbol* symbol = containerScope->Lookup(importedNamespaceNameScopeLookup::this_and_parent);
781         if (symbol)
782         {
783             if (symbol->GetSymbolType() == SymbolType::namespaceSymbol)
784             {
785                 ContainerScope* symbolContainerScope = symbol->GetContainerScope();
786                 if (std::find(containerScopes.begin()containerScopes.end()symbolContainerScope) == containerScopes.end())
787                 {
788                     containerScopes.push_back(symbolContainerScope);
789                 }
790             }
791             else
792             {
793                 throw Exception("'" + ToUtf8(namespaceImportNode->Ns()->Str()) + "' does not denote a namespace"namespaceImportNode->Ns()->GetSpan()namespaceImportNode->Ns()->ModuleId());
794             }
795         }
796         else
797         {
798             throw Exception("referred namespace symbol '" + ToUtf8(namespaceImportNode->Ns()->Str()) + "' not found"namespaceImportNode->Ns()->GetSpan()namespaceImportNode->Ns()->ModuleId());
799         }
800     }
801     catch (const Exception&;)
802     {
803         throw ;
804     }
805 }
806 
807 Symbol* FileScope::Lookup(const std::u32string& name) const
808 {
809     return Lookup(nameScopeLookup::this_);
810 }
811 
812 Symbol* FileScope::Lookup(const std::u32string& nameScopeLookup lookup) const
813 {
814     if (lookup != ScopeLookup::this_)
815     {
816         throw std::runtime_error("file scope supports only this scope lookup");
817     }
818     std::unordered_set<Symbol*> foundSymbols;
819     auto it = aliasSymbolMap.find(name);
820     if (it != aliasSymbolMap.cend())
821     {
822         Symbol* symbol = it->second;
823         foundSymbols.insert(symbol);
824     }
825     else
826     {
827         for (ContainerScope* containerScope : containerScopes)
828         {
829             Symbol* symbol = containerScope->Lookup(nameScopeLookup::this_);
830             if (symbol)
831             {
832                 foundSymbols.insert(symbol);
833             }
834         }
835     }
836     if (foundSymbols.empty())
837     {
838         return nullptr;
839     }
840     else if (foundSymbols.size() > 1)
841     {
842         std::string message("reference to object '" + ToUtf8(name) + "' is ambiguous: ");
843         bool first = true;
844         Span span;
845         boost::uuids::uuid moduleId;
846         for (Symbol* symbol : foundSymbols)
847         {
848             if (first)
849             {
850                 first = false;
851                 span = symbol->GetSpan();
852                 moduleId = symbol->SourceModuleId();
853             }
854             else
855             {
856                 message.append(" or ");
857             }
858             message.append(ToUtf8(symbol->FullName()));
859         }
860         throw Exception(messagespanmoduleId);
861     }
862     else
863     {
864         return *foundSymbols.begin();
865     }
866 }
867 
868 std::std::vector<CCSymbolEntry>FileScope::LookupBeginWith(conststd::u32string&prefix) const
869 {
870     return LookupBeginWith(prefixScopeLookup::this_);
871 }
872 
873 std::std::vector<CCSymbolEntry>FileScope::LookupBeginWith(conststd::u32string&prefixScopeLookuplookup) const
874 {
875     std::vector<CCSymbolEntry> matches;
876     auto it = aliasSymbolMap.lower_bound(prefix);
877     if (it != aliasSymbolMap.cend())
878     {
879         while (it != aliasSymbolMap.cend() && StartsWith(it->firstprefix))
880         {
881             matches.push_back(CCSymbolEntry(it->secondprefix.length()it->second->Name()));
882             ++it;
883         }
884     }
885     for (ContainerScope* containerScope : containerScopes)
886     {
887         std::vector<CCSymbolEntry> m = containerScope->LookupBeginWith(prefixScopeLookup::this_);
888         AddMatches(matchesm);
889     }
890     return matches;
891 }
892 
893 void FileScope::CollectViableFunctions(int arityconst std::u32string&  groupNamestd::std::unordered_set<ContainerScope*>&scopesLookedUpViableFunctionSet&viableFunctions
894     Module* module)
895 {
896     for (ContainerScope* containerScope : containerScopes)
897     {
898         if (scopesLookedUp.find(containerScope) == scopesLookedUp.end())
899         {
900             containerScope->CollectViableFunctions(aritygroupNamescopesLookedUpScopeLookup::this_viableFunctionsmodule);
901             scopesLookedUp.insert(containerScope);
902         }
903     }
904 }
905 
906 } } // namespace cmajor::symbols