2018-06-26 00:10:44 +02:00
|
|
|
#include "./binaryserializationcodegenerator.h"
|
2017-10-25 17:41:19 +02:00
|
|
|
#include "./codefactory.h"
|
2017-10-28 16:31:07 +02:00
|
|
|
#include "./jsonserializationcodegenerator.h"
|
2017-10-25 17:41:19 +02:00
|
|
|
|
|
|
|
#include "resources/config.h"
|
|
|
|
|
|
|
|
#include <c++utilities/application/argumentparser.h>
|
|
|
|
#include <c++utilities/application/commandlineutils.h>
|
2017-11-17 21:42:49 +01:00
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
2017-10-25 17:41:19 +02:00
|
|
|
#include <c++utilities/io/ansiescapecodes.h>
|
|
|
|
#include <c++utilities/io/misc.h>
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
2018-02-02 18:21:04 +01:00
|
|
|
#include <unordered_map>
|
2017-10-25 17:41:19 +02:00
|
|
|
|
|
|
|
using namespace std;
|
2019-06-10 22:46:06 +02:00
|
|
|
using namespace CppUtilities;
|
|
|
|
using namespace CppUtilities::EscapeCodes;
|
2017-10-25 17:41:19 +02:00
|
|
|
using namespace ReflectiveRapidJSON;
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
SET_APPLICATION_INFO;
|
|
|
|
CMD_UTILS_CONVERT_ARGS_TO_UTF8;
|
|
|
|
|
|
|
|
// setup argument parser
|
|
|
|
ArgumentParser parser;
|
2018-01-20 19:32:46 +01:00
|
|
|
OperationArgument generateArg("generate", '\0', "runs the code generator");
|
2017-11-06 15:31:21 +01:00
|
|
|
generateArg.setImplicit(true);
|
2018-01-20 18:10:58 +01:00
|
|
|
ConfigValueArgument inputFileArg("input-file", '\0', "specifies the input file", { "path" });
|
2017-11-23 15:18:44 +01:00
|
|
|
inputFileArg.setRequired(true);
|
2018-01-20 19:32:46 +01:00
|
|
|
ConfigValueArgument outputFileArg("output-file", '\0', "specifies the output file", { "path" });
|
|
|
|
Argument generatorsArg("generators", '\0', "specifies the generators (by default all generators are enabled)");
|
2019-10-05 01:36:21 +02:00
|
|
|
generatorsArg.setValueNames({ "json", "binary" });
|
|
|
|
generatorsArg.setPreDefinedCompletionValues("json binary");
|
2017-10-25 17:41:19 +02:00
|
|
|
generatorsArg.setRequiredValueCount(Argument::varValueCount);
|
|
|
|
generatorsArg.setCombinable(true);
|
2018-01-20 19:32:46 +01:00
|
|
|
ConfigValueArgument clangOptionsArg("clang-opt", '\0', "specifies arguments/options to be passed to Clang", { "option" });
|
2017-11-06 21:25:45 +01:00
|
|
|
clangOptionsArg.setRequiredValueCount(Argument::varValueCount);
|
2018-02-03 15:47:25 +01:00
|
|
|
ConfigValueArgument errorResilientArg("error-resilient", '\0', "turns most errors into warnings");
|
2017-10-25 17:41:19 +02:00
|
|
|
HelpArgument helpArg(parser);
|
|
|
|
NoColorArgument noColorArg;
|
2018-02-03 15:47:25 +01:00
|
|
|
generateArg.setSubArguments({ &inputFileArg, &outputFileArg, &generatorsArg, &clangOptionsArg, &errorResilientArg });
|
2017-11-11 12:37:24 +01:00
|
|
|
JsonSerializationCodeGenerator::Options jsonOptions;
|
|
|
|
jsonOptions.appendTo(&generateArg);
|
2018-06-23 17:25:30 +02:00
|
|
|
BinarySerializationCodeGenerator::Options binaryOptions;
|
|
|
|
binaryOptions.appendTo(&generateArg);
|
2017-11-06 15:31:21 +01:00
|
|
|
parser.setMainArguments({ &generateArg, &noColorArg, &helpArg });
|
2017-10-25 17:41:19 +02:00
|
|
|
|
|
|
|
// parse arguments
|
2019-06-10 22:46:06 +02:00
|
|
|
parser.parseArgs(argc, argv, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
|
2017-11-23 15:18:44 +01:00
|
|
|
if (helpArg.isPresent() || !generateArg.isPresent()) {
|
2017-10-25 17:41:19 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup output stream
|
|
|
|
ostream *os = nullptr;
|
|
|
|
try {
|
|
|
|
ofstream outputFile;
|
|
|
|
if (outputFileArg.isPresent()) {
|
|
|
|
outputFile.exceptions(ios_base::badbit | ios_base::failbit);
|
|
|
|
outputFile.open(outputFileArg.values(0).front(), ios_base::out | ios_base::trunc | ios_base::binary);
|
|
|
|
os = &outputFile;
|
|
|
|
} else {
|
|
|
|
os = &cout;
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:42:49 +01:00
|
|
|
// compose options passed to the clang tool invocation
|
|
|
|
vector<string> clangOptions;
|
2017-11-18 00:27:25 +01:00
|
|
|
if (clangOptionsArg.isPresent()) {
|
2017-11-17 21:42:49 +01:00
|
|
|
// add additional options specified via CLI argument
|
2017-11-18 00:27:25 +01:00
|
|
|
for (const auto *const value : clangOptionsArg.values(0)) {
|
2017-11-17 21:42:49 +01:00
|
|
|
// split options by ";" - not nice but this eases using CMake generator expressions
|
|
|
|
const auto splittedValues(splitString<vector<string>>(value, ";", EmptyPartsTreat::Omit));
|
2017-11-18 00:27:25 +01:00
|
|
|
for (const auto &splittedValue : splittedValues) {
|
2017-11-17 21:42:49 +01:00
|
|
|
clangOptions.emplace_back(move(splittedValue));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-02 18:21:04 +01:00
|
|
|
// instantiate the code factory and add generators to it
|
2017-11-18 00:27:25 +01:00
|
|
|
CodeFactory factory(parser.executable(), inputFileArg.values(0), clangOptions, *os);
|
2018-02-03 15:47:25 +01:00
|
|
|
factory.setErrorResilient(errorResilientArg.isPresent());
|
2018-02-02 18:21:04 +01:00
|
|
|
// add specified generators if the --generator argument is present; otherwise add default generators
|
2017-10-25 17:41:19 +02:00
|
|
|
if (generatorsArg.isPresent()) {
|
2018-02-03 15:47:25 +01:00
|
|
|
// define mapping of generator names to generator constructors (add new generators here!)
|
2018-02-02 18:21:04 +01:00
|
|
|
// clang-format off
|
|
|
|
const std::unordered_map<std::string, std::function<void()>> generatorsByName{
|
2018-06-23 17:25:30 +02:00
|
|
|
{ "json", factory.bindGenerator<JsonSerializationCodeGenerator, const JsonSerializationCodeGenerator::Options &>(jsonOptions) },
|
|
|
|
{ "binary", factory.bindGenerator<BinarySerializationCodeGenerator, const BinarySerializationCodeGenerator::Options &>(binaryOptions) },
|
2018-02-02 18:21:04 +01:00
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
2017-10-25 17:41:19 +02:00
|
|
|
// find and construct generators by name
|
|
|
|
for (const char *generatorName : generatorsArg.values(0)) {
|
2018-02-02 18:21:04 +01:00
|
|
|
try {
|
|
|
|
generatorsByName.at(generatorName)();
|
|
|
|
} catch (const out_of_range &) {
|
|
|
|
cerr << Phrases::Error << "The specified generator \"" << generatorName << "\" does not exist." << Phrases::End;
|
|
|
|
cerr << "Available generators:";
|
|
|
|
for (const auto &generators : generatorsByName) {
|
|
|
|
cerr << ' ' << generators.first;
|
|
|
|
}
|
|
|
|
cerr << endl;
|
2017-10-25 17:41:19 +02:00
|
|
|
return -5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// add default generators
|
2017-11-06 15:31:21 +01:00
|
|
|
factory.addGenerator<JsonSerializationCodeGenerator>(jsonOptions);
|
2017-10-25 17:41:19 +02:00
|
|
|
}
|
|
|
|
|
2017-10-27 17:38:57 +02:00
|
|
|
// read AST elements from input files and run the code generator
|
|
|
|
if (!factory.run()) {
|
|
|
|
cerr << Phrases::Error << "Errors occured." << Phrases::EndFlush;
|
2017-10-25 17:41:19 +02:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2019-03-13 19:10:29 +01:00
|
|
|
} catch (const std::ios_base::failure &failure) {
|
|
|
|
const char *errorMessage = failure.what();
|
2017-10-25 17:41:19 +02:00
|
|
|
if (os) {
|
|
|
|
errorMessage = os->fail() || os->bad() ? "An IO error occured when writing to the output stream." : "An IO error occured.";
|
|
|
|
} else {
|
|
|
|
errorMessage = "An IO error when opening output stream.";
|
|
|
|
}
|
|
|
|
cerr << Phrases::Error << errorMessage << Phrases::EndFlush;
|
|
|
|
return -4;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|