aboutsummaryrefslogtreecommitdiff
path: root/source/20-codegen-compiler/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/20-codegen-compiler/main.cpp')
-rw-r--r--source/20-codegen-compiler/main.cpp325
1 files changed, 193 insertions, 132 deletions
diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp
index 5e052a3..326e4a9 100644
--- a/source/20-codegen-compiler/main.cpp
+++ b/source/20-codegen-compiler/main.cpp
@@ -302,6 +302,8 @@ enum EnumMetaGenOptions {
EMGO_ToString,
EMGO_FromString,
EMGO_ExcludeUseHeuristics,
+ EMGO_RemovePrefix,
+ EMGO_AddPrefix,
EMGO_COUNT,
};
@@ -310,6 +312,8 @@ RSTR_LUT_DECL(EnumMetaGenOptions, 0, EMGO_COUNT) {
RSTR_LUT_MAP(EMGO_ToString, "ToString");
RSTR_LUT_MAP(EMGO_FromString, "FromString");
RSTR_LUT_MAP(EMGO_ExcludeUseHeuristics, "ExcludeHeuristics");
+ RSTR_LUT_MAP(EMGO_RemovePrefix, "RemovePrefix");
+ RSTR_LUT_MAP(EMGO_AddPrefix, "AddPrefix");
}
void GenerateEnumStringArray(CodegenOutput& out, const DeclEnum& decl, const char* arrayName, const std::vector<DeclEnumElement>& filteredElements) {
@@ -328,7 +332,7 @@ void GenerateEnumStringMap(CodegenOutput& out, const DeclEnum& decl, const char*
out.AddOutputThing(std::move(thing));
}
-void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const DeclEnum& decl, EnumFlags<EnumMetaGenOptions> options) {
+void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const DeclEnum& decl) {
char enumName[2048];
if (decl.container) {
snprintf(enumName, sizeof(enumName), "%.*s::%s", PRINTF_STRING_VIEW(decl.container->fullname), decl.name.c_str());
@@ -339,14 +343,24 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
// TODO mangle to prevent name conflicts of enum in different namespaces
auto& declIdName = decl.name;
- auto useExcludeHeuristics = options.IsSet(EMGO_ExcludeUseHeuristics);
+ auto useExcludeHeuristics = decl.generateExcludeUseHeuristics;
auto filteredElements = [&]() {
if (useExcludeHeuristics) {
decltype(decl.elements) result;
for (auto& elm : decl.elements) {
if (elm.name.ends_with("COUNT")) continue;
- result.push_back(elm);
+ std::string_view trimmedName = elm.name;
+ if (!decl.generateRemovingPrefix.empty() &&
+ elm.name.starts_with(decl.generateRemovingPrefix))
+ {
+ trimmedName = trimmedName.substr(decl.generateRemovingPrefix.size());
+ }
+
+ result.push_back(DeclEnumElement{
+ .name = decl.generatingAddingPrefix + std::string(trimmedName),
+ .value = elm.value,
+ });
}
return result;
} else {
@@ -354,7 +368,7 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
}
}();
- if (options.IsSet(EMGO_ToString)) {
+ if (decl.generateToString) {
// Generate value -> string lookup table and function
INPLACE_FMT(val2StrName, "gCG_%s_Val2Str", declIdName.c_str());
@@ -400,7 +414,7 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
}
}
- if (options.IsSet(EMGO_FromString)) {
+ if (decl.generateFromString) {
// Generate string -> value lookup table
INPLACE_FMT(str2ValName, "gCG_%s_Str2Val", declIdName.c_str());
@@ -489,7 +503,95 @@ void GenerateForClassMetadata(
sourceOutput.AddOutputThing(std::move(queryFunc));
}
-void HandleInputFile(AppState& state, std::string_view filenameStem, std::string_view source) {
+struct NamespaceStackframe {
+ // The current namespace that owns the brace level, see example
+ DeclNamespace* ns = nullptr;
+ // Brace depth `ns` was created at (e.g. [std::details].depth == 0)
+ int depth = 0;
+};
+
+struct ParserState {
+ CodegenInput input;
+ CodegenOutput headerOutput;
+ CodegenOutput sourceOutput;
+ CodegenOutput standaloneSourceOutput;
+
+ // Example:
+ // namespace std::details {
+ // /* [stack top].ns = std::details */
+ // /* [stack top].depth = std */
+ // }
+ // namespace foo {
+ // /* [stack top].ns = foo */
+ // /* [stack top].depth = foo */
+ // namespace details {
+ // /* [stack top].ns = foo::details */
+ // /* [stack top].depth = foo::details */
+ // }
+ // }
+ std::vector<NamespaceStackframe> nsStack;
+ // The current effective namespace, see example
+ DeclNamespace* currentNamespace = nullptr;
+
+ DeclStruct* currentStruct = nullptr;
+ DeclEnum* currentEnum = nullptr;
+ int currentBraceDepth = 0;
+ int currentStructBraceDepth = -1;
+ int currentEnumBraceDepth = -1;
+};
+
+void HandleDirectiveEnum(AppState& as, ParserState& ps, CodegenLexer& lexer) {
+ // Consume the directive
+ ++lexer.idx;
+
+ if (!ps.currentEnum) {
+ printf("[ERROR] BRUSSEL_ENUM must be used within a enum\n");
+ return;
+ }
+
+ auto argList = TryConsumeDirectiveArgumentList(lexer);
+ auto& lut = RSTR_LUT(EnumMetaGenOptions);
+ for (auto& arg : argList) {
+ if (arg.empty()) {
+ printf("[ERROR] empty argument is invalid in BRUSSEL_ENUM\n");
+ continue;
+ }
+
+ auto& optionDirective = arg[0]->text;
+ auto iter = lut.find(optionDirective);
+ if (iter == lut.end()) {
+ printf("[ERROR] BRUSSEL_ENUM: invalid option '%s'\n", optionDirective.c_str());
+ }
+
+ auto option = iter->second;
+ switch (option) {
+ case EMGO_ToString: ps.currentEnum->generateToString = true; break;
+ case EMGO_FromString: ps.currentEnum->generateFromString = true; break;
+ case EMGO_ExcludeUseHeuristics: ps.currentEnum->generateExcludeUseHeuristics = true; break;
+
+ case EMGO_RemovePrefix: {
+ if (argList.size() <= 1) {
+ printf("[ERROR] missing argument for RemovePrefix");
+ break;
+ }
+ ps.currentEnum->generateRemovingPrefix = arg[1]->text;
+ } break;
+ case EMGO_AddPrefix: {
+ if (argList.size() <= 1) {
+ printf("[ERROR] missing argument for AddPrefix");
+ break;
+ }
+ ps.currentEnum->generatingAddingPrefix = arg[1]->text;
+ } break;
+
+ case EMGO_COUNT: break;
+ }
+ }
+
+ ps.currentEnum->generating = true;
+}
+
+void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_view source) {
CodegenLexer lexer;
lexer.InitializeFrom(source);
@@ -513,43 +615,12 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
printf("END tokens\n");
#endif
- CodegenInput cgInput;
- CodegenOutput cgHeaderOutput;
- CodegenOutput cgSourceOutput;
+ ParserState ps;
{
INPLACE_FMT(hpp, "%.*s.gh.inl", PRINTF_STRING_VIEW(filenameStem));
INPLACE_FMT(cpp, "%.*s.gs.inl", PRINTF_STRING_VIEW(filenameStem));
- Utils::ProduceGeneratedHeader(hpp, cgHeaderOutput, cpp, cgSourceOutput);
+ Utils::ProduceGeneratedHeader(hpp, ps.headerOutput, cpp, ps.sourceOutput);
}
- CodegenOutput cgStandaloneSourceOutput;
-
- int currentBraceDepth = 0;
- // The current effective namespace, see example
- DeclNamespace* currentNamespace = nullptr;
- DeclStruct* currentStruct = nullptr;
- int currentStructBraceDepth = 0;
-
- struct NamespaceStackframe {
- // The current namespace that owns the brace level, see example
- DeclNamespace* ns = nullptr;
- // Brace depth `ns` was created at (e.g. [std::details].depth == 0)
- int depth = 0;
- };
- std::vector<NamespaceStackframe> nsStack;
-
- // Example:
- // namespace std::details {
- // /* [stack top].ns = std::details */
- // /* [stack top].depth = std */
- // }
- // namespace foo {
- // /* [stack top].ns = foo */
- // /* [stack top].depth = foo */
- // namespace details {
- // /* [stack top].ns = foo::details */
- // /* [stack top].depth = foo::details */
- // }
- // }
auto& tokens = lexer.tokens;
auto& idx = lexer.idx;
@@ -592,8 +663,8 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
break;
}
- currentNamespace = cgInput.AddNamespace(DeclNamespace{
- .container = currentNamespace,
+ ps.currentNamespace = ps.input.AddNamespace(DeclNamespace{
+ .container = ps.currentNamespace,
.name = tokens[idx].text,
});
@@ -608,9 +679,9 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
}
- nsStack.push_back(NamespaceStackframe{
- .ns = currentNamespace,
- .depth = currentBraceDepth,
+ ps.nsStack.push_back(NamespaceStackframe{
+ .ns = ps.currentNamespace,
+ .depth = ps.currentBraceDepth,
});
goto endCaseCLEX_id;
@@ -631,9 +702,9 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
DEBUG_PRINTF("[DEBUG] found struct named %s\n", idenTok.text.c_str());
auto& name = idenTok.text;
- auto fullname = Utils::MakeFullName(name, currentNamespace);
+ auto fullname = Utils::MakeFullName(name, ps.currentNamespace);
DeclStruct structDecl;
- structDecl.container = currentNamespace;
+ structDecl.container = ps.currentNamespace;
structDecl.name = name;
// Consume the identifier token
@@ -651,8 +722,8 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
// TODO support namespace qualified names
- auto baseClassFullname = Utils::MakeFullName(idenTok.text, currentNamespace);
- auto baseClassDecl = cgInput.FindStruct(baseClassFullname);
+ auto baseClassFullname = Utils::MakeFullName(idenTok.text, ps.currentNamespace);
+ auto baseClassDecl = ps.input.FindStruct(baseClassFullname);
if (baseClassDecl) {
// 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);
@@ -679,9 +750,9 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
{
// Get a pointer to the decl inside CodegenInput's storage
- auto decl = cgInput.AddStruct(std::move(fullname), std::move(structDecl));
- currentStruct = decl;
- currentStructBraceDepth = currentBraceDepth;
+ auto decl = ps.input.AddStruct(std::move(fullname), std::move(structDecl));
+ ps.currentStruct = decl;
+ ps.currentStructBraceDepth = ps.currentBraceDepth;
}
endCase:
@@ -704,10 +775,16 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
DEBUG_PRINTF("[DEBUG] found enum named %s\n", idenTok->text.c_str());
}
+ auto& name = tokens[idx].text;
+ auto fullname = Utils::MakeFullName(name, ps.currentNamespace);
DeclEnum enumDecl;
- enumDecl.container = currentNamespace;
+ enumDecl.container = ps.currentNamespace;
enumDecl.underlyingType = EUT_Int32; // TODO
- enumDecl.name = tokens[idx].text;
+ enumDecl.name = name;
+
+ // Temporarily bind the pointers to local variable, HandleDirectiveEnum() and other functions expect these to the set
+ ps.currentEnum = &enumDecl;
+ ps.currentEnumBraceDepth = ps.currentBraceDepth;
// Consume the enum name identifier
++idx;
@@ -718,14 +795,20 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
auto& token = tokens[idx];
switch (token.type) {
case CLEX_id: {
- auto& vec = enumDecl.elements;
- // Set to the previous enum element's value + 1, or starting from 0 if this is the first
- // Also overridden in the CLEX_intlit branch
- auto value = vec.empty() ? 0 : vec.back().value + 1;
- vec.push_back(DeclEnumElement{
- .name = token.text,
- .value = value,
- });
+ if (token.text == "BRUSSEL_ENUM") {
+ // Consume the argument list and skip advancing index: this function already consumed all the tokens about BRUSSEL_ENUM
+ HandleDirectiveEnum(as, ps, lexer);
+ continue;
+ } else {
+ auto& vec = enumDecl.elements;
+ // Set to the previous enum element's value + 1, or starting from 0 if this is the first
+ // Also overridden in the CLEX_intlit branch
+ auto value = vec.empty() ? 0 : vec.back().value + 1;
+ vec.push_back(DeclEnumElement{
+ .name = token.text,
+ .value = value,
+ });
+ }
} break;
case CLEX_intlit: {
@@ -753,8 +836,16 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
++idx;
}
- auto fullname = Utils::MakeFullName(enumDecl.name, currentNamespace);
- cgInput.AddEnum(std::move(fullname), std::move(enumDecl));
+ if (ps.currentEnum->generating) {
+ GenerateForEnum(ps.headerOutput, ps.sourceOutput, *ps.currentEnum);
+ }
+
+ {
+ auto decl = ps.input.AddEnum(std::move(fullname), std::move(enumDecl));
+ ps.currentEnum = decl;
+ ps.currentEnumBraceDepth = ps.currentBraceDepth;
+ }
+
goto endCaseCLEX_id;
}
@@ -782,13 +873,13 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
++idx;
incrementTokenIdx = false;
- if (!currentStruct) {
+ if (!ps.currentStruct) {
printf("[ERROR] BRUSSEL_CLASS must be used within a class or struct\n");
break;
}
// Always-on option
- currentStruct->generating = true;
+ ps.currentStruct->generating = true;
auto argList = TryConsumeDirectiveArgumentList(lexer);
auto& lut = RSTR_LUT(StructMetaGenOptions);
@@ -802,7 +893,7 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
auto iter = lut.find(optionDirective);
if (iter == lut.end()) continue;
switch (iter->second) {
- case SMGO_InheritanceHiearchy: currentStruct->generatingInheritanceHiearchy = true; break;
+ case SMGO_InheritanceHiearchy: ps.currentStruct->generatingInheritanceHiearchy = true; break;
case SMGO_COUNT: break;
}
}
@@ -815,8 +906,8 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
++idx;
incrementTokenIdx = false;
- if (!currentStruct ||
- !currentStruct->generating)
+ if (!ps.currentStruct ||
+ !ps.currentStruct->generating)
{
printf("[ERROR] BRUSSEL_PROPERTY must be used within a class or struct, that has the BRUSSEL_CLASS directive\n");
break;
@@ -884,7 +975,7 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
}
- currentStruct->memberVariables.push_back(std::move(decl));
+ ps.currentStruct->memberVariables.push_back(std::move(decl));
goto endCaseCLEX_id;
}
@@ -897,42 +988,8 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
goto endCaseCLEX_id;
}
- case CD_Enum: {
- // Consume the directive
- ++idx;
- incrementTokenIdx = false;
-
- auto& optionsStrMap = RSTR_LUT(EnumMetaGenOptions);
- auto argList = TryConsumeDirectiveArgumentList(lexer);
-
- if (argList.size() < 1) {
- printf("[ERROR] invalid syntax for BRUSSEL_ENUM\n");
- break;
- }
-
- auto& enumName = argList[0][0]->text;
- auto enumDecl = cgInput.FindEnum(Utils::MakeFullName(enumName, currentNamespace));
- if (!enumDecl) {
- printf("[ERROR] BRUSSEL_ENUM: referring to non-existent enum '%s'\n", enumName.c_str());
- break;
- }
-
- auto& directiveOptions = argList[1];
- EnumFlags<EnumMetaGenOptions> options;
- for (auto optionTok : directiveOptions) {
- auto iter = optionsStrMap.find(optionTok->text);
- if (iter != optionsStrMap.end()) {
- options |= iter->second;
- } else {
- printf("[ERROR] BRUSSEL_ENUM: invalid option '%s'\n", optionTok->text.c_str());
- }
- }
-
- GenerateForEnum(cgHeaderOutput, cgSourceOutput, *enumDecl, options);
-
- goto endCaseCLEX_id;
- }
-
+ // This directive always appear inside a enum{} block, which is handled above in the keywords section
+ case CD_Enum:
case CD_COUNT: break;
}
@@ -940,46 +997,50 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
} break;
case '{': {
- currentBraceDepth++;
- if (currentBraceDepth < 0) {
+ ps.currentBraceDepth++;
+ if (ps.currentBraceDepth < 0) {
printf("[WARNING] unbalanced brace\n");
}
} break;
case '}': {
- currentBraceDepth--;
- if (currentBraceDepth < 0) {
+ ps.currentBraceDepth--;
+ if (ps.currentBraceDepth < 0) {
printf("[WARNING] unbalanced brace\n");
}
- if (!nsStack.empty()) {
- auto& ns = nsStack.back();
- if (ns.depth == currentBraceDepth) {
- nsStack.pop_back();
+ if (!ps.nsStack.empty()) {
+ auto& ns = ps.nsStack.back();
+ if (ns.depth == ps.currentBraceDepth) {
+ ps.nsStack.pop_back();
- if (!nsStack.empty()) {
- currentNamespace = nsStack.back().ns;
+ if (!ps.nsStack.empty()) {
+ ps.currentNamespace = ps.nsStack.back().ns;
} else {
- currentNamespace = nullptr;
+ ps.currentNamespace = nullptr;
}
}
}
- if (currentStruct &&
- currentBraceDepth == currentStructBraceDepth)
- {
+ if (ps.currentStruct && ps.currentBraceDepth == ps.currentStructBraceDepth) {
// Exit struct
- if (currentStruct->generating) {
- GenerateForClassMetadata(cgHeaderOutput, cgSourceOutput, *currentStruct);
+ if (ps.currentStruct->generating) {
+ GenerateForClassMetadata(ps.headerOutput, ps.sourceOutput, *ps.currentStruct);
}
- if (currentStruct->generatingInheritanceHiearchy) {
+ if (ps.currentStruct->generatingInheritanceHiearchy) {
// NOTE: this option is transitive to all child classes (as long as they have the basic annotation)
// TODO
}
- currentStruct = nullptr;
- currentStructBraceDepth = 0;
+ ps.currentStruct = nullptr;
+ ps.currentStructBraceDepth = 0;
+ }
+ if (ps.currentEnum && ps.currentBraceDepth == ps.currentEnumBraceDepth) {
+ // Exit enum
+
+ ps.currentEnum = nullptr;
+ ps.currentEnumBraceDepth = 0;
}
} break;
}
@@ -989,16 +1050,16 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
}
- if (currentBraceDepth != 0) {
- printf("[WARNING] unbalanced brace at end of file.");
+ if (ps.currentBraceDepth != 0) {
+ printf("[WARNING] unbalanced brace at end of file\n");
}
- INPLACE_FMT(generatedHeaderInlName, "%.*s/%.*s.gh.inl", PRINTF_STRING_VIEW(state.outputDir), PRINTF_STRING_VIEW(filenameStem));
- Utils::WriteOutputFile(cgHeaderOutput, generatedHeaderInlName);
- INPLACE_FMT(generatedSourceInlName, "%.*s/%.*s.gs.inl", PRINTF_STRING_VIEW(state.outputDir), PRINTF_STRING_VIEW(filenameStem));
- Utils::WriteOutputFile(cgSourceOutput, generatedSourceInlName);
- INPLACE_FMT(generatedCppName, "%.*s/%.*s.g.cpp", PRINTF_STRING_VIEW(state.outputDir), PRINTF_STRING_VIEW(filenameStem));
- Utils::WriteOutputFile(cgStandaloneSourceOutput, generatedCppName);
+ INPLACE_FMT(generatedHeaderInlName, "%.*s/%.*s.gh.inl", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(filenameStem));
+ Utils::WriteOutputFile(ps.headerOutput, generatedHeaderInlName);
+ INPLACE_FMT(generatedSourceInlName, "%.*s/%.*s.gs.inl", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(filenameStem));
+ Utils::WriteOutputFile(ps.sourceOutput, generatedSourceInlName);
+ INPLACE_FMT(generatedCppName, "%.*s/%.*s.g.cpp", PRINTF_STRING_VIEW(as.outputDir), PRINTF_STRING_VIEW(filenameStem));
+ Utils::WriteOutputFile(ps.standaloneSourceOutput, generatedCppName);
}
enum InputOpcode {