aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-05-29 21:57:53 -0700
committerrtk0c <[email protected]>2022-05-29 21:57:53 -0700
commit6f29abe5571eb68207986bdadb97b207264ac958 (patch)
treee30d5d36e550e8f08cc832f905c97cbeba3515aa
parent5112858f9a4adcf76240bcddad19179a5c56d4f3 (diff)
Changeset: 49 Convert codegen output to use template specialization
-rw-r--r--CMakeLists.txt45
-rw-r--r--README.md9
-rw-r--r--buildtools/codegen/CodegenOutput.inl3
-rw-r--r--buildtools/codegen/main.cpp144
-rw-r--r--buildtools/codegen/tests/examples/TestEnum.hpp.txt (renamed from buildtools/codegen/tests/examples/TestEnum.hpp)2
-rw-r--r--source-codegen-base/MetadataBase.hpp14
6 files changed, 157 insertions, 60 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19518bf..0e8dc26 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,10 +15,10 @@ add_subdirectory(3rdparty/tracy)
# ==============================================================================
-file(GLOB_RECURSE commonthings_SOURCES source-common/*.c source-common/*.cpp)
-add_library(commonthings OBJECT ${commonthings_SOURCES})
+file(GLOB_RECURSE things_common_SOURCES source-common/*.c source-common/*.cpp)
+add_library(things_common OBJECT ${things_common_SOURCES})
-set_target_properties(commonthings PROPERTIES
+set_target_properties(things_common PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
@@ -27,8 +27,8 @@ set_target_properties(commonthings PROPERTIES
UNITY_BUILD OFF
)
-target_include_directories(commonthings PUBLIC source-common)
-target_link_libraries(commonthings PUBLIC
+target_include_directories(things_common PUBLIC source-common)
+target_link_libraries(things_common PUBLIC
# External dependencies
${CONAN_LIBS}
glm::glm
@@ -37,25 +37,45 @@ target_link_libraries(commonthings PUBLIC
# ==============================================================================
# NOTE: delibrately not recursive, see README.md in the folder for details
-file(GLOB meta_codegen_SOURCES buildtools/codegen/*.c buildtools/codegen/*.cpp)
-add_executable(meta_codegen ${meta_codegen_SOURCES})
+file(GLOB codegen_SOURCES buildtools/codegen/*.c buildtools/codegen/*.cpp)
+add_executable(codegen ${codegen_SOURCES})
-set_target_properties(meta_codegen PROPERTIES
+set_target_properties(codegen PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
UNITY_BUILD OFF
)
-target_link_libraries(meta_codegen PRIVATE
+target_link_libraries(codegen PRIVATE
# External dependencies
${CONAN_LIBS}
# Project internal components
- commonthings
+ things_common
)
-target_flag_rtti(meta_codegen OFF)
+target_flag_rtti(codegen OFF)
+
+# ==============================================================================
+
+file(GLOB_RECURSE things_codegen_base_SOURCES source-common/*.c source-common/*.cpp)
+add_library(things_codegen_base OBJECT ${things_codegen_base_SOURCES})
+
+set_target_properties(things_common PROPERTIES
+ CXX_STANDARD 20
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+)
+
+target_include_directories(things_codegen_base PUBLIC source-codegen-base)
+target_link_libraries(things_codegen_base PUBLIC
+ # External dependencies
+ ${CONAN_LIBS}
+
+ # Project internal components
+ things_common
+)
# ==============================================================================
@@ -95,7 +115,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
tracy
# Project internal components
- commonthings
+ things_common
+ things_metadata
)
option(BRUSSEL_ENABLE_PROFILING "Whether profiling support is enabled or not." OFF)
diff --git a/README.md b/README.md
index dc0b4c1..5caf9f7 100644
--- a/README.md
+++ b/README.md
@@ -5,3 +5,12 @@
+ [Urho3D](https://urho3d.io/)
+ [godot](https://godotengine.org/)
+ Everything else in `3rdparty/`
+
+## Project Structure
+- `buildtools`
+ - `cmake`: CMake scripts consumed by the root `CMakeLists.txt`.
+ - `codegen`: Code generator similar to Qt MOC.
+ Currently runs on: `source`.
+- `source-common`: Code that's compiled as a part of all targets. Check each target's build script for details.
+- `source-codegen-base`: Code that's consumed along with output of `buildtools/codegen`.
+- `source`: The main game.
diff --git a/buildtools/codegen/CodegenOutput.inl b/buildtools/codegen/CodegenOutput.inl
index d1f2e50..edd9abc 100644
--- a/buildtools/codegen/CodegenOutput.inl
+++ b/buildtools/codegen/CodegenOutput.inl
@@ -38,9 +38,8 @@ public:
std::move(other.mOutFunctions.begin(), other.mOutFunctions.end(), std::back_inserter(this->mOutFunctions));
}
- void Write(FILE* file) {
+ void Write(FILE* file) const {
for (auto& thing : mOutThings) {
- WRITE_LIT(file, "// Output thing\n");
fwrite(thing.text.c_str(), sizeof(char), thing.text.size(), file);
WRITE_LIT(file, "\n");
}
diff --git a/buildtools/codegen/main.cpp b/buildtools/codegen/main.cpp
index df52b66..e759c31 100644
--- a/buildtools/codegen/main.cpp
+++ b/buildtools/codegen/main.cpp
@@ -273,7 +273,7 @@ std::string GenerateEnumStringMap(CodegenOutput& out, const DeclEnum& decl, bool
return mapName;
}
-void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMetaGenOptions> options) {
+void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const DeclEnum& decl, EnumFlags<EnumMetaGenOptions> options) {
bool useExcludeHeuristics = options.IsSet(EMGO_ExcludeUseHeuristics);
if (options.IsSet(EMGO_ToString)) {
@@ -281,7 +281,7 @@ void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMet
switch (decl.GetPattern()) {
case EVP_Continuous: {
- auto arrayName = GenerateEnumStringArray(out, decl, useExcludeHeuristics);
+ auto arrayName = GenerateEnumStringArray(sourceOut, decl, useExcludeHeuristics);
int minVal = decl.elements.front().value;
int maxVal = decl.elements.back().value;
if (useExcludeHeuristics &&
@@ -292,23 +292,30 @@ void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMet
maxVal = decl.elements[decl.elements.size() - 2].value;
}
- CodegenOutputThing lookupFunction;
- 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, "}");
+ CodegenOutputThing lookupFunctionDecl;
+ auto& o1 = lookupFunctionDecl.text;
+ APPEND_LIT_LN(o1, "template <>");
+ APPEND_FMT_LN(o1, "std::string_view Metadata::EnumToString<%s>(%s);", decl.name.c_str(), decl.name.c_str());
- out.AddOutputThing(std::move(lookupFunction));
+ 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, "}");
+
+ headerOut.AddOutputThing(std::move(lookupFunctionDecl));
+ sourceOut.AddOutputThing(std::move(lookupFunctionDef));
} break;
case EVP_Bits: {
- auto arrayName = GenerateEnumStringArray(out, decl, useExcludeHeuristics);
+ auto arrayName = GenerateEnumStringArray(sourceOut, decl, useExcludeHeuristics);
// TODO
} break;
case EVP_Random: {
- auto mapName = GenerateEnumStringMap(out, decl, useExcludeHeuristics);
+ auto mapName = GenerateEnumStringMap(sourceOut, decl, useExcludeHeuristics);
// TODO
} break;
@@ -330,19 +337,26 @@ void GenerateForEnum(CodegenOutput& out, const DeclEnum& decl, EnumFlags<EnumMet
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, "}");
+ CodegenOutputThing lookupFunctionDecl;
+ auto& o2 = lookupFunctionDecl.text;
+ APPEND_LIT_LN(o2, "template <>");
+ APPEND_FMT_LN(o2, "std::optional<%s> Metadata::EnumFromString<%s>(std::string_view);", decl.name.c_str(), decl.name.c_str());
+
+ 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, "}");
- out.AddOutputThing(std::move(lookupTable));
- out.AddOutputThing(std::move(lookupFunction));
+ sourceOut.AddOutputThing(std::move(lookupTable));
+ headerOut.AddOutputThing(std::move(lookupFunctionDecl));
+ sourceOut.AddOutputThing(std::move(lookupFunctionDef));
}
}
@@ -358,8 +372,9 @@ void HandleInputFile(AppState& state, std::string_view source) {
printf("END tokens\n");
#endif
- CodegenInput fileInput;
- CodegenOutput fileOutput;
+ CodegenInput cgInput;
+ auto& cgHeaderOutput = state.headerOutput;
+ auto& cgSourceOutput = state.sourceOutput;
int bracePairDepth = 0;
while (idx < tokens.size()) {
@@ -444,7 +459,7 @@ void HandleInputFile(AppState& state, std::string_view source) {
++idx;
}
- fileInput.AddEnum(std::move(enumDecl));
+ cgInput.AddEnum(std::move(enumDecl));
goto endIdenCase;
}
@@ -480,7 +495,7 @@ void HandleInputFile(AppState& state, std::string_view source) {
}
auto& enumName = argList[0][0]->text;
- auto enumDecl = fileInput.FindEnumByName(enumName);
+ auto enumDecl = cgInput.FindEnumByName(enumName);
if (!enumDecl) {
printf("[ERROR] BRUSSEL_ENUM: referring to non-existent enum '%s'\n", enumName.c_str());
break;
@@ -497,7 +512,7 @@ void HandleInputFile(AppState& state, std::string_view source) {
}
}
- GenerateForEnum(fileOutput, *enumDecl, options);
+ GenerateForEnum(cgHeaderOutput, cgSourceOutput, *enumDecl, options);
idx = newIdx;
incrementTokenIdx = false;
@@ -530,8 +545,6 @@ void HandleInputFile(AppState& state, std::string_view source) {
if (bracePairDepth != 0) {
printf("[WARNING] unbalanced brace at end of file.");
}
-
- state.sourceOutput.MergeContents(std::move(fileOutput));
}
std::string ReadFileAtOnce(const fs::path& path) {
@@ -596,6 +609,23 @@ InputOpcode ParseInputOpcode(std::string_view text) {
return IOP_COUNT;
}
+bool WriteOutputFile(const CodegenOutput& output, const char* dirPath, const char* fileName) {
+ char path[2048];
+ snprintf(path, sizeof(path), "%s/%s", dirPath, fileName);
+
+ auto outputFile = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
+ if (!outputFile) {
+ printf("[ERROR] unable to open output file %s", path);
+ return false;
+ }
+ DEFER { fclose(outputFile); };
+
+ DEBUG_PRINTF("Writing output %s", path);
+ output.Write(outputFile);
+
+ return true;
+}
+
int main(int argc, char* argv[]) {
STR_LUT_INIT(ClexNames);
BSTR_LUT_INIT(CppKeyword);
@@ -609,14 +639,22 @@ int main(int argc, char* argv[]) {
AppState state;
+ state.headerOutput.AddOutputThing(CodegenOutputThing{
+ .text = &R"""(
+// This file is generated. Any changes will be overidden when building.
+#pragma once
+
+#include <MetadataBase.hpp>
+)"""[1],
+ });
+
state.sourceOutput.AddOutputThing(CodegenOutputThing{
.text = &R"""(
// This file is generated. Any changes will be overidden when building.
+#include "MetadataImpl.hpp"
#include <frozen/string.h>
#include <frozen/unordered_map.h>
-#include <optional>
-#include <string_view>
using namespace std::literals;
)"""[1],
});
@@ -627,7 +665,7 @@ using namespace std::literals;
// 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
+where <output path>: the directory to write generated contents to. This will NOT automatically create the directory.
<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
@@ -635,8 +673,33 @@ where <output path>: the _file_ to write generated contents to
return -1;
}
- const char* outputFilePath = argv[1];
- DEBUG_PRINTF("Outputting to file %s.\n", outputFilePath);
+ const char* outputDir = argv[1];
+ DEBUG_PRINTF("Outputting to directory %s.\n", outputDirPath);
+
+ {
+ char path[2048];
+ snprintf(path, sizeof(path), "%s/%s", outputDir, "Metadata.hpp");
+
+ auto fileContent = R"""(
+// This file is generated. Any changes will be overidden when building.
+// This file is an umbrella header for all generated metadata. End users simply include this file to get access to everything.
+#pragma once
+
+#include <MetadataBase.hpp>
+
+#include <generated/MetadataImpl.hpp>
+)"""sv.substr(1); // Get rid of the \n at the beginning
+
+ auto file = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
+ if (!file) {
+ printf("[ERROR] unable to open output file %s", path);
+ return -1;
+ }
+ DEFER { fclose(file); };
+
+ DEBUG_PRINTF("Writing output file %s", path);
+ fwrite(fileContent.data(), sizeof(decltype(fileContent)::value_type), fileContent.size(), file);
+ }
for (int i = 2; i < argc; ++i) {
std::string_view arg(argv[i]);
@@ -652,15 +715,8 @@ where <output path>: the _file_ to write generated contents to
}
}
- {
- auto outputFile = Utils::OpenCstdioFile(outputFilePath, Utils::WriteTruncate);
- if (!outputFile) {
- printf("[ERROR] unable to open output file %s", outputFilePath);
- return -1;
- }
- DEFER { fclose(outputFile); };
- state.sourceOutput.Write(outputFile);
- }
+ WriteOutputFile(state.headerOutput, outputDir, "MetadataImpl.hpp");
+ WriteOutputFile(state.sourceOutput, outputDir, "MetadataImpl.cpp");
return 0;
}
diff --git a/buildtools/codegen/tests/examples/TestEnum.hpp b/buildtools/codegen/tests/examples/TestEnum.hpp.txt
index 6b4ab33..e596c5e 100644
--- a/buildtools/codegen/tests/examples/TestEnum.hpp
+++ b/buildtools/codegen/tests/examples/TestEnum.hpp.txt
@@ -1,5 +1,3 @@
-#include "MacrosCodegen.hpp"
-
enum MyEnum {
EnumElement1,
EnumElement2,
diff --git a/source-codegen-base/MetadataBase.hpp b/source-codegen-base/MetadataBase.hpp
new file mode 100644
index 0000000..59c61da
--- /dev/null
+++ b/source-codegen-base/MetadataBase.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <optional>
+#include <string_view>
+
+namespace Metadata {
+
+template <class TEnum>
+std::string_view EnumToString(TEnum value) = delete;
+
+template <class TEnum>
+std::optional<TEnum> EnumFromString(std::string_view str) = delete;
+
+} // namespace Metadata