aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-07-17 23:09:00 -0700
committerrtk0c <[email protected]>2022-07-17 23:09:00 -0700
commit8c2b1bd5bd85667a2ea24ec3aa85cbdd97f9ea1c (patch)
tree80b12277b667747aa4f18ebcc3931c2ea618cb1e /source
parentc6e57dc94e532442ffa0bd57a16206217adbca92 (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.cpp16
-rw-r--r--source/20-codegen-compiler/CodegenDecl.hpp18
-rw-r--r--source/20-codegen-compiler/CodegenModel.cpp61
-rw-r--r--source/20-codegen-compiler/CodegenModel.hpp32
-rw-r--r--source/20-codegen-compiler/CodegenModelArchive.hpp31
-rw-r--r--source/20-codegen-compiler/CodegenOutput.cpp31
-rw-r--r--source/20-codegen-compiler/CodegenOutput.hpp7
-rw-r--r--source/20-codegen-compiler/CodegenUtils.cpp78
-rw-r--r--source/20-codegen-compiler/CodegenUtils.hpp4
-rw-r--r--source/20-codegen-compiler/main.cpp157
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;
}