diff options
author | rtk0c <[email protected]> | 2022-07-17 23:09:00 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-07-17 23:09:00 -0700 |
commit | 8c2b1bd5bd85667a2ea24ec3aa85cbdd97f9ea1c (patch) | |
tree | 80b12277b667747aa4f18ebcc3931c2ea618cb1e /source | |
parent | c6e57dc94e532442ffa0bd57a16206217adbca92 (diff) |
Changeset: 85 Work on codegen (a big blob of changes about various things, giving up on writing a clear commit message)
- stuff along the lines of cleaning up store process
- remove completed TODOs
- move code generation out of parser loop
- ^^^ also introduce some weird bugs of DeclXxx::name field disappearing -- maybe fixed, maybe didn't, can't reliably reproduce
- add infra to mangle (not included in codegen yet, also not tested)
- convert SourceFile storage map to node map, ensuring pointer stability (was broken before)
- buildsystem asan and UBsan applying to all targest
Diffstat (limited to 'source')
-rw-r--r-- | source/20-codegen-compiler/CodegenDecl.cpp | 16 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenDecl.hpp | 18 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenModel.cpp | 61 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenModel.hpp | 32 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenModelArchive.hpp | 31 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenOutput.cpp | 31 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenOutput.hpp | 7 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenUtils.cpp | 78 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenUtils.hpp | 4 | ||||
-rw-r--r-- | source/20-codegen-compiler/main.cpp | 157 |
10 files changed, 260 insertions, 175 deletions
diff --git a/source/20-codegen-compiler/CodegenDecl.cpp b/source/20-codegen-compiler/CodegenDecl.cpp index 7cf21ce..9e88cfb 100644 --- a/source/20-codegen-compiler/CodegenDecl.cpp +++ b/source/20-codegen-compiler/CodegenDecl.cpp @@ -1,7 +1,23 @@ #include "CodegenDecl.hpp" +#include "CodegenUtils.hpp" + #include <Utils.hpp> +const std::string& DeclStruct::GetMangledName() const { + if (mangledName.empty()) { + mangledName = Utils::MakeMangledName(name, container); + } + return mangledName; +} + +const std::string& DeclEnum::GetMangledName() const { + if (mangledName.empty()) { + mangledName = Utils::MakeMangledName(name, container); + } + return mangledName; +} + static EnumValuePattern NextPattern(EnumValuePattern val) { return (EnumValuePattern)(val + 1); } diff --git a/source/20-codegen-compiler/CodegenDecl.hpp b/source/20-codegen-compiler/CodegenDecl.hpp index d99f79c..eacd254 100644 --- a/source/20-codegen-compiler/CodegenDecl.hpp +++ b/source/20-codegen-compiler/CodegenDecl.hpp @@ -1,12 +1,18 @@ #pragma once +#include "CodegenOutput.hpp" + #include <string> #include <vector> // TODO replace std::string name with std::string_view into the token storage? struct SourceFile { - std::string_view filename; // View into storage map key + std::string filename; + CodegenOutput preHeaderOutput; + CodegenOutput postHeaderOutput; + CodegenOutput postSourceOutput; + CodegenOutput tuOutput; // "tu" = Translation Unit, produces a separately compiled .cpp file bool header = false; /// Whether this file is being reprocessed in this invocation of codegen.exe or not. bool reprocessing = false; @@ -27,6 +33,8 @@ struct DeclMemberVariable { std::string type; std::string getterName; std::string setterName; + bool isGetterGenerated = false; + bool isSetterGenerated = false; }; struct DeclMemberFunction { DeclStruct* containerStruct = nullptr; @@ -43,11 +51,14 @@ struct DeclStruct { std::vector<DeclMemberFunction> memberFunctions; std::vector<DeclMemberFunction> generatedFunctions; std::string name; + mutable std::string mangledName; std::string_view fullname; // Scanned generation options bool generating : 1 = false; bool generatingInheritanceHiearchy : 1 = false; + + const std::string& GetMangledName() const; }; enum EnumUnderlyingType { @@ -85,6 +96,7 @@ struct DeclEnum { SourceFile* sourceFile = nullptr; DeclNamespace* container = nullptr; std::string name; + mutable std::string mangledName; std::string_view fullname; std::vector<DeclEnumElement> elements; EnumUnderlyingType underlyingType; @@ -101,6 +113,10 @@ struct DeclEnum { // NOTE: see GenerateForEnum() for the exact heuristics bool generateExcludeUseHeuristics : 1 = false; + const std::string& GetName() const { return name; } + std::string_view GetFullName() const { return fullname; } + const std::string& GetMangledName() const; + std::string_view GetUnderlyingTypeName() const; EnumValuePattern CalcPattern() const; diff --git a/source/20-codegen-compiler/CodegenModel.cpp b/source/20-codegen-compiler/CodegenModel.cpp index e3fc810..be41e68 100644 --- a/source/20-codegen-compiler/CodegenModel.cpp +++ b/source/20-codegen-compiler/CodegenModel.cpp @@ -1,5 +1,4 @@ #include "CodegenModel.hpp" -#include "CodegenModelArchive.hpp" #include "CodegenUtils.hpp" @@ -22,8 +21,8 @@ struct SomeDecl { std::variant<DeclStruct, DeclFunction, DeclEnum> v; }; -class CodegenModel::Private { - friend class CodegenModelArchive; +class CodegenRuntimeModel::Private { + friend class CodegenArchiveModel; public: // We want address stability for everything @@ -34,7 +33,6 @@ public: // A number for `PRAGMA user_vesrion`, representing the current database version. Increment when the table format changes. #define CURRENT_DATABASE_VERSION 1 constexpr int64_t kGlobalNamespaceId = 1; -constexpr int64_t kNoFileId = 1; struct SQLiteDatabase { sqlite3* database = nullptr; @@ -94,8 +92,8 @@ void PrintErrMsgIfPresent(char*& errMsg) { } } // namespace -class CodegenModelArchive::Private { - friend class CodegenModel; +class CodegenArchiveModel::Private { + friend class CodegenRuntimeModel; public: // NOTE: this must be the first field, because we want it to destruct after all other statement fields @@ -225,9 +223,6 @@ CREATE UNIQUE INDEX Index_DeclStructMethods_Identity ON DeclStructMethods(Struct CREATE UNIQUE INDEX Index_DeclEnums_Identity ON DeclEnums(NamespaceId, Name); -INSERT INTO Files(Id, FileName) -VALUES (1, ''); - -- Special global namespace that has no parent, and Id should always be 1 INSERT INTO Namespaces(Id, ParentNamespaceId, Name) VALUES (1, NULL, '<global namespace>'); @@ -341,10 +336,10 @@ COMMIT TRANSACTION; return fileId; } - /// \return Row ID of the file + /// \return Row ID of the file, or 0 if not found. int64_t FindOrStoreFile(/*nullable*/ const SourceFile* file) { if (!file) { - return kNoFileId; + return 0; } return FindOrStoreFile(file->filename); } @@ -392,7 +387,7 @@ private: for (auto it = namespaceNames.rbegin(); it != namespaceNames.rend(); ++it) { fullname.append(*it); - if (!append && std::next(it) != namespaceNames.rend()) { + if (append || std::next(it) != namespaceNames.rend()) { fullname.append("::"); } } @@ -438,12 +433,12 @@ private: } }; -CodegenModel::CodegenModel() +CodegenRuntimeModel::CodegenRuntimeModel() : m{ new Private() } // { } -CodegenModel::~CodegenModel() { +CodegenRuntimeModel::~CodegenRuntimeModel() { delete m; } @@ -455,7 +450,7 @@ CodegenModel::~CodegenModel() { declRef.fullname = key; \ return &declRef -DeclEnum* CodegenModel::AddEnum(std::string fullname, DeclEnum decl) { +DeclEnum* CodegenRuntimeModel::AddEnum(std::string fullname, DeclEnum decl) { #if CODEGEN_DEBUG_PRINT printf("Committed enum '%s'\n", decl.name.c_str()); for (auto& elm : decl.elements) { @@ -466,7 +461,7 @@ DeclEnum* CodegenModel::AddEnum(std::string fullname, DeclEnum decl) { STORE_DECL_OF_TYPE(DeclEnum, fullname, decl); } -DeclStruct* CodegenModel::AddStruct(std::string fullname, DeclStruct decl) { +DeclStruct* CodegenRuntimeModel::AddStruct(std::string fullname, DeclStruct decl) { #if CODEGEN_DEBUG_PRINT printf("Committed struct '%s'\n", decl.name.c_str()); printf(" Base classes:\n"); @@ -488,15 +483,15 @@ DeclStruct* CodegenModel::AddStruct(std::string fullname, DeclStruct decl) { } \ return nullptr -const DeclEnum* CodegenModel::FindEnum(std::string_view name) const { +const DeclEnum* CodegenRuntimeModel::FindEnum(std::string_view name) const { FIND_DECL_OF_TYPE(DeclEnum); } -const DeclStruct* CodegenModel::FindStruct(std::string_view name) const { +const DeclStruct* CodegenRuntimeModel::FindStruct(std::string_view name) const { FIND_DECL_OF_TYPE(DeclStruct); } -DeclNamespace* CodegenModel::AddNamespace(DeclNamespace ns) { +DeclNamespace* CodegenRuntimeModel::AddNamespace(DeclNamespace ns) { auto path = Utils::MakeFullName(""sv, &ns); auto [iter, success] = m->namespaces.try_emplace(std::move(path), std::move(ns)); auto& nsRef = iter->second; @@ -506,7 +501,7 @@ DeclNamespace* CodegenModel::AddNamespace(DeclNamespace ns) { return &nsRef; } -const DeclNamespace* CodegenModel::FindNamespace(std::string_view fullname) const { +const DeclNamespace* CodegenRuntimeModel::FindNamespace(std::string_view fullname) const { auto iter = m->namespaces.find(fullname); if (iter != m->namespaces.end()) { return &iter->second; @@ -515,11 +510,11 @@ const DeclNamespace* CodegenModel::FindNamespace(std::string_view fullname) cons } } -DeclNamespace* CodegenModel::FindNamespace(std::string_view name) { - return const_cast<DeclNamespace*>(const_cast<const CodegenModel*>(this)->FindNamespace(name)); +DeclNamespace* CodegenRuntimeModel::FindNamespace(std::string_view name) { + return const_cast<DeclNamespace*>(const_cast<const CodegenRuntimeModel*>(this)->FindNamespace(name)); } -CodegenModelArchive::CodegenModelArchive(std::string_view dbPath) +CodegenArchiveModel::CodegenArchiveModel(std::string_view dbPath) : m{ new Private() } // { std::string zstrPath(dbPath); @@ -571,11 +566,11 @@ CodegenModelArchive::CodegenModelArchive(std::string_view dbPath) m->storeNamespaceStmt.Initialize(m->database, "INSERT INTO Namespaces(ParentNamespaceId, Name) VALUES (?1, ?2) RETURNING Id"); } -CodegenModelArchive::~CodegenModelArchive() { +CodegenArchiveModel::~CodegenArchiveModel() { delete m; } -void CodegenModelArchive::DeleteDeclsRelatedToFile(std::string_view filename) { +void CodegenArchiveModel::DeleteDeclsRelatedToFile(std::string_view filename) { // -Argument- -Description- // ?1 The filename to delete m->deleteFunctionDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclFunctions WHERE FileId = (SELECT Id FROM Files WHERE FileName = ?1)"sv); @@ -598,11 +593,11 @@ void CodegenModelArchive::DeleteDeclsRelatedToFile(std::string_view filename) { m->CommitTransaction(); } -void CodegenModelArchive::Store(const CodegenModel& cgModel) { +void CodegenArchiveModel::Store(const CodegenRuntimeModel& cgModel) { auto& cgm = cgModel.GetPimpl(); struct Visiter { - CodegenModelArchive* self; + CodegenArchiveModel* self; void operator()(const DeclStruct& decl) const { self->StoreStruct(decl); @@ -629,12 +624,12 @@ void CodegenModelArchive::Store(const CodegenModel& cgModel) { m->CommitTransaction(); } -void CodegenModelArchive::LoadInto(CodegenModel& model) const { +void CodegenArchiveModel::LoadInto(CodegenRuntimeModel& model) const { // TODO } -CodegenModel CodegenModelArchive::Load() const { - CodegenModel cgModel; +CodegenRuntimeModel CodegenArchiveModel::Load() const { + CodegenRuntimeModel cgModel; // TODO files // TODO namespaces @@ -733,7 +728,7 @@ CodegenModel CodegenModelArchive::Load() const { return cgModel; } -void CodegenModelArchive::StoreStruct(const DeclStruct& decl) { +void CodegenArchiveModel::StoreStruct(const DeclStruct& decl) { // -Argument- -Description- // ?1 Namespace ID // ?2 Struct name @@ -810,11 +805,11 @@ VALUES (?1, ?2, ?3, ?4, ?5, ?6) } } -void CodegenModelArchive::StoreFunction(const DeclFunction& decl) { +void CodegenArchiveModel::StoreFunction(const DeclFunction& decl) { // TODO } -void CodegenModelArchive::StoreEnum(const DeclEnum& decl) { +void CodegenArchiveModel::StoreEnum(const DeclEnum& decl) { // -Argument- -Description- // ?1 Namespace ID // ?2 Enum name diff --git a/source/20-codegen-compiler/CodegenModel.hpp b/source/20-codegen-compiler/CodegenModel.hpp index 31ca04f..99c345d 100644 --- a/source/20-codegen-compiler/CodegenModel.hpp +++ b/source/20-codegen-compiler/CodegenModel.hpp @@ -2,22 +2,25 @@ #include "CodegenConfig.hpp" #include "CodegenDecl.hpp" +#include "CodegenModel.hpp" #include "CodegenUtils.hpp" +#include <sqlite3.h> #include <cinttypes> +#include <cstdint> #include <string> #include <string_view> using namespace std::literals; -class CodegenModel { +class CodegenRuntimeModel { private: class Private; Private* m; public: - CodegenModel(); - ~CodegenModel(); + CodegenRuntimeModel(); + ~CodegenRuntimeModel(); // Implementation detail helper, don't use outside Private& GetPimpl() const { return *m; } @@ -33,3 +36,26 @@ public: const DeclNamespace* FindNamespace(std::string_view fullname) const; DeclNamespace* FindNamespace(std::string_view name); }; + +class CodegenArchiveModel { +private: + class Private; + Private* m; + +public: + CodegenArchiveModel(std::string_view dbPath); + ~CodegenArchiveModel(); + + // Implementation detail helper, don't use outside + Private& GetPimpl() const { return *m; } + + void DeleteDeclsRelatedToFile(std::string_view filename); + + void Store(const CodegenRuntimeModel& model); + void LoadInto(CodegenRuntimeModel& model) const; + CodegenRuntimeModel Load() const; + + void StoreStruct(const DeclStruct& decl); + void StoreFunction(const DeclFunction& decl); + void StoreEnum(const DeclEnum& decl); +}; diff --git a/source/20-codegen-compiler/CodegenModelArchive.hpp b/source/20-codegen-compiler/CodegenModelArchive.hpp deleted file mode 100644 index e67f4d9..0000000 --- a/source/20-codegen-compiler/CodegenModelArchive.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "CodegenDecl.hpp" -#include "CodegenModel.hpp" - -#include <sqlite3.h> -#include <cstdint> -#include <string_view> - -class CodegenModelArchive { -private: - class Private; - Private* m; - -public: - CodegenModelArchive(std::string_view dbPath); - ~CodegenModelArchive(); - - // Implementation detail helper, don't use outside - Private& GetPimpl() const { return *m; } - - void DeleteDeclsRelatedToFile(std::string_view filename); - - void Store(const CodegenModel& model); - void LoadInto(CodegenModel& model) const; - CodegenModel Load() const; - - void StoreStruct(const DeclStruct& decl); - void StoreFunction(const DeclFunction& decl); - void StoreEnum(const DeclEnum& decl); -}; diff --git a/source/20-codegen-compiler/CodegenOutput.cpp b/source/20-codegen-compiler/CodegenOutput.cpp index ccd163c..d85feac 100644 --- a/source/20-codegen-compiler/CodegenOutput.cpp +++ b/source/20-codegen-compiler/CodegenOutput.cpp @@ -8,15 +8,22 @@ void CodegenOutput::AddRequestInclude(std::string_view include) { } } -void CodegenOutput::AddOutputThing(CodegenOutputThing thing) { - mOutThings.push_back(std::move(thing)); +void CodegenOutput::AddOutputThing(CodegenOutputThing thing, int placementLocation) { + if (placementLocation < 0 || placementLocation >= mOutThings.size()) { + mOutThings.push_back(std::move(thing)); + } else { + int maxIndex = (int)mOutThings.size() - 1; + if (placementLocation > maxIndex) { + placementLocation = maxIndex; + } + + auto placementIter = mOutThings.begin() + placementLocation; + mOutThings.insert(placementIter, std::move(thing)); + } } void CodegenOutput::MergeContents(CodegenOutput other) { std::move(other.mOutThings.begin(), other.mOutThings.end(), std::back_inserter(this->mOutThings)); - std::move(other.mOutStructs.begin(), other.mOutStructs.end(), std::back_inserter(this->mOutStructs)); - std::move(other.mOutEnums.begin(), other.mOutEnums.end(), std::back_inserter(this->mOutEnums)); - std::move(other.mOutFunctions.begin(), other.mOutFunctions.end(), std::back_inserter(this->mOutFunctions)); } void CodegenOutput::Write(FILE* file) const { @@ -29,18 +36,4 @@ void CodegenOutput::Write(FILE* file) const { fwrite(thing.text.c_str(), sizeof(char), thing.text.size(), file); WRITE_LIT(file, "\n"); } - - for (auto& declStruct : mOutStructs) { - WRITE_FMT_LN(file, "struct %s {", declStruct.name.c_str()); - // TODO - WRITE_LIT_LN(file, "};"); - } - - for (auto& declEnum : mOutEnums) { - // TODO - } - - for (auto& declFunc : mOutFunctions) { - // TODO - } } diff --git a/source/20-codegen-compiler/CodegenOutput.hpp b/source/20-codegen-compiler/CodegenOutput.hpp index aa28715..df949f5 100644 --- a/source/20-codegen-compiler/CodegenOutput.hpp +++ b/source/20-codegen-compiler/CodegenOutput.hpp @@ -1,7 +1,5 @@ #pragma once -#include "CodegenDecl.hpp" - #include <Utils.hpp> #include <robin_hood.h> @@ -20,9 +18,6 @@ class CodegenOutput { private: robin_hood::unordered_set<std::string, StringHash, StringEqual> mRequestIncludes; std::vector<CodegenOutputThing> mOutThings; - std::vector<DeclStruct> mOutStructs; - std::vector<DeclEnum> mOutEnums; - std::vector<DeclFunction> mOutFunctions; public: std::string optionOutPrefix; @@ -31,7 +26,7 @@ public: public: void AddRequestInclude(std::string_view include); - void AddOutputThing(CodegenOutputThing thing); + void AddOutputThing(CodegenOutputThing thing, int placementLocation = -1); void MergeContents(CodegenOutput other); diff --git a/source/20-codegen-compiler/CodegenUtils.cpp b/source/20-codegen-compiler/CodegenUtils.cpp index 415a183..5bc5d79 100644 --- a/source/20-codegen-compiler/CodegenUtils.cpp +++ b/source/20-codegen-compiler/CodegenUtils.cpp @@ -7,13 +7,17 @@ #include <cstdio> #include <cstdlib> +using namespace std::literals; + bool Utils::WriteOutputFile(const CodegenOutput& output, const char* path) { auto outputFile = Utils::OpenCstdioFile(path, Utils::WriteTruncate); if (!outputFile) { printf("[ERROR] unable to open output file %s\n", path); return false; } - DEFER { fclose(outputFile); }; + DEFER { + fclose(outputFile); + }; DEBUG_PRINTF("Writing output %s\n", path); output.Write(outputFile); @@ -21,32 +25,59 @@ bool Utils::WriteOutputFile(const CodegenOutput& output, const char* path) { return true; } -std::string Utils::MakeFullName(std::string_view name, DeclNamespace* ns) { +std::string Utils::JoinNames(DeclNamespace* ns, std::string_view prefix, std::string_view suffix, std::string_view delimiter) { size_t length = 0; - std::vector<std::string_view> components; - if (!name.empty()) { - components.push_back(name); - length += name.length(); + if (!prefix.empty()) { + length += prefix.length() + delimiter.length(); } + if (!suffix.empty()) { + length += suffix.length() + delimiter.length(); + } + size_t nsCount = 0; + { + DeclNamespace* curr = ns; + while (curr) { + length += curr->name.length() + delimiter.length(); - DeclNamespace* currentNamespace = ns; - while (currentNamespace) { - components.push_back(currentNamespace->name); - length += currentNamespace->name.size() + /*::*/ 2; - currentNamespace = currentNamespace->container; + curr = curr->container; + ++nsCount; + } } + length -= delimiter.length(); - std::string fullname; - fullname.reserve(length); - for (auto it = components.rbegin(); it != components.rend(); ++it) { - fullname += *it; - fullname += "::"; + std::string joined; + joined.reserve(length); + + if (!prefix.empty()) { + joined += prefix; + joined += delimiter; } - // Get rid of the last "::" - fullname.pop_back(); - fullname.pop_back(); + { + DeclNamespace* curr = ns; + size_t i = 0; + while (curr) { + joined += curr->name; + if (!suffix.empty() || i != (nsCount - 1)) { + joined += delimiter; + } - return fullname; + curr = curr->container; + ++i; + } + } + if (!suffix.empty()) { + joined += suffix; + } + + return joined; +} + +std::string Utils::MakeFullName(std::string_view name, DeclNamespace* ns) { + return JoinNames(ns, ""sv, name, "::"sv); +} + +std::string Utils::MakeMangledName(std::string_view name, DeclNamespace* ns) { + return JoinNames(ns, ""sv, name, "_"sv); } // NOTE: assuming we are only dealing with ASCII characters @@ -119,7 +150,6 @@ void Utils::ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& he CodegenOutputThing headerOut; headerOut.text += &R"""( // This file is generated. Any changes will be overidden when building. -#pragma once #include <MetadataBase.hpp> #include <cstddef> #include <cstdint> @@ -129,13 +159,13 @@ void Utils::ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& he APPEND_LIT_LN(sourceOut.text, "// This file is generated. Any changes will be overidden when building."); APPEND_FMT_LN(sourceOut.text, "#include \"%s\"", headerFilename); sourceOut.text += &R"""( -#include <MetadataDetails.hpp> #include <frozen/string.h> #include <frozen/unordered_map.h> +#include <MetadataDetails.hpp> using namespace std::literals; using namespace Metadata; )"""[1]; - header.AddOutputThing(std::move(headerOut)); - source.AddOutputThing(std::move(sourceOut)); + header.AddOutputThing(std::move(headerOut), 0); + source.AddOutputThing(std::move(sourceOut), 0); } diff --git a/source/20-codegen-compiler/CodegenUtils.hpp b/source/20-codegen-compiler/CodegenUtils.hpp index be62f1e..2d5b684 100644 --- a/source/20-codegen-compiler/CodegenUtils.hpp +++ b/source/20-codegen-compiler/CodegenUtils.hpp @@ -5,6 +5,7 @@ #include "CodegenOutput.hpp" #include <algorithm> +#include <string> #include <string_view> // I give up, hopefully nothing overflows this buffer @@ -44,7 +45,10 @@ namespace Utils { bool WriteOutputFile(const CodegenOutput& output, const char* path); +std::string JoinNames(DeclNamespace* ns, std::string_view prefix, std::string_view suffix, std::string_view delimiter); std::string MakeFullName(std::string_view name, DeclNamespace* ns = nullptr); +std::string MakeMangledName(std::string_view name, DeclNamespace* ns = nullptr); + std::vector<std::string_view> SplitIdentifier(std::string_view name); std::string MakePascalCase(std::string_view name); diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp index 5350f8e..af51900 100644 --- a/source/20-codegen-compiler/main.cpp +++ b/source/20-codegen-compiler/main.cpp @@ -2,7 +2,6 @@ #include "CodegenDecl.hpp" #include "CodegenLexer.hpp" #include "CodegenModel.hpp" -#include "CodegenModelArchive.hpp" #include "CodegenOutput.hpp" #include "CodegenUtils.hpp" @@ -30,9 +29,12 @@ namespace fs = std::filesystem; // TOOD maybe switch to libclang, maintaining this parser is just too painful struct AppState { - CodegenModel* model; - CodegenModelArchive* modelArchive; - robin_hood::unordered_map<std::string, SourceFile, StringHash, StringEqual> sourceFiles; + CodegenRuntimeModel* runtimeModel; + CodegenArchiveModel* archiveModel; + // NOTE: decl objects reference the SourceFile objects by pointer + robin_hood::unordered_node_map<std::string, SourceFile, StringHash, StringEqual> sourceFiles; + std::vector<DeclEnum*> enumsToRevisit; + std::vector<DeclStruct*> structsToRevisit; std::string_view outputDir; std::string_view databaseFilePath; @@ -42,10 +44,11 @@ struct AppState { return iter->second; } else { auto [iter, success] = sourceFiles.try_emplace(std::string(filename), SourceFile{}); - auto& filename = iter->first; // NOTE: shadows the parameter `filename` - auto& sourceFile = iter->second; - sourceFile.filename = filename; - return sourceFile; + // NOTE: "persistent" means pointer stable below + auto& persistentFilename = iter->first; + auto& persistentSourceFile = iter->second; + persistentSourceFile.filename = persistentFilename; + return persistentSourceFile; } } }; @@ -536,11 +539,13 @@ void GenerateForClassMetadata( if (!decl.baseClasses.empty()) { // Forward declare the variables (which may appear before this section, after this section, or in another TU) for (auto& baseClass : decl.baseClasses) { - APPEND_FMT_LN(data.text, "extern const TypeInfo gCGtype_%s_TypeInfo;", declIdName); + auto baseClassIdName = baseClass->name.c_str(); + APPEND_FMT_LN(data.text, "extern const TypeInfo gCGtype_%s_TypeInfo;", baseClassIdName); } APPEND_FMT_LN(data.text, "const TypeInfo* const gCGtype_%s_BaseClasses[] = {", declIdName); for (auto& baseClass : decl.baseClasses) { - APPEND_FMT_LN(data.text, "gCGtype_%s_TypeInfo,", declIdName); + auto baseClassIdName = baseClass->name.c_str(); + APPEND_FMT_LN(data.text, "gCGtype_%s_TypeInfo,", baseClassIdName); } APPEND_LIT_LN(data.text, "};"); } @@ -593,10 +598,6 @@ struct ParserState { }; struct ParserOutput { - CodegenOutput headerOutput; - CodegenOutput sourceOutput; - CodegenOutput standaloneSourceOutput; - // Example: // namespace std::details { // /* [stack top].ns = std::details */ @@ -706,11 +707,6 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s // TODO move lexedTokens and consumption related functions to ParserState struct ParserOutput po; - { - INPLACE_FMT(hpp, "%.*s.gh.inl", PRINTF_STRING_VIEW(filenameStem)); - INPLACE_FMT(cpp, "%.*s.gs.inl", PRINTF_STRING_VIEW(filenameStem)); - Utils::ProduceGeneratedHeader(hpp, po.headerOutput, cpp, po.sourceOutput); - } auto& tokens = ls.tokens; auto& idx = ls.idx; @@ -744,7 +740,7 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s break; } - po.currentNamespace = as.model->AddNamespace(DeclNamespace{ + po.currentNamespace = as.runtimeModel->AddNamespace(DeclNamespace{ .container = po.currentNamespace, .name = tokens[idx].text, }); @@ -816,8 +812,10 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s // TODO support namespace qualified names auto baseClassFullname = Utils::MakeFullName(idenTok.text, po.currentNamespace); - auto baseClassDecl = as.model->FindStruct(baseClassFullname); + auto baseClassDecl = as.runtimeModel->FindStruct(baseClassFullname); if (baseClassDecl) { + // TODO retreive class from database + // ---- Or just silent create it, and assume the code was valid? // We silently ignore a non-existent base class, because they may reside in a file that we didn't scan structDecl.baseClasses.push_back(baseClassDecl); } @@ -843,7 +841,7 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s { // Get a pointer to the decl inside CodegenInput's storage - auto decl = as.model->AddStruct(std::move(fullname), std::move(structDecl)); + auto decl = as.runtimeModel->AddStruct(std::move(fullname), std::move(structDecl)); po.currentStruct = decl; po.currentStructBraceDepth = po.currentBraceDepth; } @@ -940,12 +938,16 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s ++idx; } + // if (po.currentEnum->generating) { + // GenerateForEnum(po.headerOutput, po.sourceOutput, *po.currentEnum); + // } if (po.currentEnum->generating) { - GenerateForEnum(po.headerOutput, po.sourceOutput, *po.currentEnum); + as.enumsToRevisit.push_back(po.currentEnum); } { - auto decl = as.model->AddEnum(std::move(fullname), std::move(enumDecl)); + auto decl = as.runtimeModel->AddEnum(std::move(fullname), std::move(enumDecl)); + // Fix pointers po.currentEnum = decl; po.currentEnumBraceDepth = po.currentBraceDepth; } @@ -1069,15 +1071,8 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s // NOTE: intentionally shadowing INPLACE_FMT(getterName, "Get%s", GetPascalCasedName().c_str()); - // TODO work with pass-by-value vs pass-by-reference - // this probably needs libclang to detect the size and existance of trivial copy-ctors - CodegenOutputThing data; - APPEND_FMT_LN(data.text, "const %s& %.*s::%s() const {", decl.type.c_str(), PRINTF_STRING_VIEW(decl.containerStruct->fullname), getterName); - APPEND_FMT_LN(data.text, " return %s;", decl.name.c_str()); - APPEND_LIT_LN(data.text, "}"); - - po.sourceOutput.AddOutputThing(std::move(data)); decl.getterName = getterName; + decl.isGetterGenerated = true; } else { decl.getterName = getterName; } @@ -1090,13 +1085,8 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s // NOTE: intentionally shadowing INPLACE_FMT(setterName, "Set%s", GetPascalCasedName().c_str()); - CodegenOutputThing data; - APPEND_FMT_LN(data.text, "void %.*s::%s(const %s& value) const {", PRINTF_STRING_VIEW(decl.containerStruct->fullname), setterName, decl.type.c_str()); - APPEND_FMT_LN(data.text, " this->%s = value;", decl.name.c_str()); - APPEND_LIT_LN(data.text, "}"); - - po.sourceOutput.AddOutputThing(std::move(data)); decl.setterName = setterName; + decl.isSetterGenerated = true; } else { decl.setterName = setterName; } @@ -1157,11 +1147,7 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s // Exit struct if (po.currentStruct->generating) { - GenerateForClassMetadata(po.headerOutput, po.sourceOutput, *po.currentStruct); - } - if (po.currentStruct->generatingInheritanceHiearchy) { - // NOTE: this option is transitive to all child classes (as long as they have the basic annotation) - // TODO + as.structsToRevisit.push_back(po.currentStruct); } po.currentStruct = nullptr; @@ -1170,6 +1156,11 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s if (po.currentEnum && po.currentBraceDepth == po.currentEnumBraceDepth) { // Exit enum + // TODO this is unused currently, see CKw_Enum branch + if (po.currentEnum->generating) { + as.enumsToRevisit.push_back(po.currentEnum); + } + po.currentEnum = nullptr; po.currentEnumBraceDepth = -1; } @@ -1185,14 +1176,7 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s printf("[WARNING] unbalanced brace at end of file\n"); } - INPLACE_FMT(generatedHeaderInlName, "%.*s/%.*s.gh.inl", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(filenameStem)); - Utils::WriteOutputFile(po.headerOutput, generatedHeaderInlName); - INPLACE_FMT(generatedSourceInlName, "%.*s/%.*s.gs.inl", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(filenameStem)); - Utils::WriteOutputFile(po.sourceOutput, generatedSourceInlName); - INPLACE_FMT(generatedCppName, "%.*s/%.*s.g.cpp", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(filenameStem)); - Utils::WriteOutputFile(po.standaloneSourceOutput, generatedCppName); - - as.modelArchive->DeleteDeclsRelatedToFile(filenameStem); + as.archiveModel->DeleteDeclsRelatedToFile(filenameStem); // as.modelArchive->Store(po.model); } @@ -1346,11 +1330,10 @@ where --output-dir=<path>: the *directory* to write generated contents to. Thi DEBUG_PRINTF("Outputting to directory %.*s.\n", PRINTF_STRING_VIEW(as.outputDir)); DEBUG_PRINTF("Databse file: %.*s.\n", PRINTF_STRING_VIEW(as.databaseFilePath)); - // TODO make every input command share the same CodegenModel // TODO move the actual output logic after processing all input commands, based on SQLite batabase model instead of the in-memory CodegenModel model // this allows better consistency between direct in-file entities (like enums) vs. multi-file entities (like struct inheritance hierarchy) // this would also mean almost rewriting the whole codegen logic, to work on a changelist fetched from SQLite database instead of being embedded inside the parser loop - // TODO how do we detect the case of + // TODO how do we detect the case of // 1. has: Foo.hpp Bar.hpp // 2. struct Foo; struct Bar : Foo; // 3. struct Foo is removed from Foo.hpp, but our parser only recieves Foo.hpp as file changed--and can't figure out that there is still a reference to Foo in Bar.hpp @@ -1358,11 +1341,14 @@ where --output-dir=<path>: the *directory* to write generated contents to. Thi // - use some kind of database scanner to review all references to a class when removing (e.g. detect for logic error on foreign key linked columns) // - follow the file links in database, and propagate parsing to those files in the hierarchy // - pretty much defeats the purpose of using an incremental parser: some classes like GameObject will have links throughout a very large portion of the project code - CodegenModel model; - CodegenModelArchive modelArchive(as.databaseFilePath); + // - [x] out of parser generation + // - [ ] database readback + // - [ ] full database based generation (tentative) + CodegenRuntimeModel runtimeModel; + CodegenArchiveModel archiveModel(as.databaseFilePath); - as.model = &model; - as.modelArchive = &modelArchive; + as.runtimeModel = &runtimeModel; + as.archiveModel = &archiveModel; // Positional argument pass for (int i = 1; i < argc; ++i) { @@ -1383,7 +1369,62 @@ where --output-dir=<path>: the *directory* to write generated contents to. Thi } } - modelArchive.Store(model); + for (auto decl : as.enumsToRevisit) { + auto& headerOutput = decl->sourceFile->postHeaderOutput; + auto& sourceOutput = decl->sourceFile->postSourceOutput; + GenerateForEnum(headerOutput, sourceOutput, *decl); + } + for (auto decl : as.structsToRevisit) { + auto& headerOutput = decl->sourceFile->postHeaderOutput; + auto& sourceOutput = decl->sourceFile->postSourceOutput; + + // Always-on metdata + GenerateForClassMetadata(headerOutput, sourceOutput, *decl); + + if (decl->generatingInheritanceHiearchy) { + // TODO + } + + for (auto& property : decl->memberVariables) { + if (property.isGetterGenerated) { + // TODO work with pass-by-value vs pass-by-reference + // this probably needs libclang to detect the size and existance of trivial copy-ctors + CodegenOutputThing data; + APPEND_FMT_LN(data.text, "const %s& %.*s::%s() const {", property.type.c_str(), PRINTF_STRING_VIEW(property.containerStruct->fullname), property.getterName.c_str()); + APPEND_FMT_LN(data.text, " return %s;", property.name.c_str()); + APPEND_LIT_LN(data.text, "}"); + + sourceOutput.AddOutputThing(std::move(data)); + } + if (property.isSetterGenerated) { + CodegenOutputThing data; + APPEND_FMT_LN(data.text, "void %.*s::%s(const %s& value) const {", PRINTF_STRING_VIEW(property.containerStruct->fullname), property.setterName.c_str(), property.type.c_str()); + APPEND_FMT_LN(data.text, " this->%s = value;", property.name.c_str()); + APPEND_LIT_LN(data.text, "}"); + + sourceOutput.AddOutputThing(std::move(data)); + } + } + for (auto& method : decl->memberFunctions) { + // TODO + } + } + + archiveModel.Store(runtimeModel); + + // Write output files + for (auto&& [_, sourceFile] : as.sourceFiles) { + INPLACE_FMT(hpp, "%.*s.gh.inl", PRINTF_STRING_VIEW(sourceFile.filename)); + INPLACE_FMT(cpp, "%.*s.gs.inl", PRINTF_STRING_VIEW(sourceFile.filename)); + Utils::ProduceGeneratedHeader(hpp, sourceFile.postHeaderOutput, cpp, sourceFile.postSourceOutput); + + INPLACE_FMT(generatedHeaderInlName, "%.*s/%s", PRINTF_STRING_VIEW(as.outputDir), hpp); + Utils::WriteOutputFile(sourceFile.postHeaderOutput, generatedHeaderInlName); + INPLACE_FMT(generatedSourceInlName, "%.*s/%s", PRINTF_STRING_VIEW(as.outputDir), cpp); + Utils::WriteOutputFile(sourceFile.postSourceOutput, generatedSourceInlName); + INPLACE_FMT(generatedCppName, "%.*s/%.*s.g.cpp", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(sourceFile.filename)); + Utils::WriteOutputFile(sourceFile.tuOutput, generatedCppName); + } return 0; } |