1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/symbols/EditModuleCache.hpp>
  7 #include <cmajor/symbols/GlobalFlags.hpp>
  8 #include <cmajor/symbols/ModuleCache.hpp>
  9 #include <soulng/util/MappedInputFile.hpp>
 10 #include <soulng/util/Sha1.hpp>
 11 #include <soulng/util/Unicode.hpp>
 12 
 13 namespace cmajor { namespace symbols {
 14 
 15 using namespace soulng::unicode;
 16 
 17 ReadProjectFunc readProjectFunction;
 18 
 19 void SetReadProjectFunction(ReadProjectFunc readProjectFunc)
 20 {
 21     readProjectFunction = readProjectFunc;
 22 }
 23 
 24 std::string MakeEditModuleKey(const std::string& projectFilePathconst std::string& backendStrconst std::string& configurationStr)
 25 {
 26     std::string editModuleKey = projectFilePath;
 27     editModuleKey.append(":").append(backendStr).append(":").append(configurationStr);
 28     return editModuleKey;
 29 }
 30 
 31 bool toolChainsRead = false;
 32 
 33 std::unique_ptr<EditModuleCache> EditModuleCache::instance;
 34 
 35 void EditModuleCache::Init()
 36 {
 37     instance.reset(new EditModuleCache());
 38 }
 39 
 40 void EditModuleCache::Done()
 41 {
 42     instance.reset();
 43 }
 44 
 45 EditModuleCache::EditModuleCache()
 46 {
 47 }
 48 
 49 LoadEditModuleResult EditModuleCache::LoadEditModule(const std::string& projectFilePathconst std::string& backendStrconst std::string& configurationStr)
 50 {
 51     LoadEditModuleResult result;
 52     result.ok = true;
 53     result.error = std::string();
 54     result.startLoading = std::chrono::steady_clock::now();
 55     result.resultKind = LoadEditModuleResultKind::moduleLoaded;
 56     cmajor::symbols::ResetGlobalFlags();
 57     std::string projectFileContent = ReadFile(projectFilePath);
 58     std::string projectFileHash = GetSha1MessageDigest(projectFileContent);
 59     int index = editModules.size();
 60     std::string editModuleKey = MakeEditModuleKey(projectFilePathbackendStrconfigurationStr);
 61     result.key = editModuleKey;
 62     auto it = editModuleMap.find(editModuleKey);
 63     if (it != editModuleMap.cend())
 64     {
 65         const std::std::pair<Module*std::string>&moduleHashPair=it->second;
 66         const std::string& prevHash = moduleHashPair.second;
 67         if (prevHash == projectFileHash)
 68         {
 69             result.resultKind = LoadEditModuleResultKind::moduleUpToDate;
 70             result.endLoading = std::chrono::steady_clock::now();
 71             return result;
 72         }
 73         Module* module = moduleHashPair.first;
 74         index = module->Index();
 75         result.resultKind = LoadEditModuleResultKind::moduleReloaded;
 76     }
 77     if (!toolChainsRead)
 78     {
 79         toolChainsRead = true;
 80         ReadToolChains(GetGlobalFlag(cmajor::symbols::GlobalFlags::verbose));
 81     }
 82     ResetToolChain();
 83     sngcm::ast::BackEnd backend = sngcm::ast::BackEnd::llvm;
 84     if (backendStr == "cpp")
 85     {
 86         backend = sngcm::ast::BackEnd::cppcm;
 87         SetBackEnd(cmajor::symbols::BackEnd::cmcpp);
 88     }
 89     else if (backendStr == "llvm")
 90     {
 91         backend = sngcm::ast::BackEnd::llvm;
 92         SetBackEnd(cmajor::symbols::BackEnd::llvm);
 93     }
 94     sngcm::ast::Config config = sngcm::ast::Config::debug;
 95     if (configurationStr == "release")
 96     {
 97         cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::release);
 98         config = sngcm::ast::Config::release;
 99     }
100     if (!readProjectFunction)
101     {
102         result.ok = false;
103         result.error = "read project function not set";
104         return result;
105     }
106     std::unique_ptr<Project> project = readProjectFunction(projectFilePath);
107     std::unique_ptr<Module> module(new Module(project->Name()project->ModuleFilePath()project->GetTarget()));
108     module->SetIndex(index);
109     module->SetRootModule();
110     SetRootModuleForCurrentThread(module.get());
111     module->SetLogStreamId(project->LogStreamId());
112     module->SetCurrentProjectName(project->Name());
113     module->SetCurrentToolName(U"cmccs");
114     module->SetFlag(cmajor::symbols::ModuleFlags::compiling);
115     PrepareModuleForCompilation(module.get()project->References()project->GetTarget());
116     module->SetSources(new Sources(project->SourceFilePaths()));
117     ParseResult parseResult = module->ParseSources();
118     result.ok = parseResult.ok;
119     result.numberOfErrors = parseResult.numberOfErrors;
120     result.synchronized = parseResult.synchronized;
121     result.error = parseResult.error;
122     result.startParsing = parseResult.start;
123     result.endParsing = parseResult.end;
124     while (index >= editModules.size())
125     {
126         editModules.push_back(std::unique_ptr<Module>());
127     }
128     editModuleMap[editModuleKey] = std::make_pair(module.get()projectFileHash);
129     editModules[index].reset(module.release());
130     result.endLoading = std::chrono::steady_clock::now();
131     return result;
132 }
133 
134 Module* EditModuleCache::GetEditModule(const std::string& projectFilePathconst std::string& backendStrconst std::string& configurationStr)
135 {
136     std::string editModuleKey = MakeEditModuleKey(projectFilePathbackendStrconfigurationStr);
137     auto it = editModuleMap.find(editModuleKey);
138     if (it != editModuleMap.cend())
139     {
140         return it->second.first;
141     }
142     else
143     {
144         return nullptr;
145     }
146 }
147 
148 void InitEditModuleCache()
149 {
150     EditModuleCache::Init();
151 }
152 
153 void DoneEditModuleCache()
154 {
155     EditModuleCache::Done();
156 }
157 
158 } } // namespace cmajor::symbols