1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/symbols/ConceptSymbol.hpp>
  7 #include <cmajor/symbols/ModuleCache.hpp>
  8 #include <cmajor/symbols/Exception.hpp>
  9 #include <cmajor/symbols/SymbolWriter.hpp>
 10 #include <cmajor/symbols/SymbolReader.hpp>
 11 #include <cmajor/symbols/SymbolTable.hpp>
 12 #include <cmajor/symbols/SymbolCollector.hpp>
 13 #include <cmajor/symbols/Module.hpp>
 14 #include <soulng/util/Unicode.hpp>
 15 #include <boost/uuid/uuid_generators.hpp>
 16 #include <boost/uuid/uuid_io.hpp>
 17 
 18 namespace cmajor { namespace symbols {
 19 
 20 using namespace soulng::unicode;
 21 
 22 ConceptGroupSymbol::ConceptGroupSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) : Symbol(SymbolType::conceptGroupSymbolspan_sourceModuleId_name_)
 23 {
 24 }
 25 
 26 void ConceptGroupSymbol::AddConcept(ConceptSymbol* conceptSymbol)
 27 {
 28     Assert(conceptSymbol->GroupName() == Name()"wrong concept group");
 29     int arity = conceptSymbol->Arity();
 30     auto it = arityConceptMap.find(arity);
 31     if (it != arityConceptMap.cend())
 32     {
 33         throw Exception("concept group '" + ToUtf8(FullName()) + "' already has concept with arity " + std::to_string(arity)GetSpan()SourceModuleId());
 34     }
 35     arityConceptMap[arity] = conceptSymbol;
 36     conceptSymbol->SetConceptGroup(this);
 37 }
 38 
 39 void ConceptGroupSymbol::RemoveConcept(ConceptSymbol* conceptSymbol)
 40 {
 41     int arity = conceptSymbol->Arity();
 42     arityConceptMap.erase(arity);
 43 }
 44 
 45 bool ConceptGroupSymbol::IsEmpty() const
 46 {
 47     return arityConceptMap.empty();
 48 }
 49 
 50 ConceptSymbol* ConceptGroupSymbol::GetConcept(int arity)
 51 {
 52     auto it = arityConceptMap.find(arity);
 53     if (it != arityConceptMap.cend())
 54     {
 55         return it->second;
 56     }
 57     else
 58     {
 59         throw Exception("concept with arity " + std::to_string(arity) + " not found from concept group '" + ToUtf8(FullName()) + "'"GetSpan()SourceModuleId());
 60     }
 61 }
 62 
 63 bool ConceptGroupSymbol::HasProjectMembers() const
 64 {
 65     for (const auto& p : arityConceptMap)
 66     {
 67         ConceptSymbol* conceptSymbol = p.second;
 68         if (conceptSymbol->IsProject())
 69         {
 70             return true;
 71         }
 72     }
 73     return false;
 74 }
 75 
 76 void ConceptGroupSymbol::AppendChildElements(sngxml::dom::Element* elementTypeMap& typeMap) const
 77 {
 78     for (const auto& p : arityConceptMap)
 79     {
 80         ConceptSymbol* conceptSymbol = p.second;
 81         if (conceptSymbol->IsProject())
 82         {
 83             std::unique_ptr<sngxml::dom::Element> conceptElement = conceptSymbol->ToDomElement(typeMap);
 84             element->AppendChild(std::unique_ptr<sngxml::dom::Node>(conceptElement.release()));
 85         }
 86     }
 87 }
 88 
 89 void ConceptGroupSymbol::Check()
 90 {
 91     Symbol::Check();
 92     for (const auto& p : arityConceptMap)
 93     {
 94         if (!p.second)
 95         {
 96             throw SymbolCheckException("concept group symbol has no concept symbol"GetSpan()SourceModuleId());
 97         }
 98     }
 99 }
100 
101 std::string ConceptGroupSymbol::GetSymbolHelp() const
102 {
103     if (arityConceptMap.size() == 1)
104     {
105         ConceptSymbol* cs = arityConceptMap.begin()->second;
106         return cs->GetSymbolHelp();
107     }
108     std::string help = "(";
109     help.append(GetSymbolCategoryDescription()).append(") ");
110     help.append(ToUtf8(FullName())).append(" (").append(std::to_string(arityConceptMap.size())).append(" concepts)");
111     return help;
112 }
113 
114 ConceptSymbol::ConceptSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
115     ContainerSymbol(SymbolType::conceptSymbolspan_sourceModuleId_name_)refinedConcept(nullptr)typeId(boost::uuids::nil_uuid())hasSource(false)conceptGroup(nullptr)
116 {
117 }
118 
119 void ConceptSymbol::Write(SymbolWriter& writer)
120 {
121     ContainerSymbol::Write(writer);
122     Assert(!typeId.is_nil()"type id not initialized");
123     writer.GetBinaryWriter().Write(typeId);
124     writer.GetBinaryWriter().Write(groupName);
125     boost::uuids::uuid refineConceptId = boost::uuids::nil_uuid();
126     if (refinedConcept)
127     {
128         refineConceptId = refinedConcept->TypeId();
129     }
130     writer.GetBinaryWriter().Write(refineConceptId);
131     uint32_t n = templateParameters.size();
132     writer.GetBinaryWriter().WriteULEB128UInt(n);
133     for (uint32_t i = 0; i < n; ++i)
134     {
135         TemplateParameterSymbol* templateParameter = templateParameters[i];
136         Assert(!templateParameter->TypeId().is_nil()"type id not initialized");
137         writer.GetBinaryWriter().Write(templateParameter->TypeId());
138     }
139     Node* node = GetRootModuleForCurrentThread()->GetSymbolTable().GetNode(this);
140     Assert(node->IsConceptNode()"concept node expected");
141     writer.GetAstWriter().Write(node);
142     writer.GetBinaryWriter().Write(hasSource);
143 }
144 
145 void ConceptSymbol::Read(SymbolReader& reader)
146 {
147     ContainerSymbol::Read(reader);
148     reader.GetBinaryReader().ReadUuid(typeId);
149     reader.GetSymbolTable()->AddTypeOrConceptSymbolToTypeIdMap(this);
150     groupName = reader.GetBinaryReader().ReadUtf32String();
151     boost::uuids::uuid refinedConcepId;
152     reader.GetBinaryReader().ReadUuid(refinedConcepId);
153     if (!refinedConcepId.is_nil())
154     {
155         reader.GetSymbolTable()->EmplaceConceptRequest(readerthisrefinedConcepId);
156     }
157     uint32_t n = reader.GetBinaryReader().ReadULEB128UInt();
158     templateParameters.resize(n);
159     for (uint32_t i = 0; i < n; ++i)
160     {
161         boost::uuids::uuid templateParameterId;
162         reader.GetBinaryReader().ReadUuid(templateParameterId);
163         reader.GetSymbolTable()->EmplaceTypeRequest(readerthistemplateParameterIdi);
164     }
165     conceptNode.reset(reader.GetAstReader().ReadConceptNode());
166     hasSource = reader.GetBinaryReader().ReadBool();
167 }
168 
169 void ConceptSymbol::EmplaceConcept(ConceptSymbol* conceptSymbol)
170 {
171     refinedConcept = conceptSymbol;
172 }
173 
174 void ConceptSymbol::EmplaceType(TypeSymbol* typeSymbolint index)
175 {
176     if (index >= 0 && index < templateParameters.size())
177     {
178         if (typeSymbol->GetSymbolType() == SymbolType::templateParameterSymbol)
179         {
180             TemplateParameterSymbol* templateParameter = static_cast<TemplateParameterSymbol*>(typeSymbol);
181             templateParameters[index] = templateParameter;
182         }
183         else
184         {
185             throw Exception("invalid emplace type"GetSpan()SourceModuleId());
186         }
187     }
188     else
189     {
190         throw Exception("invalid emplace type index"GetSpan()SourceModuleId());
191     }
192 }
193 
194 void ConceptSymbol::Accept(SymbolCollector* collector)
195 {
196     if (IsProject() && Access() == SymbolAccess::public_)
197     {
198         collector->AddConcept(this);
199     }
200 }
201 
202 void ConceptSymbol::Dump(CodeFormatter& formatter)
203 {
204     formatter.WriteLine(ToUtf8(Name()));
205     formatter.WriteLine("group name: " + ToUtf8(groupName));
206     formatter.WriteLine("full name: " + ToUtf8(FullNameWithSpecifiers()));
207     formatter.WriteLine("mangled name: " + ToUtf8(MangledName()));
208     formatter.WriteLine("typeid: " + boost::uuids::to_string(typeId));
209     if (refinedConcept)
210     {
211         formatter.WriteLine("refined concept: " + ToUtf8(refinedConcept->FullName()));
212     }
213 }
214 
215 void ConceptSymbol::AddMember(Symbol* member)
216 {
217     ContainerSymbol::AddMember(member);
218     if (member->GetSymbolType() == SymbolType::templateParameterSymbol)
219     {
220         templateParameters.push_back(static_cast<TemplateParameterSymbol*>(member));
221     }
222 }
223 
224 void ConceptSymbol::ComputeName()
225 {
226     std::u32string name = groupName;
227     bool first = true;
228     name.append(1'<');
229     for (TemplateParameterSymbol* templateParameter : templateParameters)
230     {
231         if (first)
232         {
233             first = false;
234         }
235         else
236         {
237             name.append(U", ");
238         }
239         name.append(templateParameter->Name());
240     }
241     name.append(1'>');
242     SetName(name);
243     ComputeMangledName();
244 }
245 
246 void ConceptSymbol::SetSpecifiers(Specifiers specifiers)
247 {
248     Specifiers accessSpecifiers = specifiers & Specifiers::access_;
249     SetAccess(accessSpecifiers);
250     if ((specifiers & Specifiers::static_) != Specifiers::none)
251     {
252         throw Exception("concept symbol cannot be static"GetSpan()SourceModuleId());
253     }
254     if ((specifiers & Specifiers::virtual_) != Specifiers::none)
255     {
256         throw Exception("concept symbol cannot be virtual"GetSpan()SourceModuleId());
257     }
258     if ((specifiers & Specifiers::override_) != Specifiers::none)
259     {
260         throw Exception("concept symbol cannot be override"GetSpan()SourceModuleId());
261     }
262     if ((specifiers & Specifiers::abstract_) != Specifiers::none)
263     {
264         throw Exception("concept symbol cannot be abstract"GetSpan()SourceModuleId());
265     }
266     if ((specifiers & Specifiers::inline_) != Specifiers::none)
267     {
268         throw Exception("concept symbol cannot be inline"GetSpan()SourceModuleId());
269     }
270     if ((specifiers & Specifiers::explicit_) != Specifiers::none)
271     {
272         throw Exception("concept symbol cannot be explicit"GetSpan()SourceModuleId());
273     }
274     if ((specifiers & Specifiers::external_) != Specifiers::none)
275     {
276         throw Exception("concept symbol cannot be external"GetSpan()SourceModuleId());
277     }
278     if ((specifiers & Specifiers::suppress_) != Specifiers::none)
279     {
280         throw Exception("concept symbol cannot be suppressed"GetSpan()SourceModuleId());
281     }
282     if ((specifiers & Specifiers::default_) != Specifiers::none)
283     {
284         throw Exception("concept symbol cannot be default"GetSpan()SourceModuleId());
285     }
286     if ((specifiers & Specifiers::constexpr_) != Specifiers::none)
287     {
288         throw Exception("concept symbol cannot be constexpr"GetSpan()SourceModuleId());
289     }
290     if ((specifiers & Specifiers::cdecl_) != Specifiers::none)
291     {
292         throw Exception("concept symbol cannot be decl"GetSpan()SourceModuleId());
293     }
294     if ((specifiers & Specifiers::nothrow_) != Specifiers::none)
295     {
296         throw Exception("concept symbol cannot be nothrow"GetSpan()SourceModuleId());
297     }
298     if ((specifiers & Specifiers::throw_) != Specifiers::none)
299     {
300         throw Exception("concept symbol cannot be throw"GetSpan()SourceModuleId());
301     }
302     if ((specifiers & Specifiers::new_) != Specifiers::none)
303     {
304         throw Exception("concept symbol cannot be new"GetSpan()SourceModuleId());
305     }
306     if ((specifiers & Specifiers::const_) != Specifiers::none)
307     {
308         throw Exception("concept symbol cannot be const"GetSpan()SourceModuleId());
309     }
310     if ((specifiers & Specifiers::unit_test_) != Specifiers::none)
311     {
312         throw Exception("concept symbol cannot be unit_test"GetSpan()SourceModuleId());
313     }
314 }
315 
316 void ConceptSymbol::Check()
317 {
318     ContainerSymbol::Check();
319     if (typeId.is_nil())
320     {
321         throw SymbolCheckException("concept symbol has empty type id"GetSpan()SourceModuleId());
322     }
323     if (groupName.empty())
324     {
325         throw SymbolCheckException("concept symbol has empty group name"GetSpan()SourceModuleId());
326     }
327     for (TemplateParameterSymbol* templateParameter : templateParameters)
328     {
329         if (!templateParameter)
330         {
331             throw SymbolCheckException("concept symbol has no template parameter"GetSpan()SourceModuleId());
332         }
333     }
334 }
335 
336 std::std::unique_ptr<Symbol>ConceptSymbol::RemoveFromParent()
337 {
338     std::unique_ptr<Symbol> symbol = ContainerSymbol::RemoveFromParent();
339     if (conceptGroup)
340     {
341         conceptGroup->RemoveConcept(this);
342         if (conceptGroup->IsEmpty())
343         {
344             std::unique_ptr<Symbol> conceptGroupSymbol = conceptGroup->RemoveFromParent();
345         }
346     }
347     return symbol;
348 }
349 
350 AxiomSymbol::AxiomSymbol(const Span& span_const boost::uuids::uuid& sourceModuleIdconst std::u32string& name_) :
351     ContainerSymbol(SymbolType::axiomSymbolspan_sourceModuleIdname_)
352 {
353 }
354 
355 } } // namespace cmajor::symbols