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.cpp121
1 files changed, 99 insertions, 22 deletions
diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp
index c1559ec..1431ae5 100644
--- a/source/20-codegen-compiler/main.cpp
+++ b/source/20-codegen-compiler/main.cpp
@@ -1,7 +1,8 @@
#include "CodegenConfig.hpp"
#include "CodegenDecl.hpp"
-#include "CodegenInput.hpp"
#include "CodegenLexer.hpp"
+#include "CodegenModel.hpp"
+#include "CodegenModelArchive.hpp"
#include "CodegenOutput.hpp"
#include "CodegenUtils.hpp"
@@ -28,7 +29,9 @@ namespace fs = std::filesystem;
// TODO support codegen target in .cpp files
struct AppState {
+ /*nullable*/ CodegenModelArchive* modelArchive = nullptr;
std::string_view outputDir;
+ std::string_view databaseFilePath;
};
FSTR_LUT_DECL(ClexNames, CLEX_eof, CLEX_ext_COUNT) {
@@ -511,7 +514,7 @@ struct NamespaceStackframe {
};
struct ParserState {
- CodegenInput input;
+ CodegenModel model;
CodegenOutput headerOutput;
CodegenOutput sourceOutput;
CodegenOutput standaloneSourceOutput;
@@ -663,7 +666,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
break;
}
- ps.currentNamespace = ps.input.AddNamespace(DeclNamespace{
+ ps.currentNamespace = ps.model.AddNamespace(DeclNamespace{
.container = ps.currentNamespace,
.name = tokens[idx].text,
});
@@ -723,7 +726,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
// TODO support namespace qualified names
auto baseClassFullname = Utils::MakeFullName(idenTok.text, ps.currentNamespace);
- auto baseClassDecl = ps.input.FindStruct(baseClassFullname);
+ auto baseClassDecl = ps.model.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);
@@ -750,7 +753,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
{
// Get a pointer to the decl inside CodegenInput's storage
- auto decl = ps.input.AddStruct(std::move(fullname), std::move(structDecl));
+ auto decl = ps.model.AddStruct(std::move(fullname), std::move(structDecl));
ps.currentStruct = decl;
ps.currentStructBraceDepth = ps.currentBraceDepth;
}
@@ -780,6 +783,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
DeclEnum enumDecl;
enumDecl.container = ps.currentNamespace;
enumDecl.underlyingType = EUT_Int32; // TODO
+ enumDecl.underlyingTypeStr = "int";
enumDecl.name = name;
// Temporarily bind the pointers to local variable, HandleDirectiveEnum() and other functions expect these to the set
@@ -841,7 +845,7 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
}
{
- auto decl = ps.input.AddEnum(std::move(fullname), std::move(enumDecl));
+ auto decl = ps.model.AddEnum(std::move(fullname), std::move(enumDecl));
ps.currentEnum = decl;
ps.currentEnumBraceDepth = ps.currentBraceDepth;
}
@@ -1064,15 +1068,20 @@ void HandleInputFile(AppState& as, std::string_view filenameStem, std::string_vi
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);
+
+ if (as.modelArchive) {
+ as.modelArchive->Store(ps.model);
+ }
}
enum InputOpcode {
IOP_ProcessSingleFile,
IOP_ProcessRecursively,
+ IOP_ProcessFileList,
IOP_COUNT,
};
-void HandleArgument(AppState& state, InputOpcode opcode, std::string_view operand) {
+void HandleArgument(AppState& as, InputOpcode opcode, std::string_view operand) {
switch (opcode) {
case IOP_ProcessSingleFile: {
DEBUG_PRINTF("Processing single file %.*s\n", PRINTF_STRING_VIEW(operand));
@@ -1080,7 +1089,7 @@ void HandleArgument(AppState& state, InputOpcode opcode, std::string_view operan
fs::path path(operand);
auto filenameStem = path.stem().string();
auto source = Utils::ReadFileAsString(path);
- HandleInputFile(state, filenameStem, source);
+ HandleInputFile(as, filenameStem, source);
} break;
case IOP_ProcessRecursively: {
@@ -1105,7 +1114,33 @@ void HandleArgument(AppState& state, InputOpcode opcode, std::string_view operan
auto filenameStem = pathStem.string();
auto source = Utils::ReadFileAsString(path);
- HandleInputFile(state, filenameStem, source);
+ HandleInputFile(as, filenameStem, source);
+ }
+ } break;
+
+ case IOP_ProcessFileList: {
+ DEBUG_PRINTF("Processing file list %.*s\n", PRINTF_STRING_VIEW(operand));
+
+ fs::path fileListPath(operand);
+ auto fileList = Utils::OpenCstdioFile(fileListPath, Utils::Read);
+ if (!fileList) {
+ // NOTE: need this because our dirty-file-list generation algorithm in CMakeLists.txt doesn't produce a file when nothing is changed
+ DEBUG_PRINTF("File-list file does not exist, silently skipping.\n");
+ break;
+ }
+ DEFER { fclose(fileList); };
+
+ std::string line;
+ while (Utils::ReadCstdioLine(fileList, line)) {
+ // Remove '\n'
+ line.pop_back();
+
+ DEBUG_PRINTF("Processing file in list %.*s\n", line.c_str());
+
+ fs::path path(line);
+ auto filenameStem = path.stem().string();
+ auto source = Utils::ReadFileAsString(path);
+ HandleInputFile(as, filenameStem, source);
}
} break;
@@ -1118,9 +1153,11 @@ InputOpcode ParseInputOpcode(std::string_view text) {
return IOP_ProcessSingleFile;
} else if (text == "rec"sv) {
return IOP_ProcessRecursively;
+ } else if (text == "fileList"sv) {
+ return IOP_ProcessFileList;
} else {
- DEBUG_PRINTF("Unknown input opcode %s\n", text.data());
- throw std::runtime_error("Unknown input opcode");
+ INPLACE_FMT(msg, "Unknown input opcode %s\n", text.data());
+ throw std::runtime_error(msg);
}
}
@@ -1139,15 +1176,16 @@ int main(int argc, char* argv[]) {
// option 1: use cxxopts and positional arguments
// option 2: take one argument only, being a json objecet
- AppState state;
+ AppState as;
// 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) {
+ if (argc <= 1) {
// 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 directory to write generated contents to. This will NOT automatically create the directory.
+USAGE: codegen.exe --output-dir=<path> [--database=<path>] [<opcode>:<input path>]...
+where --output-dir=<path>: the *directory* to write generated contents to. This will NOT automatically create the directory.
+ --database=<path>: the *file* to use for the code model database.
<opcode> is one of:
"single" process this <input path> file only
"rec" starting at the given directory <input path>, recursively process all .h .hpp files
@@ -1155,13 +1193,52 @@ where <output path>: the directory to write generated contents to. This will N
return -1;
}
- state.outputDir = std::string_view(argv[1]);
- DEBUG_PRINTF("Outputting to directory %.*s.\n", PRINTF_STRING_VIEW(state.outputDir));
+ // Named argument pass
+ robin_hood::unordered_map<std::string_view, std::string_view*> namedArguments{
+ { "output-dir"sv, &as.outputDir },
+ { "database"sv, &as.databaseFilePath },
+ };
+ for (int i = 1; i < argc; ++i) {
+ std::string_view arg(argv[i]);
+ if (!arg.starts_with("--")) {
+ // Convention: a "--" argument indicates everything afterwords are positional arguments
+ if (arg.size() == 2) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ size_t equalLoc = arg.find('=');
+ auto oper = arg.substr(/*--*/ 2, equalLoc - 2);
+ auto iter = namedArguments.find(oper);
+ if (iter != namedArguments.end()) {
+ auto storage = iter->second;
+ if (storage) {
+ if (equalLoc == std::string_view::npos) {
+ *storage = ""sv;
+ } else {
+ *storage = arg.substr(equalLoc + 1);
+ }
+ }
+ }
+ }
+
+ DEBUG_PRINTF("Outputting to directory %.*s.\n", PRINTF_STRING_VIEW(as.outputDir));
+ DEBUG_PRINTF("Databse file: %.*s.\n", PRINTF_STRING_VIEW(as.databaseFilePath));
+
+ // TODO model archive is broken right now, see each TODO in CodegenModel.cpp
+ // CodegenModelArchive archive(as.databaseFilePath);
+ // as.modelArchive = &archive;
+
+ // Positional argument pass
+ for (int i = 1; i < argc; ++i) {
+ std::string_view arg(argv[i]);
+ if (arg.starts_with("--")) {
+ continue;
+ }
- for (int i = 2; i < argc; ++i) {
- const char* argRaw = argv[i];
- std::string_view arg(argRaw);
- DEBUG_PRINTF("Processing input command %s\n", argRaw);
+ DEBUG_PRINTF("Processing input command %s\n", argv[i]);
auto separatorLoc = arg.find(':');
if (separatorLoc != std::string_view::npos) {
@@ -1169,7 +1246,7 @@ where <output path>: the directory to write generated contents to. This will N
auto opcode = ParseInputOpcode(opcodeString);
auto operand = arg.substr(separatorLoc + 1);
- HandleArgument(state, opcode, operand);
+ HandleArgument(as, opcode, operand);
}
}