decompose pip_cmg
add serialization/pijsonserialization.h for JSON de/serialization add -J flag for pip_cmg to make JSON serialization methods not finished yet, but basically workable now
This commit is contained in:
@@ -127,7 +127,21 @@ public:
|
|||||||
//! \~russian
|
//! \~russian
|
||||||
//! Прибавить координаты второй точки и сохранить.
|
//! Прибавить координаты второй точки и сохранить.
|
||||||
//! \details Является копией метода \a translate().
|
//! \details Является копией метода \a translate().
|
||||||
void operator+=(const PIPoint<Type> & p) { translate(p); }
|
PIPoint<Type> & operator+=(const PIPoint<Type> & p) {
|
||||||
|
translate(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIPoint<Type> & operator*=(Type v) {
|
||||||
|
x *= v;
|
||||||
|
y *= v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
PIPoint<Type> & operator/=(Type v) {
|
||||||
|
x /= v;
|
||||||
|
y /= v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//! \~russian Сложить координаты двух точек.
|
//! \~russian Сложить координаты двух точек.
|
||||||
PIPoint<Type> operator+(const PIPoint<Type> & p) { return PIPoint<Type>(x + p.x, y + p.y); }
|
PIPoint<Type> operator+(const PIPoint<Type> & p) { return PIPoint<Type>(x + p.x, y + p.y); }
|
||||||
@@ -144,6 +158,12 @@ public:
|
|||||||
//! \~russian Инвертировать координаты точки.
|
//! \~russian Инвертировать координаты точки.
|
||||||
PIPoint<Type> operator-() { return PIPoint<Type>(-x, -y); }
|
PIPoint<Type> operator-() { return PIPoint<Type>(-x, -y); }
|
||||||
|
|
||||||
|
//! \~russian Умножить координаты точки.
|
||||||
|
PIPoint<Type> operator*(Type v) { return PIPoint<Type>(x * v, y * v); }
|
||||||
|
|
||||||
|
//! \~russian Делить координаты точки.
|
||||||
|
PIPoint<Type> operator/(Type v) { return PIPoint<Type>(x / v, y / v); }
|
||||||
|
|
||||||
//! \~russian Проверить равенство координат двух точек.
|
//! \~russian Проверить равенство координат двух точек.
|
||||||
bool operator==(const PIPoint<Type> & p) const { return (x == p.x && y == p.y); }
|
bool operator==(const PIPoint<Type> & p) const { return (x == p.x && y == p.y); }
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "piioutilsmodule.h"
|
#include "piioutilsmodule.h"
|
||||||
#include "piliterals.h"
|
#include "piliterals.h"
|
||||||
#include "pimathmodule.h"
|
#include "pimathmodule.h"
|
||||||
|
#include "piserializationmodule.h"
|
||||||
#include "pistatemachinemodule.h"
|
#include "pistatemachinemodule.h"
|
||||||
#include "pisystemmodule.h"
|
#include "pisystemmodule.h"
|
||||||
#include "pithreadmodule.h"
|
#include "pithreadmodule.h"
|
||||||
|
|||||||
395
libs/main/serialization/pijsonserialization.h
Normal file
395
libs/main/serialization/pijsonserialization.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pijsonserialization_H
|
||||||
|
#define pijsonserialization_H
|
||||||
|
|
||||||
|
#include "pijson.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---
|
||||||
|
// serialize, PIJSON = piSerializeJSON(T)
|
||||||
|
// ---
|
||||||
|
|
||||||
|
|
||||||
|
// enum & arithmetic
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||||
|
inline PIJSON piSerializeJSON(const T & v) {
|
||||||
|
return PIJSON() = (int)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,
|
||||||
|
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
||||||
|
inline PIJSON piSerializeJSON(const T & v) {
|
||||||
|
return PIJSON() = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,
|
||||||
|
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_arithmetic<T>::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<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const complex<T> & v) {
|
||||||
|
PIJSON ret;
|
||||||
|
ret << v.real() << v.imag();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIFlags<T> & 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<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIPoint<T> & v) {
|
||||||
|
PIJSON ret;
|
||||||
|
ret["x"] = piSerializeJSON(v.x);
|
||||||
|
ret["y"] = piSerializeJSON(v.y);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PILine<T> & v) {
|
||||||
|
PIJSON ret;
|
||||||
|
ret["p0"] = piSerializeJSON(v.p0);
|
||||||
|
ret["p1"] = piSerializeJSON(v.p1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIRect<T> & v) {
|
||||||
|
PIJSON ret;
|
||||||
|
ret["bl"] = piSerializeJSON(v.bottomLeft());
|
||||||
|
ret["tr"] = piSerializeJSON(v.topRigth());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// containers
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
inline PIJSON piSerializeJSON(const PIPair<T1, T2> & v) {
|
||||||
|
PIJSON ret;
|
||||||
|
ret << piSerializeJSON(v.first) << piSerializeJSON(v.second);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIVector<T> & v) {
|
||||||
|
if (v.isEmpty()) return PIJSON::newArray();
|
||||||
|
PIJSON ret;
|
||||||
|
for (const auto & i: v)
|
||||||
|
ret << piSerializeJSON(i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIDeque<T> & v) {
|
||||||
|
if (v.isEmpty()) return PIJSON::newArray();
|
||||||
|
PIJSON ret;
|
||||||
|
for (const auto & i: v)
|
||||||
|
ret << piSerializeJSON(i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIVector2D<T> & v) {
|
||||||
|
PIJSON ret;
|
||||||
|
ret["cols"] = v.cols();
|
||||||
|
ret["rows"] = v.rows();
|
||||||
|
ret["mat"] = piSerializeJSON(v.plainVector());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PISet<T> & v) {
|
||||||
|
if (v.isEmpty()) return PIJSON::newArray();
|
||||||
|
PIJSON ret;
|
||||||
|
for (const auto & i: v)
|
||||||
|
ret << piSerializeJSON(i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
inline PIJSON piSerializeJSON(const PIMap<K, T> & 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<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||||
|
inline void piDeserializeJSON(T & v, const PIJSON & js) {
|
||||||
|
v = (T)js.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,
|
||||||
|
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
||||||
|
inline void piDeserializeJSON(T & v, const PIJSON & js) {
|
||||||
|
v = js.value().value<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,
|
||||||
|
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_arithmetic<T>::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<typename T>
|
||||||
|
inline void piDeserializeJSON(complex<T> & v, const PIJSON & js) {
|
||||||
|
T c[2];
|
||||||
|
piDeserializeJSON(c[0], js[0]);
|
||||||
|
piDeserializeJSON(c[1], js[1]);
|
||||||
|
v = complex<T>(c[0], c[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void piDeserializeJSON(PIFlags<T> & 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<typename T>
|
||||||
|
inline void piDeserializeJSON(PIPoint<T> & v, const PIJSON & js) {
|
||||||
|
piDeserializeJSON(v.x, js["x"]);
|
||||||
|
piDeserializeJSON(v.y, js["y"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void piDeserializeJSON(PILine<T> & v, const PIJSON & js) {
|
||||||
|
piDeserializeJSON(v.p0, js["p0"]);
|
||||||
|
piDeserializeJSON(v.p1, js["p1"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void piDeserializeJSON(PIRect<T> & v, const PIJSON & js) {
|
||||||
|
PIPoint<T> bl, tr;
|
||||||
|
piDeserializeJSON(bl, js["bl"]);
|
||||||
|
piDeserializeJSON(tr, js["tr"]);
|
||||||
|
v = PIRect<T>(bl, tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// containers
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
inline void piDeserializeJSON(PIPair<T1, T2> & v, const PIJSON & js) {
|
||||||
|
v = {};
|
||||||
|
if (!js.isArray()) return;
|
||||||
|
piDeserializeJSON(v.first, js[0]);
|
||||||
|
piDeserializeJSON(v.second, js[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void piDeserializeJSON(PIVector<T> & 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<typename T>
|
||||||
|
inline void piDeserializeJSON(PIDeque<T> & 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<typename T>
|
||||||
|
inline void piDeserializeJSON(PIVector2D<T> & 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<typename T>
|
||||||
|
inline void piDeserializeJSON(PISet<T> & 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<typename K, typename T>
|
||||||
|
inline void piDeserializeJSON(PIMap<K, T> & 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<K>()], it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // pijsonserialization_h
|
||||||
@@ -54,6 +54,7 @@
|
|||||||
#include "pibinarystream.h"
|
#include "pibinarystream.h"
|
||||||
#include "pichunkstream.h"
|
#include "pichunkstream.h"
|
||||||
#include "pijson.h"
|
#include "pijson.h"
|
||||||
|
#include "pijsonserialization.h"
|
||||||
#include "pivaluetree_conversions.h"
|
#include "pivaluetree_conversions.h"
|
||||||
|
|
||||||
#endif // PISERIALIZATIONMODULE_H
|
#endif // PISERIALIZATIONMODULE_H
|
||||||
|
|||||||
@@ -793,7 +793,7 @@ public:
|
|||||||
//! \~english Add to the end data "data" with size "size"
|
//! \~english Add to the end data "data" with size "size"
|
||||||
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
|
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
|
||||||
PIByteArray & push_back(const void * data_, int size_) {
|
PIByteArray & push_back(const void * data_, int size_) {
|
||||||
const uint ps = size();
|
const size_t ps = size();
|
||||||
enlarge(size_);
|
enlarge(size_);
|
||||||
memcpy(data(ps), data_, size_);
|
memcpy(data(ps), data_, size_);
|
||||||
return *this;
|
return *this;
|
||||||
@@ -1092,7 +1092,7 @@ public:
|
|||||||
//! \~english Add to the end data "data" with size "size"
|
//! \~english Add to the end data "data" with size "size"
|
||||||
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
|
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
|
||||||
PIByteArray & append(const void * data_, int size_) {
|
PIByteArray & append(const void * data_, int size_) {
|
||||||
const uint ps = size();
|
const size_t ps = size();
|
||||||
enlarge(size_);
|
enlarge(size_);
|
||||||
memcpy(data(ps), data_, size_);
|
memcpy(data(ps), data_, size_);
|
||||||
return *this;
|
return *this;
|
||||||
@@ -1101,7 +1101,7 @@ public:
|
|||||||
//! \~english Add to the end byte array "data"
|
//! \~english Add to the end byte array "data"
|
||||||
//! \~russian Добавляет в конец массива содержимое массива "data"
|
//! \~russian Добавляет в конец массива содержимое массива "data"
|
||||||
PIByteArray & append(const PIByteArray & data_) {
|
PIByteArray & append(const PIByteArray & data_) {
|
||||||
const uint ps = size();
|
const size_t ps = size();
|
||||||
enlarge(data_.size_s());
|
enlarge(data_.size_s());
|
||||||
memcpy(data(ps), data_.data(), data_.size());
|
memcpy(data(ps), data_.data(), data_.size());
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ set_deploy_property(pip_cmg
|
|||||||
COMPANY "${PIP_COMPANY}"
|
COMPANY "${PIP_COMPANY}"
|
||||||
INFO "Platform-Independent Primitives")
|
INFO "Platform-Independent Primitives")
|
||||||
make_rc(pip_cmg _RC)
|
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)
|
target_link_libraries(pip_cmg pip)
|
||||||
if (DEFINED LIB)
|
if (DEFINED LIB)
|
||||||
install(TARGETS pip_cmg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
install(TARGETS pip_cmg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
|
|||||||
127
utils/code_model_generator/common.cpp
Normal file
127
utils/code_model_generator/common.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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(<type>);\n"
|
||||||
|
"BINARY_STREAM_READ (<type>);\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=<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 <output_file> [-I<include_dir1>] [-I<include_dir1>] [...] [-D<define1>] [-D<define1>] [...] "
|
||||||
|
"<file1> [<file2>] [<file3>] [...]\""
|
||||||
|
<< 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<include_dir> " << Green << "- add include dir (e.g. -I.. -I../some_dir -I/usr/include)";
|
||||||
|
piCout << "-D<define> " << 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 <output_file> " << 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 << "<file> " << 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;
|
||||||
|
}
|
||||||
39
utils/code_model_generator/common.h
Normal file
39
utils/code_model_generator/common.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
44
utils/code_model_generator/enum.cpp
Normal file
44
utils/code_model_generator/enum.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
utils/code_model_generator/enum.h
Normal file
27
utils/code_model_generator/enum.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pip_cmg_enum_H
|
||||||
|
#define pip_cmg_enum_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
void makeEnumInfo(Runtime & rt, const PICodeParser::Enum * e);
|
||||||
|
|
||||||
|
#endif
|
||||||
48
utils/code_model_generator/getter.cpp
Normal file
48
utils/code_model_generator/getter.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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";
|
||||||
|
}
|
||||||
28
utils/code_model_generator/getter.h
Normal file
28
utils/code_model_generator/getter.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
125
utils/code_model_generator/json.cpp
Normal file
125
utils/code_model_generator/json.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
#include "pitranslator.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool writeClassJSONMembersOut(Runtime & rt, const PICodeParser::Entity * e) {
|
||||||
|
PIVector<PICodeParser::Member> 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<PICodeParser::Member> 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<int> 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;
|
||||||
|
}
|
||||||
30
utils/code_model_generator/json.h
Normal file
30
utils/code_model_generator/json.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -17,467 +17,28 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 "picli.h"
|
||||||
#include "picodeparser.h"
|
#include "picodeparser.h"
|
||||||
#include "piiostream.h"
|
#include "piiostream.h"
|
||||||
#include "pitranslator.h"
|
#include "pitranslator.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
using namespace PICoutManipulators;
|
using namespace PICoutManipulators;
|
||||||
|
|
||||||
PICodeParser parser;
|
|
||||||
|
|
||||||
const char help_string[] = "-M (Metainfo)\n"
|
bool writeModel(PICodeParser & parser,
|
||||||
"Generate classes and structs info. It contains\n"
|
PICLI & cli,
|
||||||
"names, subclass info, all methods and variables.\n"
|
const PIString out,
|
||||||
"Place information:\n"
|
bool meta,
|
||||||
" * classes and structs - PICODEINFO::classes()\n"
|
bool enums,
|
||||||
" * methods - ClassInfo::functions\n"
|
bool streams,
|
||||||
" * variables - ClassInfo::variables\n"
|
bool json,
|
||||||
"\n"
|
bool texts,
|
||||||
"-E (Enums)\n"
|
bool getters) {
|
||||||
"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(<type>);\n"
|
|
||||||
"BINARY_STREAM_READ (<type>);\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=<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 <output_file> [-I<include_dir1>] [-I<include_dir1>] [...] [-D<define1>] [-D<define1>] [...] "
|
|
||||||
"<file1> [<file2>] [<file3>] [...]\""
|
|
||||||
<< 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<include_dir> " << Green << "- add include dir (e.g. -I.. -I../some_dir -I/usr/include)";
|
|
||||||
piCout << "-D<define> " << 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 <output_file> " << 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 << "<file> " << 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<PICodeParser::Member> 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<int> 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<PICodeParser::Member> 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<int> 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) {
|
|
||||||
PIString defname = "CCM_" + PIString::fromNumber(out.hash()) + "_H";
|
PIString defname = "CCM_" + PIString::fromNumber(out.hash()) + "_H";
|
||||||
PISet<PIString> inc_files;
|
PISet<PIString> inc_files;
|
||||||
for (const PICodeParser::Entity * e: parser.entities)
|
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;
|
PIString inc_string;
|
||||||
PIVector<PIString> incf = inc_files.toVector();
|
PIVector<PIString> incf = inc_files.toVector();
|
||||||
for (const PIString & i: incf) {
|
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");
|
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 << "#include \"" << out << ".h\"\n";
|
||||||
ts << "\nusing namespace PICodeInfo;\n";
|
ts << "\nusing namespace PICodeInfo;\n";
|
||||||
|
|
||||||
|
Runtime rt{parser, cli, ts};
|
||||||
|
|
||||||
if (meta || enums || getters) {
|
if (meta || enums || getters) {
|
||||||
if (getters) {
|
if (getters) {
|
||||||
ts << "\n\n// Getter funtions\n";
|
ts << "\n\n// Getter funtions\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
||||||
makeGetterType(ts, e);
|
makeGetterType(rt, e);
|
||||||
makeGetterValue(ts, e);
|
makeGetterValue(rt, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts << "\n\n// Metainformation\n\n__ClassInfo_" << defname << "_Initializer__::__ClassInfo_" << defname << "_Initializer__() {\n";
|
ts << "\n\n// Metainformation\n\n__ClassInfo_" << defname << "_Initializer__::__ClassInfo_" << defname << "_Initializer__() {\n";
|
||||||
ts << "\tstatic __ClassInfo_" << defname << "_Initializer__::Content content;\n";
|
ts << "\tstatic __ClassInfo_" << defname << "_Initializer__::Content content;\n";
|
||||||
ts << "}\n\n";
|
ts << "}\n\n";
|
||||||
ts << "__ClassInfo_" << defname << "_Initializer__::Content::Content() {\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) {
|
if (meta) {
|
||||||
ts << "\tClassInfo * pci = new ClassInfo();\n";
|
ts << "\tClassInfo * pci = new ClassInfo();\n";
|
||||||
ts << "\t(*PICodeInfo::__Storage__::instance()->classesInfo)[\"\"] = pci;\n";
|
ts << "\tci_ci[\"\"] = pci;\n";
|
||||||
}
|
}
|
||||||
if (enums && !parser.enums.isEmpty()) {
|
if (enums && !parser.enums.isEmpty()) {
|
||||||
ts << "\tEnumInfo * ei;\n";
|
ts << "\tEnumInfo * ei;\n";
|
||||||
@@ -524,41 +96,46 @@ bool writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool met
|
|||||||
ts << "\n\n// Classes\n";
|
ts << "\n\n// Classes\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (e->name.startsWith("_PI")) continue;
|
if (e->name.startsWith("_PI")) continue;
|
||||||
makeClassInfo(ts, e);
|
makeClassInfo(rt, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (enums) {
|
if (enums) {
|
||||||
ts << "\n// Enums\n";
|
ts << "\n// Enums\n";
|
||||||
for (const PICodeParser::Enum & e: parser.enums)
|
for (const PICodeParser::Enum & e: parser.enums)
|
||||||
makeEnumInfo(ts, &e);
|
makeEnumInfo(rt, &e);
|
||||||
}
|
}
|
||||||
if (getters) {
|
if (getters) {
|
||||||
ts << "\n// Getters\n";
|
ts << "\n// Getters\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!needClassStream(e)) continue;
|
if (!needClassStream(e)) continue;
|
||||||
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
||||||
ts << "\t(*PICodeInfo::__Storage__::instance()->accessValueFunctions)[\"" << e->name << "\"] = getterValue"
|
ts << "\tci_avf[\"" << e->name << "\"] = getterValue" << toCName(e->name) << ";\n";
|
||||||
<< toCName(e->name) << ";\n";
|
ts << "\tci_atf[\"" << e->name << "\"] = getterType" << toCName(e->name) << ";\n";
|
||||||
ts << "\t(*PICodeInfo::__Storage__::instance()->accessTypeFunctions)[\"" << e->name << "\"] = getterType"
|
|
||||||
<< toCName(e->name) << ";\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts << "}\n\n";
|
ts << "}\n\n";
|
||||||
ts << "__ClassInfo_" << defname << "_Initializer__::Content::~Content() {\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) {
|
if (meta) {
|
||||||
ts << "\n// Classes clean\n";
|
ts << "\n// Classes clean\n";
|
||||||
for (const PICodeParser::Entity * e: parser.entities) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (e->name.startsWith("_PI")) continue;
|
if (e->name.startsWith("_PI")) continue;
|
||||||
ts << "\tpiDeleteSafety((*PICodeInfo::__Storage__::instance()->classesInfo)[\"" << e->name << "\"]);\n";
|
ts << "\tpiDeleteSafety(ci_ci[\"" << e->name << "\"]);\n";
|
||||||
ts << "\tPICodeInfo::__Storage__::instance()->classesInfo->remove(\"" << e->name << "\");\n";
|
ts << "\tci_ins->classesInfo->remove(\"" << e->name << "\");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (enums) {
|
if (enums) {
|
||||||
ts << "\n// Enums clean\n";
|
ts << "\n// Enums clean\n";
|
||||||
for (const PICodeParser::Enum & e: parser.enums) {
|
for (const PICodeParser::Enum & e: parser.enums) {
|
||||||
if (e.name.isNotEmpty()) {
|
if (e.name.isNotEmpty()) {
|
||||||
ts << "\tpiDeleteSafety((*PICodeInfo::__Storage__::instance()->enumsInfo)[\"" << e.name << "\"]);\n";
|
ts << "\tpiDeleteSafety(ci_ei[\"" << e.name << "\"]);\n";
|
||||||
ts << "\tPICodeInfo::__Storage__::instance()->enumsInfo->remove(\"" << 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) {
|
for (const PICodeParser::Entity * e: parser.entities) {
|
||||||
if (!needClassStream(e)) continue;
|
if (!needClassStream(e)) continue;
|
||||||
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
if (!e->has_name || e->name.startsWith("_PI")) continue;
|
||||||
ts << "\tPICodeInfo::__Storage__::instance()->accessValueFunctions->remove(\"" << e->name << "\");\n";
|
ts << "\tci_avf.remove(\"" << e->name << "\");\n";
|
||||||
ts << "\tPICodeInfo::__Storage__::instance()->accessTypeFunctions->remove(\"" << e->name << "\");\n";
|
ts << "\tci_atf.remove(\"" << e->name << "\");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts << "}\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 << "#ifndef " << defname << "\n#define " << defname << "\n\n";
|
||||||
ts << "#include <pivariant.h>\n#include <picodeinfo.h>";
|
ts << "#include <pivariant.h>\n#include <picodeinfo.h>";
|
||||||
if (streams || texts) ts << "\n#include <pichunkstream.h>";
|
if (streams || texts) ts << "\n#include <pichunkstream.h>";
|
||||||
|
if (json) ts << "\n#include <pijsonserialization.h>";
|
||||||
ts << inc_string << "\n";
|
ts << inc_string << "\n";
|
||||||
if (streams) {
|
if (streams) {
|
||||||
ts << "\n\n// Stream operators\n";
|
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") ||
|
if (!e->has_name || e->name.startsWith("_PI") ||
|
||||||
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
|
!(e->visibility == PICodeParser::Global || e->visibility == PICodeParser::Public))
|
||||||
continue;
|
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) {
|
if (meta || enums || getters) {
|
||||||
@@ -633,6 +220,7 @@ int main(int argc, char * argv[]) {
|
|||||||
cli.addArgument("Metainfo");
|
cli.addArgument("Metainfo");
|
||||||
cli.addArgument("Enum");
|
cli.addArgument("Enum");
|
||||||
cli.addArgument("Stream");
|
cli.addArgument("Stream");
|
||||||
|
cli.addArgument("JSON");
|
||||||
cli.addArgument("Getter");
|
cli.addArgument("Getter");
|
||||||
cli.addArgument("Text");
|
cli.addArgument("Text");
|
||||||
cli.addArgument("print");
|
cli.addArgument("print");
|
||||||
@@ -647,6 +235,7 @@ int main(int argc, char * argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
piDebug = !cli.hasArgument("quiet");
|
piDebug = !cli.hasArgument("quiet");
|
||||||
|
PICodeParser parser;
|
||||||
for (const PIString & a: cli.rawArguments()) {
|
for (const PIString & a: cli.rawArguments()) {
|
||||||
if (a.startsWith("-I")) parser.includeDirectory(a.mid(2));
|
if (a.startsWith("-I")) parser.includeDirectory(a.mid(2));
|
||||||
if (a.startsWith("-D")) parser.addDefine(a.mid(2), PIString());
|
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("Metainfo") || all,
|
||||||
cli.hasArgument("Enum") || all,
|
cli.hasArgument("Enum") || all,
|
||||||
cli.hasArgument("Stream") || all,
|
cli.hasArgument("Stream") || all,
|
||||||
|
cli.hasArgument("JSON") || all,
|
||||||
cli.hasArgument("Text") || all,
|
cli.hasArgument("Text") || all,
|
||||||
cli.hasArgument("Getter") || all))
|
cli.hasArgument("Getter") || all))
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
154
utils/code_model_generator/metainfo.cpp
Normal file
154
utils/code_model_generator/metainfo.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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}";
|
||||||
|
}
|
||||||
27
utils/code_model_generator/metainfo.h
Normal file
27
utils/code_model_generator/metainfo.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef pip_cmg_metainfo_H
|
||||||
|
#define pip_cmg_metainfo_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e);
|
||||||
|
|
||||||
|
#endif
|
||||||
186
utils/code_model_generator/stream.cpp
Normal file
186
utils/code_model_generator/stream.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include "pitranslator.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) {
|
||||||
|
PIVector<PICodeParser::Member> 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<int> 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<PICodeParser::Member> 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<int> 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;
|
||||||
|
}
|
||||||
30
utils/code_model_generator/stream.h
Normal file
30
utils/code_model_generator/stream.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
Reference in New Issue
Block a user