summaryrefslogtreecommitdiffstats
path: root/tools/qscxmlc/scxmlcppdumper.cpp
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@theqtcompany.com>2016-01-29 12:02:04 +0100
committerErik Verbruggen <erik.verbruggen@theqtcompany.com>2016-02-05 13:46:13 +0000
commitd9fb4e37573e55d85b1cfbb24c94d48d93350a54 (patch)
treed61be7734ca364421b9bfd8b0a9b117819b14eb7 /tools/qscxmlc/scxmlcppdumper.cpp
parent9ada7aa0f5a41312c953ee3c34053edc4cf15df9 (diff)
Change staticMetaObject generation.
The full meta-object generation is replaced with the moc generator. This gives a fully functional meta-object without any overhead during object instantiation. Change-Id: Ibf62a6f1bfc0873cd00dd2e4bbad38c8d165005a Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
Diffstat (limited to 'tools/qscxmlc/scxmlcppdumper.cpp')
-rw-r--r--tools/qscxmlc/scxmlcppdumper.cpp272
1 files changed, 230 insertions, 42 deletions
diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp
index 3ccfb0e..26d497b 100644
--- a/tools/qscxmlc/scxmlcppdumper.cpp
+++ b/tools/qscxmlc/scxmlcppdumper.cpp
@@ -32,6 +32,9 @@
#include <algorithm>
#include <functional>
#include <QFileInfo>
+#include <QBuffer>
+
+#include "generator.h"
QT_BEGIN_NAMESPACE
struct StringListDumper {
@@ -98,9 +101,9 @@ struct ClassDump {
Method init;
Method initDataModel;
StringListDumper dataMethods;
+ StringListDumper classMethods;
Method constructor;
Method destructor;
- StringListDumper properties;
StringListDumper signalMethods;
QList<Method> publicMethods;
QList<Method> protectedMethods;
@@ -112,6 +115,8 @@ struct ClassDump {
ClassDump()
: needsEventFilter(false)
{}
+
+ QByteArray metaData;
};
namespace {
@@ -170,7 +175,6 @@ static QString toHex(const QString &str)
static const char *headerStart =
"#include <QScxmlStateMachine>\n"
- "#include <QAbstractState>\n"
"#include <QString>\n"
"#include <QByteArray>\n"
"\n";
@@ -216,6 +220,7 @@ public:
addSubStateMachineProperties(doc);
addEvents();
+ generateMetaObject();
generateTables();
}
@@ -318,11 +323,12 @@ protected:
QString name = mangledName(node);
QString stateName = QStringLiteral("state_") + name;
// Property stuff:
- clazz.properties << QStringLiteral("Q_PROPERTY(QAbstractState *%1 READ %1() CONSTANT)").arg(name);
- Method getter(QStringLiteral("QAbstractState *%1() const").arg(name));
- getter.impl << QStringLiteral("QAbstractState *%2::%1() const").arg(name)
- << QStringLiteral("{ return &data->%1; }").arg(stateName);
- clazz.publicMethods << getter;
+ if (m_qtMode) {
+ Method getter(QStringLiteral("bool %1() const").arg(name));
+ getter.impl << QStringLiteral("bool %2::%1() const").arg(name)
+ << QStringLiteral("{ return data->%1.active(); }").arg(stateName);
+ clazz.publicMethods << getter;
+ }
// Declaration:
if (node->type == State::Final) {
@@ -345,6 +351,16 @@ protected:
if (node->type == State::Parallel) {
clazz.init.impl << stateName + QStringLiteral(".setChildMode(QState::ParallelStates);");
}
+ if (!node->id.isEmpty()) {
+ clazz.init.impl << QStringLiteral("QObject::connect(&")
+ + stateName
+ + QStringLiteral(", SIGNAL(activeChanged(bool)), &stateMachine, SIGNAL(")
+ + node->id
+ + QStringLiteral("Changed(bool)));");
+ }
+
+ m_stateNames.append(node->id);
+ m_stateFieldNames.append(stateName);
// visit the kids:
m_parents.append(node);
@@ -417,7 +433,13 @@ protected:
bool visit(Transition *node) Q_DECL_OVERRIDE
{
const QString tName = transitionName(node);
- m_knownEvents.unite(node->events.toSet());
+ if (m_qtMode) {
+ foreach (const QString &event, node->events) {
+ if (isValidCppIdentifier(event)) {
+ m_knownEvents.insert(event);
+ }
+ }
+ }
// Declaration:
clazz.classFields << QStringLiteral("QScxmlTransition ") + tName + QLatin1Char(';');
@@ -541,6 +563,7 @@ protected:
if (m_qtMode && node->type == QStringLiteral("qt:signal")) {
if (!m_signals.contains(node->event)) {
m_signals.insert(node->event);
+ m_signalNames.append(node->event);
clazz.signalMethods << QStringLiteral("void %1(const QVariant &data);").arg(node->event);
}
}
@@ -637,33 +660,29 @@ private:
void addSubStateMachineProperties(ScxmlDocument *doc)
{
- QStringList serviceProps;
foreach (ScxmlDocument *subDocs, doc->allSubDocuments) {
QString name = subDocs->root->name;
if (name.isEmpty())
continue;
+ auto mangledName = CppDumper::mangleId(name);
+ auto qualifiedName = namespacePrefix + mangledName;
+ if (m_serviceProps.contains(qMakePair(mangledName, qualifiedName)))
+ continue;
+ m_serviceProps.append(qMakePair(mangledName, qualifiedName));
+ clazz.classFields << QStringLiteral("%1 *%2;").arg(qualifiedName, mangledName);
+ clazz.constructor.initializer << QStringLiteral("%1(Q_NULLPTR)").arg(mangledName);
- serviceProps.append(name);
- clazz.classFields << QStringLiteral("%1%2 *%2;").arg(namespacePrefix, name);
- clazz.constructor.initializer << QStringLiteral("%1(Q_NULLPTR)").arg(name);
- clazz.properties << QStringLiteral("Q_PROPERTY(%1%2 *%2 READ %2() NOTIFY %2Changed())").arg(namespacePrefix, name);
- Method getter(QStringLiteral("%1%2 *%2() const").arg(namespacePrefix, name));
- getter.impl << QStringLiteral("%1%2 *%3::%2() const").arg(namespacePrefix, name, clazz.className)
- << QStringLiteral("{ return data->%1; }").arg(name);
- clazz.publicMethods << getter;
- clazz.signalMethods << QStringLiteral("void %1Changed();").arg(name);
- }
-
- if (!serviceProps.isEmpty()) {
- Method reg(QStringLiteral("void setService(const QString &id, QScxmlInvokableService *service) Q_DECL_OVERRIDE Q_DECL_FINAL"));
- reg.impl << QStringLiteral("void %1::setService(const QString &id, QScxmlInvokableService *service) {").arg(clazz.className);
- foreach (const QString &prop, serviceProps) {
- reg.impl << QStringLiteral(" SET_SERVICE_PROP(%1, %2, %3%2, %2Changed)")
- .arg(addString(prop))
- .arg(prop, namespacePrefix);
+ if (m_qtMode) {
+ Method getter(QStringLiteral("%1 *%2() const").arg(qualifiedName, mangledName));
+ getter.impl << QStringLiteral("%1 *%2::%3() const").arg(qualifiedName, clazz.className, mangledName)
+ << QStringLiteral("{ return data->%1; }").arg(mangledName);
+ clazz.publicMethods << getter;
+ clazz.signalMethods << QStringLiteral("void %1Changed(%2 *statemachine);").arg(mangledName, qualifiedName);
}
- reg.impl << QStringLiteral("}");
- clazz.protectedMethods.append(reg);
+
+ clazz.dataMethods << QStringLiteral("%1 *machine_%2() const").arg(qualifiedName, mangledName)
+ << QStringLiteral("{ return %1; }").arg(name)
+ << QString();
}
}
@@ -689,17 +708,17 @@ private:
}
}
- if (!m_signals.isEmpty()) {
+ if (!m_signalNames.isEmpty()) {
clazz.needsEventFilter = true;
clazz.init.impl << QStringLiteral("stateMachine.setScxmlEventFilter(this);");
auto &dm = clazz.dataMethods;
dm << QStringLiteral("bool handle(QScxmlEvent *event, QScxmlStateMachine *stateMachine) Q_DECL_OVERRIDE {");
if (m_qtMode) {
dm << QStringLiteral(" if (event->originType() != QStringLiteral(\"qt:signal\")) { return true; }")
- << QStringLiteral(" %1 *m = qobject_cast<%1 *>(stateMachine);").arg(clazz.className);
- foreach (const QString &s, m_signals) {
+ << QStringLiteral(" %1 *m = static_cast<%1 *>(stateMachine);").arg(clazz.className);
+ foreach (const QString &signalName, m_signalNames) {
dm << QStringLiteral(" if (event->name() == %1) { emit m->%2(event->data()); return false; }")
- .arg(qba(s), CppDumper::mangleId(s));
+ .arg(qba(signalName), CppDumper::mangleId(signalName));
}
}
dm << QStringLiteral(" return true;")
@@ -995,7 +1014,7 @@ private:
for (int i = 0, ei = strings.size(); i < ei; ++i) {
QString s = strings.at(i);
QString comment = cEscape(s);
- t << QStringLiteral("QT_UNICODE_LITERAL_II(\"%1\") // %2").arg(toHex(s) + QStringLiteral("\\x00"), comment);
+ t << QStringLiteral("QT_UNICODE_LITERAL_II(\"%1\") // %3: %2").arg(toHex(s) + QStringLiteral("\\x00"), comment, QString::number(i));
}
}
t << QStringLiteral("};") << QStringLiteral("");
@@ -1021,6 +1040,159 @@ private:
}
}
+ void generateMetaObject()
+ {
+ ClassDef classDef;
+ classDef.classname = clazz.className.toUtf8();
+ classDef.qualified = classDef.classname;
+ classDef.superclassList << qMakePair(QByteArray("QScxmlStateMachine"), FunctionDef::Public);
+ classDef.hasQObject = true;
+
+ // Event signals:
+ foreach (const QString &signalName, m_signalNames) {
+ FunctionDef signal;
+ signal.type.name = "void";
+ signal.type.rawName = signal.type.name;
+ signal.normalizedType = signal.type.name;
+ signal.name = signalName.toUtf8();
+ signal.access = FunctionDef::Public;
+ signal.isSignal = true;
+
+ ArgumentDef arg;
+ arg.type.name = "const QVariant &";
+ arg.type.rawName = arg.type.name;
+ arg.normalizedType = "QVariant";
+ arg.name = "data";
+ arg.typeNameForCast = arg.normalizedType + "*";
+ signal.arguments << arg;
+
+ classDef.signalList << signal;
+ }
+
+ // stateNames:
+ foreach (const QString &stateName, m_stateNames) {
+ if (stateName.isEmpty())
+ continue;
+
+ QByteArray mangledStateName = CppDumper::mangleId(stateName).toUtf8();
+
+ FunctionDef signal;
+ signal.type.name = "void";
+ signal.type.rawName = signal.type.name;
+ signal.normalizedType = signal.type.name;
+ signal.name = mangledStateName + "Changed";
+ signal.access = FunctionDef::Private;
+ signal.isSignal = true;
+ if (!m_qtMode) {
+ signal.implementation = "QMetaObject::activate(_o, &staticMetaObject, %d, _a);";
+ } else {
+ clazz.signalMethods << QStringLiteral("void %1Changed(bool active);").arg(stateName);
+ }
+ ArgumentDef arg;
+ arg.type.name = "bool";
+ arg.type.rawName = arg.type.name;
+ arg.normalizedType = arg.type.name;
+ arg.name = "active";
+ arg.typeNameForCast = arg.type.name + "*";
+ signal.arguments << arg;
+ classDef.signalList << signal;
+
+ ++classDef.notifyableProperties;
+ PropertyDef prop;
+ prop.name = stateName.toUtf8();
+ prop.type = "bool";
+ prop.read = "data->state_" + mangledStateName + ".active";
+ prop.notify = mangledStateName + "Changed";
+ prop.notifyId = classDef.signalList.size() - 1;
+ prop.gspec = PropertyDef::ValueSpec;
+ prop.scriptable = "true";
+ classDef.propertyList << prop;
+ }
+
+ // event slots:
+ foreach (const QString &eventName, m_knownEvents) {
+ FunctionDef slot;
+ slot.type.name = "void";
+ slot.type.rawName = slot.type.name;
+ slot.normalizedType = slot.type.name;
+ slot.name = eventName.toUtf8();
+ slot.access = FunctionDef::Public;
+ slot.isSlot = true;
+
+ classDef.slotList << slot;
+
+ ArgumentDef arg;
+ arg.type.name = "const QVariant &";
+ arg.type.rawName = arg.type.name;
+ arg.normalizedType = "QVariant";
+ arg.name = "data";
+ arg.typeNameForCast = arg.normalizedType + "*";
+ slot.arguments << arg;
+
+ classDef.slotList << slot;
+ }
+
+ // sub-statemachines:
+ QHash<QByteArray, QByteArray> knownQObjectClasses;
+ knownQObjectClasses.insert(QByteArray("QScxmlStateMachine"), QByteArray());
+ Method reg(QStringLiteral("void setService(const QString &id, QScxmlInvokableService *service) Q_DECL_OVERRIDE Q_DECL_FINAL"));
+ reg.impl << QStringLiteral("void %1::setService(const QString &id, QScxmlInvokableService *service) {").arg(clazz.className);
+ if (m_serviceProps.isEmpty()) {
+ reg.impl << QStringLiteral(" Q_UNUSED(id);")
+ << QStringLiteral(" Q_UNUSED(service);");
+ }
+ for (const auto &service : m_serviceProps) {
+ auto serviceName = service.first;
+ QString fqServiceClass = service.second;
+ QByteArray serviceClass = fqServiceClass.toUtf8();
+ knownQObjectClasses.insert(serviceClass, "");
+
+ reg.impl << QStringLiteral(" SET_SERVICE_PROP(%1, %2, %3%2, %4)")
+ .arg(addString(serviceName))
+ .arg(serviceName, namespacePrefix).arg(classDef.signalList.size());
+
+ QByteArray mangledServiceName = CppDumper::mangleId(serviceName).toUtf8();
+
+ FunctionDef signal;
+ signal.type.name = "void";
+ signal.type.rawName = signal.type.name;
+ signal.normalizedType = signal.type.name;
+ signal.name = mangledServiceName + "Changed";
+ signal.access = FunctionDef::Private;
+ signal.isSignal = true;
+ if (!m_qtMode) {
+ signal.implementation = "QMetaObject::activate(_o, &staticMetaObject, %d, _a);";
+ }
+ ArgumentDef arg;
+ arg.type.name = serviceClass + " *";
+ arg.type.rawName = arg.type.name;
+ arg.type.referenceType = Type::Pointer;
+ arg.normalizedType = serviceClass + "*(*)";
+ arg.name = "statemachine";
+ arg.typeNameForCast = arg.type.name + "*";
+ signal.arguments << arg;
+ classDef.signalList << signal;
+
+ ++classDef.notifyableProperties;
+ PropertyDef prop;
+ prop.name = serviceName.toUtf8();
+ prop.type = serviceClass + "*";
+ prop.read = "data->machine_" + mangledServiceName;
+ prop.notify = mangledServiceName + "Changed";
+ prop.notifyId = classDef.signalList.size() - 1;
+ prop.gspec = PropertyDef::ValueSpec;
+ prop.scriptable = "true";
+ classDef.propertyList << prop;
+ }
+ reg.impl << QStringLiteral("}");
+ clazz.protectedMethods.append(reg);
+
+ QBuffer buf(&clazz.metaData);
+ buf.open(QIODevice::WriteOnly);
+ QTextStream out(&buf);
+ Generator(&classDef, QList<QByteArray>(), knownQObjectClasses, QHash<QByteArray, QByteArray>(), out).generateCode();
+ }
+
QString qba(const QString &bytes)
{
return QStringLiteral("string(%1)").arg(addString(bytes));
@@ -1039,8 +1211,12 @@ private:
TranslationUnit *translationUnit;
QHash<AbstractState *, QString> m_mangledNames;
QVector<Node *> m_parents;
+ QList<QPair<QString, QString>> m_serviceProps;
QSet<QString> m_knownEvents;
QSet<QString> m_signals;
+ QStringList m_signalNames;
+ QStringList m_stateNames;
+ QStringList m_stateFieldNames;
QString m_currentTransitionName;
bool m_bindLate;
bool m_qtMode;
@@ -1085,7 +1261,7 @@ void CppDumper::dump(TranslationUnit *unit)
writeImplEnd();
}
-QString CppDumper::mangleId(const QString &id)
+QString CppDumper::mangleId(const QString &id) // TODO: remove
{
QString mangled(id);
mangled = mangled.replace(QLatin1Char('_'), QLatin1String("__"));
@@ -1116,9 +1292,13 @@ void CppDumper::writeHeaderStart(const QString &headerGuard, const QStringList &
void CppDumper::writeClass(const ClassDump &clazz)
{
h << l("class ") << clazz.className << QStringLiteral(": public QScxmlStateMachine\n{") << endl;
- h << QLatin1String(" Q_OBJECT\n");
- clazz.properties.write(h, QStringLiteral(" "), QStringLiteral("\n"));
- h << QLatin1String("\npublic:\n");
+ h << QStringLiteral("public:") << endl
+ << QStringLiteral(" /* qmake ignore Q_OBJECT */") << endl
+ << QStringLiteral(" Q_OBJECT") << endl
+ ;
+
+ h << endl
+ << QStringLiteral("public:") << endl;
h << l(" ") << clazz.className << l("(QObject *parent = 0);") << endl;
h << l(" ~") << clazz.className << "();" << endl;
@@ -1203,9 +1383,12 @@ void CppDumper::writeImplBody(const ClassDump &clazz)
}
cpp << l(" {") << endl;
- cpp << QStringLiteral(" Data(%1 &stateMachine)\n : stateMachine(stateMachine)").arg(clazz.className) << endl;
+ cpp << QStringLiteral(" Data(%1 &stateMachine)").arg(clazz.className) << endl
+ << QStringLiteral(" : stateMachine(stateMachine)") << endl;
clazz.constructor.initializer.write(cpp, QStringLiteral(" , "), QStringLiteral("\n"));
- cpp << l(" { init(); }") << endl;
+ cpp << l(" {") << endl;
+ clazz.constructor.impl.write(cpp, QStringLiteral(" "), QStringLiteral("\n"));
+ cpp << l(" }") << endl;
cpp << endl;
cpp << l(" void init() {\n");
@@ -1220,10 +1403,12 @@ void CppDumper::writeImplBody(const ClassDump &clazz)
cpp << l("};") << endl
<< endl;
+ clazz.classMethods.write(cpp, QStringLiteral(""), QStringLiteral("\n"));
+
cpp << clazz.className << l("::") << clazz.className << l("(QObject *parent)") << endl
<< QStringLiteral(" : QScxmlStateMachine(parent)") << endl
<< QStringLiteral(" , data(new Data(*this))") << endl
- << QStringLiteral("{ qRegisterMetaType<%1 *>(); qRegisterMetaType<QAbstractState *>(); }").arg(clazz.className) << endl
+ << QStringLiteral("{ qRegisterMetaType<%1 *>(); data->init(); }").arg(clazz.className) << endl
<< endl;
cpp << clazz.className << l("::~") << clazz.className << l("()") << endl
<< l("{ delete data; }") << endl
@@ -1239,7 +1424,8 @@ void CppDumper::writeImplBody(const ClassDump &clazz)
" fq *casted = machine ? dynamic_cast<fq*>(machine->stateMachine()) : Q_NULLPTR; \\\n"
" if (data->n != casted) { \\\n"
" data->n = casted; \\\n"
- " emit sig(); \\\n"
+ " void *_a[] = { Q_NULLPTR, const_cast<void*>(reinterpret_cast<const void*>(&casted)) }; \\\n"
+ " QMetaObject::activate(this, &staticMetaObject, sig, _a); \\\n"
" } \\\n"
" return; \\\n"
" }\n"
@@ -1267,6 +1453,8 @@ void CppDumper::writeImplBody(const ClassDump &clazz)
m.impl.write(cpp, QStringLiteral(""), QStringLiteral("\n"));
}
}
+
+ cpp << endl << clazz.metaData;
}
void CppDumper::writeImplEnd()