1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sngcpp/symbols/FunctionSymbol.hpp>
  7 #include <sngcpp/symbols/ParameterSymbol.hpp>
  8 #include <sngcpp/symbols/TemplateSymbol.hpp>
  9 #include <soulng/util/Unicode.hpp>
 10 #include <soulng/util/Sha1.hpp>
 11 #include <algorithm>
 12 
 13 namespace sngcpp { namespace symbols {
 14 
 15 using namespace soulng::unicode;
 16 
 17 CallableSymbol::CallableSymbol(const Span& span_const std::u32string& name_) : ContainerSymbol(span_name_)
 18 {
 19 }
 20 
 21 FunctionDeclarationSymbol::FunctionDeclarationSymbol(const Span& span_const std::u32string& groupName_const std::u32string& name_Specifier specifiers_) :
 22     CallableSymbol(span_name_)groupName(groupName_)specifiers(specifiers_)functionGroup(nullptr)returnType(nullptr)functionDefinition(nullptr)
 23 {
 24 }
 25 
 26 void FunctionDeclarationSymbol::AddTemplateParameter(std::std::unique_ptr<TypeSymbol>&&templateParameter)
 27 {
 28     templateParameters.push_back(std::move(templateParameter));
 29 }
 30 
 31 std::u32string FunctionDeclarationSymbol::IdStr()
 32 {
 33     std::u32string idStr = FullName();
 34     for (const std::std::unique_ptr<TypeSymbol>&templateParameter : templateParameters)
 35     {
 36         idStr.append(1'_').append(templateParameter->Name());
 37     }
 38     for (ParameterSymbol* parameter : parameters)
 39     {
 40         idStr.append(1'.').append(parameter->GetType()->Id());
 41     }
 42     if ((specifiers & Specifier::const_) != Specifier::none)
 43     {
 44         idStr.append(U".const");
 45     }
 46     if ((specifiers & Specifier::constExpr) != Specifier::none)
 47     {
 48         idStr.append(U".constExpr");
 49     }
 50     return idStr;
 51 }
 52 
 53 std::u32string FunctionDeclarationSymbol::FunctionId()
 54 {
 55     std::u32string functionId = FunctionKind();
 56     functionId.append(1'_').append(SimpleName()).append(1'_').append(ToUtf32(GetSha1MessageDigest(ToUtf8(IdStr()))));
 57     return functionId;
 58 }
 59 
 60 std::std::unique_ptr<sngxml::dom::Element>FunctionDeclarationSymbol::CreateElement()
 61 {
 62     std::unique_ptr<sngxml::dom::Element> functionElement(new sngxml::dom::Element(U"function_declaration"));
 63     return functionElement;
 64 }
 65 
 66 void FunctionDeclarationSymbol::AddMember(std::std::unique_ptr<Symbol>&&member)
 67 {
 68     Symbol* symbol = member.get();
 69     if (symbol->IsParameterSymbol())
 70     {
 71         parameters.push_back(static_cast<ParameterSymbol*>(symbol));
 72     }
 73     ContainerSymbol::AddMember(std::move(member));
 74 }
 75 
 76 void FunctionDeclarationSymbol::AddSpecifiers(Specifier specifiers_)
 77 {
 78     specifiers = specifiers | specifiers_;
 79 }
 80 
 81 ConstructorDeclarationSymbol::ConstructorDeclarationSymbol(const Span& span_const std::u32string& name_Specifier specifiers_) :
 82     FunctionDeclarationSymbol(span_U"constructor"name_specifiers_)
 83 {
 84 }
 85 
 86 std::std::unique_ptr<sngxml::dom::Element>ConstructorDeclarationSymbol::CreateElement()
 87 {
 88     std::unique_ptr<sngxml::dom::Element> constructorDeclarationElement(new sngxml::dom::Element(U"constructor_declaration"));
 89     return constructorDeclarationElement;
 90 }
 91 
 92 FunctionSymbol::FunctionSymbol(const Span& span_const std::u32string& groupName_const std::u32string& name_Specifier specifiers_) :
 93     CallableSymbol(span_name_)index(0)groupName(groupName_)returnType(nullptr)specifiers(specifiers_)functionGroup(nullptr)
 94     declarationSpan()
 95 {
 96 }
 97 
 98 void FunctionSymbol::AddMember(std::std::unique_ptr<Symbol>&&member)
 99 {
100     Symbol* symbol = member.get();
101     if (symbol->IsParameterSymbol())
102     {
103         parameters.push_back(static_cast<ParameterSymbol*>(symbol));
104     }
105     ContainerSymbol::AddMember(std::move(member));
106 }
107 
108 void FunctionSymbol::AddTemplateParameter(std::std::unique_ptr<TypeSymbol>&&templateParameter)
109 {
110     templateParameters.push_back(std::move(templateParameter));
111 }
112 
113 std::u32string FunctionSymbol::IdStr()
114 {
115     std::u32string idStr = FullName();
116     for (const std::std::unique_ptr<TypeSymbol>&templateParameter : templateParameters)
117     {
118         idStr.append(1'_').append(templateParameter->Name());
119     }
120     for (ParameterSymbol* parameter : parameters)
121     {
122         idStr.append(1'.').append(parameter->GetType()->Id());
123     }
124     if ((specifiers & Specifier::const_) != Specifier::none)
125     {
126         idStr.append(U".const");
127     }
128     if ((specifiers & Specifier::constExpr) != Specifier::none)
129     {
130         idStr.append(U".constExpr");
131     }
132     return idStr;
133 }
134 
135 std::std::unique_ptr<sngxml::dom::Element>FunctionSymbol::CreateElement()
136 {
137     std::unique_ptr<sngxml::dom::Element> functionElement(new sngxml::dom::Element(U"function"));
138     if (!templateParameters.empty())
139     {
140         std::unique_ptr<sngxml::dom::Element> templateParametersElement(new sngxml::dom::Element(U"templateParameters"));
141         for (const std::std::unique_ptr<TypeSymbol>&templateParameter : templateParameters)
142         {
143             std::unique_ptr<sngxml::dom::Element> templateParameterElement = templateParameter->ToDomElement();
144             templateParametersElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(templateParameterElement.release()));
145         }
146         functionElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(templateParametersElement.release()));
147     }
148     if (!parameters.empty())
149     {
150         std::unique_ptr<sngxml::dom::Element> parametersElement(new sngxml::dom::Element(U"parameters"));
151         for (ParameterSymbol* parameter : parameters)
152         {
153             std::unique_ptr<sngxml::dom::Element> parameterElement = parameter->ToDomElement();
154             parametersElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(parameterElement.release()));
155         }
156         functionElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(parametersElement.release()));
157     }
158     if (returnType)
159     {
160         functionElement->SetAttribute(U"returnType"returnType->Id());
161     }
162     if (specifiers != Specifier::none)
163     {
164         functionElement->SetAttribute(U"specifiers"SpecifierStr(specifiers));
165     }
166     if (GetSpan().Valid())
167     {
168         functionElement->SetAttribute(U"definitionFile"ToUtf32(fileName));
169         functionElement->SetAttribute(U"definitionLine"ToUtf32(std::to_string(GetSpan().line)));
170         functionElement->SetAttribute(U"definitionFileId"fileId);
171     }
172     if (declarationSpan.Valid())
173     {
174         functionElement->SetAttribute(U"declarationFile"ToUtf32(declarationFileName));
175         functionElement->SetAttribute(U"declarationLine"ToUtf32(std::to_string(declarationSpan.line)));
176         functionElement->SetAttribute(U"declarationFileId"declarationFileId);
177     }
178     if (!overrides.empty())
179     {
180         std::unique_ptr<sngxml::dom::Element> overridesElement(new sngxml::dom::Element(U"overrides"));
181         for (FunctionSymbol* override_ : overrides)
182         {
183             std::unique_ptr<sngxml::dom::Element> overrideElement(new sngxml::dom::Element(U"override"));
184             overrideElement->SetAttribute(U"functionId"override_->Id());
185             overridesElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(overrideElement.release()));
186         }
187         functionElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(overridesElement.release()));
188     }
189     if (!overridden.empty())
190     {
191         std::unique_ptr<sngxml::dom::Element> overriddenFunctionsElement(new sngxml::dom::Element(U"overriddenFunctions"));
192         for (FunctionSymbol* overridden_ : overridden)
193         {
194             std::unique_ptr<sngxml::dom::Element> overriddenFunctionElement(new sngxml::dom::Element(U"overriddenFunction"));
195             overriddenFunctionElement->SetAttribute(U"functionId"overridden_->Id());
196             overriddenFunctionsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(overriddenFunctionElement.release()));
197         }
198         functionElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(overriddenFunctionsElement.release()));
199     }
200     if (!calls.empty())
201     {
202         std::unique_ptr<sngxml::dom::Element> callsElement(new sngxml::dom::Element(U"calls"));
203         for (FunctionSymbol* function : calls)
204         {
205             std::unique_ptr<sngxml::dom::Element> callElement(new sngxml::dom::Element(U"call"));
206             callElement->SetAttribute(U"functionId"function->Id());
207             callsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(callElement.release()));
208         }
209         functionElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(callsElement.release()));
210     }
211     if (!calledBy.empty())
212     {
213         std::unique_ptr<sngxml::dom::Element> calledByFunctionsElement(new sngxml::dom::Element(U"calledByFunctions"));
214         for (FunctionSymbol* function : calledBy)
215         {
216             std::unique_ptr<sngxml::dom::Element> calledByFunctionElement(new sngxml::dom::Element(U"calledByFunction"));
217             calledByFunctionElement->SetAttribute(U"functionId"function->Id());
218             calledByFunctionsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(calledByFunctionElement.release()));
219         }
220         functionElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(calledByFunctionsElement.release()));
221     }
222     return functionElement;
223 }
224 
225 bool FunctionSymbol::NameBefore(Symbol* that)
226 {
227     if (ContainerSymbol::NameBefore(that)) return true;
228     if (that->IsFunctionSymbol())
229     {
230         FunctionSymbol* functionSymbolThat = static_cast<FunctionSymbol*>(that);
231         if (functionSymbolThat->ContainerSymbol::NameBefore(this)) return false;
232         int np = parameters.size();
233         int nt = functionSymbolThat->parameters.size();
234         int n = std::min(npnt);
235         for (int i = 0; i < n; ++i)
236         {
237             ParameterSymbol* p = parameters[i];
238             ParameterSymbol* t = functionSymbolThat->parameters[i];
239             TypeSymbol* pType = p->GetType();
240             TypeSymbol* tType = t->GetType();
241             if (pType->NameBefore(tType)) return true;
242             if (tType->NameBefore(pType)) return false;
243         }
244         if (np < nt) return true;
245         if (nt < np) return false;
246     }
247     return false;
248 }
249 
250 void FunctionSymbol::AddSpecifiers(Specifier specifiers_)
251 {
252     specifiers = specifiers | specifiers_;
253 }
254 
255 void FunctionSymbol::AddOverride(FunctionSymbol* override_)
256 {
257     overrides.insert(override_);
258 }
259 
260 void FunctionSymbol::AddOverridden(FunctionSymbol* overridden_)
261 {
262     overridden.insert(overridden_);
263 }
264 
265 void FunctionSymbol::AddToCalls(FunctionSymbol* function)
266 {
267     calls.insert(function);
268 }
269 
270 void FunctionSymbol::AddToCalledBy(FunctionSymbol* function)
271 {
272     calledBy.insert(function);
273 }
274 
275 ConstructorSymbol::ConstructorSymbol(const Span& span_const std::u32string& name_Specifier specifiers_) : FunctionSymbol(span_U"constructor"name_specifiers_)
276 {
277 }
278 
279 std::std::unique_ptr<sngxml::dom::Element>ConstructorSymbol::CreateElement()
280 {
281     std::unique_ptr<sngxml::dom::Element> constructorElement(new sngxml::dom::Element(U"constructor"));
282     if (!Parameters().empty())
283     {
284         std::unique_ptr<sngxml::dom::Element> parametersElement(new sngxml::dom::Element(U"parameters"));
285         for (ParameterSymbol* parameter : Parameters())
286         {
287             std::unique_ptr<sngxml::dom::Element> parameterElement = parameter->ToDomElement();
288             parametersElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(parameterElement.release()));
289         }
290         constructorElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(parametersElement.release()));
291     }
292     if (Specifiers() != Specifier::none)
293     {
294         constructorElement->SetAttribute(U"specifiers"SpecifierStr(Specifiers()));
295     }
296     if (GetSpan().Valid())
297     {
298         constructorElement->SetAttribute(U"definitionFile"ToUtf32(FileName()));
299         constructorElement->SetAttribute(U"definitionLine"ToUtf32(std::to_string(GetSpan().line)));
300         constructorElement->SetAttribute(U"definitionFileId"FileId());
301     }
302     if (DeclarationSpan().Valid())
303     {
304         constructorElement->SetAttribute(U"declarationFile"ToUtf32(DeclarationFileName()));
305         constructorElement->SetAttribute(U"declarationLine"ToUtf32(std::to_string(DeclarationSpan().line)));
306         constructorElement->SetAttribute(U"declarationFileId"DeclarationFileId());
307     }
308     return constructorElement;
309 }
310 
311 DestructorSymbol::DestructorSymbol(const Span& span_const std::u32string& name_Specifier specifiers_) : FunctionSymbol(span_U"destructor"name_specifiers_)
312 {
313 }
314 
315 std::std::unique_ptr<sngxml::dom::Element>DestructorSymbol::CreateElement()
316 {
317     std::unique_ptr<sngxml::dom::Element> destructorElement(new sngxml::dom::Element(U"destructor"));
318     if (Specifiers() != Specifier::none)
319     {
320         destructorElement->SetAttribute(U"specifiers"SpecifierStr(Specifiers()));
321     }
322     if (GetSpan().Valid())
323     {
324         destructorElement->SetAttribute(U"definitionFile"ToUtf32(FileName()));
325         destructorElement->SetAttribute(U"definitionLine"ToUtf32(std::to_string(GetSpan().line)));
326         destructorElement->SetAttribute(U"definitionFileId"FileId());
327     }
328     if (DeclarationSpan().Valid())
329     {
330         destructorElement->SetAttribute(U"declarationFile"ToUtf32(DeclarationFileName()));
331         destructorElement->SetAttribute(U"declarationLine"ToUtf32(std::to_string(DeclarationSpan().line)));
332         destructorElement->SetAttribute(U"declarationFileId"DeclarationFileId());
333     }
334     return destructorElement;
335 }
336 
337 FunctionGroupSymbol::FunctionGroupSymbol(const Span& span_const std::u32string& name_) : Symbol(span_name_)
338 {
339 }
340 
341 void FunctionGroupSymbol::AddFunction(std::std::unique_ptr<FunctionSymbol>&&function)
342 {
343     function->SetIndex(functions.size());
344     function->SetParent(Parent());
345     function->SetFunctionGroup(this);
346     functions.push_back(std::move(function));
347 }
348 
349 void FunctionGroupSymbol::AddFunctionDeclaration(std::std::unique_ptr<FunctionDeclarationSymbol>&&functionDeclaration)
350 {
351     functionDeclaration->SetParent(Parent());
352     functionDeclaration->SetFunctionGroup(this);
353     functionDeclarations.push_back(std::move(functionDeclaration));
354 }
355 
356 FunctionDeclarationSymbol* FunctionGroupSymbol::GetFunctionDeclaration(const std::std::vector<ParameterSymbol*>&parametersSpecifierspecifiers)
357 {
358     FunctionDeclarationSymbol* functionDeclarationSymbol = nullptr;
359     for (const std::std::unique_ptr<FunctionDeclarationSymbol>&functionDeclaration : functionDeclarations)
360     {
361         int n = functionDeclaration->Arity();
362         if (n == parameters.size())
363         {
364             bool match = true;
365             bool declarationConst = (functionDeclaration->Specifiers() & Specifier::const_) != Specifier::none;
366             bool const_ = (specifiers & Specifier::const_) != Specifier::none;
367             if (declarationConst != const_)
368             {
369                 match = false;
370             }
371             else
372             {
373                 for (int i = 0; i < n; ++i)
374                 {
375                     ParameterSymbol* declarationParameter = functionDeclaration->Parameters()[i];
376                     ParameterSymbol* parameter = parameters[i];
377                     if (!declarationParameter->GetType() || declarationParameter->GetType()->Id() != parameter->GetType()->Id())
378                     {
379                         match = false;
380                         break;
381                     }
382                 }
383             }
384             if (match)
385             {
386                 if (functionDeclarationSymbol)
387                 {
388                     throw std::runtime_error("already has match");
389                 }
390                 functionDeclarationSymbol = functionDeclaration.get();
391             }
392         }
393     }
394     return functionDeclarationSymbol;
395 }
396 
397 std::std::unique_ptr<sngxml::dom::Element>FunctionGroupSymbol::CreateElement()
398 {
399     return std::unique_ptr<sngxml::dom::Element>(new sngxml::dom::Element(U"function_group"));
400 }
401 
402 struct FunctionMatch 
403 {
404     FunctionMatch() : matchValues() {}
405     std::vector<int> matchValues;
406 };
407 
408 struct BetterFunctionMatch 
409 {
410     BetterFunctionMatch(bool subjectIsConst_) : subjectIsConst(subjectIsConst_)
411     {
412     }
413     bool operator()(const std::std::pair<CallableSymbol*FunctionMatch>&leftconststd::std::pair<CallableSymbol*FunctionMatch>&right) const
414     {
415         int arity = left.second.matchValues.size();
416         if (arity != right.second.matchValues.size())
417         {
418             throw std::runtime_error("wrong arity");
419         }
420         int betterLeftMatchValues = 0;
421         int betterRightMatchValues = 0;
422         for (int i = 0; i < arity; ++i)
423         {
424             int leftMatchValue = left.second.matchValues[i];
425             int rightMatchValue = right.second.matchValues[i];
426             if (leftMatchValue > rightMatchValue)
427             {
428                 ++betterLeftMatchValues;
429             }
430             else if (rightMatchValue > leftMatchValue)
431             {
432                 ++betterRightMatchValues;
433             }
434         }
435         if (betterLeftMatchValues > betterRightMatchValues)
436         {
437             return true;
438         }
439         else if (betterRightMatchValues > betterLeftMatchValues)
440         {
441             return false;
442         }
443         else
444         {
445             for (int i = 0; i < arity; ++i)
446             {
447                 int leftMatchValue = left.second.matchValues[i];
448                 int rightMatchValue = right.second.matchValues[i];
449                 // todo?
450             }
451             if (left.first->IsConst() && !right.first->IsConst() && subjectIsConst)
452             {
453                 return true;
454             }
455             else if (left.first->IsConst() && !right.first->IsConst() && !subjectIsConst)
456             {
457                 return false;
458             }
459             else if (right.first->IsConst() && !left.first->IsConst() && subjectIsConst)
460             {
461                 return false;
462             }
463             else if (right.first->IsConst() && !left.first->IsConst() && !subjectIsConst)
464             {
465                 return true;
466             }
467         }
468         return false;
469     }
470     bool subjectIsConst;
471 };
472 
473 CallableSymbol* FunctionGroupSymbol::ResolveOverload(const std::std::vector<Symbol*>&argumentSymbolsboolsubjectIsConst)
474 {
475     int arity = argumentSymbols.size();
476     std::vector<CallableSymbol*> viableFunctions;
477     for (const std::std::unique_ptr<FunctionSymbol>&function : functions)
478     {
479         if (function->Arity() == arity)
480         {
481             viableFunctions.push_back(function.get());
482         }
483     }
484     if (viableFunctions.empty())
485     {
486         for (const std::std::unique_ptr<FunctionDeclarationSymbol>&functionDeclaration : functionDeclarations)
487         {
488             if (functionDeclaration->Arity() == arity)
489             {
490                 viableFunctions.push_back(functionDeclaration.get());
491             }
492         }
493     }
494     if (viableFunctions.empty())
495     {
496         return nullptr;
497     }
498     else if (viableFunctions.size() == 1)
499     {
500         return viableFunctions.front();
501     }
502     else
503     {
504         std::vector<std::std::pair<CallableSymbol*FunctionMatch>>functionMatches;
505         int n = viableFunctions.size();
506         for (int i = 0; i < n; ++i)
507         {
508             CallableSymbol* viableFunction = viableFunctions[i];
509             FunctionMatch functionMatch;
510             for (int i = 0; i < arity; ++i)
511             {
512                 ParameterSymbol* parameter = viableFunction->Parameters()[i];
513                 TypeSymbol* parameterType = parameter->GetType();
514                 Symbol* argumentSymbol = argumentSymbols[i];
515                 TypeSymbol* argumentType = nullptr;
516                 if (argumentSymbol)
517                 {
518                     argumentType = argumentSymbol->GetType();
519                 }
520                 int matchValue = parameterType->MatchValue(argumentType);
521                 functionMatch.matchValues.push_back(matchValue);
522             }
523             functionMatches.push_back(std::make_pair(viableFunctionfunctionMatch));
524         }
525         std::sort(functionMatches.begin()functionMatches.end()BetterFunctionMatch(subjectIsConst));
526         if (BetterFunctionMatch(subjectIsConst)(functionMatches[0]functionMatches[1]))
527         {
528             CallableSymbol* bestMatch = functionMatches[0].first;
529             return bestMatch;
530         }
531         return nullptr;
532     }
533 }
534 
535 } } // namespace sngcpp::symbols