aboutsummaryrefslogtreecommitdiff
path: root/buildtools/codegen/main.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-05-30 15:52:19 -0700
committerrtk0c <[email protected]>2022-05-30 15:52:19 -0700
commit7d8bca09b3c4bf1418e758bd3bd0d6f85672153e (patch)
treef6e411e1ec949187889d268f2993e38cddb74d53 /buildtools/codegen/main.cpp
parentce9559e8c2b69d46cff064241bd9a04c014af44f (diff)
Changeset: 52 Add support for namespaced enums
Diffstat (limited to 'buildtools/codegen/main.cpp')
-rw-r--r--buildtools/codegen/main.cpp189
1 files changed, 145 insertions, 44 deletions
diff --git a/buildtools/codegen/main.cpp b/buildtools/codegen/main.cpp
index 3a3e443..2c259a4 100644
--- a/buildtools/codegen/main.cpp
+++ b/buildtools/codegen/main.cpp
@@ -75,6 +75,7 @@ STR_LUT_DECL(ClexNames, CLEX_eof, CLEX_ext_COUNT) {
}
enum CppKeyword {
+ CKw_Namespace,
CKw_Struct,
CKw_Class,
CKw_Enum,
@@ -83,6 +84,7 @@ enum CppKeyword {
BSTR_LUT_DECL(CppKeyword, 0, CKw_COUNT) {
BSTR_LUT_MAP_FOR(CppKeyword);
+ BSTR_LUT_MAP(CKw_Namespace, "namespace");
BSTR_LUT_MAP(CKw_Struct, "struct");
BSTR_LUT_MAP(CKw_Class, "class");
BSTR_LUT_MAP(CKw_Enum, "enum");
@@ -277,7 +279,27 @@ std::string GenerateEnumStringMap(CodegenOutput& out, const DeclEnum& decl, bool
}
void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const DeclEnum& decl, EnumFlags<EnumMetaGenOptions> options) {
- bool useExcludeHeuristics = options.IsSet(EMGO_ExcludeUseHeuristics);
+ char enumName[2048];
+ if (decl.container) {
+ snprintf(enumName, sizeof(enumName), "%.*s::%s", PRINTF_STRING_VIEW(decl.container->fullname), decl.name.c_str());
+ } else {
+ strncpy(enumName, decl.name.c_str(), sizeof(enumName));
+ }
+
+ auto useExcludeHeuristics = options.IsSet(EMGO_ExcludeUseHeuristics);
+ auto filteredElements = [&]() {
+ if (useExcludeHeuristics) {
+ decltype(decl.elements) result;
+ for (auto& elm : decl.elements) {
+ if (elm.name.ends_with("COUNT")) continue;
+
+ result.push_back(elm);
+ }
+ return result;
+ } else {
+ return decl.elements;
+ }
+ }();
if (options.IsSet(EMGO_ToString)) {
// Generate value -> string lookup table and function
@@ -285,23 +307,18 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
switch (decl.GetPattern()) {
case EVP_Continuous: {
auto arrayName = GenerateEnumStringArray(sourceOut, decl, useExcludeHeuristics);
- int minVal = decl.elements.front().value;
- int maxVal = decl.elements.back().value;
- if (useExcludeHeuristics &&
- decl.elements.back().name.ends_with("COUNT") &&
- decl.elements.size() >= 2)
- {
- // Skip the last *_COUNT element if instructed to use heuristics
- maxVal = decl.elements[decl.elements.size() - 2].value;
- }
+ int minVal = filteredElements.empty() ? 0 : filteredElements.front().value;
+ int maxVal = filteredElements.empty() ? 0 : filteredElements.back().value;
CodegenOutputThing lookupFunctionDef;
- auto& o2 = lookupFunctionDef.text;
- APPEND_LIT_LN(o2, "template <>");
- APPEND_FMT_LN(o2, "std::string_view Metadata::EnumToString<%s>(%s value) {", decl.name.c_str(), decl.name.c_str());
- APPEND_FMT_LN(o2, " if (value < 0 || value >= %d) return {};", maxVal);
- APPEND_FMT_LN(o2, " return %s[value - %d];", arrayName.c_str(), minVal);
- APPEND_LIT_LN(o2, "}");
+ {
+ auto& o = lookupFunctionDef.text;
+ APPEND_LIT_LN(o, "template <>");
+ APPEND_FMT_LN(o, "std::string_view Metadata::EnumToString<%s>(%s value) {", enumName, enumName);
+ APPEND_FMT_LN(o, " if (value < %d || value > %d) return {};", minVal, maxVal);
+ APPEND_FMT_LN(o, " return %s[value - %d];", arrayName.c_str(), minVal);
+ APPEND_LIT_LN(o, "}");
+ }
sourceOut.AddOutputThing(std::move(lookupFunctionDef));
} break;
@@ -323,28 +340,34 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
if (options.IsSet(EMGO_FromString)) {
// Generate string -> value lookup table
char mapName[1024];
+ // TODO mangle to prevent name conflicts of enum in different namespaces
snprintf(mapName, sizeof(mapName), "gCG_%s_Str2Val", decl.name.c_str());
CodegenOutputThing lookupTable;
- auto& o1 = lookupTable.text;
- APPEND_FMT_LN(o1, "constinit frozen::unordered_map<frozen::string, %s, %" PRId64 "> %s = {", decl.name.c_str(), decl.elements.size(), mapName);
- for (auto& elm : decl.elements) {
- APPEND_FMT_LN(o1, "{\"%s\", %s::%s},", elm.name.c_str(), decl.name.c_str(), elm.name.c_str());
+ {
+ 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(), mapName);
+ for (auto& elm : filteredElements) {
+ APPEND_FMT_LN(o, "{\"%s\", %" PRId64 "},", elm.name.c_str(), elm.value);
+ }
+ APPEND_LIT_LN(o, "};");
}
- APPEND_LIT_LN(o1, "};");
// Generate lookup function
CodegenOutputThing lookupFunctionDef;
- auto& o3 = lookupFunctionDef.text;
- APPEND_LIT_LN(o3, "template <>");
- APPEND_FMT_LN(o3, "std::optional<%s> Metadata::EnumFromString<%s>(std::string_view value) {", decl.name.c_str(), decl.name.c_str());
- APPEND_FMT_LN(o3, " auto iter = %s.find(value);", mapName);
- APPEND_FMT_LN(o3, " if (iter != %s.end()) {", mapName);
- APPEND_LIT_LN(o3, " return iter->second;");
- APPEND_LIT_LN(o3, " } else {");
- APPEND_LIT_LN(o3, " return {};");
- APPEND_LIT_LN(o3, " }");
- APPEND_LIT_LN(o3, "}");
+ {
+ auto& o = lookupFunctionDef.text;
+ APPEND_LIT_LN(o, "template <>");
+ APPEND_FMT_LN(o, "std::optional<%s> Metadata::EnumFromString<%s>(std::string_view value) {", enumName, enumName);
+ APPEND_FMT_LN(o, " auto iter = %s.find(value);", mapName);
+ APPEND_FMT_LN(o, " if (iter != %s.end()) {", mapName);
+ APPEND_FMT_LN(o, " return (%s)iter->second;", enumName);
+ APPEND_LIT_LN(o, " } else {");
+ APPEND_LIT_LN(o, " return {};");
+ APPEND_LIT_LN(o, " }");
+ APPEND_LIT_LN(o, "}");
+ }
sourceOut.AddOutputThing(std::move(lookupTable));
sourceOut.AddOutputThing(std::move(lookupFunctionDef));
@@ -369,7 +392,32 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
CodegenOutput cgSourceOutput;
Utils::ProduceGeneratedSourceFileHeader(cgSourceOutput);
- int bracePairDepth = 0;
+ int currentBraceDepth = 0;
+ // The current effective namespace, see example
+ DeclNamespace* currentNamespace = nullptr;
+
+ 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 */
+ // }
+ // }
+
while (idx < tokens.size()) {
auto& token = tokens[idx];
@@ -388,6 +436,40 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
}
switch (keyword) {
+ case CKw_Namespace: {
+ ++idx;
+ incrementTokenIdx = false;
+
+ while (true) {
+ if (tokens[idx].type != CLEX_id) {
+ // TODO better error recovery
+ printf("[ERROR] invalid syntax for namespace\n");
+ break;
+ }
+
+ currentNamespace = cgInput.AddNamespace(DeclNamespace{
+ .container = currentNamespace,
+ .name = tokens[idx].text,
+ });
+
+ if (tokens[idx + 1].text[0] == ':' &&
+ tokens[idx + 2].text[0] == ':')
+ {
+ // Skip the two ':' tokens, try parse the next identifier
+ idx += 3;
+ } else {
+ break;
+ }
+ }
+
+ nsStack.push_back(NamespaceStackframe{
+ .ns = currentNamespace,
+ .depth = currentBraceDepth,
+ });
+
+ goto endIdenCase;
+ }
+
case CKw_Struct:
case CKw_Class: {
auto& idenTok = tokens[idx + 1]; // TODO handle end of list
@@ -401,6 +483,7 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
incrementTokenIdx = false;
DeclEnum enumDecl;
+ enumDecl.container = currentNamespace;
enumDecl.underlyingType = EUT_Int32; // TODO
if (tokens[idx].text == "class") {
@@ -452,7 +535,8 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
++idx;
}
- cgInput.AddEnum(std::move(enumDecl));
+ auto fullname = Utils::MakeFullName(enumDecl.name, currentNamespace);
+ cgInput.AddEnum(std::move(fullname), std::move(enumDecl));
goto endIdenCase;
}
@@ -488,7 +572,7 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
auto& enumName = argList[0][0]->text;
- auto enumDecl = cgInput.FindEnumByName(enumName);
+ auto enumDecl = cgInput.FindEnumByName(Utils::MakeFullName(enumName, currentNamespace));
if (!enumDecl) {
printf("[ERROR] BRUSSEL_ENUM: referring to non-existent enum '%s'\n", enumName.c_str());
break;
@@ -519,15 +603,32 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
break;
}
- case '{': {
- bracePairDepth++;
- CheckBraceDepth(bracePairDepth);
- } break;
+ case CLEX_ext_single_char:
+ switch (token.text[0]) {
+ case '{': {
+ currentBraceDepth++;
+ CheckBraceDepth(currentBraceDepth);
+ } break;
- case '}': {
- bracePairDepth--;
- CheckBraceDepth(bracePairDepth);
- } break;
+ case '}': {
+ currentBraceDepth--;
+ CheckBraceDepth(currentBraceDepth);
+
+ if (!nsStack.empty()) {
+ auto& ns = nsStack.back();
+ if (ns.depth == currentBraceDepth) {
+ nsStack.pop_back();
+
+ if (!nsStack.empty()) {
+ currentNamespace = nsStack.back().ns;
+ } else {
+ currentNamespace = nullptr;
+ }
+ }
+ }
+ } break;
+ }
+ break;
}
if (incrementTokenIdx) {
@@ -535,7 +636,7 @@ void HandleInputFile(AppState& state, std::string_view filenameStem, std::string
}
}
- if (bracePairDepth != 0) {
+ if (currentBraceDepth != 0) {
printf("[WARNING] unbalanced brace at end of file.");
}
@@ -632,7 +733,7 @@ where <output path>: the directory to write generated contents to. This will N
}
state.outputDir = std::string_view(argv[1]);
- DEBUG_PRINTF("Outputting to directory %s.\n", outputDir);
+ DEBUG_PRINTF("Outputting to directory %.*s.\n", PRINTF_STRING_VIEW(state.outputDir));
for (int i = 2; i < argc; ++i) {
const char* argRaw = argv[i];