/*
PIP - Platform Independent Primitives
Code model generator
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
#include "enum.h"
#include "getter.h"
#include "json.h"
#include "metainfo.h"
#include "picli.h"
#include "picodeparser.h"
#include "piiostream.h"
#include "pitranslator.h"
#include "stream.h"
using namespace PICoutManipulators;
bool writeModel(PICodeParser & parser,
PICLI & cli,
const PIString out,
bool meta,
bool enums,
bool streams,
bool json,
bool texts,
bool getters) {
PIString defname = "CCM_" + PIString::fromNumber(out.hash()) + "_H";
PISet inc_files;
for (const PICodeParser::Entity * e: parser.entities)
if (!e->name.startsWith("_PI")) inc_files << e->file;
PIString inc_string;
PIVector incf = inc_files.toVector();
for (const PIString & i: incf) {
if ((i != parser.mainFile()) && (streams || json || texts || getters)) inc_string += "\n#include \"" + i + "\"";
}
PIFile f(out + ".cpp");
f.clear();
if (!f.open(PIIODevice::WriteOnly)) {
piCerr << "Error: can`t open output file \"%1\""_tr("pip_cmg").arg(f.path());
return false;
}
PIIOTextStream ts(&f);
ts << "// Generated by \"PIP Code model generator\" " << PIDateTime::current().toString("dd.MM.yyyy hh:mm:ss\n\n");
ts << "#include \n";
ts << "#include \"" << out << ".h\"\n";
ts << "\nusing namespace PICodeInfo;\n";
Runtime rt{parser, cli, ts};
if (meta || enums || getters) {
if (getters) {
ts << "\n\n// Getter funtions\n";
ts << "\n#define PICODEINFO_OFFSET(type, member) reinterpret_cast(&reinterpret_cast((((type "
"*)nullptr)->member)))\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
makeGetterType(rt, e);
makeGetterValue(rt, e);
makeGetterOffset(rt, e);
}
ts << "\n#undef PICODEINFO_OFFSET\n";
}
ts << "\n\n// Metainformation\n\n__ClassInfo_" << defname << "_Initializer__::__ClassInfo_" << defname << "_Initializer__() {\n";
ts << "\tstatic __ClassInfo_" << defname << "_Initializer__::Content content;\n";
ts << "}\n\n";
ts << "__ClassInfo_" << defname << "_Initializer__::Content::Content() {\n";
ts << "\tauto * ci_ins = PICodeInfo::__Storage__::instance();\n";
if (meta) ts << "\tauto & ci_ci(*ci_ins->classesInfo);\n";
if (enums) ts << "\tauto & ci_ei(*ci_ins->enumsInfo);\n";
if (getters) {
ts << "\tauto & ci_avf(*ci_ins->accessValueFunctions);\n";
ts << "\tauto & ci_atf(*ci_ins->accessTypeFunctions);\n";
ts << "\tauto & ci_aof(*ci_ins->accessOffsetFunctions);\n";
}
if (meta) {
ts << "\tClassInfo * pci = new ClassInfo();\n";
ts << "\tci_ci[\"\"] = pci;\n";
}
if (enums && !parser.enums.isEmpty()) {
ts << "\tEnumInfo * ei;\n";
}
if (meta) {
ts << "\n\n// Classes\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (e->name.startsWith("_PI") || e->is_anonymous) continue;
makeClassInfo(rt, e);
}
}
if (enums) {
ts << "\n// Enums\n";
for (const PICodeParser::Enum & e: parser.enums)
makeEnumInfo(rt, &e);
}
if (getters) {
ts << "\n// Getters\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (!needClassStream(e)) continue;
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
auto cname = toCName(e->name);
ts << "\tci_avf[\"" << e->name << "\"] = getterValue" << cname << ";\n";
ts << "\tci_atf[\"" << e->name << "\"] = getterType" << cname << ";\n";
ts << "\tci_aof[\"" << e->name << "\"] = getterOffset" << cname << ";\n";
}
}
ts << "}\n\n";
ts << "__ClassInfo_" << defname << "_Initializer__::Content::~Content() {\n";
ts << "\tauto * ci_ins = PICodeInfo::__Storage__::instance();\n";
if (meta) ts << "\tauto & ci_ci(*ci_ins->classesInfo);\n";
if (enums) ts << "\tauto & ci_ei(*ci_ins->enumsInfo);\n";
if (getters) {
ts << "\tauto & ci_avf(*ci_ins->accessValueFunctions);\n";
ts << "\tauto & ci_atf(*ci_ins->accessTypeFunctions);\n";
ts << "\tauto & ci_aof(*ci_ins->accessOffsetFunctions);\n";
}
if (meta) {
ts << "\n// Classes clean\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (e->name.startsWith("_PI") || e->is_anonymous) continue;
ts << "\tpiDeleteSafety(ci_ci[\"" << e->name << "\"]);\n";
ts << "\tci_ins->classesInfo->remove(\"" << e->name << "\");\n";
}
}
if (enums) {
ts << "\n// Enums clean\n";
for (const PICodeParser::Enum & e: parser.enums) {
if (e.name.isNotEmpty()) {
ts << "\tpiDeleteSafety(ci_ei[\"" << e.name << "\"]);\n";
ts << "\tci_ins->enumsInfo->remove(\"" << e.name << "\");\n";
}
}
}
if (getters) {
ts << "\n// Getters clean\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (!needClassStream(e)) continue;
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
ts << "\tci_avf.remove(\"" << e->name << "\");\n";
ts << "\tci_atf.remove(\"" << e->name << "\");\n";
ts << "\tci_aof.remove(\"" << e->name << "\");\n";
}
}
ts << "}\n";
}
f.close();
f.setPath(out + ".h");
f.clear();
if (!f.open(PIIODevice::WriteOnly)) {
piCerr << "Error: can`t open output file \"%1\""_tr("pip_cmg").arg(f.path());
return false;
}
ts << "// Generated by \"PIP Code model generator\" " << PIDateTime::current().toString("dd.MM.yyyy hh:mm:ss\n");
ts << "// Execute command:\n";
for (const PIString & _a: cli.rawArguments())
ts << "// \"" << _a << "\"\n";
ts << "\n";
ts << "#ifndef " << defname << "\n#define " << defname << "\n\n";
ts << "#include \n#include ";
if (streams || texts) ts << "\n#include ";
if (json) ts << "\n#include ";
ts << inc_string << "\n";
if (streams) {
ts << "\n\n// Stream operators\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (e->is_anonymous || e->name.startsWith("_PI") ||
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
continue;
if (!makeClassStream(rt, e)) return false;
}
}
if (json) {
ts << "\n\n// JSON serialization\n";
for (const PICodeParser::Entity * e: parser.entities) {
if (e->is_anonymous || e->name.startsWith("_PI") ||
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
continue;
if (!makeClassJSON(rt, e)) return false;
}
}
if (meta || enums || getters) {
ts << "\n\n// Metainformation\n\nclass __ClassInfo_" << defname << "_Initializer__ {\n";
ts << "public:\n";
ts << "\t__ClassInfo_" << defname << "_Initializer__();\n";
ts << "private:\n";
ts << "\tclass Content {\n";
ts << "\tpublic:\n";
ts << "\t\tContent();\n";
ts << "\t\t~Content();\n";
ts << "\t};\n";
ts << "};\n";
ts << "\nstatic __ClassInfo_" << defname << "_Initializer__ __classinfo_" << defname.toLowerCase() << "_initializer__;\n";
}
ts << "\n\n#endif // " << defname << "\n";
f.close();
return true;
}
int main(int argc, char * argv[]) {
PICLI cli(argc, argv);
// piCout << cli.rawArguments();
cli.setOptionalArgumentsCount(-1);
cli.addArgument("output", true);
cli.addArgument("help");
cli.addArgument("Help");
cli.addArgument("quiet");
cli.addArgument("All");
cli.addArgument("Metainfo");
cli.addArgument("Enum");
cli.addArgument("Stream");
cli.addArgument("JSON");
cli.addArgument("Getter");
cli.addArgument("Text");
cli.addArgument("print");
cli.addArgument("Print");
cli.addArgument("single");
if (cli.hasArgument("Help")) {
help();
return 0;
}
if (cli.hasArgument("help") || cli.argumentValue("output").isEmpty() || cli.optionalArguments().isEmpty()) {
usage();
return 0;
}
piDebug = !cli.hasArgument("quiet");
PICodeParser parser;
for (const PIString & a: cli.rawArguments()) {
if (a.startsWith("-I")) parser.includeDirectory(a.mid(2));
if (a.startsWith("-D")) parser.addDefine(a.mid(2), PIString());
}
PIStringList files;
for (const PIString & a: cli.optionalArguments())
if (!a.startsWith("-")) files << a;
piCout << Cyan << Bold << "Parse files" << files << "...";
parser.parseFiles(files, !cli.hasArgument("single"));
piCout << Cyan << Bold << "Parsing done";
piCout << Cyan << Bold << "Writing code model ...";
bool all = cli.hasArgument("All");
if (!writeModel(parser,
cli,
cli.argumentValue("output"),
cli.hasArgument("Metainfo") || all,
cli.hasArgument("Enum") || all,
cli.hasArgument("Stream") || all,
cli.hasArgument("JSON") || all,
cli.hasArgument("Text") || all,
cli.hasArgument("Getter") || all))
return 1;
piCout << Cyan << Bold << "Writing done";
if (cli.hasArgument("print") || cli.hasArgument("Print")) {
bool womain = cli.hasArgument("print");
piDebug = true;
PIStringList pf(parser.parsedFiles());
for (const PIString & f: pf) {
if (!womain || (f != parser.mainFile())) piCout << f;
}
}
return 0;
}