aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/20-codegen-compiler/CodegenLexer.cpp21
-rw-r--r--source/20-codegen-compiler/CodegenLexer.hpp4
-rw-r--r--source/20-codegen-compiler/CodegenModel.cpp83
-rw-r--r--source/20-codegen-compiler/CodegenModelArchive.hpp1
-rw-r--r--source/20-codegen-compiler/CodegenUtils.cpp7
-rw-r--r--source/20-codegen-compiler/CodegenUtils.hpp1
-rw-r--r--source/20-codegen-compiler/main.cpp172
-rw-r--r--source/20-codegen-compiler/test/examples/TestEnum.hpp.txt2
-rw-r--r--source/20-codegen-runtime/MetadataBase.hpp10
-rw-r--r--source/30-game/GameObject.hpp2
-rw-r--r--source/30-game/Level.hpp3
-rw-r--r--source/30-game/Player.hpp6
-rw-r--r--source/30-game/SceneThings.hpp8
13 files changed, 233 insertions, 87 deletions
diff --git a/source/20-codegen-compiler/CodegenLexer.cpp b/source/20-codegen-compiler/CodegenLexer.cpp
index dab6aea..ecb2186 100644
--- a/source/20-codegen-compiler/CodegenLexer.cpp
+++ b/source/20-codegen-compiler/CodegenLexer.cpp
@@ -2,6 +2,14 @@
#include <cassert>
+int StbLexerToken::Reamalgamate() const {
+ if (type == CLEX_ext_single_char) {
+ return text[0];
+ } else {
+ return type;
+ }
+}
+
bool StbTokenIsSingleChar(int lexerToken) {
return lexerToken >= 0 && lexerToken < 256;
}
@@ -10,16 +18,27 @@ bool StbTokenIsMultiChar(int lexerToken) {
return !StbTokenIsMultiChar(lexerToken);
}
-std::string CombineTokens(std::span<const StbLexerToken> tokens) {
+std::string CombineTokens(std::span<const StbLexerToken> tokens, std::string_view separator) {
+ if (tokens.empty()) {
+ return {};
+ }
+
size_t length = 0;
for (auto& token : tokens) {
length += token.text.size();
+ length += separator.size();
}
+ // Intentionally counting an extra separator: leave space for the last append below
+
std::string result;
result.reserve(length);
for (auto& token : tokens) {
result += token.text;
+ result += separator;
}
+ // Remove the trailing separator
+ result.resize(result.size() - separator.size());
+
return result;
}
diff --git a/source/20-codegen-compiler/CodegenLexer.hpp b/source/20-codegen-compiler/CodegenLexer.hpp
index 76adce6..ec8c8b7 100644
--- a/source/20-codegen-compiler/CodegenLexer.hpp
+++ b/source/20-codegen-compiler/CodegenLexer.hpp
@@ -25,11 +25,13 @@ struct StbLexerToken {
// Can either be CLEX_* or CLEX_ext_* values
int type;
+
+ int Reamalgamate() const;
};
bool StbTokenIsSingleChar(int lexerToken);
bool StbTokenIsMultiChar(int lexerToken);
-std::string CombineTokens(std::span<const StbLexerToken> tokens);
+std::string CombineTokens(std::span<const StbLexerToken> tokens, std::string_view separator = {});
struct CodegenLexer {
std::vector<StbLexerToken> tokens;
diff --git a/source/20-codegen-compiler/CodegenModel.cpp b/source/20-codegen-compiler/CodegenModel.cpp
index 97a53b8..943d72c 100644
--- a/source/20-codegen-compiler/CodegenModel.cpp
+++ b/source/20-codegen-compiler/CodegenModel.cpp
@@ -110,19 +110,26 @@ public:
SQLiteStatement deleteStructDeclByFilenameStmt;
SQLiteStatement deleteEnumDeclByFilenameStmt;
- void InitializeCoreStatements() {
+ void InitializeDatabase() {
char* errMsg = nullptr;
int result = sqlite3_exec(database, "PRAGMA user_version = " STRINGIFY(CURRENT_DATABASE_VERSION), nullptr, nullptr, &errMsg);
PrintErrMsgIfPresent(errMsg);
assert(result == SQLITE_OK);
+ // TODO create a table of file names
// TODO unique with overloading, and container structs
result = sqlite3_exec(database, R"""(
BEGIN TRANSACTION;
-CREATE TABLE Namespaces(
+CREATE TABLE Files(
-- NOTE: SQLite forbids foreign keys referencing the implicit `rowid` column, we have to create an alias for it
Id INTEGER PRIMARY KEY,
+ FileName TEXT,
+ UNIQUE (FileName)
+);
+
+CREATE TABLE Namespaces(
+ Id INTEGER PRIMARY KEY,
ParentNamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
UNIQUE (ParentNamespaceId, Name)
@@ -132,7 +139,7 @@ CREATE TABLE DeclFunctions(
Id INTEGER PRIMARY KEY,
NamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
- FileName TEXT
+ FileId INTEGER REFERENCES Files(Id)
);
CREATE TABLE DeclFunctionParameters(
FunctionId INTEGER REFERENCES DeclFunctions(Id) ON DELETE CASCADE,
@@ -145,7 +152,7 @@ CREATE TABLE DeclStructs(
Id INTEGER PRIMARY KEY,
NamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
- FileName TEXT,
+ FileId INTEGER REFERENCES Files(Id),
IsMetadataMarked INTEGER
);
CREATE TABLE DeclStructBaseClassRelations(
@@ -186,7 +193,7 @@ CREATE TABLE DeclEnums(
NamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
UnderlyingType TEXT,
- FileName TEXT
+ FileId INTEGER REFERENCES Files(Id)
);
CREATE TABLE DeclEnumElements(
EnumId INTEGER REFERENCES DeclEnums(Id) ON DELETE CASCADE,
@@ -195,9 +202,9 @@ CREATE TABLE DeclEnumElements(
UNIQUE (EnumId, Name)
);
-CREATE INDEX Index_DeclFunctions_FileName ON DeclFunctions(FileName);
-CREATE INDEX Index_DeclStructs_FileName ON DeclStructs(FileName);
-CREATE INDEX Index_DeclEnums_FileName ON DeclEnums(FileName);
+CREATE INDEX Index_DeclFunctions_FileId ON DeclFunctions(FileId);
+CREATE INDEX Index_DeclStructs_FileId ON DeclStructs(FileId);
+CREATE INDEX Index_DeclEnums_FileId ON DeclEnums(FileId);
CREATE UNIQUE INDEX Index_DeclFunctions_Identity ON DeclFunctions(NamespaceId, Name);
@@ -439,7 +446,7 @@ CodegenModelArchive::CodegenModelArchive(std::string_view dbPath)
if (currentDatabaseVersion == 0) {
// Newly created database, initialize it
- m->InitializeCoreStatements();
+ m->InitializeDatabase();
} else if (currentDatabaseVersion == CURRENT_DATABASE_VERSION) {
// Same version, no need to do anything
} else {
@@ -448,6 +455,7 @@ CodegenModelArchive::CodegenModelArchive(std::string_view dbPath)
}
}
+ // Initialize core statements
m->beginTransactionStmt.InitializeLazily(m->database, "BEGIN TRANSACTION");
m->commitTransactionStmt.InitializeLazily(m->database, "COMMIT TRANSACTION");
m->rollbackTransactionStmt.InitializeLazily(m->database, "ROLLBACK TRANSACTION");
@@ -460,9 +468,9 @@ CodegenModelArchive::~CodegenModelArchive() {
void CodegenModelArchive::DeleteDeclsRelatedToFile(std::string_view filename) {
// -Argument- -Description-
// ?1 The filename to delete
- m->deleteFunctionDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclFunctions WHERE FileName = ?1"sv);
- 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->deleteFunctionDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclFunctions WHERE FileId = (SELECT Id FROM Files WHERE FileName = ?1)"sv);
+ m->deleteStructDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclStructs WHERE FileId = (SELECT Id FROM Files WHERE FileName = ?1);"sv);
+ m->deleteEnumDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclEnums WHERE FileId = (SELECT Id FROM Files WHERE FileName = ?1);"sv);
m->BeginTransaction();
auto stmtList = {
@@ -517,11 +525,16 @@ void CodegenModelArchive::StoreStruct(const DeclStruct& decl) {
// ?2 Struct name
// ?3 File containing the struct
m->storeStructStmt.InitializeLazily(m->database, R"""(
-INSERT INTO DeclStructs(NamespaceId, Name, FileName, IsMetadataMarked)
- VALUES (?1, ?2, ?3, TRUE)
- ON CONFLICT DO UPDATE SET
- FileName = ?3
- RETURNING Id
+INSERT OR IGNORE INTO Files(FileName)
+VALUES (?3);
+
+WITH
+ const AS (SELECT Id AS fileId FROM Files WHERE FileName = ?3)
+INSERT INTO DeclStructs(NamespaceId, Name, FileId, IsMetadataMarked)
+VALUES (?1, ?2, const.fileId, TRUE)
+ON CONFLICT DO UPDATE SET
+ FileId = const.fileId
+RETURNING Id
)"""sv);
// -Argument- -Description-
@@ -530,7 +543,7 @@ INSERT INTO DeclStructs(NamespaceId, Name, FileName, IsMetadataMarked)
// ?3 Parent struct's name
m->storeStructBaseClassStmt.InitializeLazily(m->database, R"""(
INSERT INTO DeclStructBaseClassRelations(StructId, ParentStructNamespaceId, ParentStructName)
- VALUES (?1, ?2, ?3)
+VALUES (?1, ?2, ?3)
)"""sv);
// -Argument- -Description-
@@ -541,9 +554,11 @@ INSERT INTO DeclStructBaseClassRelations(StructId, ParentStructNamespaceId, Pare
// ?5 Setter name (optional)
m->storeStructPropertyStmt.InitializeLazily(m->database, R"""(
INSERT INTO DeclStructProperties(StructId, Name, Type, GetterName, SetterName, IsMetadataMarked)
- VALUES (?1, ?2, ?3, ?4, ?5, TRUE)
+VALUES (?1, ?2, ?3, ?4, ?5, TRUE)
)"""sv);
+ int result;
+
sqlite3_bind_int64(m->storeStructStmt, 1, m->FindNamespace(decl.container));
sqlite3_bind_text(m->storeStructStmt, 2, decl.name.c_str(), decl.name.size(), nullptr);
if (decl.sourceFile) {
@@ -551,7 +566,8 @@ INSERT INTO DeclStructProperties(StructId, Name, Type, GetterName, SetterName, I
} else {
sqlite3_bind_text(m->storeStructStmt, 3, "", 0, nullptr);
}
- int result = sqlite3_step(m->storeStructStmt);
+ result = sqlite3_step(m->storeStructStmt);
+ result = sqlite3_step(m->storeStructStmt);
assert(result == SQLITE_ROW);
int64_t structId = sqlite3_column_int64(m->storeStructStmt, 0);
sqlite3_reset(m->storeStructStmt);
@@ -594,13 +610,19 @@ void CodegenModelArchive::StoreEnum(const DeclEnum& decl) {
// ?2 Enum name
// ?3 Enum underlying type
// ?4 File containing the enum
+ // TODO this is breaking sqlite: cannot find const.fileId
m->storeEnumStmt.InitializeLazily(m->database, R"""(
-INSERT INTO DeclEnums(NamespaceId, Name, UnderlyingType, FileName)
- VALUES (?1, ?2, ?3, ?4)
- ON CONFLICT DO UPDATE SET
- UnderlyingType = ?3,
- FileName = ?4
- RETURNING Id
+INSERT OR IGNORE INTO Files(FileName)
+VALUES (?4);
+
+WITH
+ const AS (SELECT Id AS fileId FROM Files WHERE FileName = ?4)
+INSERT INTO DeclEnums(NamespaceId, Name, UnderlyingType, FileId)
+VALUES (?1, ?2, ?3, const.fileId)
+ON CONFLICT DO UPDATE SET
+ UnderlyingType = ?3,
+ FileId = const.fileId
+RETURNING Id
)"""sv);
// -Argument- -Description-
@@ -609,10 +631,12 @@ INSERT INTO DeclEnums(NamespaceId, Name, UnderlyingType, FileName)
// ?3 Enum element value
m->storeEnumElmStmt.InitializeLazily(m->database, R"""(
INSERT INTO DeclEnumElements(EnumId, Name, Value)
- VALUES (?1, ?2, ?3)
- ON CONFLICT DO UPDATE SET Value=?3
+VALUES (?1, ?2, ?3)
+ON CONFLICT DO UPDATE SET Value=?3
)"""sv);
+ int result;
+
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);
@@ -621,7 +645,8 @@ INSERT INTO DeclEnumElements(EnumId, Name, Value)
} else {
sqlite3_bind_text(m->storeEnumStmt, 4, "", 0, nullptr);
}
- int result = sqlite3_step(m->storeEnumStmt);
+ result = sqlite3_step(m->storeEnumStmt);
+ result = sqlite3_step(m->storeEnumStmt);
assert(result == SQLITE_ROW);
auto enumId = sqlite3_column_int64(m->storeEnumStmt, 0);
sqlite3_reset(m->storeEnumStmt);
diff --git a/source/20-codegen-compiler/CodegenModelArchive.hpp b/source/20-codegen-compiler/CodegenModelArchive.hpp
index 21cc32c..f548048 100644
--- a/source/20-codegen-compiler/CodegenModelArchive.hpp
+++ b/source/20-codegen-compiler/CodegenModelArchive.hpp
@@ -5,6 +5,7 @@
#include <sqlite3.h>
#include <string_view>
+#include <cstdint>
class CodegenModelArchive {
private:
diff --git a/source/20-codegen-compiler/CodegenUtils.cpp b/source/20-codegen-compiler/CodegenUtils.cpp
index 0c70cb6..415a183 100644
--- a/source/20-codegen-compiler/CodegenUtils.cpp
+++ b/source/20-codegen-compiler/CodegenUtils.cpp
@@ -133,14 +133,9 @@ void Utils::ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& he
#include <frozen/string.h>
#include <frozen/unordered_map.h>
using namespace std::literals;
+using namespace Metadata;
)"""[1];
header.AddOutputThing(std::move(headerOut));
source.AddOutputThing(std::move(sourceOut));
}
-
-void Utils::ProduceClassTypeInfo(CodegenOutput& source, std::string_view className, const DeclNamespace* ns) {
- CodegenOutputThing thing;
-
- source.AddOutputThing(std::move(thing));
-}
diff --git a/source/20-codegen-compiler/CodegenUtils.hpp b/source/20-codegen-compiler/CodegenUtils.hpp
index 62d5400..be62f1e 100644
--- a/source/20-codegen-compiler/CodegenUtils.hpp
+++ b/source/20-codegen-compiler/CodegenUtils.hpp
@@ -49,6 +49,5 @@ std::vector<std::string_view> SplitIdentifier(std::string_view name);
std::string MakePascalCase(std::string_view name);
void ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& header, const char* sourceFilename, CodegenOutput& source);
-void ProduceClassTypeInfo(CodegenOutput& source, std::string_view className, const DeclNamespace* ns = nullptr);
} // namespace Utils
diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp
index 2068962..e9a449c 100644
--- a/source/20-codegen-compiler/main.cpp
+++ b/source/20-codegen-compiler/main.cpp
@@ -27,9 +27,10 @@ using namespace std::literals;
namespace fs = std::filesystem;
// TODO support codegen target in .cpp files
+// TOOD maybe switch to libclang, maintaining this parser is just too painful
struct AppState {
- /*nullable*/ CodegenModelArchive* modelArchive = nullptr;
+ CodegenModelArchive* modelArchive;
robin_hood::unordered_map<std::string, SourceFile, StringHash, StringEqual> sourceFiles;
std::string_view outputDir;
std::string_view databaseFilePath;
@@ -149,6 +150,8 @@ enum CppKeyword {
CKw_Protected,
CKw_Private,
CKw_Virtual,
+ CKw_Using,
+ CKw_Template,
CKw_COUNT,
};
@@ -162,6 +165,8 @@ RSTR_LUT_DECL(CppKeyword, 0, CKw_COUNT) {
RSTR_LUT_MAP(CKw_Protected, "protected");
RSTR_LUT_MAP(CKw_Private, "private");
RSTR_LUT_MAP(CKw_Virtual, "virtual");
+ RSTR_LUT_MAP(CKw_Using, "using");
+ RSTR_LUT_MAP(CKw_Template, "template");
}
enum CodegenDirective {
@@ -299,6 +304,30 @@ found:
return result;
}
+EnumUnderlyingType TryConsumeEnumUnderlyingType(CodegenLexer& lexer) {
+ // Try 1, 2, 3, 4 tokens from the current position
+ // NOTE: see the FSTR map initialization code for reference that there is max 4 tokens
+ for (int i = 4; i >= 1; --i) {
+ auto text = CombineTokens(std::span(&lexer.Current(), i), " "sv);
+ auto iter = RSTR_LUT(EnumUnderlyingType).find(text);
+ if (iter != RSTR_LUT(EnumUnderlyingType).end()) {
+ lexer.idx += i;
+ return iter->second;
+ }
+ }
+ return EUT_COUNT;
+}
+
+// Also includes the ':' token in the front
+EnumUnderlyingType TryConsumeEnumUnderlyingTypeClause(CodegenLexer& lexer) {
+ if (lexer.Current().text != ":") {
+ return EUT_COUNT;
+ }
+
+ ++lexer.idx;
+ return TryConsumeEnumUnderlyingType(lexer);
+}
+
enum StructMetaGenOptions {
SMGO_InheritanceHiearchy,
SMGO_COUNT,
@@ -445,7 +474,7 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
{
auto& o = lookupTable.text;
// TODO use correct underlying type
- APPEND_FMT_LN(o, "constinit frozen::unordered_map<frozen::string, uint64_t, %" PRId64 "> %s = {", filteredElements.size(), str2ValName);
+ APPEND_FMT_LN(o, "constinit frozen::unordered_map<frozen::string, %s, %" PRId64 "> %s = {", decl.underlyingTypeStr.c_str(), filteredElements.size(), str2ValName);
for (auto& elm : filteredElements) {
APPEND_FMT_LN(o, "{\"%s\", %" PRId64 "},", elm.name.c_str(), elm.value);
}
@@ -481,7 +510,11 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
}
void GenerateClassProperty(CodegenOutput& headerOutput, CodegenOutput& sourceOutput) {
- // TODO
+ CodegenOutputThing thing;
+ APPEND_FMT_LN(thing.text, "TypePropertyInfo gCGtype_%s_%s_Property = {", "TODO", "TODO");
+ APPEND_LIT_LN(thing.text, "};");
+
+ sourceOutput.AddOutputThing(std::move(thing));
}
void GenerateClassFunction(CodegenOutput& headerOutput, CodegenOutput& sourceOutput) {
@@ -498,20 +531,41 @@ void GenerateForClassMetadata(
CodegenOutputThing data;
// TODO generate type id, this needs global scanning
- APPEND_FMT_LN(data.text, "const TypeInfo* const gCGtype_%s_BaseClasses[] = {", declIdName);
- for (auto& baseClass : decl.baseClasses) {
- // TODO get ptr to TypeInfo, this needs global scanning for non-file local classes
+
+ 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);
+ }
+ 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);
+ }
+ APPEND_LIT_LN(data.text, "};");
}
- APPEND_LIT_LN(data.text, "};");
- APPEND_FMT_LN(data.text, "const TypePropertyInfo gCGtype_%s_Properties[] = {", declIdName);
- for (auto& property : decl.memberVariables) {
- APPEND_FMT_LN(data.text, "{.name=\"%s\"sv, .getterName=\"%s\"sv, .setterName=\"%s\"sv},", property.name.c_str(), property.getterName.c_str(), property.setterName.c_str());
+
+ if (!decl.memberVariables.empty()) {
+ APPEND_FMT_LN(data.text, "const TypePropertyInfo gCGtype_%s_Properties[] = {", declIdName);
+ for (auto& property : decl.memberVariables) {
+ APPEND_FMT_LN(data.text, "{.name=\"%s\"sv, .getterName=\"%s\"sv, .setterName=\"%s\"sv},", property.name.c_str(), property.getterName.c_str(), property.setterName.c_str());
+ }
+ APPEND_LIT_LN(data.text, "};");
}
- APPEND_LIT_LN(data.text, "};");
+
+ if (!decl.memberFunctions.empty()) {
+ APPEND_FMT_LN(data.text, "const TypeMethodInfo gCGtype_%s_Methods[] = {", declIdName);
+ for (auto& method : decl.memberFunctions) {
+ // TODO
+ }
+ APPEND_LIT_LN(data.text, "};");
+ }
+
APPEND_FMT_LN(data.text, "const TypeInfo gCGtype_%s_TypeInfo = {", declIdName);
APPEND_FMT_LN(data.text, ".name = \"%s\"sv,", declIdName);
- APPEND_FMT_LN(data.text, ".parents = gCGtype_%s_BaseClasses,", declIdName);
- APPEND_FMT_LN(data.text, ".properties = gCGtype_%s_Properties};", declIdName);
+ if (!decl.baseClasses.empty()) APPEND_FMT_LN(data.text, ".parents = gCGtype_%s_BaseClasses,", declIdName);
+ if (!decl.memberVariables.empty()) APPEND_FMT_LN(data.text, ".properties = gCGtype_%s_Properties,", declIdName);
+ if (!decl.memberFunctions.empty()) APPEND_FMT_LN(data.text, ".methods = gCGtype_%s_Methods,", declIdName);
+ APPEND_LIT_LN(data.text, "};");
CodegenOutputThing queryFunc;
APPEND_FMT(queryFunc.text,
@@ -664,16 +718,7 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
auto& token = ls.Current();
bool incrementTokenIdx = true;
-
- // Reamalgamate token type and single char tokens
- int tokenKey;
- if (token.type == CLEX_ext_single_char) {
- tokenKey = token.text[0];
- } else {
- tokenKey = token.type;
- }
-
- switch (tokenKey) {
+ switch (token.Reamalgamate()) {
case CLEX_id: {
CppKeyword keyword;
{
@@ -797,6 +842,11 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
}
case CKw_Enum: {
+ if (po.currentStruct) {
+ // TODO parsing enums inside classes is currently broken (1. model database is not modeled for this 2. codegen logic is not modeled)
+ break;
+ }
+
// Consume the "enum" keyword
++idx;
incrementTokenIdx = false;
@@ -817,9 +867,8 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
DeclEnum enumDecl;
enumDecl.sourceFile = &sourceFile;
enumDecl.container = po.currentNamespace;
- enumDecl.underlyingType = EUT_Int32; // TODO
- enumDecl.underlyingTypeStr = "int";
enumDecl.name = name;
+ // Setting underlying type: see below
// Temporarily bind the pointers to local variable, HandleDirectiveEnum() and other functions expect these to the set
po.currentEnum = &enumDecl;
@@ -828,11 +877,26 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
// Consume the enum name identifier
++idx;
+ // Setting underlying type
+ // NOTE: these two variables are only valid if we enter the EUT found branch
+ size_t eutClauseBegin = idx + /* The ':' token */ 1;
+ size_t eutClauseEnd;
+ if (auto eut = TryConsumeEnumUnderlyingTypeClause(ls);
+ eut != EUT_COUNT)
+ {
+ eutClauseEnd = idx;
+ enumDecl.underlyingType = eut;
+ enumDecl.underlyingTypeStr = CombineTokens(std::span(tokens.begin() + eutClauseBegin, eutClauseEnd - eutClauseBegin), " "sv);
+ } else {
+ enumDecl.underlyingType = EUT_Int32;
+ enumDecl.underlyingTypeStr = "int";
+ }
+
int enumClosingBraceCount = 0;
int enumBraceDepth = 0;
while (enumClosingBraceCount == 0 && idx < tokens.size()) {
auto& token = tokens[idx];
- switch (token.type) {
+ switch (token.Reamalgamate()) {
case CLEX_id: {
if (token.text == "BRUSSEL_ENUM") {
// Consume the argument list and skip advancing index: this function already consumed all the tokens about BRUSSEL_ENUM
@@ -858,17 +922,13 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
}
} break;
- case CLEX_ext_single_char: {
- switch (token.text[0]) {
- case '{': {
- ++enumBraceDepth;
- } break;
+ case '{': {
+ ++enumBraceDepth;
+ } break;
- case '}': {
- --enumBraceDepth;
- ++enumClosingBraceCount;
- } break;
- }
+ case '}': {
+ --enumBraceDepth;
+ ++enumClosingBraceCount;
} break;
}
@@ -892,6 +952,18 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
goto endCaseCLEX_id;
}
+ // Consume the whole statement, because this statement may contain `enum` or `class` keywords that will pollute the parser
+ case CKw_Template: {
+ // `template` is either a template list which we don't care about, or a part of a type which we don't care about,
+ // unless it's a part of a function declaration, where the tokens are handled inside CG_ClassMethod parsing
+ // TODO handle nested templates or operator> inside template expression
+ ls.SkipUntilTokenSingleChar('>');
+ } break;
+ case CKw_Using: {
+ // `using` indicates a type alias or namespace import which we don't care about
+ ls.SkipUntilTokenSingleChar(';');
+ } break;
+
// We don't care about these keywords
case CKw_Public:
case CKw_Protected:
@@ -963,6 +1035,7 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
break;
}
auto& decl = declOpt.value();
+ decl.containerStruct = po.currentStruct;
// Different option's common logic
std::string pascalCaseName;
@@ -985,14 +1058,20 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
if (iter == lut.end()) continue;
switch (iter->second) {
case SPO_Getter: {
- // TODO I'm too lazy to write error checks, just let the codegen crash
+ // NOTE: I'm too lazy to write error checks, just let the codegen crash if syntax is invalid
auto& getterName = arg.at(1)->text;
if (getterName == "auto") {
// NOTE: intentionally shadowing
INPLACE_FMT(getterName, "Get%s", GetPascalCasedName().c_str());
- // TODO generate getter function
+ // 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;
} else {
decl.getterName = getterName;
@@ -1000,14 +1079,18 @@ void ParseInputFileAndGenerate(AppState& as, CodegenLexer& /*lexingState*/ ls, s
} break;
case SPO_Setter: {
- // TODO
+ // NOTE: I'm too lazy to write error checks, just let the codegen crash if syntax is invalid
auto& setterName = arg.at(1)->text;
if (setterName == "auto") {
// NOTE: intentionally shadowing
INPLACE_FMT(setterName, "Set%s", GetPascalCasedName().c_str());
- // TODO generate setter function
+ 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;
} else {
decl.setterName = setterName;
@@ -1162,7 +1245,9 @@ void HandleArgument(AppState& as, InputOpcode opcode, std::string_view operand)
DEBUG_PRINTF("File-list file does not exist, silently skipping.\n");
break;
}
- DEFER { fclose(fileList); };
+ DEFER {
+ fclose(fileList);
+ };
std::string line;
while (Utils::ReadCstdioLine(fileList, line)) {
@@ -1258,8 +1343,13 @@ 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));
+#define BRUSSEL_ENABLE_CODEGEN_ARCHIVE 0
+#if BRUSSEL_ENABLE_CODEGEN_ARCHIVE
CodegenModelArchive archive(as.databaseFilePath);
as.modelArchive = &archive;
+#else
+ as.modelArchive = nullptr;
+#endif
// Positional argument pass
for (int i = 1; i < argc; ++i) {
diff --git a/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt b/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
index 428c47f..132bac0 100644
--- a/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
+++ b/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
@@ -13,7 +13,7 @@ enum class CountedEnumAll {
CEA_COUNT,
};
-enum CountedEnum {
+enum CountedEnum : unsigned short int {
BRUSSEL_ENUM(ToString, FromString, RemovePrefix CE_, AddPrefix CustomPrefix, ExcludeHeuristics)
CE_Foo,
CE_Bar,
diff --git a/source/20-codegen-runtime/MetadataBase.hpp b/source/20-codegen-runtime/MetadataBase.hpp
index c1ad894..f84a152 100644
--- a/source/20-codegen-runtime/MetadataBase.hpp
+++ b/source/20-codegen-runtime/MetadataBase.hpp
@@ -30,7 +30,7 @@ struct TypeMethodInfo {
struct TypeInfo {
TypeId typeId;
std::string_view name;
- std::span<const TypeInfo*> parents;
+ std::span<const TypeInfo* const> parents;
std::span<const TypePropertyInfo> properties;
std::span<const TypeMethodInfo> methods;
@@ -42,12 +42,12 @@ struct TypeInfo {
template <typename T>
const TypeInfo* GetTypeInfo();
-// NOTE: implemented by generating specializations; not-generated ones should generated an error in the linking phase
+// NOTE: implemented by generating specializations
template <typename TEnum>
-std::string_view EnumToString(TEnum value);
+std::string_view EnumToString(TEnum value) = delete;
-// NOTE: implemented by generating specializations; not-generated ones should generated an error in the linking phase
+// NOTE: implemented by generating specializations
template <typename TEnum>
-std::optional<TEnum> EnumFromString(std::string_view str);
+std::optional<TEnum> EnumFromString(std::string_view str) = delete;
} // namespace Metadata
diff --git a/source/30-game/GameObject.hpp b/source/30-game/GameObject.hpp
index 56beb80..40c52e7 100644
--- a/source/30-game/GameObject.hpp
+++ b/source/30-game/GameObject.hpp
@@ -31,6 +31,8 @@ enum class GameObjectKind {
class GameWorld;
class GameObject {
+ BRUSSEL_CLASS(InheritanceHiearchy)
+
public:
using Kind = Tags::GameObjectKind;
using enum Tags::GameObjectKind;
diff --git a/source/30-game/Level.hpp b/source/30-game/Level.hpp
index 9114a64..c030b8e 100644
--- a/source/30-game/Level.hpp
+++ b/source/30-game/Level.hpp
@@ -3,6 +3,7 @@
#include "EditorCore.hpp"
#include "GameObject.hpp"
+#include <MacrosCodegen.hpp>
#include <RcPtr.hpp>
#include <Uid.hpp>
@@ -80,6 +81,8 @@ private:
};
class LevelWrapperObject : public GameObject {
+ BRUSSEL_CLASS()
+
private:
RcPtr<Level> mLevel;
diff --git a/source/30-game/Player.hpp b/source/30-game/Player.hpp
index d003a25..5a6bab7 100644
--- a/source/30-game/Player.hpp
+++ b/source/30-game/Player.hpp
@@ -2,9 +2,11 @@
#include "GameObject.hpp"
#include "Material.hpp"
-#include "RcPtr.hpp"
#include "Sprite.hpp"
+#include <MacrosCodegen.hpp>
+#include <RcPtr.hpp>
+
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
@@ -27,6 +29,8 @@ struct PlayerKeyBinds {
};
class Player : public GameObject {
+ BRUSSEL_CLASS()
+
public:
std::vector<GLFWkeyboard*> boundKeyboards;
PlayerKeyBinds keybinds;
diff --git a/source/30-game/SceneThings.hpp b/source/30-game/SceneThings.hpp
index c261fbb..761eb59 100644
--- a/source/30-game/SceneThings.hpp
+++ b/source/30-game/SceneThings.hpp
@@ -4,17 +4,21 @@
#include "GameObject.hpp"
#include "Renderer.hpp"
+#include <MacrosCodegen.hpp>
+
#include <glm/glm.hpp>
#include <vector>
class SimpleGeometryObject : public GameObject {
+ BRUSSEL_CLASS()
+
private:
RenderObject mRenderObject;
glm::vec3 mSize;
RgbaColor mXFaceColor;
RgbaColor mYFaceColor;
RgbaColor mZFaceColor;
- mutable bool mNeedsRebuildMesh ;
+ mutable bool mNeedsRebuildMesh;
public:
SimpleGeometryObject(GameWorld* world);
@@ -31,6 +35,8 @@ public:
};
class BuildingObject : public GameObject {
+ BRUSSEL_CLASS()
+
private:
RenderObject mRenderObject;