aboutsummaryrefslogtreecommitdiff
path: root/source/20-codegen-compiler
diff options
context:
space:
mode:
Diffstat (limited to 'source/20-codegen-compiler')
-rw-r--r--source/20-codegen-compiler/CodegenDecl.hpp12
-rw-r--r--source/20-codegen-compiler/CodegenModel.cpp106
-rw-r--r--source/20-codegen-compiler/CodegenModelArchive.hpp1
-rw-r--r--source/20-codegen-compiler/main.cpp33
-rw-r--r--source/20-codegen-compiler/test/examples/TestEnum.hpp.txt24
5 files changed, 132 insertions, 44 deletions
diff --git a/source/20-codegen-compiler/CodegenDecl.hpp b/source/20-codegen-compiler/CodegenDecl.hpp
index 739dbe4..00fc18e 100644
--- a/source/20-codegen-compiler/CodegenDecl.hpp
+++ b/source/20-codegen-compiler/CodegenDecl.hpp
@@ -5,7 +5,16 @@
// TODO replace std::string name with std::string_view into the token storage?
+struct SourceFile {
+ std::string_view filename; // View into storage map key
+ bool header = false;
+ /// Whether this file is being reprocessed in this invocation of codegen.exe or not.
+ bool reprocessing = false;
+};
+
struct DeclNamespace {
+ // NOTE: namespace doesn't have a source file field, because the same namespace can be "reopened" in multipled files
+
DeclNamespace* container = nullptr;
std::string name;
std::string_view fullname; // View into storage map key
@@ -26,6 +35,7 @@ struct DeclMemberFunction {
// Structs or classes
struct DeclStruct {
+ SourceFile* sourceFile = nullptr;
DeclNamespace* container = nullptr;
std::vector<const DeclStruct*> baseClasses;
std::vector<DeclMemberVariable> memberVariables;
@@ -72,6 +82,7 @@ struct DeclEnumElement {
};
struct DeclEnum {
+ SourceFile* sourceFile = nullptr;
DeclNamespace* container = nullptr;
std::string name;
std::string_view fullname;
@@ -101,6 +112,7 @@ struct DeclFunctionArgument {
};
struct DeclFunction {
+ SourceFile* sourceFile = nullptr;
DeclNamespace* container = nullptr;
// Things like extern, static, etc. that gets written before the function return type
std::string prefix;
diff --git a/source/20-codegen-compiler/CodegenModel.cpp b/source/20-codegen-compiler/CodegenModel.cpp
index 08323bc..4a9a8f8 100644
--- a/source/20-codegen-compiler/CodegenModel.cpp
+++ b/source/20-codegen-compiler/CodegenModel.cpp
@@ -31,7 +31,7 @@ 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 kGlobalNamespaceRowId = 1;
+constexpr int64_t kGlobalNamespaceId = 1;
struct SQLiteDatabase {
sqlite3* database = nullptr;
@@ -49,6 +49,11 @@ struct SQLiteDatabase {
struct SQLiteStatement {
sqlite3_stmt* stmt = nullptr;
+ SQLiteStatement(const SQLiteStatement&) = delete;
+ SQLiteStatement& operator=(const SQLiteStatement&) = delete;
+
+ SQLiteStatement() = default;
+
~SQLiteStatement() {
// NOTE: calling with NULL is a harmless no-op
// NOTE: we don't care about the error code, because they are returned if the statement has errored in the most recent execution
@@ -97,6 +102,8 @@ public:
SQLiteStatement findOrStoreNamespaceStmt;
SQLiteStatement storeEnumStmt;
SQLiteStatement storeEnumElmStmt;
+ SQLiteStatement deleteStructDeclByFilenameStmt;
+ SQLiteStatement deleteEnumDeclByFilenameStmt;
void InitializeCoreStatements() {
char* errMsg = nullptr;
@@ -108,34 +115,45 @@ public:
result = sqlite3_exec(database, R"""(
BEGIN TRANSACTION;
CREATE TABLE Namespaces(
- ParentNamespaceRowId INTEGER REFERENCES Namespaces(rowid),
+ -- NOTE: SQLite forbids foreign keys referencing the implicit `rowid` column, we have to create an alias for it
+ Id INTEGER PRIMARY KEY,
+ ParentNamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
- UNIQUE (ParentNamespaceRowId, Name)
+ UNIQUE (ParentNamespaceId, Name)
);
CREATE TABLE DeclStructs(
- NamespaceRowId INTEGER REFERENCES Namespaces(rowid),
- ParentStructRowId INTEGER REFERENCES DeclStructs(rowid),
+ Id INTEGER PRIMARY KEY,
+ NamespaceId INTEGER REFERENCES Namespaces(Id),
+ ParentStructId INTEGER REFERENCES DeclStructs(Id),
Name TEXT,
- UNIQUE (NamespaceRowId, Name)
+ FileName TEXT,
+ UNIQUE (NamespaceId, Name)
);
CREATE TABLE DeclEnums(
- NamespaceRowId INTEGER REFERENCES Namespaces(rowid),
+ Id INTEGER PRIMARY KEY,
+ NamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
UnderlyingType TEXT,
- UNIQUE (NamespaceRowId, Name)
+ FileName TEXT,
+ UNIQUE (NamespaceId, Name)
);
CREATE TABLE DeclEnumElements(
- EnumRowId INTEGER REFERENCES DeclEnums(rowid),
+ EnumId INTEGER REFERENCES DeclEnums(Id) ON DELETE CASCADE,
Name TEXT,
Value INTEGER,
- UNIQUE (EnumRowId, Name)
+ UNIQUE (EnumId, Name)
);
-INSERT INTO Namespaces(rowid, ParentNamespaceRowId, Name)
+CREATE INDEX Index_DeclStructs_FileName
+ ON DeclStructs(FileName);
+CREATE INDEX Index_DeclEnums_FileName
+ ON DeclEnums(FileName);
+
+INSERT INTO Namespaces(Id, ParentNamespaceId, Name)
VALUES
- -- Special global namespace that has no parent, and rowid should always be 1
+ -- Special global namespace that has no parent, and Id should always be 1
(1, NULL, "<global namespace>");
COMMIT TRANSACTION;
@@ -168,7 +186,7 @@ COMMIT TRANSACTION;
/// \return Row ID of the namespace, or 0 if it currently doesn't exist.
int64_t FindNamespace(const DeclNamespace* ns) {
if (!ns) {
- return kGlobalNamespaceRowId;
+ return kGlobalNamespaceId;
}
InitializeStmt_findNamespaceStmt();
@@ -178,7 +196,7 @@ COMMIT TRANSACTION;
/// \return Row ID of the namespace.
int64_t FindOrStoreNamespace(const DeclNamespace* ns) {
if (!ns) {
- return kGlobalNamespaceRowId;
+ return kGlobalNamespaceId;
}
InitializeStmt_findNamespaceStmt();
@@ -189,15 +207,15 @@ COMMIT TRANSACTION;
private:
void InitializeStmt_findNamespaceStmt() {
findNamespaceStmt.InitializeLazily(database, R"""(
-SELECT rowid FROM Namespaces WHERE ParentNamespaceRowId = ?1 AND Name = ?2;
+SELECT Id FROM Namespaces WHERE ParentNamespaceId = ?1 AND Name = ?2;
)"""sv);
}
void InitializeStmt_findOrStoreNamespaceStmt() {
findOrStoreNamespaceStmt.InitializeLazily(database, R"""(
-INSERT INTO Namespaces(ParentNamespaceRowId, Name)
+INSERT INTO Namespaces(ParentNamespaceId, Name)
VALUES (?1, ?2)
- RETURNING rowid;
+ RETURNING Id;
)"""sv);
}
@@ -210,7 +228,7 @@ INSERT INTO Namespaces(ParentNamespaceRowId, Name)
return 0;
}
} else {
- parentNsRowId = kGlobalNamespaceRowId;
+ parentNsRowId = kGlobalNamespaceId;
}
return FindNamespaceImpl(ns, parentNsRowId);
@@ -239,7 +257,7 @@ INSERT INTO Namespaces(ParentNamespaceRowId, Name)
sqlite3_stmt* stmt = findOrStoreNamespaceStmt;
int64_t parentRowId = ns.container
? FindOrStoreNamespaceImpl(*ns.container)
- : kGlobalNamespaceRowId;
+ : kGlobalNamespaceId;
sqlite3_bind_int64(stmt, 1, parentRowId);
sqlite3_bind_text(stmt, 2, ns.name.c_str(), ns.name.size(), nullptr);
int result = sqlite3_step(stmt);
@@ -367,8 +385,10 @@ CodegenModelArchive::CodegenModelArchive(std::string_view dbPath)
}
}
- // This database is used for a buildsystem and can be regenerated at any time. We don't care for the slightest about data integrity, we just want fast updates
// NOTE: These pragmas are not persistent, so we need to set them every time
+ // SQLite3 as of 2022-06-24 defaults to foreign_keys = OFF, we need this to be on for ON DELETE CASCADE and etc. to work
+ sqlite3_exec(m->database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
+ // This database is used for a buildsystem and can be regenerated at any time. We don't care for the slightest about data integrity, we just want fast updates
sqlite3_exec(m->database, "PRAGMA synchronous = OFF", nullptr, nullptr, nullptr);
sqlite3_exec(m->database, "PRAGMA journal_mode = MEMORY", nullptr, nullptr, nullptr);
@@ -381,6 +401,27 @@ CodegenModelArchive::~CodegenModelArchive() {
delete m;
}
+void CodegenModelArchive::DeleteDeclsRelatedToFile(std::string_view filename) {
+ // -Argument- -Description-
+ // ?1 The filename to delete
+ m->deleteStructDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclStructs WHERE FileName = ?1;"sv);
+ m->deleteEnumDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclEnums WHERE FileName = ?1;"sv);
+
+ m->BeginTransaction();
+ auto stmtList = {
+ m->deleteStructDeclByFilenameStmt.stmt,
+ m->deleteEnumDeclByFilenameStmt.stmt,
+ };
+ for (auto& stmt : stmtList) {
+ sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), nullptr);
+ int result = sqlite3_step(stmt);
+ assert(result == SQLITE_DONE);
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ }
+ m->CommitTransaction();
+}
+
void CodegenModelArchive::Store(const CodegenModel& cgInput) {
auto& cgm = cgInput.GetPimpl();
@@ -425,35 +466,42 @@ void CodegenModelArchive::StoreEnum(const DeclEnum& decl) {
// ?1 Namespace ID
// ?2 Enum name
// ?3 Enum underlying type
+ // ?4 File containing the enum
m->storeEnumStmt.InitializeLazily(m->database, R"""(
-INSERT INTO DeclEnums(NamespaceRowId, Name, UnderlyingType)
- VALUES (?1, ?2, ?3)
- ON CONFLICT DO UPDATE SET UnderlyingType=?3
- RETURNING rowid;
+INSERT INTO DeclEnums(NamespaceId, Name, UnderlyingType, FileName)
+ VALUES (?1, ?2, ?3, ?4)
+ ON CONFLICT DO UPDATE SET
+ UnderlyingType = ?3,
+ FileName = ?4
+ RETURNING Id;
)"""sv);
// -Argument- -Description-
- // ?1 Container enum's rowid
+ // ?1 Container enum's id
// ?2 Enum element name
// ?3 Enum element value
m->storeEnumElmStmt.InitializeLazily(m->database, R"""(
-INSERT INTO DeclEnumElements(EnumRowId, Name, Value)
+INSERT INTO DeclEnumElements(EnumId, Name, Value)
VALUES (?1, ?2, ?3)
ON CONFLICT DO UPDATE SET Value=?3;
)"""sv);
- // TODO delete non-existent enums
sqlite3_bind_int(m->storeEnumStmt, 1, m->FindNamespace(decl.container));
sqlite3_bind_text(m->storeEnumStmt, 2, decl.name.c_str(), decl.name.size(), nullptr);
sqlite3_bind_text(m->storeEnumStmt, 3, decl.underlyingTypeStr.c_str(), decl.underlyingTypeStr.size(), nullptr);
+ if (decl.sourceFile) {
+ sqlite3_bind_text(m->storeEnumStmt, 4, decl.sourceFile->filename.data(), decl.sourceFile->filename.size(), nullptr);
+ } else {
+ sqlite3_bind_text(m->storeEnumElmStmt, 4, "", 0, nullptr);
+ }
int result = sqlite3_step(m->storeEnumStmt);
assert(result == SQLITE_ROW);
- auto enumRowId = sqlite3_column_int64(m->storeEnumStmt, 0);
+ auto EnumId = sqlite3_column_int64(m->storeEnumStmt, 0);
sqlite3_reset(m->storeEnumStmt);
sqlite3_clear_bindings(m->storeEnumStmt);
for (auto& elm : decl.elements) {
- sqlite3_bind_int64(m->storeEnumElmStmt, 1, enumRowId);
+ sqlite3_bind_int64(m->storeEnumElmStmt, 1, EnumId);
sqlite3_bind_text(m->storeEnumElmStmt, 2, elm.name.c_str(), elm.name.size(), nullptr);
sqlite3_bind_int64(m->storeEnumElmStmt, 3, elm.value);
int result = sqlite3_step(m->storeEnumElmStmt);
diff --git a/source/20-codegen-compiler/CodegenModelArchive.hpp b/source/20-codegen-compiler/CodegenModelArchive.hpp
index 0e0e5ad..21cc32c 100644
--- a/source/20-codegen-compiler/CodegenModelArchive.hpp
+++ b/source/20-codegen-compiler/CodegenModelArchive.hpp
@@ -18,6 +18,7 @@ public:
// Implementation detail helper, don't use outside
Private& GetPimpl() const { return *m; }
+ void DeleteDeclsRelatedToFile(std::string_view filename);
void Store(const CodegenModel& cgInput);
void StoreStruct(const DeclStruct& decl);
void StoreFunction(const DeclFunction& decl);
diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp
index 5a59b5d..c393fb0 100644
--- a/source/20-codegen-compiler/main.cpp
+++ b/source/20-codegen-compiler/main.cpp
@@ -30,8 +30,22 @@ namespace fs = std::filesystem;
struct AppState {
/*nullable*/ CodegenModelArchive* modelArchive = nullptr;
+ robin_hood::unordered_map<std::string, SourceFile, StringHash, StringEqual> sourceFiles;
std::string_view outputDir;
std::string_view databaseFilePath;
+
+ SourceFile& GetOrCreateSourceFile(std::string_view filename) {
+ auto iter = sourceFiles.find(filename);
+ if (iter != sourceFiles.end()) {
+ 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;
+ }
+ }
};
FSTR_LUT_DECL(ClexNames, CLEX_eof, CLEX_ext_COUNT) {
@@ -85,21 +99,28 @@ RSTR_LUT_DECL(EnumUnderlyingType, 0, EUT_COUNT) {
RSTR_LUT_MAP_FOR(EnumUnderlyingType);
// Platform-dependent types
- // TODO all of these can be suffixde with "int"
RSTR_LUT_MAP(EUT_Int16, "short");
+ RSTR_LUT_MAP(EUT_Int16, "short int");
RSTR_LUT_MAP(EUT_Uint16, "unsigned short");
+ RSTR_LUT_MAP(EUT_Uint16, "unsigned short int");
RSTR_LUT_MAP(EUT_Int32, "int");
RSTR_LUT_MAP(EUT_Uint32, "unsigned");
RSTR_LUT_MAP(EUT_Uint32, "unsigned int");
#ifdef _WIN32
RSTR_LUT_MAP(EUT_Int32, "long");
+ RSTR_LUT_MAP(EUT_Int32, "long int");
RSTR_LUT_MAP(EUT_Uint32, "unsigned long");
+ RSTR_LUT_MAP(EUT_Uint32, "unsigned long int");
#else
RSTR_LUT_MAP(EUT_Int64, "long");
+ RSTR_LUT_MAP(EUT_Int64, "long int");
RSTR_LUT_MAP(EUT_Uint64, "unsigned long");
+ RSTR_LUT_MAP(EUT_Uint64, "unsigned long int");
#endif
RSTR_LUT_MAP(EUT_Int64, "long long");
+ RSTR_LUT_MAP(EUT_Int64, "long long int");
RSTR_LUT_MAP(EUT_Uint64, "unsigned long long");
+ RSTR_LUT_MAP(EUT_Uint64, "unsigned long long int");
// Sized types
RSTR_LUT_MAP(EUT_Int8, "int8_t");
@@ -279,7 +300,6 @@ found:
}
enum StructMetaGenOptions {
- // TODO how tf do we implement this one: needs full source scanning
SMGO_InheritanceHiearchy,
SMGO_COUNT,
};
@@ -618,6 +638,10 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
printf("END tokens\n");
#endif
+ auto& sourceFile = as.GetOrCreateSourceFile(filenameStem);
+ sourceFile.header = true;
+ sourceFile.reprocessing = true;
+
ParserState ps;
{
INPLACE_FMT(hpp, "%.*s.gh.inl", PRINTF_STRING_VIEW(filenameStem));
@@ -707,6 +731,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
auto& name = idenTok.text;
auto fullname = Utils::MakeFullName(name, ps.currentNamespace);
DeclStruct structDecl;
+ structDecl.sourceFile = &sourceFile;
structDecl.container = ps.currentNamespace;
structDecl.name = name;
@@ -781,6 +806,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
auto& name = tokens[idx].text;
auto fullname = Utils::MakeFullName(name, ps.currentNamespace);
DeclEnum enumDecl;
+ enumDecl.sourceFile = &sourceFile;
enumDecl.container = ps.currentNamespace;
enumDecl.underlyingType = EUT_Int32; // TODO
enumDecl.underlyingTypeStr = "int";
@@ -1070,6 +1096,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
Utils::WriteOutputFile(ps.standaloneSourceOutput, generatedCppName);
if (as.modelArchive) {
+ as.modelArchive->DeleteDeclsRelatedToFile(filenameStem);
as.modelArchive->Store(ps.model);
}
}
@@ -1189,6 +1216,7 @@ where --output-dir=<path>: the *directory* to write generated contents to. Thi
<opcode> is one of:
"single" process this <input path> file only
"rec" starting at the given directory <input path>, recursively process all .h .hpp files
+ "fileList" read <input path> as a text file, and process each line as a separate file path
)"""[1]);
return -1;
}
@@ -1227,7 +1255,6 @@ 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 model archive is broken right now, see each TODO in CodegenModel.cpp
CodegenModelArchive archive(as.databaseFilePath);
as.modelArchive = &archive;
diff --git a/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt b/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
index fea1f6d..428c47f 100644
--- a/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
+++ b/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
@@ -22,23 +22,23 @@ enum CountedEnum {
};
namespace MyNamespace {
-enum class MyNamespacedEnum {
- BRUSSEL_ENUM(ToString, FromString, ExcludeHeuristics)
- MNE_Foo,
- MNE_Bar,
-};
-
-namespace details {
- enum MyNamespacedEnum {
+ enum class MyNamespacedEnum {
BRUSSEL_ENUM(ToString, FromString, ExcludeHeuristics)
MNE_Foo,
MNE_Bar,
};
-}
+
+ namespace details {
+ enum MyNamespacedEnum {
+ BRUSSEL_ENUM(ToString, FromString, ExcludeHeuristics)
+ MNE_Foo,
+ MNE_Bar,
+ };
+ }
}
namespace foo::details {
-enum Enum {
- BRUSSEL_ENUM(ToString, FromString, ExcludeHeuristics)
-};
+ enum Enum {
+ BRUSSEL_ENUM(ToString, FromString, ExcludeHeuristics)
+ };
}