1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/binder/JsonAttributeProcessor.hpp>
  7 #include <cmajor/binder/StatementBinder.hpp>
  8 #include <cmajor/binder/TypeBinder.hpp>
  9 #include <cmajor/binder/BoundNode.hpp>
 10 #include <cmajor/binder/BoundStatement.hpp>
 11 #include <cmajor/binder/BoundFunction.hpp>
 12 #include <cmajor/binder/BoundClass.hpp>
 13 #include <cmajor/binder/TypeResolver.hpp>
 14 #include <cmajor/symbols/Exception.hpp>
 15 #include <cmajor/symbols/ClassTypeSymbol.hpp>
 16 #include <cmajor/symbols/SymbolTable.hpp>
 17 #include <cmajor/symbols/Warning.hpp>
 18 #include <cmajor/symbols/SymbolCreatorVisitor.hpp>
 19 #include <cmajor/symbols/Module.hpp>
 20 #include <sngcm/ast/Expression.hpp>
 21 #include <sngcm/ast/Identifier.hpp>
 22 #include <sngcm/ast/Literal.hpp>
 23 #include <soulng/util/Unicode.hpp>
 24 
 25 namespace cmajor { namespace binder {
 26 
 27 using namespace soulng::unicode;
 28 using namespace cmajor::symbols;
 29 
 30 JsonAttributeProcessor::JsonAttributeProcessor(Module* module_) : AttributeProcessor(U"json")module(module_)
 31 {
 32 }
 33 
 34 void JsonAttributeProcessor::TypeCheck(AttributeNode* attributeSymbol* symbol)
 35 {
 36     switch (symbol->GetSymbolType())
 37     {
 38         case SymbolType::classTypeSymbol: case SymbolType::classTemplateSpecializationSymbol: case SymbolType::memberVariableSymbol:
 39         {
 40             if (attribute->Value() == U"true" || attribute->Value() == U"false")
 41             {
 42                 if (symbol->IsClassTypeSymbol())
 43                 {
 44                     ClassTypeSymbol* classTypeSymbol = static_cast<ClassTypeSymbol*>(symbol);
 45                     ClassTypeSymbol* baseClass = classTypeSymbol->BaseClass();
 46                     if (baseClass)
 47                     {
 48                         bool baseClassHasJsonAttribute = false;
 49                         AttributesNode* baseClassAttributes = baseClass->GetAttributes();
 50                         if (baseClassAttributes)
 51                         {
 52                             AttributeNode* jsonAttribute = baseClassAttributes->GetAttribute(U"json");
 53                             if (jsonAttribute)
 54                             {
 55                                 baseClassHasJsonAttribute = true;
 56                             }
 57                         }
 58                         if (!baseClassHasJsonAttribute)
 59                         {
 60                             Warning warning(module->GetCurrentProjectName()"base class '" + ToUtf8(baseClass->FullName()) + "' of json-attributed class '" + 
 61                                 ToUtf8(classTypeSymbol->FullName()) + "' does not explicitly declare 'json' attribute value to \"true\" or \"false\"");
 62                             warning.SetDefined(classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
 63                             std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
 64                             references.push_back(std::make_pair(baseClass->GetSpan()baseClass->SourceModuleId()));
 65                             warning.SetReferences(references);
 66                             module->WarningCollection().AddWarning(warning);
 67                         }
 68                     }
 69                 }
 70                 return;
 71             }
 72             else
 73             {
 74                 throw Exception("unknown attribute value '" + ToUtf8(attribute->Value()) + "' for attribute '" + ToUtf8(attribute->Name()) + "'"attribute->GetSpan()attribute->ModuleId());
 75             }
 76         }
 77     }
 78     AttributeProcessor::TypeCheck(attributesymbol);
 79 }
 80 
 81 void JsonAttributeProcessor::GenerateSymbols(AttributeNode* attributeSymbol* symbolBoundCompileUnit& boundCompileUnitContainerScope* containerScope)
 82 {
 83     if (symbol->IsClassTypeSymbol())
 84     {
 85         ClassTypeSymbol* classTypeSymbol = static_cast<ClassTypeSymbol*>(symbol);
 86         if (attribute->Value() == U"true")
 87         {
 88             GenerateMemberVariableJsonFieldNames(classTypeSymbol);
 89             std::map<std::u32stringAttributeNode*> memberVariableFieldNames;
 90             CheckMemberVariableJsonFieldNames(classTypeSymbolmemberVariableFieldNames);
 91             GenerateJsonCreatorFunctionSymbol(attributeclassTypeSymbol);
 92             GenerateJsonConstructorSymbol(attributeclassTypeSymbol);
 93             GenerateToJsonJsonObjectSymbol(attributeclassTypeSymbol);
 94             GenerateToJsonSymbol(attributeclassTypeSymbolboundCompileUnitcontainerScope);
 95         }
 96     }
 97 }
 98 
 99 void JsonAttributeProcessor::CheckMemberVariableJsonFieldNames(ClassTypeSymbol* classTypeSymbolstd::std::map<std::u32stringAttributeNode*>&memberVariableFieldNames)
100 {
101     if (classTypeSymbol->BaseClass())
102     {
103         AttributesNode* attributes = classTypeSymbol->BaseClass()->GetAttributes();
104         AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
105         if (jsonAttribute && jsonAttribute->Value() != U"false")
106         {
107             CheckMemberVariableJsonFieldNames(classTypeSymbol->BaseClass()memberVariableFieldNames);
108         }
109     }
110     for (MemberVariableSymbol* memberVariableSymbol : classTypeSymbol->MemberVariables())
111     {
112         AttributesNode* attributes = memberVariableSymbol->GetAttributes();
113         if (attributes)
114         {
115             AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
116             if (jsonAttribute)
117             {
118                 if (jsonAttribute->Value() == U"false")
119                 {
120                     continue;
121                 }
122             }
123             AttributeNode* jsonFieldNameAttribute = attributes->GetAttribute(U"jsonFieldName");
124             if (jsonFieldNameAttribute)
125             {
126                 auto it = memberVariableFieldNames.find(jsonFieldNameAttribute->Value());
127                 if (it != memberVariableFieldNames.cend())
128                 {
129                     AttributeNode* prev = it->second;
130                     throw Exception("error in JSON field name generation: 'jsonFieldName' attribute not unique among member variable names of the current class and its base classes"
131                         jsonFieldNameAttribute->GetSpan()jsonFieldNameAttribute->ModuleId()prev->GetSpan()prev->ModuleId());
132                 }
133                 memberVariableFieldNames[jsonFieldNameAttribute->Value()] = jsonFieldNameAttribute;
134             }
135             else
136             {
137                 throw Exception("internal error in JSON field name generation: 'jsonFieldName' attribute not found"memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId());
138             }
139         }
140         else
141         {
142             throw Exception("internal error in JSON field name generation: attributes not found"memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId());
143         }
144     }
145 }
146 
147 void JsonAttributeProcessor::GenerateMemberVariableJsonFieldNames(ClassTypeSymbol* classTypeSymbol)
148 {
149     for (MemberVariableSymbol* memberVariableSymbol : classTypeSymbol->MemberVariables())
150     {
151         bool hasJsonFieldAttribute = false;
152         AttributesNode* attributes = memberVariableSymbol->GetAttributes();
153         if (attributes)
154         {
155             AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
156             if (jsonAttribute)
157             {
158                 if (jsonAttribute->Value() == U"false")
159                 {
160                     continue;
161                 }
162             }
163             AttributeNode* jsonFieldNameAttribute = attributes->GetAttribute(U"jsonFieldName");
164             if (jsonFieldNameAttribute)
165             {
166                 hasJsonFieldAttribute = true;
167             }
168         }
169         else
170         {
171             memberVariableSymbol->SetAttributes(std::unique_ptr<AttributesNode>(new AttributesNode(classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId())));
172             attributes = memberVariableSymbol->GetAttributes();
173         }
174         if (!hasJsonFieldAttribute)
175         {
176             attributes->AddAttribute(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()U"jsonFieldName"memberVariableSymbol->Name());
177         }
178     }
179 }
180 
181 void JsonAttributeProcessor::GenerateJsonCreatorFunctionSymbol(AttributeNode* attributeClassTypeSymbol* classTypeSymbol)
182 {
183     MemberFunctionSymbol* jsonCreatorFunctionSymbol = new MemberFunctionSymbol(attribute->GetSpan()attribute->ModuleId()U"Create");
184     jsonCreatorFunctionSymbol->SetGroupName(U"Create");
185     jsonCreatorFunctionSymbol->SetModule(module);
186     module->GetSymbolTable().SetFunctionIdFor(jsonCreatorFunctionSymbol);
187     jsonCreatorFunctionSymbol->SetAccess(SymbolAccess::public_);
188     jsonCreatorFunctionSymbol->SetStatic();
189     Symbol* jsonValue = classTypeSymbol->GetModule()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonValue");
190     if (!jsonValue || jsonValue->GetSymbolType() != SymbolType::classGroupTypeSymbol)
191     {
192         throw Exception("System.Json.JsonValue class not found from the symbol table"attribute->GetSpan()attribute->ModuleId()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
193     }
194     ClassGroupTypeSymbol* jsonValueGroup = static_cast<ClassGroupTypeSymbol*>(jsonValue);
195     ClassTypeSymbol* jsonValueClass = jsonValueGroup->GetClass(0);
196     if (!jsonValueClass)
197     {
198         throw Exception("System.Json.JsonValue class not found from the symbol table"attribute->GetSpan()attribute->ModuleId()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
199     }
200     ParameterSymbol* jsonValueParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"@value");
201     jsonValueParam->SetType(jsonValueClass->AddPointer(attribute->GetSpan()attribute->ModuleId()));
202     jsonCreatorFunctionSymbol->AddMember(jsonValueParam);
203     jsonCreatorFunctionSymbol->SetReturnType(module->GetSymbolTable().GetTypeByName(U"void")->AddPointer(attribute->GetSpan()attribute->ModuleId()));
204     classTypeSymbol->AddMember(jsonCreatorFunctionSymbol);
205     jsonCreatorFunctionSymbol->ComputeName();
206     jsonCreatorMap[classTypeSymbol] = jsonCreatorFunctionSymbol;
207 }
208 
209 void JsonAttributeProcessor::GenerateJsonConstructorSymbol(AttributeNode* attributeClassTypeSymbol* classTypeSymbol)
210 {
211     ConstructorSymbol* jsonConstructorSymbol = new ConstructorSymbol(attribute->GetSpan()attribute->ModuleId()U"@constructor");
212     jsonConstructorSymbol->SetModule(module);
213     module->GetSymbolTable().SetFunctionIdFor(jsonConstructorSymbol);
214     ParameterSymbol* thisParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"this");
215     thisParam->SetType(classTypeSymbol->AddPointer(attribute->GetSpan()attribute->ModuleId()));
216     ParameterSymbol* jsonValueParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"@value");
217     Symbol* jsonValue = classTypeSymbol->GetModule()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonValue");
218     if (!jsonValue || jsonValue->GetSymbolType() != SymbolType::classGroupTypeSymbol)
219     {
220         throw Exception("System.Json.JsonValue class not found from the symbol table"attribute->GetSpan()attribute->ModuleId()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
221     }
222     ClassGroupTypeSymbol* jsonValueGroup = static_cast<ClassGroupTypeSymbol*>(jsonValue);
223     ClassTypeSymbol* jsonValueClass = jsonValueGroup->GetClass(0);
224     if (!jsonValueClass)
225     {
226         throw Exception("System.Json.JsonValue class not found from the symbol table"attribute->GetSpan()attribute->ModuleId()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
227     }
228     jsonValueParam->SetType(jsonValueClass->AddPointer(attribute->GetSpan()attribute->ModuleId()));
229     jsonConstructorSymbol->SetAccess(SymbolAccess::public_);
230     jsonConstructorSymbol->SetExplicit();
231     jsonConstructorSymbol->AddMember(thisParam);
232     jsonConstructorSymbol->AddMember(jsonValueParam);
233     classTypeSymbol->AddMember(jsonConstructorSymbol);
234     jsonConstructorSymbol->ComputeName();
235     jsonConstructorMap[classTypeSymbol] = jsonConstructorSymbol;
236 }
237 
238 void JsonAttributeProcessor::GenerateToJsonJsonObjectSymbol(AttributeNode* attributeClassTypeSymbol* classTypeSymbol)
239 {
240     MemberFunctionSymbol* toJsonJsonObjectMemberFunctionSymbol = new MemberFunctionSymbol(attribute->GetSpan()attribute->ModuleId()U"ToJson");
241     toJsonJsonObjectMemberFunctionSymbol->SetModule(module);
242     toJsonJsonObjectMemberFunctionSymbol->SetGroupName(U"ToJson");
243     ClassTypeSymbol* baseClass = classTypeSymbol->BaseClass();
244     bool jsonBase = false;
245     if (baseClass)
246     {
247         AttributesNode* attributes = baseClass->GetAttributes();
248         if (attributes)
249         {
250             AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
251             if (jsonAttribute)
252             {
253                 if (jsonAttribute->Value() == U"true")
254                 {
255                     jsonBase = true;
256                 }
257             }
258         }
259     }
260     if (!jsonBase)
261     {
262         toJsonJsonObjectMemberFunctionSymbol->SetVirtual();
263     }
264     else
265     {
266         toJsonJsonObjectMemberFunctionSymbol->SetOverride();
267     }
268     GetRootModuleForCurrentThread()->GetSymbolTable().SetFunctionIdFor(toJsonJsonObjectMemberFunctionSymbol);
269     ParameterSymbol* thisParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"this");
270     thisParam->SetType(classTypeSymbol->AddPointer(attribute->GetSpan()attribute->ModuleId()));
271     ParameterSymbol* jsonObjectParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"@object");
272     Symbol* jsonObject = GetRootModuleForCurrentThread()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonObject");
273     if (!jsonObject || jsonObject->GetSymbolType() != SymbolType::classGroupTypeSymbol)
274     {
275         throw Exception("System.Json.JsonObject class not found from the symbol table"attribute->GetSpan()attribute->ModuleId()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
276     }
277     ClassGroupTypeSymbol* jsonObjectGroup = static_cast<ClassGroupTypeSymbol*>(jsonObject);
278     ClassTypeSymbol* jsonObjectClass = jsonObjectGroup->GetClass(0);
279     if (!jsonObjectClass)
280     {
281         throw Exception("System.Json.JsonObject class not found from the symbol table"attribute->GetSpan()attribute->ModuleId()classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId());
282     }
283     jsonObjectParam->SetType(jsonObjectClass->AddPointer(attribute->GetSpan()attribute->ModuleId()));
284     toJsonJsonObjectMemberFunctionSymbol->SetReturnType(module->GetSymbolTable().GetTypeByName(U"void"));
285     toJsonJsonObjectMemberFunctionSymbol->SetAccess(SymbolAccess::public_);
286     toJsonJsonObjectMemberFunctionSymbol->AddMember(thisParam);
287     toJsonJsonObjectMemberFunctionSymbol->AddMember(jsonObjectParam);
288     classTypeSymbol->AddMember(toJsonJsonObjectMemberFunctionSymbol);
289     toJsonJsonObjectMemberFunctionSymbol->ComputeName();
290     toJsonJsonObjectMemberFunctionSymbolMap[classTypeSymbol] = toJsonJsonObjectMemberFunctionSymbol;
291 }
292 
293 void JsonAttributeProcessor::GenerateToJsonSymbol(AttributeNode* attributeClassTypeSymbol* classTypeSymbolBoundCompileUnit& boundCompileUnitContainerScope* containerScope)
294 {
295     MemberFunctionSymbol* toJsonMemberFunctionSymbol = new MemberFunctionSymbol(attribute->GetSpan()attribute->ModuleId()U"ToJson");
296     toJsonMemberFunctionSymbol->SetModule(module);
297     toJsonMemberFunctionSymbol->SetGroupName(U"ToJson");
298     ClassTypeSymbol* baseClass = classTypeSymbol->BaseClass();
299     bool jsonBase = false;
300     if (baseClass)
301     {
302         AttributesNode* attributes = baseClass->GetAttributes();
303         if (attributes)
304         {
305             AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
306             if (jsonAttribute)
307             {
308                 if (jsonAttribute->Value() == U"true")
309                 {
310                     jsonBase = true;
311                 }
312             }
313         }
314     }
315     if (!jsonBase)
316     {
317         toJsonMemberFunctionSymbol->SetVirtual();
318     }
319     else
320     {
321         toJsonMemberFunctionSymbol->SetOverride();
322     }
323     GetRootModuleForCurrentThread()->GetSymbolTable().SetFunctionIdFor(toJsonMemberFunctionSymbol);
324     ParameterSymbol* thisParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"this");
325     thisParam->SetType(classTypeSymbol->AddPointer(attribute->GetSpan()attribute->ModuleId()));
326     TemplateIdNode templateId(attribute->GetSpan()attribute->ModuleId()new IdentifierNode(attribute->GetSpan()attribute->ModuleId()U"System.UniquePtr"));
327     templateId.AddTemplateArgument(new IdentifierNode(attribute->GetSpan()attribute->ModuleId()U"System.Json.JsonValue"));
328     TypeSymbol* uniquePtrJsonValueType = ResolveType(&templateIdboundCompileUnitcontainerScope);
329     toJsonMemberFunctionSymbol->SetReturnType(uniquePtrJsonValueType);
330     ParameterSymbol* returnParam = new ParameterSymbol(attribute->GetSpan()attribute->ModuleId()U"@return");
331     returnParam->SetParent(toJsonMemberFunctionSymbol);
332     returnParam->SetType(uniquePtrJsonValueType->AddPointer(attribute->GetSpan()attribute->ModuleId()));
333     toJsonMemberFunctionSymbol->SetReturnParam(returnParam);
334     toJsonMemberFunctionSymbol->SetAccess(SymbolAccess::public_);
335     toJsonMemberFunctionSymbol->AddMember(thisParam);
336     classTypeSymbol->AddMember(toJsonMemberFunctionSymbol);
337     toJsonMemberFunctionSymbol->ComputeName();
338     toJsonObjectMemberFunctionSymbolMap[classTypeSymbol] = toJsonMemberFunctionSymbol;
339 }
340 
341 void JsonAttributeProcessor::GenerateImplementation(AttributeNode* attributeSymbol* symbolStatementBinder* statementBinder)
342 {
343     if (symbol->IsClassTypeSymbol())
344     {
345         ClassTypeSymbol* classTypeSymbol = static_cast<ClassTypeSymbol*>(symbol);
346         auto it = jsonConstructorMap.find(symbol);
347         if (it != jsonConstructorMap.cend())
348         {
349             ConstructorSymbol* jsonConstructorSymbol = it->second;
350             GenerateJsonConstructorImplementation(attributeclassTypeSymboljsonConstructorSymbolstatementBinder);
351         }
352         else
353         {
354             throw Exception("internal error in JSON attribute implementation: constructor symbol for symbol '" + ToUtf8(symbol->FullName()) + "' not found"attribute->GetSpan()attribute->ModuleId());
355         }
356         auto it1 = jsonCreatorMap.find(symbol);
357         if (it1 != jsonCreatorMap.cend())
358         {
359             MemberFunctionSymbol* jsonCreatorSymbol = it1->second;
360             GenerateJsonCreatorImplementation(attributeclassTypeSymboljsonCreatorSymbolstatementBinder);
361         }
362         else
363         {
364             throw Exception("internal error in JSON attribute implementation: Creator function symbol for symbol '" + ToUtf8(symbol->FullName()) + "' not found"attribute->GetSpan()attribute->ModuleId());
365         }
366         auto it2 = toJsonJsonObjectMemberFunctionSymbolMap.find(symbol);
367         if (it2 != toJsonJsonObjectMemberFunctionSymbolMap.cend())
368         {
369             MemberFunctionSymbol* toJsonJsonObjectMemberFunctionSymbol = it2->second;
370             GenerateToJsonJsonObjectImplementation(attributeclassTypeSymboltoJsonJsonObjectMemberFunctionSymbolstatementBinder);
371         }
372         else
373         {
374             throw Exception("internal error in JSON attribute implementation: member function 'ToJson' symbol for symbol '" + ToUtf8(symbol->FullName()) + "' not found"attribute->GetSpan()attribute->ModuleId());
375         }
376         auto it3 = toJsonObjectMemberFunctionSymbolMap.find(symbol);
377         if (it3 != toJsonObjectMemberFunctionSymbolMap.cend())
378         {
379             MemberFunctionSymbol* toJsonMemberFunctionSymbol = it3->second;
380             GenerateToJsonImplementation(attributeclassTypeSymboltoJsonMemberFunctionSymbolstatementBinder);
381         }
382         else
383         {
384             throw Exception("internal error in JSON attribute implementation: member function 'ToJson' symbol for symbol '" + ToUtf8(symbol->FullName()) + "' not found"attribute->GetSpan()attribute->ModuleId());
385         }
386         SymbolTable& symbolTable = module->GetSymbolTable();
387         symbolTable.AddJsonClass(classTypeSymbol->FullName());
388     }
389 }
390 
391 void JsonAttributeProcessor::GenerateJsonCreatorImplementation(AttributeNode* attributeClassTypeSymbol* classTypeSymbolMemberFunctionSymbol* jsonCreatorFunctionSymbolStatementBinder* statementBinder)
392 {
393     try
394     {
395         FileScope* fileScope = new FileScope();
396         Symbol* jsonValue = classTypeSymbol->GetModule()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonValue");
397         if (jsonValue)
398         {
399             fileScope->AddContainerScope(jsonValue->Ns()->GetContainerScope());
400         }
401         statementBinder->GetBoundCompileUnit().AddFileScope(fileScope);
402         std::unique_ptr<BoundFunction> boundFunction(new BoundFunction(&statementBinder->GetBoundCompileUnit()jsonCreatorFunctionSymbol));
403         Span span = attribute->GetSpan();
404         boost::uuids::uuid moduleId = attribute->ModuleId();
405         CompoundStatementNode compoundStatementNode(spanmoduleId);
406         compoundStatementNode.SetEndBraceSpan(span);
407         NewNode* newNode = new NewNode(spanmoduleIdnew IdentifierNode(spanmoduleIdclassTypeSymbol->FullName()));
408         newNode->AddArgument(new IdentifierNode(spanmoduleIdU"@value"));
409         ReturnStatementNode* returnStatementNode = new ReturnStatementNode(spanmoduleIdnewNode);
410         compoundStatementNode.AddStatement(returnStatementNode);
411         SymbolTable& symbolTable = statementBinder->GetBoundCompileUnit().GetSymbolTable();
412         symbolTable.BeginContainer(jsonCreatorFunctionSymbol);
413         SymbolCreatorVisitor symbolCreatorVisitor(symbolTable);
414         compoundStatementNode.Accept(symbolCreatorVisitor);
415         symbolTable.EndContainer();
416         TypeBinder typeBinder(statementBinder->GetBoundCompileUnit());
417         ContainerScope* containerScope = statementBinder->GetContainerScope();
418         typeBinder.SetContainerScope(containerScope);
419         statementBinder->SetContainerScope(jsonCreatorFunctionSymbol->GetContainerScope());
420         typeBinder.SetCurrentFunctionSymbol(jsonCreatorFunctionSymbol);
421         compoundStatementNode.Accept(typeBinder);
422         BoundFunction* prevFunction = statementBinder->CurrentFunction();
423         statementBinder->SetCurrentFunction(boundFunction.get());
424         compoundStatementNode.Accept(*statementBinder);
425         statementBinder->SetContainerScope(containerScope);
426         BoundStatement* boundStatement = statementBinder->ReleaseStatement();
427         Assert(boundStatement->GetBoundNodeType() == BoundNodeType::boundCompoundStatement"bound compound statement expected");
428         BoundCompoundStatement* compoundStatement = static_cast<BoundCompoundStatement*>(boundStatement);
429         boundFunction->SetBody(std::unique_ptr<BoundCompoundStatement>(compoundStatement));
430         statementBinder->CurrentClass()->AddMember(std::move(boundFunction));
431         statementBinder->SetCurrentFunction(prevFunction);
432         statementBinder->GetBoundCompileUnit().RemoveLastFileScope();
433     }
434     catch (const Exception& ex;)
435     {
436         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
437         references.push_back(std::make_pair(ex.Defined()ex.DefinedModuleId()));
438         references.insert(references.end()ex.References().begin()ex.References().end());
439         throw Exception("error in JSON attribute generation: could not create JSON Create() function for class '" + ToUtf8(classTypeSymbol->FullName()) + "': " + ex.Message()
440             classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId()references);
441     }
442 }
443 
444 void JsonAttributeProcessor::GenerateJsonConstructorImplementation(AttributeNode* attributeClassTypeSymbol* classTypeSymbolConstructorSymbol* jsonConstructorSymbolStatementBinder* statementBinder)
445 {
446     try
447     {
448         FileScope* fileScope = new FileScope();
449         Symbol* jsonValue = classTypeSymbol->GetModule()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonValue");
450         if (jsonValue)
451         {
452             fileScope->AddContainerScope(jsonValue->Ns()->GetContainerScope());
453         }
454         statementBinder->GetBoundCompileUnit().AddFileScope(fileScope);
455         std::unique_ptr<BoundFunction> boundFunction(new BoundFunction(&statementBinder->GetBoundCompileUnit()jsonConstructorSymbol));
456         Span span = attribute->GetSpan();
457         boost::uuids::uuid moduleId = attribute->ModuleId();
458         ConstructorNode constructorNode(spanmoduleId);
459         CompoundStatementNode compoundStatementNode(spanmoduleId);
460         compoundStatementNode.SetEndBraceSpan(span);
461         ClassTypeSymbol* baseClass = classTypeSymbol->BaseClass();
462         if (baseClass)
463         {
464             AttributesNode* attributes = baseClass->GetAttributes();
465             if (attributes)
466             {
467                 AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
468                 if (jsonAttribute)
469                 {
470                     if (jsonAttribute->Value() == U"true")
471                     {
472                         BaseInitializerNode* baseInitializer = new BaseInitializerNode(spanmoduleId);
473                         baseInitializer->AddArgument(new IdentifierNode(spanmoduleIdU"@value"));
474                         constructorNode.AddInitializer(baseInitializer);
475                     }
476                 }
477             }
478         }
479         for (MemberVariableSymbol* memberVariableSymbol : classTypeSymbol->MemberVariables())
480         {
481             std::u32string jsonFieldName = memberVariableSymbol->Name();
482             AttributesNode* attributes = memberVariableSymbol->GetAttributes();
483             if (attributes)
484             {
485                 AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
486                 if (jsonAttribute)
487                 {
488                     if (jsonAttribute->Value() == U"false")
489                     {
490                         continue;
491                     }
492                 }
493                 AttributeNode* jsonFieldNameAttribute = attributes->GetAttribute(U"jsonFieldName");
494                 if (jsonFieldNameAttribute)
495                 {
496                     jsonFieldName = jsonFieldNameAttribute->Value();
497                 }
498             }
499             InvokeNode* invokeNode = new InvokeNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()new IdentifierNode(spanmoduleIdU"FromJson"));
500             invokeNode->AddArgument(new IdentifierNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()U"@value"));
501             invokeNode->AddArgument(new UStringLiteralNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()jsonFieldName));
502             invokeNode->AddArgument(new IdentifierNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()memberVariableSymbol->Name()));
503             ExpressionStatementNode* fromJsonStatement = new ExpressionStatementNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()invokeNode);
504             compoundStatementNode.AddStatement(fromJsonStatement);
505         }
506         SymbolTable& symbolTable = statementBinder->GetBoundCompileUnit().GetSymbolTable();
507         symbolTable.BeginContainer(jsonConstructorSymbol);
508         SymbolCreatorVisitor symbolCreatorVisitor(symbolTable);
509         compoundStatementNode.Accept(symbolCreatorVisitor);
510         symbolTable.EndContainer();
511         TypeBinder typeBinder(statementBinder->GetBoundCompileUnit());
512         ContainerScope* containerScope = statementBinder->GetContainerScope();
513         typeBinder.SetContainerScope(containerScope);
514         statementBinder->SetContainerScope(jsonConstructorSymbol->GetContainerScope());
515         typeBinder.SetCurrentFunctionSymbol(jsonConstructorSymbol);
516         compoundStatementNode.Accept(typeBinder);
517         BoundFunction* prevFunction = statementBinder->CurrentFunction();
518         statementBinder->SetCurrentFunction(boundFunction.get());
519         ConstructorSymbol* prevConstructorSymbol = statementBinder->CurrentConstructorSymbol();
520         ConstructorNode* prevConstructorNode = statementBinder->CurrentConstructorNode();
521         statementBinder->SetCurrentConstructor(jsonConstructorSymbol&constructorNode);
522         compoundStatementNode.Accept(*statementBinder);
523         statementBinder->SetContainerScope(containerScope);
524         BoundStatement* boundStatement = statementBinder->ReleaseStatement();
525         Assert(boundStatement->GetBoundNodeType() == BoundNodeType::boundCompoundStatement"bound compound statement expected");
526         BoundCompoundStatement* compoundStatement = static_cast<BoundCompoundStatement*>(boundStatement);
527         boundFunction->SetBody(std::unique_ptr<BoundCompoundStatement>(compoundStatement));
528         statementBinder->CurrentClass()->AddMember(std::move(boundFunction));
529         statementBinder->SetCurrentConstructor(prevConstructorSymbolprevConstructorNode);
530         statementBinder->SetCurrentFunction(prevFunction);
531         statementBinder->GetBoundCompileUnit().RemoveLastFileScope();
532     }
533     catch (const Exception& ex;)
534     {
535         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
536         references.push_back(std::make_pair(ex.Defined()ex.DefinedModuleId()));
537         references.insert(references.end()ex.References().begin()ex.References().end());
538         throw Exception("error in JSON attribute generation: could not create JSON constructor for class '" + ToUtf8(classTypeSymbol->FullName()) + "': " + ex.Message()
539             classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId()references);
540     }
541 }
542 
543 void JsonAttributeProcessor::GenerateToJsonJsonObjectImplementation(AttributeNode* attributeClassTypeSymbol* classTypeSymbolMemberFunctionSymbol* toJsonJsonObjectMemberFunctionSymbolStatementBinder* statementBinder)
544 {
545     try
546     {
547         FileScope* fileScope = new FileScope();
548         Symbol* jsonObject = GetRootModuleForCurrentThread()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonObject");
549         if (jsonObject)
550         {
551             fileScope->AddContainerScope(jsonObject->Ns()->GetContainerScope());
552         }
553         statementBinder->GetBoundCompileUnit().AddFileScope(fileScope);
554         std::unique_ptr<BoundFunction> boundFunction(new BoundFunction(&statementBinder->GetBoundCompileUnit()toJsonJsonObjectMemberFunctionSymbol));
555         Span span = attribute->GetSpan();
556         boost::uuids::uuid moduleId = attribute->ModuleId();
557         CompoundStatementNode compoundStatementNode(spanmoduleId);
558         compoundStatementNode.SetEndBraceSpan(span);
559         ClassTypeSymbol* baseClass = classTypeSymbol->BaseClass();
560         if (baseClass)
561         {
562             AttributesNode* attributes = baseClass->GetAttributes();
563             if (attributes)
564             {
565                 AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
566                 if (jsonAttribute)
567                 {
568                     if (jsonAttribute->Value() == U"true")
569                     {
570                         BaseNode* baseNode = new BaseNode(spanmoduleId);
571                         ArrowNode* arrowNode = new ArrowNode(spanmoduleIdbaseNodenew IdentifierNode(spanmoduleIdU"ToJson"));
572                         InvokeNode* toJsonInvokeNode = new InvokeNode(spanmoduleIdarrowNode);
573                         toJsonInvokeNode->AddArgument(new IdentifierNode(spanmoduleIdU"@object"));
574                         ExpressionStatementNode* toJsonStatement = new ExpressionStatementNode(spanmoduleIdtoJsonInvokeNode);
575                         compoundStatementNode.AddStatement(toJsonStatement);
576                     }
577                 }
578             }
579         }
580         for (MemberVariableSymbol* memberVariableSymbol : classTypeSymbol->MemberVariables())
581         {
582             std::u32string jsonFieldName = memberVariableSymbol->Name();
583             AttributesNode* attributes = memberVariableSymbol->GetAttributes();
584             if (attributes)
585             {
586                 AttributeNode* jsonAttribute = attributes->GetAttribute(U"json");
587                 if (jsonAttribute)
588                 {
589                     if (jsonAttribute->Value() == U"false")
590                     {
591                         continue;
592                     }
593                 }
594                 AttributeNode* jsonFieldNameAttribute = attributes->GetAttribute(U"jsonFieldName");
595                 if (jsonFieldNameAttribute)
596                 {
597                     jsonFieldName = jsonFieldNameAttribute->Value();
598                 }
599             }
600             InvokeNode* toJsonInvokeNode = new InvokeNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()new IdentifierNode(spanmoduleIdU"ToJson"));
601             toJsonInvokeNode->AddArgument(new IdentifierNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()memberVariableSymbol->Name()));
602             ArrowNode* arrowNode = new ArrowNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"@object")new IdentifierNode(spanmoduleIdU"AddField"));
603             InvokeNode* addFieldInvokeNode = new InvokeNode(spanmoduleIdarrowNode);
604             addFieldInvokeNode->AddArgument(new UStringLiteralNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()jsonFieldName));
605             addFieldInvokeNode->AddArgument(toJsonInvokeNode);
606             ExpressionStatementNode* addFieldStatement = new ExpressionStatementNode(memberVariableSymbol->GetSpan()memberVariableSymbol->SourceModuleId()addFieldInvokeNode);
607             compoundStatementNode.AddStatement(addFieldStatement);
608         }
609         SymbolTable& symbolTable = statementBinder->GetBoundCompileUnit().GetSymbolTable();
610         symbolTable.BeginContainer(toJsonJsonObjectMemberFunctionSymbol);
611         SymbolCreatorVisitor symbolCreatorVisitor(symbolTable);
612         compoundStatementNode.Accept(symbolCreatorVisitor);
613         symbolTable.EndContainer();
614         TypeBinder typeBinder(statementBinder->GetBoundCompileUnit());
615         ContainerScope* containerScope = statementBinder->GetContainerScope();
616         typeBinder.SetContainerScope(containerScope);
617         statementBinder->SetContainerScope(toJsonJsonObjectMemberFunctionSymbol->GetContainerScope());
618         typeBinder.SetCurrentFunctionSymbol(toJsonJsonObjectMemberFunctionSymbol);
619         compoundStatementNode.Accept(typeBinder);
620         BoundFunction* prevFunction = statementBinder->CurrentFunction();
621         statementBinder->SetCurrentFunction(boundFunction.get());
622         compoundStatementNode.Accept(*statementBinder);
623         statementBinder->SetContainerScope(containerScope);
624         BoundStatement* boundStatement = statementBinder->ReleaseStatement();
625         Assert(boundStatement->GetBoundNodeType() == BoundNodeType::boundCompoundStatement"bound compound statement expected");
626         BoundCompoundStatement* compoundStatement = static_cast<BoundCompoundStatement*>(boundStatement);
627         boundFunction->SetBody(std::unique_ptr<BoundCompoundStatement>(compoundStatement));
628         statementBinder->CurrentClass()->AddMember(std::move(boundFunction));
629         statementBinder->SetCurrentFunction(prevFunction);
630         statementBinder->GetBoundCompileUnit().RemoveLastFileScope();
631     }
632     catch (const Exception& ex;)
633     {
634         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
635         references.push_back(std::make_pair(ex.Defined()ex.DefinedModuleId()));
636         references.insert(references.end()ex.References().begin()ex.References().end());
637         throw Exception("error in JSON attribute generation: could not create 'void ToJson(JsobObject*)' member function for class '" + ToUtf8(classTypeSymbol->FullName()) + "': " + ex.Message()
638             classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId()references);
639     }
640 }
641 
642 void JsonAttributeProcessor::GenerateToJsonImplementation(AttributeNode* attributeClassTypeSymbol* classTypeSymbolMemberFunctionSymbol* toJsonMemberFunctionSymbolStatementBinder* statementBinder)
643 {
644     try
645     {
646         FileScope* fileScope = new FileScope();
647         Symbol* jsonObject = GetRootModuleForCurrentThread()->GetSymbolTable().GlobalNs().GetContainerScope()->Lookup(U"System.Json.JsonObject");
648         if (jsonObject)
649         {
650             fileScope->AddContainerScope(jsonObject->Ns()->GetContainerScope());
651         }
652         statementBinder->GetBoundCompileUnit().AddFileScope(fileScope);
653         std::unique_ptr<BoundFunction> boundFunction(new BoundFunction(&statementBinder->GetBoundCompileUnit()toJsonMemberFunctionSymbol));
654         Span span = attribute->GetSpan();
655         boost::uuids::uuid moduleId = attribute->ModuleId();
656         CompoundStatementNode compoundStatementNode(spanmoduleId);
657         compoundStatementNode.SetEndBraceSpan(span);
658         TemplateIdNode* uniquePtrJsonObject = new TemplateIdNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"UniquePtr"));
659         uniquePtrJsonObject->AddTemplateArgument(new IdentifierNode(spanmoduleIdU"JsonObject"));
660         ConstructionStatementNode* constructJsonObjectStatement = new ConstructionStatementNode(spanmoduleIduniquePtrJsonObjectnew IdentifierNode(spanmoduleIdU"@object"));
661         constructJsonObjectStatement->AddArgument(new NewNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"JsonObject")));
662         compoundStatementNode.AddStatement(constructJsonObjectStatement);
663         InvokeNode* invokeToJson = new InvokeNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"ToJson"));
664         invokeToJson->AddArgument(new InvokeNode(spanmoduleIdnew DotNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"@object")new IdentifierNode(spanmoduleIdU"Get"))));
665         ExpressionStatementNode* callToJsonStatement = new ExpressionStatementNode(spanmoduleIdinvokeToJson);
666         compoundStatementNode.AddStatement(callToJsonStatement);
667         TemplateIdNode* uniquePtrJsonValue = new TemplateIdNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"UniquePtr"));
668         uniquePtrJsonValue->AddTemplateArgument(new IdentifierNode(spanmoduleIdU"JsonValue"));
669         InvokeNode* invokeJsonValue = new InvokeNode(spanmoduleIduniquePtrJsonValue);
670         invokeJsonValue->AddArgument(new InvokeNode(spanmoduleIdnew DotNode(spanmoduleIdnew IdentifierNode(spanmoduleIdU"@object")new IdentifierNode(spanmoduleIdU"Release"))));
671         ReturnStatementNode* returnStatement = new ReturnStatementNode(spanmoduleIdinvokeJsonValue);
672         compoundStatementNode.AddStatement(returnStatement);
673         SymbolTable& symbolTable = statementBinder->GetBoundCompileUnit().GetSymbolTable();
674         symbolTable.BeginContainer(toJsonMemberFunctionSymbol);
675         SymbolCreatorVisitor symbolCreatorVisitor(symbolTable);
676         compoundStatementNode.Accept(symbolCreatorVisitor);
677         symbolTable.EndContainer();
678         TypeBinder typeBinder(statementBinder->GetBoundCompileUnit());
679         ContainerScope* containerScope = statementBinder->GetContainerScope();
680         typeBinder.SetContainerScope(containerScope);
681         statementBinder->SetContainerScope(toJsonMemberFunctionSymbol->GetContainerScope());
682         typeBinder.SetCurrentFunctionSymbol(toJsonMemberFunctionSymbol);
683         compoundStatementNode.Accept(typeBinder);
684         BoundFunction* prevFunction = statementBinder->CurrentFunction();
685         statementBinder->SetCurrentFunction(boundFunction.get());
686         compoundStatementNode.Accept(*statementBinder);
687         statementBinder->SetContainerScope(containerScope);
688         BoundStatement* boundStatement = statementBinder->ReleaseStatement();
689         Assert(boundStatement->GetBoundNodeType() == BoundNodeType::boundCompoundStatement"bound compound statement expected");
690         BoundCompoundStatement* compoundStatement = static_cast<BoundCompoundStatement*>(boundStatement);
691         boundFunction->SetBody(std::unique_ptr<BoundCompoundStatement>(compoundStatement));
692         statementBinder->CurrentClass()->AddMember(std::move(boundFunction));
693         statementBinder->SetCurrentFunction(prevFunction);
694         statementBinder->GetBoundCompileUnit().RemoveLastFileScope();
695     }
696     catch (const Exception& ex;)
697     {
698         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
699         references.push_back(std::make_pair(ex.Defined()ex.DefinedModuleId()));
700         references.insert(references.end()ex.References().begin()ex.References().end());
701         throw Exception("error in JSON attribute generation: could not create 'UniquePtr<JsonValue> ToJson()' member function for class '" + ToUtf8(classTypeSymbol->FullName()) + "': " + ex.Message()
702             classTypeSymbol->GetSpan()classTypeSymbol->SourceModuleId()references);
703     }
704 }
705 
706 JsonFieldNameAttributeProcessor::JsonFieldNameAttributeProcessor() : AttributeProcessor(U"jsonFieldName")
707 {
708 }
709 
710 void JsonFieldNameAttributeProcessor::TypeCheck(AttributeNode* attributeSymbol* symbol)
711 {
712     if (symbol->GetSymbolType() == SymbolType::memberVariableSymbol)
713     {
714         if (attribute->Value().empty())
715         {
716             throw Exception("attribute value '" + ToUtf8(attribute->Value()) + "' for attribute '" + ToUtf8(attribute->Name()) + "' cannot be empty string"attribute->GetSpan()attribute->ModuleId());
717         }
718         return;
719     }
720     AttributeProcessor::TypeCheck(attributesymbol);
721 }
722 
723 } } // namespace cmajor::binder