pip_cmg now works with new nested entities approach Getters now can access to bitfields
272 lines
9.1 KiB
C++
Executable File
272 lines
9.1 KiB
C++
Executable File
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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<PIString> inc_files;
|
|
for (const PICodeParser::Entity * e: parser.entities)
|
|
if (!e->name.startsWith("_PI")) inc_files << e->file;
|
|
PIString inc_string;
|
|
PIVector<PIString> 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 <string.h>\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";
|
|
for (const PICodeParser::Entity * e: parser.entities) {
|
|
if (e->is_anonymous || e->name.startsWith("_PI")) continue;
|
|
makeGetterType(rt, e);
|
|
makeGetterValue(rt, e);
|
|
}
|
|
}
|
|
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";
|
|
}
|
|
|
|
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;
|
|
ts << "\tci_avf[\"" << e->name << "\"] = getterValue" << toCName(e->name) << ";\n";
|
|
ts << "\tci_atf[\"" << e->name << "\"] = getterType" << toCName(e->name) << ";\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";
|
|
}
|
|
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 << "}\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 <pivariant.h>\n#include <picodeinfo.h>";
|
|
if (streams || texts) ts << "\n#include <pichunkstream.h>";
|
|
if (json) ts << "\n#include <pijsonserialization.h>";
|
|
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;
|
|
}
|