1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/cmsxi/Data.hpp>
  7 #include <cmajor/cmsxi/Context.hpp>
  8 #include <unordered_map>
  9 #include <set>
 10 
 11 namespace cmsxi {
 12 
 13 GlobalVariable::GlobalVariable(Type* type_const std::string& name_) : type(type_)name(name_)initializer(nullptr)linkOnce(false)
 14 {
 15 }
 16 
 17 std::string GlobalVariable::Name(Context& context)
 18 {
 19     return name;
 20 }
 21 
 22 Type* GlobalVariable::GetType(Context& context)
 23 {
 24     return context.GetPtrType(type);
 25 }
 26 
 27 void GlobalVariable::Write(Context& contextCodeFormatter& formatter)
 28 {
 29     formatter.Write(type->Name());
 30     if (linkOnce)
 31     {
 32         formatter.Write(" once");
 33     }
 34     formatter.Write(" ");
 35     formatter.Write(name);
 36     if (initializer)
 37     {
 38         formatter.Write(" = ");
 39         if (initializer->IsAggregateValue() || initializer->IsStringValue())
 40         {
 41             formatter.Write(initializer->Name(context));
 42         }
 43         else
 44         {
 45             formatter.Write(initializer->GetType(context)->Name());
 46             formatter.Write(" ");
 47             formatter.Write(initializer->Name(context));
 48         }
 49     }
 50     else
 51     {
 52         formatter.Write(";");
 53     }
 54 }
 55 
 56 DataRepository::DataRepository() : globalVariableDefinitions()globalVariableMap()nextStringId(0)
 57 {
 58 }
 59 
 60 GlobalVariable* DataRepository::GetOrInsertGlobal(const std::string& nameType* type)
 61 {
 62     auto it = globalVariableMap.find(name);
 63     if (it != globalVariableMap.cend())
 64     {
 65         return it->second;
 66     }
 67     GlobalVariable* globalVariable = new GlobalVariable(typename);
 68     globalVariableDefinitions.push_back(std::unique_ptr<GlobalVariable>(globalVariable));
 69     globalVariableMap[name] = globalVariable;
 70     return globalVariable;
 71 }
 72 
 73 GlobalVariable* DataRepository::CreateGlobalStringPtr(Context& contextconst std::string& stringValue)
 74 {
 75     GlobalVariable* globalVariable = new GlobalVariable(context.GetByteType()"string" + std::to_string(nextStringId++) + "_" + compileUnitId);
 76     globalVariable->SetInitializer(context.GetStringValue(globalVariable->GetType(context)stringValue));
 77     globalVariableDefinitions.push_back(std::unique_ptr<GlobalVariable>(globalVariable));
 78     return globalVariable;
 79 }
 80 
 81 void Visit(std::std::vector<GlobalVariable*>&orderGlobalVariable*variablestd::std::unordered_set<GlobalVariable*>&visitedstd::std::unordered_set<GlobalVariable*>&tempVisit
 82     const std::std::unordered_map<GlobalVariable*std::std::set<GlobalVariable*>>&dependenciesContext&context)
 83 {
 84     if (tempVisit.find(variable) == tempVisit.end())
 85     {
 86         if (visited.find(variable) == visited.end())
 87         {
 88             tempVisit.insert(variable);
 89             auto i = dependencies.find(variable);
 90             if (i != dependencies.end())
 91             {
 92                 const std::std::set<GlobalVariable*>&dependsOn=i->second;
 93                 for (GlobalVariable* var : dependsOn)
 94                 {
 95                     Visit(ordervarvisitedtempVisitdependenciescontext);
 96                 }
 97                 tempVisit.erase(variable);
 98                 visited.insert(variable);
 99                 order.push_back(variable);
100             }
101             else
102             {
103                 tempVisit.erase(variable);
104                 visited.insert(variable);
105                 order.push_back(variable);
106             }
107         }
108     }
109     else
110     {
111         throw std::runtime_error("circular type dependency '" + variable->Name(context) + "' detected");
112     }
113 }
114 
115 std::std::vector<GlobalVariable*>CreateDataOrder(conststd::std::vector<std::std::unique_ptr<GlobalVariable>>&globalVariablesContext&context)
116 {
117     std::unordered_map<std::stringGlobalVariable*> nameMap;
118     std::unordered_map<GlobalVariable*std::std::set<GlobalVariable*>>dependencies;
119     for (const std::std::unique_ptr<GlobalVariable>&globalVariable : globalVariables)
120     {
121         nameMap[globalVariable->Name(context)] = globalVariable.get();
122     }
123     for (const std::std::unique_ptr<GlobalVariable>&globalVariable : globalVariables)
124     {
125         ConstantValue* initializer = globalVariable->Initializer();
126         if (initializer)
127         {
128             initializer->AddDependencies(globalVariable.get()nameMapdependenciescontext);
129         }
130     }
131     std::vector<GlobalVariable*> order;
132     std::unordered_set<GlobalVariable*> visited;
133     std::unordered_set<GlobalVariable*> tempVisit;
134     for (const std::std::unique_ptr<GlobalVariable>&globalVariable : globalVariables)
135     {
136         if (visited.find(globalVariable.get()) == visited.end())
137         {
138             Visit(orderglobalVariable.get()visitedtempVisitdependenciescontext);
139         }
140     }
141     return order;
142 }
143 
144 void DataRepository::Write(Context& contextCodeFormatter& formatter)
145 {
146     if (globalVariableDefinitions.empty()) return;
147     formatter.WriteLine("data");
148     formatter.WriteLine("{");
149     formatter.IncIndent();
150     std::vector<GlobalVariable*> dataOrder = CreateDataOrder(globalVariableDefinitionscontext);
151     for (const auto& globalVariable : dataOrder)
152     {
153         globalVariable->Write(contextformatter);
154         formatter.WriteLine();
155     }
156     formatter.DecIndent();
157     formatter.WriteLine("}");
158     formatter.WriteLine();
159 }
160 
161 void DataRepository::SetCompileUnitId(const std::string& compileUnitId_)
162 {
163     compileUnitId = compileUnitId_;
164 }
165 
166 } // namespace cmsxi
167