pip_cmg now works with new nested entities approach Getters now can access to bitfields
196 lines
6.5 KiB
C++
196 lines
6.5 KiB
C++
/*
|
|
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, PIString var_prefix) {
|
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
|
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 (m.isBitfield()) continue;
|
|
if (m.attributes[PICodeParser::Static]) continue;
|
|
if (m.meta.value("id") == "-") continue;
|
|
auto type = findEntity(rt, m.type);
|
|
if (type) {
|
|
if (type->is_anonymous) {
|
|
if (!writeClassStreamMembersOut(rt, type, cnt, simple, var_prefix + m.name)) return false;
|
|
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." << var_prefix << m.name << ";\n";
|
|
} else {
|
|
rt.ts << "\tcs.add(" << cnt << ", ";
|
|
if (rt.parser.isEnum(m.type)) rt.ts << "(int)";
|
|
rt.ts << "v." << var_prefix << 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." << var_prefix << m.name << "))[i];\n";
|
|
} else {
|
|
rt.ts << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(" << "v." << var_prefix
|
|
<< m.name << "), ";
|
|
rt.ts << size << "));\n";
|
|
}
|
|
}
|
|
if (is_union) break;
|
|
}
|
|
if (is_union) return true;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple, PIString var_prefix) {
|
|
if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
|
|
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 (m.isBitfield()) continue;
|
|
if (m.attributes[PICodeParser::Static]) continue;
|
|
if (m.meta.value("id") == "-") continue;
|
|
auto type = findEntity(rt, m.type);
|
|
if (type) {
|
|
if (type->is_anonymous) {
|
|
if (!writeClassStreamMembersIn(rt, type, cnt, simple, var_prefix + m.name)) return false;
|
|
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." << var_prefix << m.name << ";";
|
|
if (is_enum) rt.ts << " v. << var_prefix" << 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." << var_prefix << m.name;
|
|
rt.ts << ");";
|
|
if (is_enum) rt.ts << " v." << var_prefix << 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." << var_prefix << 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." << var_prefix << 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;
|
|
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;
|
|
}
|