/* 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"; 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 \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; }