aboutsummaryrefslogtreecommitdiff
path: root/buildtools
diff options
context:
space:
mode:
Diffstat (limited to 'buildtools')
-rw-r--r--buildtools/codegen/CodegenDecl.cpp5
-rw-r--r--buildtools/codegen/CodegenDecl.hpp4
-rw-r--r--buildtools/codegen/CodegenMacros.hpp30
-rw-r--r--buildtools/codegen/CodegenOutput.inl25
-rw-r--r--buildtools/codegen/main.cpp98
-rw-r--r--buildtools/codegen/tests/examples/TestEnum.hpp6
6 files changed, 130 insertions, 38 deletions
diff --git a/buildtools/codegen/CodegenDecl.cpp b/buildtools/codegen/CodegenDecl.cpp
index ac6bb01..7cf21ce 100644
--- a/buildtools/codegen/CodegenDecl.cpp
+++ b/buildtools/codegen/CodegenDecl.cpp
@@ -41,8 +41,9 @@ restart:
return pattern;
}
-void DeclEnum::CalcPatternIfNecessary() {
+EnumValuePattern DeclEnum::GetPattern() const {
if (pattern == EVP_COUNT) {
- CalcPattern();
+ pattern = CalcPattern();
}
+ return pattern;
}
diff --git a/buildtools/codegen/CodegenDecl.hpp b/buildtools/codegen/CodegenDecl.hpp
index c2d8dbb..b7c1ee4 100644
--- a/buildtools/codegen/CodegenDecl.hpp
+++ b/buildtools/codegen/CodegenDecl.hpp
@@ -44,10 +44,10 @@ struct DeclEnum {
std::vector<DeclEnumElement> elements;
EnumUnderlyingType underlyingType;
// Start with invalid value, calculate on demand
- EnumValuePattern pattern = EVP_COUNT;
+ mutable EnumValuePattern pattern = EVP_COUNT;
EnumValuePattern CalcPattern() const;
- void CalcPatternIfNecessary();
+ EnumValuePattern GetPattern() const;
};
struct DeclFunctionArgument {
diff --git a/buildtools/codegen/CodegenMacros.hpp b/buildtools/codegen/CodegenMacros.hpp
new file mode 100644
index 0000000..84c9d09
--- /dev/null
+++ b/buildtools/codegen/CodegenMacros.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <algorithm>
+
+// I give up, hopefully nothing overflows this buffer
+// TODO handle buffer sizing properly
+
+#define APPEND_LIT(out, str) out += str
+
+#define APPEND_FMT(out, format, ...) \
+ { \
+ char buffer[65536]; \
+ snprintf(buffer, sizeof(buffer), format, __VA_ARGS__); \
+ out += buffer; \
+ }
+
+#define WRITE_LIT(file, str) fwrite(str, sizeof(char), sizeof(str) - 1, file)
+
+// NOTE: snprintf() returns the size written (given an infinite buffer) not including \0
+#define WRITE_FMT(file, format, ...) \
+ { \
+ char buffer[65536]; \
+ int size = snprintf(buffer, sizeof(buffer), format, __VA_ARGS__); \
+ fwrite(buffer, sizeof(char), std::min<int>(size, sizeof(buffer)), file); \
+ }
+
+#define APPEND_LIT_LN(out, str) APPEND_LIT(out, (str "\n"))
+#define APPEND_FMT_LN(out, format, ...) APPEND_FMT(out, (format "\n"), __VA_ARGS__)
+#define WRITE_LIT_LN(out, str) WRITE_LIT(out, (str "\n"))
+#define WRITE_FMT_LN(out, format, ...) WRITE_FMT(out, (format "\n"), __VA_ARGS__)
diff --git a/buildtools/codegen/CodegenOutput.inl b/buildtools/codegen/CodegenOutput.inl
index 752682c..d1f2e50 100644
--- a/buildtools/codegen/CodegenOutput.inl
+++ b/buildtools/codegen/CodegenOutput.inl
@@ -1,7 +1,9 @@
#pragma once
#include "CodegenDecl.hpp"
+#include "CodegenMacros.hpp"
+#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string>
@@ -31,15 +33,30 @@ public:
void MergeContents(CodegenOutput other) {
std::move(other.mOutThings.begin(), other.mOutThings.end(), std::back_inserter(this->mOutThings));
+ std::move(other.mOutStructs.begin(), other.mOutStructs.end(), std::back_inserter(this->mOutStructs));
+ std::move(other.mOutEnums.begin(), other.mOutEnums.end(), std::back_inserter(this->mOutEnums));
+ std::move(other.mOutFunctions.begin(), other.mOutFunctions.end(), std::back_inserter(this->mOutFunctions));
}
void Write(FILE* file) {
-#define WRITE_LITERAL(str) fwrite(str, sizeof(char), sizeof(str) - 1, file)
for (auto& thing : mOutThings) {
- WRITE_LITERAL("// Output thing\n");
+ WRITE_LIT(file, "// Output thing\n");
fwrite(thing.text.c_str(), sizeof(char), thing.text.size(), file);
- WRITE_LITERAL("\n");
+ WRITE_LIT(file, "\n");
+ }
+
+ for (auto& declStruct : mOutStructs) {
+ WRITE_FMT(file, "struct %s {\n", declStruct.name.c_str());
+ // TODO
+ WRITE_LIT(file, "}\n");
+ }
+
+ for (auto& declEnum : mOutEnums) {
+ // TODO
+ }
+
+ for (auto& declFunc : mOutFunctions) {
+ // TODO
}
-#undef WRITE_LITERAL
}
};
diff --git a/buildtools/codegen/main.cpp b/buildtools/codegen/main.cpp
index 334b195..df52b66 100644
--- a/buildtools/codegen/main.cpp
+++ b/buildtools/codegen/main.cpp
@@ -1,5 +1,6 @@
#include "CodegenConfig.hpp"
#include "CodegenDecl.hpp"
+#include "CodegenMacros.hpp"
#include "CodegenInput.inl"
#include "CodegenOutput.inl"
@@ -10,6 +11,8 @@
#include <ScopeGuard.hpp>
#include <Utils.hpp>
+#include <frozen/string.h>
+#include <frozen/unordered_map.h>
#include <robin_hood.h>
#include <stb_c_lexer.h>
#include <cinttypes>
@@ -23,8 +26,11 @@
using namespace std::literals;
namespace fs = std::filesystem;
+// TODO handle namespace
+
struct AppState {
- CodegenOutput mainOutput;
+ CodegenOutput headerOutput;
+ CodegenOutput sourceOutput;
};
enum {
@@ -229,6 +235,7 @@ BSTR_LUT_DECL(StructMetaGenOptions, 0, SMGO_COUNT) {
enum EnumMetaGenOptions {
EMGO_ToString,
+ EMGO_FromString,
EMGO_ExcludeUseHeuristics,
EMGO_COUNT,
};
@@ -236,31 +243,24 @@ enum EnumMetaGenOptions {
BSTR_LUT_DECL(EnumMetaGenOptions, 0, EMGO_COUNT) {
BSTR_LUT_MAP_FOR(EnumMetaGenOptions);
BSTR_LUT_MAP(EMGO_ToString, "ToString");
+ BSTR_LUT_MAP(EMGO_FromString, "FromString");
BSTR_LUT_MAP(EMGO_ExcludeUseHeuristics, "ExcludeHeuristics");
}
-// I give up, hopefully nothing overflows this buffer
-#define APPEND_SPRINTF(out, format, ...) \
- { \
- char buffer[65536]; \
- snprintf(buffer, sizeof(buffer), format, __VA_ARGS__); \
- out += buffer; \
- }
-
std::string GenerateEnumStringArray(CodegenOutput& out, const DeclEnum& decl, bool useHeruistics) {
std::string arrayName;
- APPEND_SPRINTF(arrayName, "gCG_%s_StringTable", decl.name.c_str());
+ APPEND_FMT(arrayName, "gCG_%s_Val2Str", decl.name.c_str());
CodegenOutputThing thing;
- APPEND_SPRINTF(thing.text, "const char* %s[] = {\n", arrayName.c_str());
+ APPEND_FMT_LN(thing.text, "const char* %s[] = {", arrayName.c_str());
for (auto& elm : decl.elements) {
if (useHeruistics && elm.name.ends_with("COUNT")) {
continue;
}
- APPEND_SPRINTF(thing.text, "\"%s\",\n", elm.name.c_str());
+ APPEND_FMT_LN(thing.text, "\"%s\",", elm.name.c_str());
}
- thing.text += "};\n";
+ APPEND_LIT_LN(thing.text, "};");
out.AddOutputThing(std::move(thing));
return arrayName;
@@ -277,9 +277,9 @@ void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMet
bool useExcludeHeuristics = options.IsSet(EMGO_ExcludeUseHeuristics);
if (options.IsSet(EMGO_ToString)) {
- // Generate name lookup table
+ // Generate value -> string lookup table and function
- switch (decl.CalcPattern()) {
+ switch (decl.GetPattern()) {
case EVP_Continuous: {
auto arrayName = GenerateEnumStringArray(out, decl, useExcludeHeuristics);
int minVal = decl.elements.front().value;
@@ -293,25 +293,57 @@ void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMet
}
CodegenOutputThing lookupFunction;
- APPEND_SPRINTF(lookupFunction.text, "std::string_view Stringify%s(%s value) {\n", decl.name.c_str(), decl.name.c_str());
- APPEND_SPRINTF(lookupFunction.text, " if (value < 0 || value >= %d) return {};\n", maxVal);
- APPEND_SPRINTF(lookupFunction.text, " return %s[value - %d];\n", arrayName.c_str(), minVal);
- lookupFunction.text += "}\n";
+ auto& o = lookupFunction.text;
+ APPEND_FMT_LN(o, "std::string_view EnumToString_%s(%s value) {", decl.name.c_str(), decl.name.c_str());
+ APPEND_FMT_LN(o, " if (value < 0 || value >= %d) return {};", maxVal);
+ APPEND_FMT_LN(o, " return %s[value - %d];", arrayName.c_str(), minVal);
+ APPEND_LIT_LN(o, "}");
out.AddOutputThing(std::move(lookupFunction));
} break;
case EVP_Bits: {
auto arrayName = GenerateEnumStringArray(out, decl, useExcludeHeuristics);
+ // TODO
} break;
case EVP_Random: {
auto mapName = GenerateEnumStringMap(out, decl, useExcludeHeuristics);
+ // TODO
} break;
case EVP_COUNT: break;
}
}
+
+ if (options.IsSet(EMGO_FromString)) {
+ // Generate string -> value lookup table
+ char mapName[1024];
+ 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());
+ }
+ APPEND_LIT_LN(o1, "};");
+
+ // Generate lookup function
+ CodegenOutputThing lookupFunction;
+ auto& o2 = lookupFunction.text;
+ APPEND_FMT_LN(o2, "std::optional<%s> EnumFromString_%s(std::string_view value) {", decl.name.c_str(), decl.name.c_str());
+ APPEND_FMT_LN(o2, " auto iter = %s.find(value);", mapName);
+ APPEND_FMT_LN(o2, " if (iter != %s.end()) {", mapName);
+ APPEND_LIT_LN(o2, " return iter->second;");
+ APPEND_LIT_LN(o2, " } else {");
+ APPEND_LIT_LN(o2, " return {};");
+ APPEND_LIT_LN(o2, " }");
+ APPEND_LIT_LN(o2, "}");
+
+ out.AddOutputThing(std::move(lookupTable));
+ out.AddOutputThing(std::move(lookupFunction));
+ }
}
void HandleInputFile(AppState& state, std::string_view source) {
@@ -499,7 +531,7 @@ void HandleInputFile(AppState& state, std::string_view source) {
printf("[WARNING] unbalanced brace at end of file.");
}
- state.mainOutput.MergeContents(std::move(fileOutput));
+ state.sourceOutput.MergeContents(std::move(fileOutput));
}
std::string ReadFileAtOnce(const fs::path& path) {
@@ -577,17 +609,29 @@ int main(int argc, char* argv[]) {
AppState state;
+ state.sourceOutput.AddOutputThing(CodegenOutputThing{
+ .text = &R"""(
+// This file is generated. Any changes will be overidden when building.
+
+#include <frozen/string.h>
+#include <frozen/unordered_map.h>
+#include <optional>
+#include <string_view>
+using namespace std::literals;
+ )"""[1],
+ });
+
// If no cli is provided (argv[0] conventionally but not mandatorily the cli), this will do thing
// Otherwise, start with the 2nd element in the array, which is the 1st actual argument
if (argc < 2) {
// NOTE: keep in sync with various enum options and parser code
printf(&R"""(
- USAGE: codegen.exe <output path> [<opcode>:<input path>]...
- where <output path>: the _file_ to write generated contents to
- <opcode> is one of:
- "single" process this <input path> file only
- "rec" starting at the given directory <input path>, recursively process all .h .c .hpp .cpp files
- )"""[1]);
+USAGE: codegen.exe <output path> [<opcode>:<input path>]...
+where <output path>: the _file_ to write generated contents to
+ <opcode> is one of:
+ "single" process this <input path> file only
+ "rec" starting at the given directory <input path>, recursively process all .h .c .hpp .cpp files
+)"""[1]);
return -1;
}
@@ -615,7 +659,7 @@ int main(int argc, char* argv[]) {
return -1;
}
DEFER { fclose(outputFile); };
- state.mainOutput.Write(outputFile);
+ state.sourceOutput.Write(outputFile);
}
return 0;
diff --git a/buildtools/codegen/tests/examples/TestEnum.hpp b/buildtools/codegen/tests/examples/TestEnum.hpp
index c498cd9..6b4ab33 100644
--- a/buildtools/codegen/tests/examples/TestEnum.hpp
+++ b/buildtools/codegen/tests/examples/TestEnum.hpp
@@ -5,14 +5,14 @@ enum MyEnum {
EnumElement2,
EnumElement3,
};
-BRUSSEL_ENUM(MyEnum, ToString);
+BRUSSEL_ENUM(MyEnum, ToString FromString);
enum CountedEnumAll {
CEA_Foo,
CEA_Bar,
CEA_COUNT,
};
-BRUSSEL_ENUM(CountedEnumAll, ToString);
+BRUSSEL_ENUM(CountedEnumAll, ToString FromString);
enum CountedEnum {
CE_Foo,
@@ -20,4 +20,4 @@ enum CountedEnum {
CE_FooBar,
CE_COUNT,
};
-BRUSSEL_ENUM(CountedEnum, ToString ExcludeHeuristics);
+BRUSSEL_ENUM(CountedEnum, ToString FromString ExcludeHeuristics);