diff options
Diffstat (limited to 'source/20-codegen-compiler/main.cpp')
-rw-r--r-- | source/20-codegen-compiler/main.cpp | 121 |
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); } } |