diff options
-rw-r--r-- | source/20-codegen-compiler/CodegenLexer.cpp | 21 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenLexer.hpp | 4 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenModel.cpp | 83 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenModelArchive.hpp | 1 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenUtils.cpp | 7 | ||||
-rw-r--r-- | source/20-codegen-compiler/CodegenUtils.hpp | 1 | ||||
-rw-r--r-- | source/20-codegen-compiler/main.cpp | 172 | ||||
-rw-r--r-- | source/20-codegen-compiler/test/examples/TestEnum.hpp.txt | 2 | ||||
-rw-r--r-- | source/20-codegen-runtime/MetadataBase.hpp | 10 | ||||
-rw-r--r-- | source/30-game/GameObject.hpp | 2 | ||||
-rw-r--r-- | source/30-game/Level.hpp | 3 | ||||
-rw-r--r-- | source/30-game/Player.hpp | 6 | ||||
-rw-r--r-- | source/30-game/SceneThings.hpp | 8 |
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; |