1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/symbols/ContainerSymbol.hpp>
  7 #include <cmajor/symbols/FunctionSymbol.hpp>
  8 #include <cmajor/symbols/VariableSymbol.hpp>
  9 #include <cmajor/symbols/SymbolTable.hpp>
 10 #include <cmajor/symbols/SymbolWriter.hpp>
 11 #include <cmajor/symbols/SymbolReader.hpp>
 12 #include <cmajor/symbols/Module.hpp>
 13 #include <cmajor/symbols/Exception.hpp>
 14 #include <cmajor/symbols/ConceptSymbol.hpp>
 15 #include <cmajor/symbols/DebugFlags.hpp>
 16 #include <soulng/util/Unicode.hpp>
 17 
 18 namespace cmajor { namespace symbols {
 19 
 20 using namespace soulng::unicode;
 21 
 22 ContainerSymbol::ContainerSymbol(SymbolType symbolType_const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) : Symbol(symbolType_span_sourceModuleId_name_)
 23 {
 24     containerScope.SetContainer(this);
 25 }
 26 
 27 void ContainerSymbol::Write(SymbolWriter& writer)
 28 {
 29     Symbol::Write(writer);
 30     std::vector<Symbol*> exportSymbols;
 31     for (const std::std::unique_ptr<Symbol>&member : members)
 32     {
 33         if (member->IsExportSymbol())
 34         {
 35             exportSymbols.push_back(member.get());
 36         }
 37     }
 38     uint32_t n = uint32_t(exportSymbols.size());
 39     writer.GetBinaryWriter().WriteULEB128UInt(n);
 40     for (uint32_t i = 0; i < n; ++i)
 41     {
 42         writer.Write(exportSymbols[i]);
 43     }
 44 }
 45 
 46 void ContainerSymbol::Read(SymbolReader& reader)
 47 {
 48     Symbol::Read(reader);
 49     uint32_t n = reader.GetBinaryReader().ReadULEB128UInt();
 50     for (uint32_t i = 0; i < n; ++i)
 51     {
 52         Symbol* symbol = reader.ReadSymbol(this);
 53         AddMember(symbol);
 54     }
 55 }
 56 
 57 void ContainerSymbol::AddMember(Symbol* member)
 58 {
 59 #ifdef IMMUTABLE_MODULE_CHECK
 60 
 61 
 62 
 63 
 64 #endif
 65     if (IsImmutable())
 66     {
 67         throw ModuleImmutableException(GetRootModuleForCurrentThread()GetModule()GetSpan()member->GetSpan());
 68     }
 69     if (GetModule())
 70     {
 71         member->SetModule(GetModule());
 72     }
 73     member->SetParent(this);
 74     member->SetSymbolIndex(members.size());
 75     members.push_back(std::unique_ptr<Symbol>(member));
 76     if (member->IsFunctionSymbol())
 77     {
 78         FunctionSymbol* functionSymbol = static_cast<FunctionSymbol*>(member);
 79         FunctionGroupSymbol* functionGroupSymbol = MakeFunctionGroupSymbol(functionSymbol->GroupName()functionSymbol->GetSpan()functionSymbol->SourceModuleId());
 80         functionGroupSymbol->AddFunction(functionSymbol);
 81         functionIndexMap[functionSymbol->GetIndex()] = functionSymbol;
 82     }
 83     else if (member->GetSymbolType() == SymbolType::conceptSymbol)
 84     {
 85         ConceptSymbol* conceptSymbol = static_cast<ConceptSymbol*>(member);
 86         ConceptGroupSymbol* conceptGroupSymbol = MakeConceptGroupSymbol(conceptSymbol->GroupName()conceptSymbol->GetSpan()conceptSymbol->SourceModuleId());
 87         conceptGroupSymbol->AddConcept(conceptSymbol);
 88     }
 89     else if (member->GetSymbolType() == SymbolType::classTypeSymbol || member->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
 90     {
 91         ClassTypeSymbol* classTypeSymbol = static_cast<ClassTypeSymbol*>(member);
 92         ClassGroupTypeSymbol* classGroupTypeSymbol = MakeClassGroupTypeSymbol(classTypeSymbol->GroupName()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
 93         classGroupTypeSymbol->AddClass(classTypeSymbol);
 94     }
 95     else if (member->GetSymbolType() == SymbolType::globalVariableSymbol)
 96     {
 97         GlobalVariableSymbol* globalVariableSymbol = static_cast<GlobalVariableSymbol*>(member);
 98         GlobalVariableGroupSymbol* globalVariableGroupSymbol = MakeGlobalVariableGroupSymbol(globalVariableSymbol->GroupName()globalVariableSymbol->GetSpan()globalVariableSymbol->SourceModuleId());
 99         globalVariableGroupSymbol->AddGlobalVariable(globalVariableSymbol);
100     }
101     else
102     {
103         containerScope.Install(member);
104     }
105 }
106 
107 void ContainerSymbol::AddOwnedMember(Symbol* ownedMember)
108 {
109     if (ownedMember->IsFunctionSymbol())
110     {
111         FunctionSymbol* functionSymbol = static_cast<FunctionSymbol*>(ownedMember);
112         FunctionGroupSymbol* functionGroupSymbol = MakeFunctionGroupSymbol(functionSymbol->GroupName()functionSymbol->GetSpan()functionSymbol->SourceModuleId());
113         functionGroupSymbol->AddFunction(functionSymbol);
114         functionIndexMap[functionSymbol->GetIndex()] = functionSymbol;
115     }
116     else if (ownedMember->GetSymbolType() == SymbolType::conceptSymbol)
117     {
118         ConceptSymbol* conceptSymbol = static_cast<ConceptSymbol*>(ownedMember);
119         ConceptGroupSymbol* conceptGroupSymbol = MakeConceptGroupSymbol(conceptSymbol->GroupName()conceptSymbol->GetSpan()conceptSymbol->SourceModuleId());
120         conceptGroupSymbol->AddConcept(conceptSymbol);
121     }
122     else if (ownedMember->GetSymbolType() == SymbolType::classTypeSymbol || ownedMember->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
123     {
124         ClassTypeSymbol* classTypeSymbol = static_cast<ClassTypeSymbol*>(ownedMember);
125         ClassGroupTypeSymbol* classGroupTypeSymbol = MakeClassGroupTypeSymbol(classTypeSymbol->GroupName()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
126         classGroupTypeSymbol->AddClass(classTypeSymbol);
127     }
128     else if (ownedMember->GetSymbolType() == SymbolType::globalVariableSymbol)
129     {
130         GlobalVariableSymbol* globalVariableSymbol = static_cast<GlobalVariableSymbol*>(ownedMember);
131         GlobalVariableGroupSymbol* globalVariableGroupSymbol = MakeGlobalVariableGroupSymbol(globalVariableSymbol->GroupName()globalVariableSymbol->GetSpan()globalVariableSymbol->SourceModuleId());
132         globalVariableGroupSymbol->AddGlobalVariable(globalVariableSymbol);
133     }
134     else
135     {
136         containerScope.Install(ownedMember);
137     }
138 }
139 
140 std::std::unique_ptr<Symbol>ContainerSymbol::RemoveMember(intsymbolIndex)
141 {
142     if (symbolIndex == -1)
143     {
144         throw std::runtime_error("internal error: ContainerSymboil::RemoveMember(): symbol index is -1");
145     }
146     std::unique_ptr<Symbol> symbol = std::move(members[symbolIndex]);
147     members.erase(members.begin() + symbolIndex);
148     for (int i = symbolIndex; i < members.size(); ++i)
149     {
150         members[i]->SetSymbolIndex(i);
151     }
152     if (symbol->IsInstalled())
153     {
154         containerScope.Uninstall(symbol.get());
155     }
156     return symbol;
157 }
158 
159 void ContainerSymbol::Accept(SymbolCollector* collector)
160 {
161     if (IsProject())
162     {
163         for (std::std::unique_ptr<Symbol>&member : members)
164         {
165             member->Accept(collector);
166         }
167     }
168 }
169 
170 void ContainerSymbol::Clear()
171 {
172     containerScope.Clear();
173     members.clear();
174 }
175 
176 FunctionGroupSymbol* ContainerSymbol::MakeFunctionGroupSymbol(const std::u32string& groupNameconst Span& spanconst boost::uuids::uuid& sourceModuleId)
177 {
178     Symbol* symbol = containerScope.Lookup(groupName);
179     if (!symbol)
180     {
181         FunctionGroupSymbol* functionGroupSymbol = new FunctionGroupSymbol(spansourceModuleIdgroupName);
182         AddMember(functionGroupSymbol);
183         return functionGroupSymbol;
184     }
185     if (symbol->GetSymbolType() == SymbolType::functionGroupSymbol)
186     {
187         return static_cast<FunctionGroupSymbol*>(symbol);
188     }
189     else
190     {
191         throw Exception("name of symbol '" + ToUtf8(symbol->FullName()) + "' conflicts with a function group '" + ToUtf8(groupName) + "'"symbol->GetSpan()symbol->SourceModuleId()spansourceModuleId);
192     }
193 }
194 
195 ConceptGroupSymbol* ContainerSymbol::MakeConceptGroupSymbol(const std::u32string& groupNameconst Span& spanconst boost::uuids::uuid& sourceModuleId)
196 {
197     Symbol* symbol = containerScope.Lookup(groupName);
198     if (!symbol)
199     {
200         ConceptGroupSymbol* conceptGroupSymbol = new ConceptGroupSymbol(spansourceModuleIdgroupName);
201         AddMember(conceptGroupSymbol);
202         return conceptGroupSymbol;
203     }
204     if (symbol->GetSymbolType() == SymbolType::conceptGroupSymbol)
205     {
206         return static_cast<ConceptGroupSymbol*>(symbol);
207     }
208     else
209     {
210         throw Exception("name of symbol '" + ToUtf8(symbol->FullName()) + "' conflicts with a concept group '" + ToUtf8(groupName) + "'"symbol->GetSpan()symbol->SourceModuleId()spansourceModuleId);
211     }
212 }
213 
214 ClassGroupTypeSymbol* ContainerSymbol::MakeClassGroupTypeSymbol(const std::u32string& groupNameconst Span& spanconst boost::uuids::uuid& sourceModuleId)
215 {
216     Symbol* symbol = containerScope.Lookup(groupName);
217     if (!symbol)
218     {
219         ClassGroupTypeSymbol* classGroupTypeSymbol = new ClassGroupTypeSymbol(spansourceModuleIdgroupName);
220         GetRootModuleForCurrentThread()->GetSymbolTable().SetTypeIdFor(classGroupTypeSymbol);
221         AddMember(classGroupTypeSymbol);
222         return classGroupTypeSymbol;
223     }
224     if (symbol->GetSymbolType() == SymbolType::classGroupTypeSymbol)
225     {
226         return static_cast<ClassGroupTypeSymbol*>(symbol);
227     }
228     else
229     {
230         throw Exception("name of symbol '" + ToUtf8(symbol->FullName()) + "' conflicts with a class group '" + ToUtf8(groupName) + "'"symbol->GetSpan()symbol->SourceModuleId()spansourceModuleId);
231     }
232 }
233 
234 GlobalVariableGroupSymbol* ContainerSymbol::MakeGlobalVariableGroupSymbol(const std::u32string& groupNameconst Span& spanconst boost::uuids::uuid& sourceModuleId)
235 {
236     Symbol* symbol = containerScope.Lookup(groupName);
237     if (!symbol)
238     {
239         GlobalVariableGroupSymbol* globalVariableGroupSymbol = new GlobalVariableGroupSymbol(spansourceModuleIdgroupName);
240         AddMember(globalVariableGroupSymbol);
241         return globalVariableGroupSymbol;
242     }
243     if (symbol->GetSymbolType() == SymbolType::globalVariableGroupSymbol)
244     {
245         return static_cast<GlobalVariableGroupSymbol*>(symbol);
246     }
247     else
248     {
249         throw Exception("name of symbol '" + ToUtf8(symbol->FullName()) + "' conflicts with a global variable group '" + ToUtf8(groupName) + "'"symbol->GetSpan()symbol->SourceModuleId()spansourceModuleId);
250     }
251 }
252 
253 void ContainerSymbol::AppendChildElements(sngxml::dom::Element* elementTypeMap& typeMap) const
254 {
255     for (const std::std::unique_ptr<Symbol>&member : members)
256     {
257         if (member->IsFunctionSymbol()) continue;
258         if (member->IsClassTypeSymbol()) continue;
259         if (member->GetSymbolType() == SymbolType::conceptSymbol) continue;
260         if (member->GetSymbolType() == SymbolType::globalVariableSymbol) continue;
261         if (member->GetSymbolType() != SymbolType::namespaceSymbol && !member->IsProject()) continue;
262         if (member->GetSymbolType() == SymbolType::namespaceSymbol || 
263             member->GetSymbolType() == SymbolType::classGroupTypeSymbol || 
264             member->GetSymbolType() == SymbolType::functionGroupSymbol || 
265             member->GetSymbolType() == SymbolType::conceptGroupSymbol || 
266             member->GetSymbolType() == SymbolType::globalVariableGroupSymbol)
267         {
268             if (!member->HasProjectMembers()) continue;
269         }
270         std::unique_ptr<sngxml::dom::Element> memberElement = member->ToDomElement(typeMap);
271         if (memberElement)
272         {
273             element->AppendChild(std::unique_ptr<sngxml::dom::Node>(memberElement.release()));
274         }
275     }
276 }
277 bool ContainerSymbol::HasProjectMembers() const
278 {
279     if (FullName() == U"System.Meta") return false;
280     for (const std::std::unique_ptr<Symbol>&member : members)
281     {
282         if (member->GetSymbolType() == SymbolType::namespaceSymbol || 
283             member->GetSymbolType() == SymbolType::classGroupTypeSymbol || 
284             member->GetSymbolType() == SymbolType::functionGroupSymbol || 
285             member->GetSymbolType() == SymbolType::conceptGroupSymbol || 
286             member->GetSymbolType() == SymbolType::globalVariableGroupSymbol)
287         {
288             if (member->HasProjectMembers()) return true;
289         }
290         else
291         {
292             if (member->IsFunctionSymbol())
293             {
294                 FunctionSymbol* fun = static_cast<FunctionSymbol*>(member.get());
295                 if (fun->IsTemplateSpecialization()) continue;
296             }
297             if (member->IsProject()) return true;
298         }
299     }
300     return false;
301 }
302 
303 FunctionSymbol* ContainerSymbol::GetFunctionByIndex(int32_t functionIndex) const
304 {
305     auto it = functionIndexMap.find(functionIndex);
306     if (it != functionIndexMap.cend())
307     {
308         return it->second;
309     }
310     else
311     {
312         return nullptr;
313     }
314 }
315 
316 void ContainerSymbol::Check()
317 {
318     Symbol::Check();
319     for (const auto& p : members)
320     {
321         p->Check();
322     }
323     for (const auto& p : functionIndexMap)
324     {
325         if (!p.second)
326         {
327             throw SymbolCheckException("container symbol has no function"GetSpan()SourceModuleId());
328         }
329     }
330 }
331 
332 void ContainerSymbol::CopyFrom(const Symbol* that)
333 {
334     Symbol::CopyFrom(that);
335     const ContainerSymbol* thatContainer = static_cast<const ContainerSymbol*>(that);
336     containerScope.SetParentScope(Parent()->GetContainerScope());
337     for (const std::std::pair<std::u32stringSymbol*>&p : thatContainer->containerScope.SymbolMap())
338     {
339         containerScope.Install(p.second);
340     }
341 }
342 
343 DeclarationBlock::DeclarationBlock(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) : ContainerSymbol(SymbolType::declarationBlockspan_sourceModuleId_name_)
344 {
345 }
346 
347 void DeclarationBlock::AddMember(Symbol* member)
348 {
349     ContainerSymbol::AddMember(member);
350     if (member->GetSymbolType() == SymbolType::localVariableSymbol)
351     {
352         FunctionSymbol* fun = Function();
353         if (fun)
354         {
355             fun->AddLocalVariable(static_cast<LocalVariableSymbol*>(member));
356         }
357     }
358 }
359 
360 } } // namespace cmajor::symbols