diff --git a/libs/main/math/pipoint.h b/libs/main/math/pipoint.h index 8bca9a15..aae3af23 100644 --- a/libs/main/math/pipoint.h +++ b/libs/main/math/pipoint.h @@ -127,7 +127,21 @@ public: //! \~russian //! Прибавить координаты второй точки и сохранить. //! \details Является копией метода \a translate(). - void operator+=(const PIPoint & p) { translate(p); } + PIPoint & operator+=(const PIPoint & p) { + translate(p); + return *this; + } + + PIPoint & operator*=(Type v) { + x *= v; + y *= v; + return *this; + } + PIPoint & operator/=(Type v) { + x /= v; + y /= v; + return *this; + } //! \~russian Сложить координаты двух точек. PIPoint operator+(const PIPoint & p) { return PIPoint(x + p.x, y + p.y); } @@ -144,6 +158,12 @@ public: //! \~russian Инвертировать координаты точки. PIPoint operator-() { return PIPoint(-x, -y); } + //! \~russian Умножить координаты точки. + PIPoint operator*(Type v) { return PIPoint(x * v, y * v); } + + //! \~russian Делить координаты точки. + PIPoint operator/(Type v) { return PIPoint(x / v, y / v); } + //! \~russian Проверить равенство координат двух точек. bool operator==(const PIPoint & p) const { return (x == p.x && y == p.y); } diff --git a/libs/main/pip.h b/libs/main/pip.h index 9bf1f68b..665c12df 100644 --- a/libs/main/pip.h +++ b/libs/main/pip.h @@ -33,6 +33,7 @@ #include "piioutilsmodule.h" #include "piliterals.h" #include "pimathmodule.h" +#include "piserializationmodule.h" #include "pistatemachinemodule.h" #include "pisystemmodule.h" #include "pithreadmodule.h" diff --git a/libs/main/serialization/pijsonserialization.h b/libs/main/serialization/pijsonserialization.h new file mode 100644 index 00000000..f14f475f --- /dev/null +++ b/libs/main/serialization/pijsonserialization.h @@ -0,0 +1,395 @@ +/*! \file pijson.h + * \ingroup Serialization + * \brief + * \~english JSON serialization + * \~russian Сериализация JSON + */ +/* + PIP - Platform Independent Primitives + JSON serialization + 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 . +*/ + +#ifndef pijsonserialization_H +#define pijsonserialization_H + +#include "pijson.h" + + +// --- +// serialize, PIJSON = piSerializeJSON(T) +// --- + + +// enum & arithmetic + +template::value, int>::type = 0> +inline PIJSON piSerializeJSON(const T & v) { + return PIJSON() = (int)v; +} + +template::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0> +inline PIJSON piSerializeJSON(const T & v) { + return PIJSON() = v; +} + +template::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0> +inline PIJSON piSerializeJSON(const T & v) { + static_assert(false, "[piSerializeJSON] Error: using undeclared piSerializeJSON() for complex type!"); + return {}; +} + + +// known types + +template<> +inline PIJSON piSerializeJSON(const PIVariant & v) { + return PIJSON() = v; +} +template +inline PIJSON piSerializeJSON(const complex & v) { + PIJSON ret; + ret << v.real() << v.imag(); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PIFlags & v) { + return PIJSON() = (int)v; +} + +template<> +inline PIJSON piSerializeJSON(const PIString & v) { + return PIJSON() = v; +} + +template<> +inline PIJSON piSerializeJSON(const PIConstChars & v) { + return PIJSON() = v.toString(); +} + +template<> +inline PIJSON piSerializeJSON(const PIByteArray & v) { + return PIJSON() = PIStringAscii(v.toBase64()); +} + +template<> +inline PIJSON piSerializeJSON(const PISystemTime & v) { + PIJSON ret; + ret["s"] = v.seconds; + ret["ns"] = v.nanoseconds; + return ret; +} + +template<> +inline PIJSON piSerializeJSON(const PITime & v) { + PIJSON ret; + ret["h"] = v.hours; + ret["m"] = v.minutes; + ret["s"] = v.seconds; + ret["z"] = v.milliseconds; + return ret; +} + +template<> +inline PIJSON piSerializeJSON(const PIDate & v) { + PIJSON ret; + ret["y"] = v.year; + ret["M"] = v.month; + ret["d"] = v.day; + return ret; +} + +template<> +inline PIJSON piSerializeJSON(const PIDateTime & v) { + PIJSON ret; + ret["y"] = v.year; + ret["M"] = v.month; + ret["d"] = v.day; + ret["h"] = v.hours; + ret["m"] = v.minutes; + ret["s"] = v.seconds; + ret["z"] = v.milliseconds; + return ret; +} + +template<> +inline PIJSON piSerializeJSON(const PINetworkAddress & v) { + return PIJSON() = v.toString(); +} + +template +inline PIJSON piSerializeJSON(const PIPoint & v) { + PIJSON ret; + ret["x"] = piSerializeJSON(v.x); + ret["y"] = piSerializeJSON(v.y); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PILine & v) { + PIJSON ret; + ret["p0"] = piSerializeJSON(v.p0); + ret["p1"] = piSerializeJSON(v.p1); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PIRect & v) { + PIJSON ret; + ret["bl"] = piSerializeJSON(v.bottomLeft()); + ret["tr"] = piSerializeJSON(v.topRigth()); + return ret; +} + + +// containers + +template +inline PIJSON piSerializeJSON(const PIPair & v) { + PIJSON ret; + ret << piSerializeJSON(v.first) << piSerializeJSON(v.second); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PIVector & v) { + if (v.isEmpty()) return PIJSON::newArray(); + PIJSON ret; + for (const auto & i: v) + ret << piSerializeJSON(i); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PIDeque & v) { + if (v.isEmpty()) return PIJSON::newArray(); + PIJSON ret; + for (const auto & i: v) + ret << piSerializeJSON(i); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PIVector2D & v) { + PIJSON ret; + ret["cols"] = v.cols(); + ret["rows"] = v.rows(); + ret["mat"] = piSerializeJSON(v.plainVector()); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PISet & v) { + if (v.isEmpty()) return PIJSON::newArray(); + PIJSON ret; + for (const auto & i: v) + ret << piSerializeJSON(i); + return ret; +} + +template +inline PIJSON piSerializeJSON(const PIMap & v) { + if (v.isEmpty()) return PIJSON::newObject(); + PIJSON ret; + auto it = v.makeIterator(); + while (it.next()) + ret[PIVariant(it.key()).toString()] = piSerializeJSON(it.value()); + return ret; +} + + +// --- +// deserialize, piDeserializeJSON(T, PIJSON) +// --- + + +// enum & arithmetic + +template::value, int>::type = 0> +inline void piDeserializeJSON(T & v, const PIJSON & js) { + v = (T)js.toInt(); +} + +template::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0> +inline void piDeserializeJSON(T & v, const PIJSON & js) { + v = js.value().value(); +} + +template::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0> +inline void piDeserializeJSON(T & v, const PIJSON & js) { + static_assert(false, "[piDeserializeJSON] Error: using undeclared piDeserializeJSON() for complex type!"); + v = {}; +} + + +// known types + +template<> +inline void piDeserializeJSON(PIVariant & v, const PIJSON & js) { + v = js.value(); +} + +template +inline void piDeserializeJSON(complex & v, const PIJSON & js) { + T c[2]; + piDeserializeJSON(c[0], js[0]); + piDeserializeJSON(c[1], js[1]); + v = complex(c[0], c[1]); +} + +template +inline void piDeserializeJSON(PIFlags & v, const PIJSON & js) { + v = js.toInt(); +} + +template<> +inline void piDeserializeJSON(PIString & v, const PIJSON & js) { + v = js.toString(); +} + +template<> +inline void piDeserializeJSON(PIByteArray & v, const PIJSON & js) { + v = PIByteArray::fromBase64(js.toString()); +} + +template<> +inline void piDeserializeJSON(PISystemTime & v, const PIJSON & js) { + piDeserializeJSON(v.seconds, js["s"]); + piDeserializeJSON(v.nanoseconds, js["ns"]); +} + +template<> +inline void piDeserializeJSON(PITime & v, const PIJSON & js) { + v.hours = js["h"].toInt(); + v.minutes = js["m"].toInt(); + v.seconds = js["s"].toInt(); + v.milliseconds = js["z"].toInt(); +} + +template<> +inline void piDeserializeJSON(PIDate & v, const PIJSON & js) { + v.year = js["y"].toInt(); + v.month = js["M"].toInt(); + v.day = js["d"].toInt(); +} + +template<> +inline void piDeserializeJSON(PIDateTime & v, const PIJSON & js) { + v.year = js["y"].toInt(); + v.month = js["M"].toInt(); + v.day = js["d"].toInt(); + v.hours = js["h"].toInt(); + v.minutes = js["m"].toInt(); + v.seconds = js["s"].toInt(); + v.milliseconds = js["z"].toInt(); +} + +template<> +inline void piDeserializeJSON(PINetworkAddress & v, const PIJSON & js) { + v = PINetworkAddress(js.toString()); +} + +template +inline void piDeserializeJSON(PIPoint & v, const PIJSON & js) { + piDeserializeJSON(v.x, js["x"]); + piDeserializeJSON(v.y, js["y"]); +} + +template +inline void piDeserializeJSON(PILine & v, const PIJSON & js) { + piDeserializeJSON(v.p0, js["p0"]); + piDeserializeJSON(v.p1, js["p1"]); +} + +template +inline void piDeserializeJSON(PIRect & v, const PIJSON & js) { + PIPoint bl, tr; + piDeserializeJSON(bl, js["bl"]); + piDeserializeJSON(tr, js["tr"]); + v = PIRect(bl, tr); +} + + +// containers + +template +inline void piDeserializeJSON(PIPair & v, const PIJSON & js) { + v = {}; + if (!js.isArray()) return; + piDeserializeJSON(v.first, js[0]); + piDeserializeJSON(v.second, js[1]); +} + +template +inline void piDeserializeJSON(PIVector & v, const PIJSON & js) { + v.clear(); + if (!js.isArray()) return; + v.resize(js.size()); + for (int i = 0; i < js.size(); ++i) + piDeserializeJSON(v[i], js[i]); +} + +template +inline void piDeserializeJSON(PIDeque & v, const PIJSON & js) { + v.clear(); + if (!js.isArray()) return; + v.resize(js.size()); + for (int i = 0; i < js.size(); ++i) + piDeserializeJSON(v[i], js[i]); +} + +template +inline void piDeserializeJSON(PIVector2D & v, const PIJSON & js) { + v.clear(); + if (!js.isObject()) return; + v.resize(js["rows"].toInt(), js["cols"].toInt()); + const auto & mat(js["mat"]); + if (!mat.isArray()) return; + piDeserializeJSON(v.plainVector(), mat); +} + +template +inline void piDeserializeJSON(PISet & v, const PIJSON & js) { + v.clear(); + if (!js.isArray()) return; + T _t; + for (int i = 0; i < js.size(); ++i) { + piDeserializeJSON(_t, js[i]); + v << _t; + } +} + +template +inline void piDeserializeJSON(PIMap & v, const PIJSON & js) { + v.clear(); + if (!js.isObject()) return; + const auto & obj(js.object()); + auto it = obj.makeIterator(); + while (it.next()) + piDeserializeJSON(v[PIVariant(it.key()).value()], it.value()); +} + + +#endif // pijsonserialization_h diff --git a/libs/main/serialization/piserializationmodule.h b/libs/main/serialization/piserializationmodule.h index acd1d11a..e96cb597 100644 --- a/libs/main/serialization/piserializationmodule.h +++ b/libs/main/serialization/piserializationmodule.h @@ -54,6 +54,7 @@ #include "pibinarystream.h" #include "pichunkstream.h" #include "pijson.h" +#include "pijsonserialization.h" #include "pivaluetree_conversions.h" #endif // PISERIALIZATIONMODULE_H diff --git a/libs/main/types/pibytearray.h b/libs/main/types/pibytearray.h index e8637e72..cc632f82 100644 --- a/libs/main/types/pibytearray.h +++ b/libs/main/types/pibytearray.h @@ -793,7 +793,7 @@ public: //! \~english Add to the end data "data" with size "size" //! \~russian Добавляет в конец массива данные по указателю "data" размером "size" PIByteArray & push_back(const void * data_, int size_) { - const uint ps = size(); + const size_t ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this; @@ -1092,7 +1092,7 @@ public: //! \~english Add to the end data "data" with size "size" //! \~russian Добавляет в конец массива данные по указателю "data" размером "size" PIByteArray & append(const void * data_, int size_) { - const uint ps = size(); + const size_t ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this; @@ -1101,7 +1101,7 @@ public: //! \~english Add to the end byte array "data" //! \~russian Добавляет в конец массива содержимое массива "data" PIByteArray & append(const PIByteArray & data_) { - const uint ps = size(); + const size_t ps = size(); enlarge(data_.size_s()); memcpy(data(ps), data_.data(), data_.size()); return *this; diff --git a/utils/code_model_generator/CMakeLists.txt b/utils/code_model_generator/CMakeLists.txt index 94d6d782..3a0da20d 100755 --- a/utils/code_model_generator/CMakeLists.txt +++ b/utils/code_model_generator/CMakeLists.txt @@ -7,7 +7,8 @@ set_deploy_property(pip_cmg COMPANY "${PIP_COMPANY}" INFO "Platform-Independent Primitives") make_rc(pip_cmg _RC) -add_executable(pip_cmg "main.cpp" ${_RC}) +file(GLOB PIP_CMG_SRC "*.cpp") +add_executable(pip_cmg ${PIP_CMG_SRC} ${_RC}) target_link_libraries(pip_cmg pip) if (DEFINED LIB) install(TARGETS pip_cmg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/utils/code_model_generator/common.cpp b/utils/code_model_generator/common.cpp new file mode 100644 index 00000000..24c2bf07 --- /dev/null +++ b/utils/code_model_generator/common.cpp @@ -0,0 +1,127 @@ +/* + 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 "common.h" + +using namespace PICoutManipulators; + +const char help_string[] = "-M (Metainfo)\n" + "Generate classes and structs info. It contains\n" + "names, subclass info, all methods and variables.\n" + "Place information:\n" + " * classes and structs - PICODEINFO::classes()\n" + " * methods - ClassInfo::functions\n" + " * variables - ClassInfo::variables\n" + "\n" + "-E (Enums)\n" + "Generate enumeration descriptions.\n" + "Useful for GUI integrations, because\n" + "you can obtain enumerators value and name.\n" + " * enums - PICODEINFO::enums()\n" + "\n" + "-S (Stream operators)\n" + "Generate store/restore operators with format\n" + "BINARY_STREAM_WRITE();\n" + "BINARY_STREAM_READ ();\n" + "Only public variables used. All variables stored/restored\n" + "using PIChunkStream. IDs are variable number, starting from 1.\n" + "You can override ID with PIMETA(id=). If in class or struct\n" + "PIMETA(simple-stream) presence, then variables stored/restored\n" + "with simple << and >> operators.\n" + "If PIMETA(no-stream) presence, then class or struct ignored.\n" + "\n" + "-G (Getter functions)\n" + "Generate anonymous access methods for member typenames and values.\n" + "Every class or struct member typename can be obtained with:\n" + "const char * getMemberType(const char * class_name, const char * member_name)\n" + "Member value can be obtained with:\n" + "PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name)\n" + "where \"p\" - class or struct pointer, and returns serialized value.\n" + "PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name)\n" + "where \"p\" - class or struct pointer, and returns value as registered PIVariant.\n" + ""; + + +void header() { + piCout << Bold << "PIP Code model generator"; + piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine; + piCout << Green << Bold << "Usage:" << Default + << "\"pip_cmg [-hHqPpsAMESTG] -o [-I] [-I] [...] [-D] [-D] [...] " + " [] [] [...]\"" + << NewLine; +} + + +void usage() { + header(); + piCout << Green << Bold << "Details:"; + piCout << Bold << "Debug control"; + piCout << "-h " << Green << "- display this message and exit"; + piCout << "-H " << Green << "- display details help"; + piCout << "-q " << Green << "- quiet, no debug output to console"; + piCout << "-P " << Green << "- print list of all parsed files to console before exit"; + piCout << "-p " << Green << "- print list of all parsed files without file with \"main\" function to console before exit"; + piCout << ""; + piCout << Bold << "Parsing control"; + piCout << "-s " << Green << "- single file (don`t follow includes)"; + piCout << "-I " << Green << "- add include dir (e.g. -I.. -I../some_dir -I/usr/include)"; + piCout << "-D " << Green + << "- add define to preprocessor, macro PICODE is always defined (e.g. -DMY_DEFINE will add MY_DEFINE define)"; + piCout << ""; + piCout << Bold << "Output control"; + piCout << "-A " << Green << "- write all"; + piCout << "-M " << Green << "- write metainfo"; + piCout << "-E " << Green << "- write enums"; + piCout << "-S " << Green << "- write stream operators"; + piCout << "-G " << Green << "- write getter functions"; + // piCout << "-T " << Green << "- write text serialize functions"; + piCout << "-o " << Green + << "- output file for code model without extension (e.g. \"ccm\" - files \"ccm.h\" and \"ccm.cpp\" will be created)"; + piCout << ""; + piCout << Bold << "Input control"; + piCout << " " << Green << "- add file to code model, all includes of this file will be proceed (e.g. \"main.cpp\")"; +} + + +void help() { + header(); + piCout << help_string; +} + + +PIString toCName(const PIString & s) { + PIString ret(s.trimmed()); + if (ret.isEmpty()) return ret; + ret.replaceAll('<', '_').replaceAll('>', '_'); + for (int i = 0; i < ret.size_s(); ++i) { + if (i == 0) { + if (!(ret[i].isAlpha() || ret[i].toAscii() == '_')) { + ret.pop_front(); + --i; + } + } else { + if (!(ret[i].isAlpha() || ret[i].isDigit() || ret[i].toAscii() == '_')) { + ret.remove(i); + --i; + } + } + } + ret.replaceAll("__", "_"); + return ret; +} diff --git a/utils/code_model_generator/common.h b/utils/code_model_generator/common.h new file mode 100644 index 00000000..d91f92e4 --- /dev/null +++ b/utils/code_model_generator/common.h @@ -0,0 +1,39 @@ +/* + 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 . +*/ + +#ifndef pip_cmg_common_H +#define pip_cmg_common_H + +#include "picli.h" +#include "picodeparser.h" +#include "piiostream.h" + +struct Runtime { + PICodeParser & parser; + PICLI & cli; + PIIOTextStream & ts; +}; + +void header(); +void usage(); +void help(); + +PIString toCName(const PIString & s); + +#endif diff --git a/utils/code_model_generator/enum.cpp b/utils/code_model_generator/enum.cpp new file mode 100644 index 00000000..6553c5ac --- /dev/null +++ b/utils/code_model_generator/enum.cpp @@ -0,0 +1,44 @@ +/* + 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" + + +void makeEnumInfo(Runtime & rt, const PICodeParser::Enum * e) { + if (e->name.isEmpty()) { + rt.ts << "\n\tei = ci_ei[\"\"];\n"; + } else { + rt.ts << "\n\tei = new EnumInfo();\n"; + rt.ts << "\tci_ei[\"" << e->name << "\"] = ei;\n"; + rt.ts << "\tei->name = \"" << e->name << "\";\n"; + if (!e->meta.isEmpty()) { + auto i = e->meta.makeIterator(); + while (i.next()) + rt.ts << "\tei->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; + } + } + for (const PICodeParser::EnumeratorInfo & m: e->members) { + rt.ts << "\tei->members << PICodeInfo::EnumeratorInfo(\"" << m.name << "\", " << m.value << ");\n"; + if (!m.meta.isEmpty()) { + auto i = m.meta.makeIterator(); + while (i.next()) + rt.ts << "\tei->members.back().meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; + } + } +} diff --git a/utils/code_model_generator/enum.h b/utils/code_model_generator/enum.h new file mode 100644 index 00000000..f7da8147 --- /dev/null +++ b/utils/code_model_generator/enum.h @@ -0,0 +1,27 @@ +/* + 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 . +*/ + +#ifndef pip_cmg_enum_H +#define pip_cmg_enum_H + +#include "common.h" + +void makeEnumInfo(Runtime & rt, const PICodeParser::Enum * e); + +#endif diff --git a/utils/code_model_generator/getter.cpp b/utils/code_model_generator/getter.cpp new file mode 100644 index 00000000..31f4d448 --- /dev/null +++ b/utils/code_model_generator/getter.cpp @@ -0,0 +1,48 @@ +/* + 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 "getter.h" + +#include "stream.h" + + +void makeGetterType(Runtime & rt, const PICodeParser::Entity * e) { + if (!needClassStream(e)) return; + rt.ts << "\nconst char * getterType" << toCName(e->name) << "(const char * name) {\n"; + rt.ts << "\tif (!name) return \"\";\n"; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; + rt.ts << "\tif (strcmp(name, \"" << m.name << "\") == 0) return \"" << m.type << "\";\n"; + } + rt.ts << "\treturn \"\";\n}\n"; +} + + +void makeGetterValue(Runtime & rt, const PICodeParser::Entity * e) { + if (!needClassStream(e)) return; + rt.ts << "\nPIByteArray getterValue" << toCName(e->name) << "(const void * p, const char * name) {\n"; + rt.ts << "\tPIByteArray ret;\n"; + rt.ts << "\tif (!p || !name) return ret;\n"; + rt.ts << "\t" << e->name << " * o = (" << e->name << "*)p;\n"; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; + rt.ts << "\tif (strcmp(name, \"" << m.name << "\") == 0) {serialize(ret, o->" << m.name << "); return ret;}\n"; + } + rt.ts << "\treturn ret;\n}\n"; +} diff --git a/utils/code_model_generator/getter.h b/utils/code_model_generator/getter.h new file mode 100644 index 00000000..58b68c5f --- /dev/null +++ b/utils/code_model_generator/getter.h @@ -0,0 +1,28 @@ +/* + 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 . +*/ + +#ifndef pip_cmg_getter_H +#define pip_cmg_getter_H + +#include "common.h" + +void makeGetterType(Runtime & rt, const PICodeParser::Entity * e); +void makeGetterValue(Runtime & rt, const PICodeParser::Entity * e); + +#endif diff --git a/utils/code_model_generator/json.cpp b/utils/code_model_generator/json.cpp new file mode 100644 index 00000000..5c08753f --- /dev/null +++ b/utils/code_model_generator/json.cpp @@ -0,0 +1,125 @@ +/* + 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 "json.h" + +#include "pitranslator.h" + + +bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e) { + PIVector ml; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; + ml << m; + } + bool is_union = e->type == "union"; + for (const PICodeParser::Member & m: ml) { + if (is_union && m.isBitfield()) continue; + if (m.attributes[PICodeParser::Static]) continue; + if (m.meta.value("id") == "-") continue; + // if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); + if (m.dims.isEmpty()) { + rt.ts << "\tret[\"" << m.name << "\"] = piSerializeJSON(v." << m.name << ");\n"; + } else { + PIString ptype = m.type.left(m.type.find('[')).trim(); + PIString size = m.dims[0]; + for (int i = 1; i < m.dims.size_s(); ++i) { + size += " * "; + size += m.dims[i]; + } + rt.ts << "\tret[\"" << m.name << "\"] = piSerializeJSON(PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name + << "), " << size << "));\n"; + } + if (is_union) break; + } + if (is_union) return true; + for (const PICodeParser::Entity * ce: e->children) { + if (ce->has_name) continue; + if (!writeClassJSONMembersOut(rt, ce)) return false; + } + return true; +} + + +bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e) { + PIVector ml; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; + ml << m; + } + bool is_union = e->type == "union"; + PISet used_id; + for (const PICodeParser::Member & m: ml) { + if (is_union && m.isBitfield()) continue; + if (m.attributes[PICodeParser::Static]) continue; + if (m.meta.value("id") == "-") continue; + // if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); + if (m.dims.isEmpty()) { + rt.ts << "\tpiDeserializeJSON(v." << m.name << ", js[\"" << m.name << "\"]);\n"; + } else { + PIString ptype = m.type.left(m.type.find('[')).trim(); + PIString size = m.dims[0]; + for (int i = 1; i < m.dims.size_s(); ++i) { + size += " * "; + size += m.dims[i]; + } + rt.ts << "\t{\n\t\tPIVector<" << ptype << " > d;\n"; + rt.ts << "\t\tpiDeserializeJSON(d, js[\"" << m.name << "\"]);\n"; + rt.ts << "\t\tint cnt = piMini(d.size_s(), " << size << ");\n"; + rt.ts << "\t\tfor (int i = 0; i < cnt; ++i)\n"; + rt.ts << "\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n"; + rt.ts << "\t}\n"; + } + if (is_union) break; + } + if (is_union) return true; + for (const PICodeParser::Entity * ce: e->children) { + if (ce->has_name) continue; + if (!writeClassJSONMembersIn(rt, ce)) return false; + } + return true; +} + + +bool needClassJSON(const PICodeParser::Entity * e) { + if (e->meta.contains("no-json")) return false; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; + if (m.attributes[PICodeParser::Static]) continue; + if (m.meta.value("id") == "-") continue; + return true; + } + return false; +} + + +bool makeClassJSON(Runtime & rt, const PICodeParser::Entity * e) { + if (!needClassJSON(e)) return true; + + rt.ts << "\ntemplate<> inline PIJSON piSerializeJSON(const " << e->name << " & v) {\n"; + rt.ts << "\tPIJSON ret;\n"; + if (!writeClassJSONMembersOut(rt, e)) return false; + rt.ts << "\treturn ret;\n}\n"; + + rt.ts << "\ntemplate<> inline void piDeserializeJSON(" << e->name << " & v, const PIJSON & js) {\n"; + if (!writeClassJSONMembersIn(rt, e)) return false; + rt.ts << "}\n"; + + return true; +} diff --git a/utils/code_model_generator/json.h b/utils/code_model_generator/json.h new file mode 100644 index 00000000..9b206040 --- /dev/null +++ b/utils/code_model_generator/json.h @@ -0,0 +1,30 @@ +/* + 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 . +*/ + +#ifndef pip_cmg_json_H +#define pip_cmg_json_H + +#include "common.h" + +bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e); +bool writeClassJSONMembersIn(Runtime & rt, const PICodeParser::Entity * e); +bool needClassJSON(const PICodeParser::Entity * e); +bool makeClassJSON(Runtime & rt, const PICodeParser::Entity * e); + +#endif diff --git a/utils/code_model_generator/main.cpp b/utils/code_model_generator/main.cpp index fd9eb2ab..c3bf2d93 100755 --- a/utils/code_model_generator/main.cpp +++ b/utils/code_model_generator/main.cpp @@ -17,467 +17,28 @@ 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; -PICodeParser parser; -const char help_string[] = "-M (Metainfo)\n" - "Generate classes and structs info. It contains\n" - "names, subclass info, all methods and variables.\n" - "Place information:\n" - " * classes and structs - PICODEINFO::classes()\n" - " * methods - ClassInfo::functions\n" - " * variables - ClassInfo::variables\n" - "\n" - "-E (Enums)\n" - "Generate enumeration descriptions.\n" - "Useful for GUI integrations, because\n" - "you can obtain enumerators value and name.\n" - " * enums - PICODEINFO::enums()\n" - "\n" - "-S (Stream operators)\n" - "Generate store/restore operators with format\n" - "BINARY_STREAM_WRITE();\n" - "BINARY_STREAM_READ ();\n" - "Only public variables used. All variables stored/restored\n" - "using PIChunkStream. IDs are variable number, starting from 1.\n" - "You can override ID with PIMETA(id=). If in class or struct\n" - "PIMETA(simple-stream) presence, then variables stored/restored\n" - "with simple << and >> operators.\n" - "If PIMETA(no-stream) presence, then class or struct ignored.\n" - "\n" - "-G (Getter functions)\n" - "Generate anonymous access methods for member typenames and values.\n" - "Every class or struct member typename can be obtained with:\n" - "const char * getMemberType(const char * class_name, const char * member_name)\n" - "Member value can be obtained with:\n" - "PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name)\n" - "where \"p\" - class or struct pointer, and returns serialized value.\n" - "PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name)\n" - "where \"p\" - class or struct pointer, and returns value as registered PIVariant.\n" - ""; - -void header() { - piCout << Bold << "PIP Code model generator"; - piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine; - piCout << Green << Bold << "Usage:" << Default - << "\"pip_cmg [-hHqPpsAMESTG] -o [-I] [-I] [...] [-D] [-D] [...] " - " [] [] [...]\"" - << NewLine; -} - -void usage() { - header(); - piCout << Green << Bold << "Details:"; - piCout << Bold << "Debug control"; - piCout << "-h " << Green << "- display this message and exit"; - piCout << "-H " << Green << "- display details help"; - piCout << "-q " << Green << "- quiet, no debug output to console"; - piCout << "-P " << Green << "- print list of all parsed files to console before exit"; - piCout << "-p " << Green << "- print list of all parsed files without file with \"main\" function to console before exit"; - piCout << ""; - piCout << Bold << "Parsing control"; - piCout << "-s " << Green << "- single file (don`t follow includes)"; - piCout << "-I " << Green << "- add include dir (e.g. -I.. -I../some_dir -I/usr/include)"; - piCout << "-D " << Green - << "- add define to preprocessor, macro PICODE is always defined (e.g. -DMY_DEFINE will add MY_DEFINE define)"; - piCout << ""; - piCout << Bold << "Output control"; - piCout << "-A " << Green << "- write all"; - piCout << "-M " << Green << "- write metainfo"; - piCout << "-E " << Green << "- write enums"; - piCout << "-S " << Green << "- write stream operators"; - piCout << "-G " << Green << "- write getter functions"; - // piCout << "-T " << Green << "- write text serialize functions"; - piCout << "-o " << Green - << "- output file for code model without extension (e.g. \"ccm\" - files \"ccm.h\" and \"ccm.cpp\" will be created)"; - piCout << ""; - piCout << Bold << "Input control"; - piCout << " " << Green << "- add file to code model, all includes of this file will be proceed (e.g. \"main.cpp\")"; -} - -void help() { - header(); - piCout << help_string; -} - - -PIString toCName(const PIString & s) { - PIString ret(s.trimmed()); - if (ret.isEmpty()) return ret; - ret.replaceAll('<', '_').replaceAll('>', '_'); - for (int i = 0; i < ret.size_s(); ++i) { - if (i == 0) { - if (!(ret[i].isAlpha() || ret[i].toAscii() == '_')) { - ret.pop_front(); - --i; - } - } else { - if (!(ret[i].isAlpha() || ret[i].isDigit() || ret[i].toAscii() == '_')) { - ret.remove(i); - --i; - } - } - } - ret.replaceAll("__", "_"); - return ret; -} - - -void makeClassInfo(PIIOTextStream & ts, const PICodeParser::Entity * e) { - ts << "\n\t{\n\tClassInfo * ci = new ClassInfo();\n"; - ts << "\tci->type = \"" << e->type << "\";\n"; - ts << "\tci->name = \"" << e->name << "\";\n"; - ts << "\tci->has_name = " << (e->has_name ? "true" : "false") << ";\n"; - if (!e->meta.isEmpty()) { - auto i = e->meta.makeIterator(); - while (i.next()) - ts << "\tci->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; - } - ts << "\t(*PICodeInfo::__Storage__::instance()->classesInfo)[ci->name] = ci;\n"; - if (e->parent_scope) { - ts << "\tpci = " - << "PICodeInfo::__Storage__::instance()->classesInfo->value(\"" << e->parent_scope->name << "\", 0);\n"; - ts << "\tif (pci) pci->children_info << ci;\n"; - } - for (const PICodeParser::Entity * p: e->parents) - ts << "\tci->parents << \"" << p->name << "\";\n"; - if (!e->members.isEmpty()) ts << "\n\tTypeInfo ti;\n"; - for (const PICodeParser::Member & m: e->members) { - ts << "\tti = TypeInfo(\"" << m.name << "\", \"" << m.type << "\""; - if (m.attributes != 0) { - bool fir = true; - ts << ", "; - if (m.attributes[PICodeParser::Const]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Const"; - } - if (m.attributes[PICodeParser::Static]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Static"; - } - if (m.attributes[PICodeParser::Mutable]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Mutable"; - } - if (m.attributes[PICodeParser::Volatile]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Volatile"; - } - if (m.attributes[PICodeParser::Inline]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Inline"; - } - if (m.attributes[PICodeParser::Virtual]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Virtual"; - } - } else { - if (m.isBitfield()) ts << ", 0"; - } - if (m.isBitfield()) ts << ", " << m.bits; - ts << ");\n"; - if (!m.meta.isEmpty()) { - for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i) - ts << "\tti.meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; - } - ts << "\tci->variables << ti;\n"; - } - PIString arg; - bool has_fi = false; - for (const PICodeParser::Member & m: e->functions) { - if (e->name.findCWord(m.name) >= 0) continue; - if (!has_fi) ts << "\n\tFunctionInfo * fi;\n"; - has_fi = true; - ts << "\tci->functions.push_back(FunctionInfo()); fi = &(ci->functions.back());\n"; - ts << "\tfi->name = \"" << m.name << "\";"; - ts << " fi->return_type = TypeInfo(\"\", \"" << m.type << "\""; - if (m.attributes[PICodeParser::Const] || m.attributes[PICodeParser::Static]) { - bool fir = true; - ts << ", "; - if (m.attributes[PICodeParser::Const]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Const"; - } - if (m.attributes[PICodeParser::Static]) { - if (fir) - fir = false; - else - ts << " | "; - ts << "Static"; - } - } - ts << ");\n"; - // piCout << "write func" << m.name; - for (const PIString & a: m.arguments_full) { - // piCout << "write arg" << a; - ts << "\tfi->arguments << TypeInfo("; - arg = a; - bool con = false; - arg.prepend(" "); - if (arg.find(" const ") >= 0) { - arg.replaceAll(" const ", " "); - con = true; - } - arg.trim(); - int i = 0; - for (i = arg.size_s() - 1; i > 0; --i) - if (!_isCChar(arg[i]) && !(arg[i].isDigit())) break; - ts << "\"" << arg.takeRight(arg.size_s() - i - 1).trim() << "\", "; - ts << "\"" << arg.trim() << "\""; - if (con) ts << ", Const"; - ts << ");\n"; - } - if (!m.meta.isEmpty()) { - for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i) - ts << "\tfi->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; - } - } - ts << "\n\t}"; -} - - -void makeEnumInfo(PIIOTextStream & ts, const PICodeParser::Enum * e) { - if (e->name.isEmpty()) { - ts << "\n\tei = (*PICodeInfo::__Storage__::instance()->enumsInfo)[\"\"];\n"; - } else { - ts << "\n\tei = new EnumInfo();\n"; - ts << "\t(*PICodeInfo::__Storage__::instance()->enumsInfo)[\"" << e->name << "\"] = ei;\n"; - ts << "\tei->name = \"" << e->name << "\";\n"; - if (!e->meta.isEmpty()) { - auto i = e->meta.makeIterator(); - while (i.next()) - ts << "\tei->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; - } - } - for (const PICodeParser::EnumeratorInfo & m: e->members) { - ts << "\tei->members << PICodeInfo::EnumeratorInfo(\"" << m.name << "\", " << m.value << ");\n"; - if (!m.meta.isEmpty()) { - auto i = m.meta.makeIterator(); - while (i.next()) - ts << "\tei->members.back().meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; - } - } -} - - -bool writeClassStreamMembersOut(PIIOTextStream & ts, const PICodeParser::Entity * e, int & cnt, bool simple) { - PIVector ml; - for (const PICodeParser::Member & m: e->members) { - if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; - ml << m; - } - bool is_union = e->type == "union"; - PISet used_id; - for (const PICodeParser::Member & m: ml) { - if (is_union && m.isBitfield()) continue; - if (m.attributes[PICodeParser::Static]) continue; - if (m.meta.value("id") == "-") continue; - ++cnt; - if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); - if (used_id[cnt]) { - piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt); - return false; - } - if (m.dims.isEmpty()) { - if (simple) { - ts << "\ts << "; - if (parser.isEnum(m.type)) ts << "(int)"; - ts << "v." << m.name << ";\n"; - } else { - ts << "\tcs.add(" << cnt << ", "; - if (parser.isEnum(m.type)) ts << "(int)"; - ts << "v." << m.name << ");\n"; - } - } else { - PIString ptype = m.type.left(m.type.find('[')).trim(); - PIString size = m.dims[0]; - for (int i = 1; i < m.dims.size_s(); ++i) { - size += " * "; - size += m.dims[i]; - } - if (simple) { - ts << "\tfor (int i = 0; i < " << size << "; ++i)\n"; - ts << "\t\ts << ((const " << ptype << " *)(v." << m.name << "))[i];\n"; - } else { - ts << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name << "), "; - ts << size << "));\n"; - } - } - if (is_union) break; - } - if (is_union) return true; - for (const PICodeParser::Entity * ce: e->children) { - if (ce->has_name) continue; - if (!writeClassStreamMembersOut(ts, ce, cnt, simple)) return false; - } - return true; -} - - -bool writeClassStreamMembersIn(PIIOTextStream & ts, const PICodeParser::Entity * e, int & cnt, bool simple) { - PIVector ml; - for (const PICodeParser::Member & m: e->members) { - if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; - ml << m; - } - bool is_union = e->type == "union"; - PISet used_id; - for (const PICodeParser::Member & m: ml) { - if (is_union && m.isBitfield()) continue; - if (m.attributes[PICodeParser::Static]) continue; - if (m.meta.value("id") == "-") continue; - ++cnt; - if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); - if (used_id[cnt]) { - piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt); - return false; - } - used_id << cnt; - if (m.dims.isEmpty()) { - bool is_enum = parser.isEnum(m.type); - if (simple) { - ts << "\t"; - if (is_enum) ts << "{int i; "; - ts << "s >> "; - if (is_enum) - ts << "i;"; - else - ts << "v." << m.name << ";"; - if (is_enum) ts << " v." << m.name << " = (" << m.type << ")i;}"; - ts << "\n"; - } else { - ts << "\t\tcase " << cnt << ":"; - if (is_enum) ts << " {int i;"; - ts << " cs.get("; - if (is_enum) - ts << "i"; - else - ts << "v." << m.name; - ts << ");"; - if (is_enum) ts << " v." << m.name << " = (" << m.type << ")i;}"; - ts << " break;\n"; - } - } else { - PIString ptype = m.type.left(m.type.find('[')).trim(); - PIString size = m.dims[0]; - for (int i = 1; i < m.dims.size_s(); ++i) { - size += " * "; - size += m.dims[i]; - } - if (simple) { - ts << "\tfor (int i = 0; i < " << size << "; ++i)\n"; - ts << "\t\ts >> ((" << ptype << " *)(v." << m.name << "))[i];\n"; - } else { - ts << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n"; - ts << "\t\t\tint cnt = piMini(d.size_s(), " << size << ");\n"; - ts << "\t\t\tfor (int i = 0; i < cnt; ++i)\n"; - ts << "\t\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n"; - ts << "\t\t\t}\n"; - ts << "\t\t\tbreak;\n"; - } - } - if (is_union) break; - } - if (is_union) return true; - for (const PICodeParser::Entity * ce: e->children) { - if (ce->has_name) continue; - if (!writeClassStreamMembersIn(ts, ce, cnt, simple)) return false; - } - return true; -} - - -bool needClassStream(const PICodeParser::Entity * e) { - if (e->meta.contains("no-stream")) return false; - for (const PICodeParser::Member & m: e->members) { - if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; - if (m.attributes[PICodeParser::Static]) continue; - if (m.meta.value("id") == "-") continue; - return true; - } - return false; -} - - -bool makeClassStream(PIIOTextStream & ts, const PICodeParser::Entity * e) { - if (!needClassStream(e)) return true; - bool simple = e->meta.contains("simple-stream"); - ts << "\nBINARY_STREAM_WRITE(" << e->name << ") {\n"; - if (!simple) ts << "\tPIChunkStream cs;\n"; - int cnt = 0; - if (!writeClassStreamMembersOut(ts, e, cnt, simple)) return false; - if (!simple) ts << "\ts << cs.data();\n"; - ts << "\treturn s;\n}\n"; - ts << "BINARY_STREAM_READ (" << e->name << ") {\n"; - if (!simple) { - // ts << "\tif (s.size_s() < 4) return s;\n"; - ts << "\tPIChunkStream cs;\n"; - ts << "\tcs.extract(s);\n"; - ts << "\twhile (!cs.atEnd()) {\n"; - ts << "\t\tswitch (cs.read()) {\n"; - } - cnt = 0; - if (!writeClassStreamMembersIn(ts, e, cnt, simple)) return false; - if (!simple) ts << "\t\t}\n\t}\n"; - ts << "\treturn s;\n}\n"; - return true; -} - - -void makeGetterType(PIIOTextStream & ts, const PICodeParser::Entity * e) { - if (!needClassStream(e)) return; - ts << "\nconst char * getterType" << toCName(e->name) << "(const char * name) {\n"; - ts << "\tif (!name) return \"\";\n"; - for (const PICodeParser::Member & m: e->members) { - if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; - ts << "\tif (strcmp(name, \"" << m.name << "\") == 0) return \"" << m.type << "\";\n"; - } - ts << "\treturn \"\";\n}\n"; -} - - -void makeGetterValue(PIIOTextStream & ts, const PICodeParser::Entity * e) { - if (!needClassStream(e)) return; - ts << "\nPIByteArray getterValue" << toCName(e->name) << "(const void * p, const char * name) {\n"; - ts << "\tPIByteArray ret;\n"; - ts << "\tif (!p || !name) return ret;\n"; - ts << "\t" << e->name << " * o = (" << e->name << "*)p;\n"; - for (const PICodeParser::Member & m: e->members) { - if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; - ts << "\tif (strcmp(name, \"" << m.name << "\") == 0) {serialize(ret, o->" << m.name << "); return ret;}\n"; - } - ts << "\treturn ret;\n}\n"; -} - - -bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool meta, bool enums, bool streams, bool texts, bool getters) { +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) @@ -485,7 +46,7 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met PIString inc_string; PIVector incf = inc_files.toVector(); for (const PIString & i: incf) { - if ((i != parser.mainFile()) && (streams || texts || getters)) inc_string += "\n#include \"" + i + "\""; + if ((i != parser.mainFile()) && (streams || json || texts || getters)) inc_string += "\n#include \"" + i + "\""; } PIFile f(out + ".cpp"); @@ -500,22 +61,33 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met 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->has_name || e->name.startsWith("_PI")) continue; - makeGetterType(ts, e); - makeGetterValue(ts, e); + 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 << "\t(*PICodeInfo::__Storage__::instance()->classesInfo)[\"\"] = pci;\n"; + ts << "\tci_ci[\"\"] = pci;\n"; } if (enums && !parser.enums.isEmpty()) { ts << "\tEnumInfo * ei;\n"; @@ -524,41 +96,46 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met ts << "\n\n// Classes\n"; for (const PICodeParser::Entity * e: parser.entities) { if (e->name.startsWith("_PI")) continue; - makeClassInfo(ts, e); + makeClassInfo(rt, e); } } if (enums) { ts << "\n// Enums\n"; for (const PICodeParser::Enum & e: parser.enums) - makeEnumInfo(ts, &e); + makeEnumInfo(rt, &e); } if (getters) { ts << "\n// Getters\n"; for (const PICodeParser::Entity * e: parser.entities) { if (!needClassStream(e)) continue; if (!e->has_name || e->name.startsWith("_PI")) continue; - ts << "\t(*PICodeInfo::__Storage__::instance()->accessValueFunctions)[\"" << e->name << "\"] = getterValue" - << toCName(e->name) << ";\n"; - ts << "\t(*PICodeInfo::__Storage__::instance()->accessTypeFunctions)[\"" << e->name << "\"] = getterType" - << toCName(e->name) << ";\n"; + 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")) continue; - ts << "\tpiDeleteSafety((*PICodeInfo::__Storage__::instance()->classesInfo)[\"" << e->name << "\"]);\n"; - ts << "\tPICodeInfo::__Storage__::instance()->classesInfo->remove(\"" << e->name << "\");\n"; + 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((*PICodeInfo::__Storage__::instance()->enumsInfo)[\"" << e.name << "\"]);\n"; - ts << "\tPICodeInfo::__Storage__::instance()->enumsInfo->remove(\"" << e.name << "\");\n"; + ts << "\tpiDeleteSafety(ci_ei[\"" << e.name << "\"]);\n"; + ts << "\tci_ins->enumsInfo->remove(\"" << e.name << "\");\n"; } } } @@ -567,8 +144,8 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met for (const PICodeParser::Entity * e: parser.entities) { if (!needClassStream(e)) continue; if (!e->has_name || e->name.startsWith("_PI")) continue; - ts << "\tPICodeInfo::__Storage__::instance()->accessValueFunctions->remove(\"" << e->name << "\");\n"; - ts << "\tPICodeInfo::__Storage__::instance()->accessTypeFunctions->remove(\"" << e->name << "\");\n"; + ts << "\tci_avf.remove(\"" << e->name << "\");\n"; + ts << "\tci_atf.remove(\"" << e->name << "\");\n"; } } ts << "}\n"; @@ -591,6 +168,7 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met 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"; @@ -598,7 +176,16 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met if (!e->has_name || e->name.startsWith("_PI") || !(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public)) continue; - if (!makeClassStream(ts, e)) return false; + if (!makeClassStream(rt, e)) return false; + } + } + if (json) { + ts << "\n\n// JSON serialization\n"; + for (const PICodeParser::Entity * e: parser.entities) { + if (!e->has_name || e->name.startsWith("_PI") || + !(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public)) + continue; + if (!makeClassJSON(rt, e)) return false; } } if (meta || enums || getters) { @@ -633,6 +220,7 @@ int main(int argc, char * argv[]) { cli.addArgument("Metainfo"); cli.addArgument("Enum"); cli.addArgument("Stream"); + cli.addArgument("JSON"); cli.addArgument("Getter"); cli.addArgument("Text"); cli.addArgument("print"); @@ -647,6 +235,7 @@ int main(int argc, char * argv[]) { 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()); @@ -665,6 +254,7 @@ int main(int argc, char * argv[]) { 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; diff --git a/utils/code_model_generator/metainfo.cpp b/utils/code_model_generator/metainfo.cpp new file mode 100644 index 00000000..bd6c5d2a --- /dev/null +++ b/utils/code_model_generator/metainfo.cpp @@ -0,0 +1,154 @@ +/* + 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 "metainfo.h" + + +void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e) { + rt.ts << "\n\t{\n\tClassInfo * ci = new ClassInfo();\n"; + rt.ts << "\tci->type = \"" << e->type << "\";\n"; + rt.ts << "\tci->name = \"" << e->name << "\";\n"; + rt.ts << "\tci->has_name = " << (e->has_name ? "true" : "false") << ";\n"; + if (!e->meta.isEmpty()) { + auto i = e->meta.makeIterator(); + while (i.next()) + rt.ts << "\tci->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; + } + rt.ts << "\tci_ci[ci->name] = ci;\n"; + if (e->parent_scope) { + rt.ts << "\tpci = " + << "ci_ci.value(\"" << e->parent_scope->name << "\", 0);\n"; + rt.ts << "\tif (pci) pci->children_info << ci;\n"; + } + for (const PICodeParser::Entity * p: e->parents) + rt.ts << "\tci->parents << \"" << p->name << "\";\n"; + if (!e->members.isEmpty()) rt.ts << "\n\tTypeInfo ti;\n"; + for (const PICodeParser::Member & m: e->members) { + rt.ts << "\tti = TypeInfo(\"" << m.name << "\", \"" << m.type << "\""; + if (m.attributes != 0) { + bool fir = true; + rt.ts << ", "; + if (m.attributes[PICodeParser::Const]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Const"; + } + if (m.attributes[PICodeParser::Static]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Static"; + } + if (m.attributes[PICodeParser::Mutable]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Mutable"; + } + if (m.attributes[PICodeParser::Volatile]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Volatile"; + } + if (m.attributes[PICodeParser::Inline]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Inline"; + } + if (m.attributes[PICodeParser::Virtual]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Virtual"; + } + } else { + if (m.isBitfield()) rt.ts << ", 0"; + } + if (m.isBitfield()) rt.ts << ", " << m.bits; + rt.ts << ");\n"; + if (!m.meta.isEmpty()) { + for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i) + rt.ts << "\tti.meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; + } + rt.ts << "\tci->variables << ti;\n"; + } + PIString arg; + bool has_fi = false; + for (const PICodeParser::Member & m: e->functions) { + if (e->name.findCWord(m.name) >= 0) continue; + if (!has_fi) rt.ts << "\n\tFunctionInfo * fi;\n"; + has_fi = true; + rt.ts << "\tci->functions.push_back(FunctionInfo()); fi = &(ci->functions.back());\n"; + rt.ts << "\tfi->name = \"" << m.name << "\";"; + rt.ts << " fi->return_type = TypeInfo(\"\", \"" << m.type << "\""; + if (m.attributes[PICodeParser::Const] || m.attributes[PICodeParser::Static]) { + bool fir = true; + rt.ts << ", "; + if (m.attributes[PICodeParser::Const]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Const"; + } + if (m.attributes[PICodeParser::Static]) { + if (fir) + fir = false; + else + rt.ts << " | "; + rt.ts << "Static"; + } + } + rt.ts << ");\n"; + // piCout << "write func" << m.name; + for (const PIString & a: m.arguments_full) { + // piCout << "write arg" << a; + rt.ts << "\tfi->arguments << TypeInfo("; + arg = a; + bool con = false; + arg.prepend(" "); + if (arg.find(" const ") >= 0) { + arg.replaceAll(" const ", " "); + con = true; + } + arg.trim(); + int i = 0; + for (i = arg.size_s() - 1; i > 0; --i) + if (!_isCChar(arg[i]) && !(arg[i].isDigit())) break; + rt.ts << "\"" << arg.takeRight(arg.size_s() - i - 1).trim() << "\", "; + rt.ts << "\"" << arg.trim() << "\""; + if (con) rt.ts << ", Const"; + rt.ts << ");\n"; + } + if (!m.meta.isEmpty()) { + for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i) + rt.ts << "\tfi->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n"; + } + } + rt.ts << "\n\t}"; +} diff --git a/utils/code_model_generator/metainfo.h b/utils/code_model_generator/metainfo.h new file mode 100644 index 00000000..127a52b9 --- /dev/null +++ b/utils/code_model_generator/metainfo.h @@ -0,0 +1,27 @@ +/* + 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 . +*/ + +#ifndef pip_cmg_metainfo_H +#define pip_cmg_metainfo_H + +#include "common.h" + +void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e); + +#endif diff --git a/utils/code_model_generator/stream.cpp b/utils/code_model_generator/stream.cpp new file mode 100644 index 00000000..3439d4d1 --- /dev/null +++ b/utils/code_model_generator/stream.cpp @@ -0,0 +1,186 @@ +/* + 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 "stream.h" + +#include "pitranslator.h" + + +bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) { + PIVector ml; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; + ml << m; + } + bool is_union = e->type == "union"; + PISet used_id; + for (const PICodeParser::Member & m: ml) { + if (is_union && m.isBitfield()) continue; + if (m.attributes[PICodeParser::Static]) continue; + if (m.meta.value("id") == "-") continue; + ++cnt; + if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); + if (used_id[cnt]) { + piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt); + return false; + } + if (m.dims.isEmpty()) { + if (simple) { + rt.ts << "\ts << "; + if (rt.parser.isEnum(m.type)) rt.ts << "(int)"; + rt.ts << "v." << m.name << ";\n"; + } else { + rt.ts << "\tcs.add(" << cnt << ", "; + if (rt.parser.isEnum(m.type)) rt.ts << "(int)"; + rt.ts << "v." << m.name << ");\n"; + } + } else { + PIString ptype = m.type.left(m.type.find('[')).trim(); + PIString size = m.dims[0]; + for (int i = 1; i < m.dims.size_s(); ++i) { + size += " * "; + size += m.dims[i]; + } + if (simple) { + rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n"; + rt.ts << "\t\ts << ((const " << ptype << " *)(v." << m.name << "))[i];\n"; + } else { + rt.ts << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name << "), "; + rt.ts << size << "));\n"; + } + } + if (is_union) break; + } + if (is_union) return true; + for (const PICodeParser::Entity * ce: e->children) { + if (ce->has_name) continue; + if (!writeClassStreamMembersOut(rt, ce, cnt, simple)) return false; + } + return true; +} + + +bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) { + PIVector ml; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; + ml << m; + } + bool is_union = e->type == "union"; + PISet used_id; + for (const PICodeParser::Member & m: ml) { + if (is_union && m.isBitfield()) continue; + if (m.attributes[PICodeParser::Static]) continue; + if (m.meta.value("id") == "-") continue; + ++cnt; + if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); + if (used_id[cnt]) { + piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt); + return false; + } + used_id << cnt; + if (m.dims.isEmpty()) { + bool is_enum = rt.parser.isEnum(m.type); + if (simple) { + rt.ts << "\t"; + if (is_enum) rt.ts << "{int i; "; + rt.ts << "s >> "; + if (is_enum) + rt.ts << "i;"; + else + rt.ts << "v." << m.name << ";"; + if (is_enum) rt.ts << " v." << m.name << " = (" << m.type << ")i;}"; + rt.ts << "\n"; + } else { + rt.ts << "\t\tcase " << cnt << ":"; + if (is_enum) rt.ts << " {int i;"; + rt.ts << " cs.get("; + if (is_enum) + rt.ts << "i"; + else + rt.ts << "v." << m.name; + rt.ts << ");"; + if (is_enum) rt.ts << " v." << m.name << " = (" << m.type << ")i;}"; + rt.ts << " break;\n"; + } + } else { + PIString ptype = m.type.left(m.type.find('[')).trim(); + PIString size = m.dims[0]; + for (int i = 1; i < m.dims.size_s(); ++i) { + size += " * "; + size += m.dims[i]; + } + if (simple) { + rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n"; + rt.ts << "\t\ts >> ((" << ptype << " *)(v." << m.name << "))[i];\n"; + } else { + rt.ts << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n"; + rt.ts << "\t\t\tint cnt = piMini(d.size_s(), " << size << ");\n"; + rt.ts << "\t\t\tfor (int i = 0; i < cnt; ++i)\n"; + rt.ts << "\t\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n"; + rt.ts << "\t\t\t}\n"; + rt.ts << "\t\t\tbreak;\n"; + } + } + if (is_union) break; + } + if (is_union) return true; + for (const PICodeParser::Entity * ce: e->children) { + if (ce->has_name) continue; + if (!writeClassStreamMembersIn(rt, ce, cnt, simple)) return false; + } + return true; +} + + +bool needClassStream(const PICodeParser::Entity * e) { + if (e->meta.contains("no-stream")) return false; + for (const PICodeParser::Member & m: e->members) { + if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; + if (m.attributes[PICodeParser::Static]) continue; + if (m.meta.value("id") == "-") continue; + return true; + } + return false; +} + + +bool makeClassStream(Runtime & rt, const PICodeParser::Entity * e) { + if (!needClassStream(e)) return true; + bool simple = e->meta.contains("simple-stream"); + rt.ts << "\nBINARY_STREAM_WRITE(" << e->name << ") {\n"; + if (!simple) rt.ts << "\tPIChunkStream cs;\n"; + int cnt = 0; + if (!writeClassStreamMembersOut(rt, e, cnt, simple)) return false; + if (!simple) rt.ts << "\ts << cs.data();\n"; + rt.ts << "\treturn s;\n}\n"; + rt.ts << "BINARY_STREAM_READ (" << e->name << ") {\n"; + if (!simple) { + // ts << "\tif (s.size_s() < 4) return s;\n"; + rt.ts << "\tPIChunkStream cs;\n"; + rt.ts << "\tcs.extract(s);\n"; + rt.ts << "\twhile (!cs.atEnd()) {\n"; + rt.ts << "\t\tswitch (cs.read()) {\n"; + } + cnt = 0; + if (!writeClassStreamMembersIn(rt, e, cnt, simple)) return false; + if (!simple) rt.ts << "\t\t}\n\t}\n"; + rt.ts << "\treturn s;\n}\n"; + return true; +} diff --git a/utils/code_model_generator/stream.h b/utils/code_model_generator/stream.h new file mode 100644 index 00000000..1de3dabe --- /dev/null +++ b/utils/code_model_generator/stream.h @@ -0,0 +1,30 @@ +/* + 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 . +*/ + +#ifndef pip_cmg_stream_H +#define pip_cmg_stream_H + +#include "common.h" + +bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple); +bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple); +bool needClassStream(const PICodeParser::Entity * e); +bool makeClassStream(Runtime & rt, const PICodeParser::Entity * e); + +#endif