summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@theqtcompany.com>2016-06-08 13:33:26 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2016-06-09 14:13:57 +0000
commit17899954bffd902b61ee4c9d339095cb618e4346 (patch)
tree6d4a74f2c8e41f3760bf9df4ec982af48cf2b798 /tools
parent60b5508b3f0fabee545e8cfd907ed4875ed55ffc (diff)
Replace the QStateMachine-based implementation.
Under the 'hood a table-based state machine is now used instead of the QStateMachine. The advantage is that states and transitions are no longer QObjects but integers (so no (private) object allocations), and we're no longer hijacking the QStateMachinePrivate to work around some implementation details. Change-Id: I47ab47ab01cbb2204b9ca0e4cdd6a72faf724ce3 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qscxmlc/cppdatamodel.t42
-rw-r--r--tools/qscxmlc/data.t125
-rw-r--r--tools/qscxmlc/decl.t21
-rw-r--r--tools/qscxmlc/generator.cpp13
-rw-r--r--tools/qscxmlc/qscxmlc.pro3
-rw-r--r--tools/qscxmlc/scxmlcppdumper.cpp2037
-rw-r--r--tools/qscxmlc/scxmlcppdumper.h28
-rw-r--r--tools/qscxmlc/templates.qrc7
8 files changed, 960 insertions, 1316 deletions
diff --git a/tools/qscxmlc/cppdatamodel.t b/tools/qscxmlc/cppdatamodel.t
new file mode 100644
index 0000000..524571b
--- /dev/null
+++ b/tools/qscxmlc/cppdatamodel.t
@@ -0,0 +1,42 @@
+QString ${datamodel}::evaluateToString(QScxmlExecutableContent::EvaluatorId id, bool *ok)
+{
+ *ok = true;
+ switch (id) {
+${evaluateToStringCases} default:
+ Q_UNREACHABLE();
+ *ok = false;
+ return QString();
+ }
+}
+
+bool ${datamodel}::evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok)
+{
+ *ok = true;
+ switch (id) {
+${evaluateToBoolCases} default:
+ Q_UNREACHABLE();
+ *ok = false;
+ return false;
+ }
+}
+
+QVariant ${datamodel}::evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok)
+{
+ *ok = true;
+ switch (id) {
+${evaluateToVariantCases} default:
+ Q_UNREACHABLE();
+ *ok = false;
+ return QVariant();
+ }
+}
+
+void ${datamodel}::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok)
+{
+ *ok = true;
+ switch (id) {
+${evaluateToVoidCases} default:
+ Q_UNREACHABLE();
+ *ok = false;
+ }
+}
diff --git a/tools/qscxmlc/data.t b/tools/qscxmlc/data.t
new file mode 100644
index 0000000..a1eece5
--- /dev/null
+++ b/tools/qscxmlc/data.t
@@ -0,0 +1,125 @@
+struct ${classname}::Data: private QScxmlTableData {
+ Data(${classname} &stateMachine)
+ : stateMachine(stateMachine)
+ {}
+
+ void init() {
+ stateMachine.setTableData(this);
+ ${dataModelInitialization}
+ }
+
+ QString name() const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return ${name}; }
+
+ QScxmlExecutableContent::ContainerId initialSetup() const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return ${initialSetup}; }
+
+ QScxmlExecutableContent::Instructions instructions() const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return theInstructions; }
+
+ QScxmlExecutableContent::StringId *dataNames(int *count) const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { *count = ${dataNameCount}; return dataIds; }
+
+ QScxmlExecutableContent::EvaluatorInfo evaluatorInfo(QScxmlExecutableContent::EvaluatorId evaluatorId) const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { Q_ASSERT(evaluatorId >= 0); Q_ASSERT(evaluatorId < ${evaluatorCount}); return evaluators[evaluatorId]; }
+
+ QScxmlExecutableContent::AssignmentInfo assignmentInfo(QScxmlExecutableContent::EvaluatorId assignmentId) const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { Q_ASSERT(assignmentId >= 0); Q_ASSERT(assignmentId < ${assignmentCount}); return assignments[assignmentId]; }
+
+ QScxmlExecutableContent::ForeachInfo foreachInfo(QScxmlExecutableContent::EvaluatorId foreachId) const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { Q_ASSERT(foreachId >= 0); Q_ASSERT(foreachId < ${foreachCount}); return foreaches[foreachId]; }
+
+ QString string(QScxmlExecutableContent::StringId id) const Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ Q_ASSERT(id >= QScxmlExecutableContent::NoString); Q_ASSERT(id < ${stringCount});
+ if (id == QScxmlExecutableContent::NoString) return QString();
+ return QString({static_cast<QStringData*>(strings.data + id)});
+ }
+
+ const qint32 *stateMachineTable() const Q_DECL_OVERRIDE Q_DECL_FINAL
+ { return theStateMachineTable; }
+
+ QScxmlInvokableServiceFactory *serviceFactory(int id) const Q_DECL_OVERRIDE Q_DECL_FINAL;
+ int signalIndexForEvent(const QString &event) const Q_DECL_OVERRIDE Q_DECL_FINAL;
+
+ ${classname} &stateMachine;
+ ${dataModelField}
+
+ static qint32 theInstructions[];
+ static QScxmlExecutableContent::StringId dataIds[];
+ static QScxmlExecutableContent::EvaluatorInfo evaluators[];
+ static QScxmlExecutableContent::AssignmentInfo assignments[];
+ static QScxmlExecutableContent::ForeachInfo foreaches[];
+ static const qint32 theStateMachineTable[];
+ static struct Strings {
+ QArrayData data[${stringCount}];
+ qunicodechar stringdata[${stringdataSize}];
+ } strings;
+
+ static std::vector<QString> outgoingEvents;
+};
+
+${classname}::${classname}(QObject *parent)
+ : QScxmlStateMachine(parent)
+ , data(new Data(*this))
+{ qRegisterMetaType<${classname} *>(); data->init(); }
+
+${classname}::~${classname}()
+{ delete data; }
+
+QScxmlInvokableServiceFactory *${classname}::Data::serviceFactory(int id) const
+{
+ switch (id) {
+ ${serviceFactories}
+ }
+}
+
+std::vector<QString> ${classname}::Data::outgoingEvents = {
+${outgoingEvents}
+};
+
+int ${classname}::Data::signalIndexForEvent(const QString &event) const
+{
+ auto it = std::lower_bound(outgoingEvents.begin(), outgoingEvents.end(), event);
+ if (it != outgoingEvents.end() && *it == event) {
+ return int(std::distance(outgoingEvents.begin(), it));
+ } else {
+ return -1;
+ }
+}
+
+qint32 ${classname}::Data::theInstructions[] = {
+${theInstructions}
+};
+
+QScxmlExecutableContent::StringId ${classname}::Data::dataIds[] = {
+${dataIds}
+};
+
+QScxmlExecutableContent::EvaluatorInfo ${classname}::Data::evaluators[] = {
+${evaluators}
+};
+
+QScxmlExecutableContent::AssignmentInfo ${classname}::Data::assignments[] = {
+${assignments}
+};
+
+QScxmlExecutableContent::ForeachInfo ${classname}::Data::foreaches[] = {
+${foreaches}
+};
+
+#define STR_LIT(idx, ofs, len) \
+ Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
+ qptrdiff(offsetof(Strings, stringdata) + ofs * sizeof(qunicodechar) - idx * sizeof(QArrayData)) \
+ )
+${classname}::Data::Strings ${classname}::Data::strings = {{
+${strLits}
+},{
+${uniLits}
+}};
+
+const qint32 ${classname}::Data::theStateMachineTable[] = ${theStateMachineTable};
+
+${metaObject}
+${getters}
+${slots}
diff --git a/tools/qscxmlc/decl.t b/tools/qscxmlc/decl.t
new file mode 100644
index 0000000..2b35d67
--- /dev/null
+++ b/tools/qscxmlc/decl.t
@@ -0,0 +1,21 @@
+class ${classname}: public QScxmlStateMachine
+{
+public:
+ /* qmake ignore Q_OBJECT */
+ Q_OBJECT
+
+public:
+ ${classname}(QObject *parent = 0);
+ ~${classname}();
+
+${getters}
+signals:
+${signals}
+public slots:
+${slots}
+private:
+ struct Data;
+ friend struct Data;
+ struct Data *data;
+};
+
diff --git a/tools/qscxmlc/generator.cpp b/tools/qscxmlc/generator.cpp
index b37e928..561bc05 100644
--- a/tools/qscxmlc/generator.cpp
+++ b/tools/qscxmlc/generator.cpp
@@ -1146,13 +1146,13 @@ void Generator::generateStaticMetacall()
Q_ASSERT(!f.normalizedType.isEmpty());
fprintf(out, " case %d: ", methodindex);
- //----
+ //---- Changed from the original in moc
if (f.implementation) {
fprintf(out, f.implementation, methodindex);
fprintf(out, " break;\n");
continue;
}
- //----
+ //---- End of change
if (f.normalizedType != "void")
fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
@@ -1327,8 +1327,13 @@ void Generator::generateStaticMetacall()
fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n",
propindex, prefix.constData(), p.read.constData());
else if (!p.read.isEmpty())
- fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n",
- propindex, p.type.constData(), prefix.constData(), p.read.constData());
+ //---- Changed from the original in moc
+ {
+ fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s%s; break;\n",
+ propindex, p.type.constData(), prefix.constData(), p.read.constData(),
+ p.read.endsWith(')') ? "" : "()");
+ }
+ //---- End of change
else
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n",
propindex, p.type.constData(), prefix.constData(), p.member.constData());
diff --git a/tools/qscxmlc/qscxmlc.pro b/tools/qscxmlc/qscxmlc.pro
index 7621eef..7620d3d 100644
--- a/tools/qscxmlc/qscxmlc.pro
+++ b/tools/qscxmlc/qscxmlc.pro
@@ -11,3 +11,6 @@ SOURCES += \
main.cpp
load(qt_tool)
+load(resources)
+
+RESOURCES += templates.qrc
diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp
index 6efa5f6..f6cc42a 100644
--- a/tools/qscxmlc/scxmlcppdumper.cpp
+++ b/tools/qscxmlc/scxmlcppdumper.cpp
@@ -33,11 +33,17 @@
#include <functional>
#include <QFileInfo>
#include <QBuffer>
+#include <QFile>
+#include <QResource>
#include "generator.h"
QT_BEGIN_NAMESPACE
+using namespace QScxmlInternal;
+
+namespace {
+
static const QString doNotEditComment = QString::fromLatin1(
"//\n"
"// Statemachine code from reading SCXML file '%1'\n"
@@ -56,91 +62,6 @@ static const QString revisionCheck = QString::fromLatin1(
"#endif\n"
);
-struct StringListDumper {
- StringListDumper &operator <<(const QString &s) {
- text.append(s);
- return *this;
- }
-
- StringListDumper &operator <<(const QLatin1String &s) {
- text.append(s);
- return *this;
- }
- StringListDumper &operator <<(const char *s) {
- text.append(QLatin1String(s));
- return *this;
- }
- StringListDumper &operator <<(int i) {
- text.append(QString::number(i));
- return *this;
- }
- StringListDumper &operator <<(const QByteArray &s) {
- text.append(QString::fromUtf8(s));
- return *this;
- }
-
- bool isEmpty() const {
- return text.isEmpty();
- }
-
- void write(QTextStream &out, const QString &prefix, const QString &suffix, const QString &mainClassName = QString()) const
- {
- foreach (QString line, text) {
- if (!mainClassName.isEmpty() && line.contains(QStringLiteral("%"))) {
- line = line.arg(mainClassName);
- }
- out << prefix << line << suffix;
- }
- }
-
- void unique()
- {
- text.sort();
- text.removeDuplicates();
- }
-
- QStringList text;
-};
-
-struct Method {
- StringListDumper initializer;
- Method(const QString &decl = QString()): decl(decl) {}
- Method(const StringListDumper &impl): impl(impl) {}
- QString decl; // void f(int i = 0);
- StringListDumper impl; // void f(int i) { m_i = ++i; }
-};
-
-struct ClassDump {
- bool needsEventFilter;
- StringListDumper implIncludes;
- QString className;
- QString dataModelClassName;
- StringListDumper classFields;
- StringListDumper tables;
- Method init;
- Method initDataModel;
- StringListDumper dataMethods;
- StringListDumper classMethods;
- Method constructor;
- Method destructor;
- StringListDumper properties;
- StringListDumper signalMethods;
- QList<Method> publicMethods;
- QList<Method> protectedMethods;
- StringListDumper publicSlotDeclarations;
- StringListDumper publicSlotDefinitions;
-
- QList<Method> dataModelMethods;
-
- ClassDump()
- : needsEventFilter(false)
- {}
-
- QByteArray metaData;
-};
-
-namespace {
-
QString cEscape(const QString &str)
{
QString res;
@@ -179,1136 +100,328 @@ QString cEscape(const QString &str)
return str;
}
+typedef QHash<QString, QString> Replacements;
+static void genTemplate(QTextStream &out, const QString &filename, const Replacements &replacements)
+{
+ QResource file(filename);
+ if (!file.isValid()) {
+ qFatal("Unable to open template '%s'", qPrintable(filename));
+ }
+ QByteArray data;
+ if (file.isCompressed() && file.size()) {
+ data = qUncompress(file.data(), int(file.size()));
+ } else {
+ data = QByteArray::fromRawData(reinterpret_cast<const char *>(file.data()),
+ int(file.size()));
+ }
+ const QString t = QString::fromLatin1(data);
+ data.clear();
+
+ int start = 0;
+ for (int openIdx = t.indexOf(QStringLiteral("${"), start); openIdx >= 0; openIdx =
+ t.indexOf(QStringLiteral("${"), start)) {
+ out << t.midRef(start, openIdx - start);
+ openIdx += 2;
+ const int closeIdx = t.indexOf(QLatin1Char('}'), openIdx);
+ Q_ASSERT(closeIdx >= openIdx);
+ QString key = t.mid(openIdx, closeIdx - openIdx);
+ if (!replacements.contains(key)) {
+ qFatal("Replacing '%s' failed: no replacement found", qPrintable(key));
+ }
+ out << replacements.value(key);
+ start = closeIdx + 1;
+ }
+ out << t.midRef(start);
+}
+
static const char *headerStart =
"#include <QScxmlStateMachine>\n"
"#include <QString>\n"
- "#include <QByteArray>\n"
+ "#include <QVariant>\n"
"\n";
using namespace DocumentModel;
-enum class Evaluator
+QString createContainer(const QString &baseType, const QString &elementType,
+ const QStringList &elements, bool useCxx11)
{
- ToVariant,
- ToString,
- ToBool,
- Assignment,
- Foreach,
- Script
-};
-
-class DumperVisitor: public QScxmlExecutableContent::Builder
-{
- Q_DISABLE_COPY(DumperVisitor)
-
-public:
- DumperVisitor(ClassDump &clazz, TranslationUnit *tu)
- : namespacePrefix(QStringLiteral("::"))
- , clazz(clazz)
- , translationUnit(tu)
- , m_bindLate(false)
- , m_qtMode(false)
- {
- if (!tu->namespaceName.isEmpty()) {
- namespacePrefix += QStringLiteral("%1::").arg(tu->namespaceName);
- }
- }
-
- void process(ScxmlDocument *doc)
- {
- Q_ASSERT(doc);
-
- clazz.className = mangleIdentifier(translationUnit->classnameForDocument.value(doc));
- m_qtMode = doc->qtMode;
-
- doc->root->accept(this);
-
- addSubStateMachineProperties(doc);
- addEvents();
-
- generateMetaObject();
- generateTables();
- }
-
- ~DumperVisitor()
- {
- Q_ASSERT(m_parents.isEmpty());
- }
-
-protected:
- using NodeVisitor::visit;
-
- bool visit(Scxml *node) Q_DECL_OVERRIDE
- {
- // init:
- if (!node->name.isEmpty()) {
- clazz.dataMethods << QStringLiteral("QString name() const Q_DECL_OVERRIDE Q_DECL_FINAL")
- << QStringLiteral("{ return string(%1); }").arg(addString(node->name))
- << QString();
- clazz.init.impl << QStringLiteral("stateMachine.setObjectName(string(%1));").arg(addString(node->name));
+ QString result;
+ if (useCxx11) {
+ if (elements.isEmpty()) {
+ result += QStringLiteral("{}");
} else {
- clazz.dataMethods << QStringLiteral("QString name() const Q_DECL_OVERRIDE Q_DECL_FINAL")
- << QStringLiteral("{ return QString(); }")
- << QString();
- }
- if (node->dataModel == Scxml::CppDataModel) {
- // Tell the builder not to generate any script strings when visiting any executable content.
- // We'll take care of the evaluators ourselves.
- setIsCppDataModel(true);
+ result += QStringLiteral("{ ") + elements.join(QStringLiteral(", ")) + QStringLiteral(" }");
}
-
- QString binding;
- switch (node->binding) {
- case Scxml::EarlyBinding:
- binding = QStringLiteral("Early");
- break;
- case Scxml::LateBinding:
- binding = QStringLiteral("Late");
- m_bindLate = true;
- break;
- default:
- Q_UNREACHABLE();
+ } else {
+ result += QStringLiteral("%1<%2>()").arg(baseType, elementType);
+ if (!elements.isEmpty()) {
+ result += QStringLiteral(" << ") + elements.join(QStringLiteral(" << "));
}
- clazz.init.impl << QStringLiteral("stateMachine.setDataBinding(QScxmlStateMachine::%1Binding);").arg(binding);
- clazz.implIncludes << QStringLiteral("qscxmlexecutablecontent.h");
- clazz.init.impl << QStringLiteral("stateMachine.setTableData(this);");
-
- foreach (AbstractState *s, node->initialStates) {
- clazz.init.impl << QStringLiteral("%1.setAsInitialStateFor(&stateMachine);")
- .arg(mangledName(s, StateName));
- }
-
- // visit the kids:
- m_parents.append(node);
- visit(node->children);
- visit(node->dataElements);
-
- m_dataElements.append(node->dataElements);
- if (node->script || !m_dataElements.isEmpty() || !node->initialSetup.isEmpty()) {
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::ContainerId initialSetup() const Q_DECL_OVERRIDE Q_DECL_FINAL")
- << QStringLiteral("{ return %1; }").arg(startNewSequence())
- << QString();
- generate(m_dataElements);
- if (node->script) {
- node->script->accept(this);
- }
- visit(&node->initialSetup);
- endSequence();
- } else {
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::ContainerId initialSetup() const Q_DECL_OVERRIDE Q_DECL_FINAL")
- << QStringLiteral("{ return QScxmlExecutableContent::NoInstruction; }")
- << QString();
- }
-
- m_parents.removeLast();
-
- { // the data model:
- switch (node->dataModel) {
- case Scxml::NullDataModel:
- clazz.classFields << QStringLiteral("QScxmlNullDataModel dataModel;");
- clazz.implIncludes << QStringLiteral("QScxmlNullDataModel");
- clazz.init.impl << QStringLiteral("stateMachine.setDataModel(&dataModel);");
- break;
- case Scxml::JSDataModel:
- clazz.classFields << QStringLiteral("QScxmlEcmaScriptDataModel dataModel;");
- clazz.implIncludes << QStringLiteral("QScxmlEcmaScriptDataModel");
- clazz.init.impl << QStringLiteral("stateMachine.setDataModel(&dataModel);");
- break;
- case Scxml::CppDataModel:
- clazz.dataModelClassName = node->cppDataModelClassName;
- clazz.implIncludes << node->cppDataModelHeaderName;
- break;
- default:
- Q_UNREACHABLE();
- }
- }
- return false;
}
+ return result;
+}
- bool visit(State *node) Q_DECL_OVERRIDE
- {
- QString name = mangledName(node, PlainName);
- QString stateName = mangledName(node, StateName);
- // Property stuff:
- if (isValidQPropertyName(node->id)) {
- clazz.properties << QStringLiteral("Q_PROPERTY(bool %1 READ %2 NOTIFY %3)")
- .arg(node->id).arg(name)
- .arg(mangledName(node, SignalName));
- }
- 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) {
- clazz.classFields << QStringLiteral("QScxmlFinalState ") + stateName + QLatin1Char(';');
- } else {
- clazz.classFields << QStringLiteral("QScxmlState ") + stateName + QLatin1Char(';');
- }
-
- // Initializer:
- clazz.constructor.initializer << generateInitializer(node);
-
- // init:
- if (!node->id.isEmpty()) {
- clazz.init.impl << stateName + QStringLiteral(".setObjectName(string(%1));").arg(addString(node->id));
- }
- if (node->type == State::Parallel) {
- clazz.init.impl << stateName + QStringLiteral(".setChildMode(QState::ParallelStates);");
- } else {
- foreach (AbstractState *initialState, node->initialStates) {
- clazz.init.impl << stateName + QStringLiteral(".setInitialState(&")
- + mangledName(initialState, StateName)
- + QStringLiteral(");");
- }
-
- }
- if (!node->id.isEmpty()) {
- clazz.init.impl << QStringLiteral("QObject::connect(&")
- + stateName
- + QStringLiteral(", SIGNAL(activeChanged(bool)), &stateMachine, SIGNAL(")
- + mangledName(node, SignalName)
- + QStringLiteral("(bool)));");
- }
-
- m_stateNames.append(node->id);
- m_stateFieldNames.append(stateName);
-
- // visit the kids:
- m_parents.append(node);
- if (!node->dataElements.isEmpty()) {
- if (m_bindLate) {
- clazz.init.impl << stateName + QStringLiteral(".setInitInstructions(%1);").arg(startNewSequence());
- generate(node->dataElements);
- endSequence();
- } else {
- m_dataElements.append(node->dataElements);
- }
- }
-
- visit(node->children);
- if (!node->onEntry.isEmpty())
- clazz.init.impl << stateName + QStringLiteral(".setOnEntryInstructions(%1);").arg(generate(node->onEntry));
- if (!node->onExit.isEmpty())
- clazz.init.impl << stateName + QStringLiteral(".setOnExitInstructions(%1);").arg(generate(node->onExit));
- if (!node->invokes.isEmpty()) {
- QStringList lines;
- for (int i = 0, ei = node->invokes.size(); i != ei; ++i) {
- Invoke *invoke = node->invokes.at(i);
- QString line = QStringLiteral("new QScxmlInvokeScxmlFactory<%1>(").arg(scxmlClassName(invoke->content.data()));
- line += QStringLiteral("%1, ").arg(Builder::createContext(QStringLiteral("invoke")));
- line += QStringLiteral("%1, ").arg(createEvaluatorString(QStringLiteral("invoke"),
- QStringLiteral("srcexpr"),
- invoke->srcexpr));
- line += QStringLiteral("%1, ").arg(addString(invoke->id));
- line += QStringLiteral("%1, ").arg(addString(node->id + QStringLiteral(".session-")));
- line += QStringLiteral("%1, ").arg(addString(invoke->idLocation));
- {
- QStringList l;
- foreach (const QString &name, invoke->namelist) {
- l.append(QString::number(addString(name)));
- }
- line += QStringLiteral("%1, ").arg(createVector(QStringLiteral("QScxmlExecutableContent::StringId"), l));
- }
- line += QStringLiteral("%1, ").arg(invoke->autoforward ? QStringLiteral("true") : QStringLiteral("false"));
- {
- QStringList l;
- foreach (DocumentModel::Param *param, invoke->params) {
- l += QStringLiteral("QScxmlInvokableServiceFactory::Param(%1, %2, %3)")
- .arg(addString(param->name))
- .arg(createEvaluatorVariant(QStringLiteral("param"), QStringLiteral("expr"), param->expr))
- .arg(addString(param->location));
- }
- line += QStringLiteral("%1, ").arg(createVector(QStringLiteral("QScxmlInvokableServiceFactory::Param"), l));
- }
- if (invoke->finalize.isEmpty()) {
- line += QStringLiteral("QScxmlExecutableContent::NoInstruction");
- } else {
- line += QString::number(startNewSequence());
- visit(&invoke->finalize);
- endSequence();
- }
- line += QLatin1Char(')');
- lines << line;
- }
- clazz.init.impl << stateName + QStringLiteral(".setInvokableServiceFactories(");
- clazz.init.impl << QStringLiteral(" ") + createVector(QStringLiteral("QScxmlInvokableServiceFactory *"), lines);
- clazz.init.impl << QStringLiteral(");");
- }
-
- if (node->type == State::Final) {
- auto id = generate(node->doneData);
- clazz.init.impl << stateName + QStringLiteral(".setDoneData(%1);").arg(id);
- }
-
- m_parents.removeLast();
- return false;
- }
-
- bool visit(Transition *node) Q_DECL_OVERRIDE
- {
- const QString tName = transitionName(node);
- if (m_qtMode) {
- foreach (const QString &event, node->events) {
- if (!DocumentModel::isEventToBeGenerated(event))
- continue;
-
- // If the event name is not filtered out, is was already validated inside:
- // bool ScxmlVerifier::visit(DocumentModel::Transition *transition)
- // by a call to: validateEventName();
- m_knownEvents.insert(event);
- }
- }
-
- // Declaration:
- clazz.classFields << QStringLiteral("QScxmlTransition ") + tName + QLatin1Char(';');
-
- // Initializer:
- QString initializer = tName + QStringLiteral("(");
- QStringList elements;
- foreach (const QString &event, node->events)
- elements.append(qba(event));
- initializer += createList(QStringLiteral("QString"), elements);
- initializer += QStringLiteral(")");
- clazz.constructor.initializer << initializer;
-
- // init:
- if (node->condition) {
- QString condExpr = *node->condition.data();
- auto cond = createEvaluatorBool(QStringLiteral("transition"), QStringLiteral("cond"), condExpr);
- clazz.init.impl << tName + QStringLiteral(".setConditionalExpression(%1);").arg(cond);
- }
-
- if (m_parents.last()->asHistoryState()) {
- clazz.init.impl << QStringLiteral("%1.setDefaultTransition(&%2);").arg(parentStateMemberName(), tName);
- } else {
- clazz.init.impl << QStringLiteral("%1.addTransitionTo(&%2);").arg(tName, parentStateMemberName());
- }
-
- if (node->type == Transition::Internal) {
- clazz.init.impl << tName + QStringLiteral(".setTransitionType(QAbstractTransition::InternalTransition);");
- }
- QStringList targetNames;
- foreach (DocumentModel::AbstractState *s, node->targetStates)
- targetNames.append(QStringLiteral("&") + mangledName(s, StateName));
- QString targets = tName + QStringLiteral(".setTargetStates(") + createList(QStringLiteral("QAbstractState*"), targetNames);
- clazz.init.impl << targets + QStringLiteral(");");
-
- // visit the kids:
- if (!node->instructionsOnTransition.isEmpty()) {
- m_parents.append(node);
- m_currentTransitionName = tName;
- clazz.init.impl << tName + QStringLiteral(".setInstructionsOnTransition(%1);").arg(startNewSequence());
- visit(&node->instructionsOnTransition);
- endSequence();
- m_parents.removeLast();
- m_currentTransitionName.clear();
- }
- return false;
- }
-
- bool visit(DocumentModel::HistoryState *node) Q_DECL_OVERRIDE
- {
- // Includes:
- clazz.implIncludes << "QScxmlHistoryState";
-
- const QString stateName = mangledName(node, StateName);
- // Declaration:
- clazz.classFields << QStringLiteral("QScxmlHistoryState ") + stateName + QLatin1Char(';');
-
- // Initializer:
- clazz.constructor.initializer << generateInitializer(node);
+QString createVector(const QString &elementType, const QStringList &elements, bool useCxx11)
+{ return createContainer(QStringLiteral("QVector"), elementType, elements, useCxx11); }
- // init:
- if (!node->id.isEmpty()) {
- clazz.init.impl << stateName + QStringLiteral(".setObjectName(string(%1));").arg(addString(node->id));
- }
- QString depth;
- switch (node->type) {
- case DocumentModel::HistoryState::Shallow:
- depth = QStringLiteral("Shallow");
- break;
- case DocumentModel::HistoryState::Deep:
- depth = QStringLiteral("Deep");
+static void generateList(QString &out, std::function<QString(int)> next)
+{
+ const int maxLineLength = 80;
+ QString line;
+ for (int i = 0; ; ++i) {
+ const QString nr = next(i);
+ if (nr.isNull())
break;
- default:
- Q_UNREACHABLE();
- }
- clazz.init.impl << stateName + QStringLiteral(".setHistoryType(QScxmlHistoryState::") + depth + QStringLiteral("History);");
-
- // visit the kid:
- if (Transition *t = node->defaultConfiguration()) {
-
- m_parents.append(node);
- t->accept(this);
- m_parents.removeLast();
- }
- return false;
- }
-
- bool visit(Send *node) Q_DECL_OVERRIDE
- {
- 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);
- }
- }
- return QScxmlExecutableContent::Builder::visit(node);
- }
-
-private:
- enum NameForm {
- PlainName,
- SignalName,
- MachineName,
- StateName
- };
+ if (i != 0)
+ line += QLatin1Char(',');
- QString mangledName(const QString &id, NameForm form) const
- {
- QString name = id;
- switch (form) {
- case PlainName: break;
- case SignalName: name.append(QStringLiteral("Changed")); break;
- case StateName: name.prepend(QStringLiteral("state_")); break;
- case MachineName: name.prepend(QStringLiteral("machine_")); break;
+ if (line.length() + nr.length() + 1 > maxLineLength) {
+ out += line + QLatin1Char('\n');
+ line.clear();
+ } else if (i != 0) {
+ line += QLatin1Char(' ');
}
-
- return name.isEmpty() ? name : mangleIdentifier(name);
- }
-
- QString mangledName(AbstractState *state, NameForm form) const
- {
- Q_ASSERT(state);
-
- QString name = m_mangledNames.value(state)[form];
- if (!name.isEmpty())
- return name;
-
- QString id = state->id;
- if (State *s = state->asState()) {
- if (s->type == State::Initial) {
- id = s->parent->asState()->id + QStringLiteral("_initial");
- }
- }
-
- name = mangledName(id, form);
- m_mangledNames[state][form] = name;
- return name;
- }
-
- QString transitionName(Transition *t) const
- {
- int idx = 0;
- QString parentName;
- auto parent = m_parents.last();
- if (State *parentState = parent->asState()) {
- parentName = mangledName(parentState, PlainName);
- idx = childIndex(t, parentState->children);
- } else if (HistoryState *historyState = parent->asHistoryState()) {
- parentName = mangledName(historyState, PlainName);
- } else if (Scxml *scxml = parent->asScxml()) {
- parentName = QStringLiteral("stateMachine");
- idx = childIndex(t, scxml->children);
- } else {
- Q_UNREACHABLE();
- }
- return QStringLiteral("transition_%1_%2").arg(parentName, QString::number(idx));
+ line += nr;
}
+ if (!line.isEmpty())
+ out += line;
+}
- static int childIndex(StateOrTransition *child, const QVector<StateOrTransition *> &children) {
- int idx = 0;
- foreach (StateOrTransition *sot, children) {
- if (sot == child)
- break;
+void generateTables(const GeneratedTableData &td, const QStringList &outgoingEvents,
+ Replacements &replacements, bool useCxx11)
+{
+ { // instructions
+ auto instr = td.theInstructions;
+ QString out;
+ generateList(out, [&instr](int idx) -> QString {
+ if (instr.isEmpty() && idx == 0) // prevent generation of empty array
+ return QStringLiteral("-1");
+ if (idx < instr.size())
+ return QString::number(instr.at(idx));
else
- ++idx;
- }
- return idx;
- }
-
- QString createList(const QString &elementType, const QStringList &elements) const
- { return createContainer(QStringLiteral("QList"), elementType, elements); }
-
- QString createVector(const QString &elementType, const QStringList &elements) const
- { return createContainer(QStringLiteral("QVector"), elementType, elements); }
-
- QString createContainer(const QString &baseType, const QString &elementType, const QStringList &elements) const
- {
- QString result;
- if (translationUnit->useCxx11) {
- if (elements.isEmpty()) {
- result += QStringLiteral("{}");
- } else {
- result += QStringLiteral("{ ") + elements.join(QStringLiteral(", ")) + QStringLiteral(" }");
- }
- } else {
- result += QStringLiteral("%1<%2>()").arg(baseType, elementType);
- if (!elements.isEmpty()) {
- result += QStringLiteral(" << ") + elements.join(QStringLiteral(" << "));
- }
- }
- return result;
- }
-
- QString generateInitializer(AbstractState *node) const
- {
- QString init = mangledName(node, StateName) + QStringLiteral("(");
- if (State *parentState = node->parent->asState()) {
- init += QStringLiteral("&") + mangledName(parentState, StateName);
- } else {
- init += QStringLiteral("&stateMachine");
- }
- init += QLatin1Char(')');
- return init;
- }
-
- void addSubStateMachineProperties(ScxmlDocument *doc)
- {
- foreach (ScxmlDocument *subDocs, doc->allSubDocuments) {
- QString name = subDocs->root->name;
- if (name.isEmpty())
- continue;
- auto plainName = mangledName(name, PlainName);
- auto qualifiedName = namespacePrefix + plainName;
- if (m_serviceProps.contains(qMakePair(plainName, qualifiedName)))
- continue;
- m_serviceProps.append(qMakePair(name, qualifiedName));
- clazz.classFields << QStringLiteral("%1 *%2;").arg(qualifiedName, plainName);
- clazz.constructor.initializer << QStringLiteral("%1(Q_NULLPTR)").arg(plainName);
- if (isValidQPropertyName(name)) {
- clazz.properties << QStringLiteral("Q_PROPERTY(%1%2 *%3 READ %2 NOTIFY %4)")
- .arg(namespacePrefix, plainName, name,
- mangledName(name, SignalName));
- }
- if (m_qtMode) {
- Method getter(QStringLiteral("%1 *%2() const").arg(qualifiedName, plainName));
- getter.impl << QStringLiteral("%1 *%2::%3() const").arg(qualifiedName,
- clazz.className, plainName)
- << QStringLiteral("{ return data->%1; }").arg(plainName);
- clazz.publicMethods << getter;
- clazz.signalMethods << QStringLiteral("void %1(%2 *statemachine);")
- .arg(mangledName(name, SignalName), qualifiedName);
+ return QString();
+ });
+ replacements[QStringLiteral("theInstructions")] = out;
+ }
+
+ { // dataIds
+ auto dataIds = td.theDataNameIds;
+ QString out;
+ generateList(out, [&dataIds](int idx) -> QString {
+ if (dataIds.size() == 0 && idx == 0) // prevent generation of empty array
+ return QStringLiteral("-1");
+ if (idx < dataIds.size())
+ return QString::number(dataIds[idx]);
+ else
+ return QString();
+ });
+ replacements[QStringLiteral("dataNameCount")] = QString::number(dataIds.size());
+ replacements[QStringLiteral("dataIds")] = out;
+ }
+
+ { // evaluators
+ auto evaluators = td.theEvaluators;
+ QString out;
+ generateList(out, [&evaluators](int idx) -> QString {
+ if (evaluators.isEmpty() && idx == 0) // prevent generation of empty array
+ return QStringLiteral("{ -1, -1 }");
+ if (idx >= evaluators.size())
+ return QString();
+
+ const auto eval = evaluators.at(idx);
+ return QStringLiteral("{ %1, %2 }").arg(eval.expr).arg(eval.context);
+ });
+ replacements[QStringLiteral("evaluatorCount")] = QString::number(evaluators.size());
+ replacements[QStringLiteral("evaluators")] = out;
+ }
+
+ { // assignments
+ auto assignments = td.theAssignments;
+ QString out;
+ generateList(out, [&assignments](int idx) -> QString {
+ if (assignments.isEmpty() && idx == 0) // prevent generation of empty array
+ return QStringLiteral("{ -1, -1, -1 }");
+ if (idx >= assignments.size())
+ return QString();
+
+ auto assignment = assignments.at(idx);
+ return QStringLiteral("{ %1, %2, %3 }")
+ .arg(assignment.dest).arg(assignment.expr).arg(assignment.context);
+ });
+ replacements[QStringLiteral("assignmentCount")] = QString::number(assignments.size());
+ replacements[QStringLiteral("assignments")] = out;
+ }
+
+ { // foreaches
+ auto foreaches = td.theForeaches;
+ QString out;
+ generateList(out, [&foreaches](int idx) -> QString {
+ if (foreaches.isEmpty() && idx == 0) // prevent generation of empty array
+ return QStringLiteral("{ -1, -1, -1, -1 }");
+ if (idx >= foreaches.size())
+ return QString();
+
+ auto foreachItem = foreaches.at(idx);
+ return QStringLiteral("{ %1, %2, %3, %4 }").arg(foreachItem.array).arg(foreachItem.item)
+ .arg(foreachItem.index).arg(foreachItem.context);
+ });
+ replacements[QStringLiteral("foreachCount")] = QString::number(foreaches.size());
+ replacements[QStringLiteral("foreaches")] = out;
+ }
+
+ { // strings
+ QString out;
+ auto strings = td.theStrings;
+ if (strings.isEmpty()) // prevent generation of empty array
+ strings.append(QStringLiteral(""));
+ int ucharCount = 0;
+ generateList(out, [&ucharCount, &strings](int idx) -> QString {
+ if (idx >= strings.size())
+ return QString();
+
+ const int length = strings.at(idx).size();
+ const QString str = QStringLiteral("STR_LIT(%1, %2, %3)").arg(
+ QString::number(idx), QString::number(ucharCount), QString::number(length));
+ ucharCount += length + 1;
+ return str;
+ });
+ replacements[QStringLiteral("stringCount")] = QString::number(strings.size());
+ replacements[QStringLiteral("strLits")] = out;
+
+ out.clear();
+ for (int i = 0, ei = strings.size(); i < ei; ++i) {
+ const QString &string = strings.at(i);
+ QString result;
+ if (i != 0)
+ result += QLatin1Char('\n');
+ for (int charPos = 0, eCharPos = string.size(); charPos < eCharPos; ++charPos) {
+ result.append(QStringLiteral("0x%1,")
+ .arg(QString::number(string.at(charPos).unicode(), 16)));
}
-
- clazz.dataMethods << QStringLiteral("%1 *%2() const")
- .arg(qualifiedName, mangledName(name, MachineName))
- << QStringLiteral("{ return %1; }").arg(plainName)
- << QString();
+ result.append(QStringLiteral("0%1 // %2: %3")
+ .arg(QLatin1String(i < ei - 1 ? "," : ""), QString::number(i),
+ cEscape(string)));
+ out += result;
}
+ replacements[QStringLiteral("uniLits")] = out;
+ replacements[QStringLiteral("stringdataSize")] = QString::number(ucharCount + 1);
}
- void addEvents()
{
- QStringList knownEventsList = m_knownEvents.toList();
- std::sort(knownEventsList.begin(), knownEventsList.end());
- if (m_qtMode) {
- foreach (const QString &event, knownEventsList) {
- clazz.publicSlotDeclarations << QStringLiteral("void ") + event + QStringLiteral("(const QVariant &eventData = QVariant());");
- clazz.publicSlotDefinitions << QStringLiteral("void ") + clazz.className
- + QStringLiteral("::")
- + event
- + QStringLiteral("(const QVariant &eventData)\n{ submitEvent(data->") + qba(event)
- + QStringLiteral(", eventData); }");
- }
- }
-
- 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 = 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(signalName), mangleIdentifier(signalName));
- }
- }
- dm << QStringLiteral(" return true;")
- << QStringLiteral("}")
- << QString();
+ QStringList items;
+ foreach (const QString &event, outgoingEvents) {
+ items += QStringLiteral("QString({static_cast<QStringData*>(strings.data + %1)})")
+ .arg(td.theStrings.indexOf(event));
}
+ replacements[QStringLiteral("outgoingEvents")] = createContainer(
+ QStringLiteral("std::vector"), QStringLiteral("QString"), items, useCxx11);
}
+}
- QString createContextString(const QString &instrName) const Q_DECL_OVERRIDE
+void generateCppDataModelEvaluators(const GeneratedTableData::DataModelInfo &info,
+ Replacements &replacements)
+{
{
- if (!m_currentTransitionName.isEmpty()) {
- QString state = parentStateName();
- return QStringLiteral("<%1> instruction in transition of state '%2'").arg(instrName, state);
- } else {
- return QStringLiteral("<%1> instruction in state '%2'").arg(instrName, parentStateName());
+ QString evals;
+ for (auto it = info.stringEvaluators.constBegin(), eit = info.stringEvaluators.constEnd();
+ it != eit; ++it) {
+ evals += QStringLiteral(" case %1:\n").arg(it.key());
+ evals += QStringLiteral(" return [this]()->QString{ return %1; }();\n")
+ .arg(it.value());
}
+ replacements[QStringLiteral("evaluateToStringCases")] = evals;
}
- QString createContext(const QString &instrName, const QString &attrName, const QString &attrValue) const Q_DECL_OVERRIDE
- {
- QString location = createContextString(instrName);
- return QStringLiteral("%1 with %2=\"%3\"").arg(location, attrName, attrValue);
- }
-
- QString parentStateName() const
{
- for (int i = m_parents.size() - 1; i >= 0; --i) {
- Node *node = m_parents.at(i);
- if (State *s = node->asState())
- return s->id;
- else if (HistoryState *h = node->asHistoryState())
- return h->id;
- else if (Scxml *l = node->asScxml())
- return l->name;
+ QString evals;
+ for (auto it = info.boolEvaluators.constBegin(), eit = info.boolEvaluators.constEnd();
+ it != eit; ++it) {
+ evals += QStringLiteral(" case %1:\n").arg(it.key());
+ evals += QStringLiteral(" return [this]()->bool{ return %1; }();\n")
+ .arg(it.value());
}
-
- return QString();
+ replacements[QStringLiteral("evaluateToBoolCases")] = evals;
}
- QString parentStateMemberName() const
{
- Node *parent = m_parents.last();
- if (State *s = parent->asState())
- return mangledName(s, StateName);
- else if (HistoryState *h = parent->asHistoryState())
- return mangledName(h, StateName);
- else if (parent->asScxml())
- return QStringLiteral("stateMachine");
- else
- Q_UNIMPLEMENTED();
- return QString();
- }
-
- static void generateList(StringListDumper &t, std::function<QString(int)> next)
- {
- const int maxLineLength = 80;
- QString line;
- for (int i = 0; ; ++i) {
- QString nr = next(i);
- if (nr.isNull())
- break;
-
- if (i != 0)
- line += QLatin1Char(',');
-
- if (line.length() + nr.length() + 1 > maxLineLength) {
- t << line;
- line.clear();
- } else if (i != 0) {
- line += QLatin1Char(' ');
- }
- line += nr;
+ QString evals;
+ for (auto it = info.variantEvaluators.constBegin(), eit = info.variantEvaluators.constEnd();
+ it != eit; ++it) {
+ evals += QStringLiteral(" case %1:\n").arg(it.key());
+ evals += QStringLiteral(" return [this]()->QVariant{ return %1; }();\n")
+ .arg(it.value());
}
- if (!line.isEmpty())
- t << line;
+ replacements[QStringLiteral("evaluateToVariantCases")] = evals;
}
- void generateTables()
{
- StringListDumper &t = clazz.tables;
- clazz.classFields << QString();
- QScopedPointer<QScxmlExecutableContent::DynamicTableData> td(tableData());
-
- { // instructions
- clazz.classFields << QStringLiteral("static qint32 theInstructions[];");
- t << QStringLiteral("qint32 %1::Data::theInstructions[] = {").arg(clazz.className);
- auto instr = td->instructionTable();
- generateList(t, [&instr](int idx) -> QString {
- if (instr.isEmpty() && idx == 0) // prevent generation of empty array
- return QStringLiteral("-1");
- if (idx < instr.size())
- return QString::number(instr.at(idx));
- else
- return QString();
- });
- t << QStringLiteral("};") << QStringLiteral("");
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::Instructions instructions() const Q_DECL_OVERRIDE Q_DECL_FINAL")
- << QStringLiteral("{ return theInstructions; }")
- << QString();
- }
-
- { // dataIds
- int count;
- auto dataIds = td->dataNames(&count);
- clazz.classFields << QStringLiteral("static QScxmlExecutableContent::StringId dataIds[];");
- t << QStringLiteral("QScxmlExecutableContent::StringId %1::Data::dataIds[] = {").arg(clazz.className);
- if (isCppDataModel()) {
- t << QStringLiteral("-1");
- } else {
- generateList(t, [&dataIds, count](int idx) -> QString {
- if (count == 0 && idx == 0) // prevent generation of empty array
- return QStringLiteral("-1");
- if (idx < count)
- return QString::number(dataIds[idx]);
- else
- return QString();
- });
- }
- t << QStringLiteral("};") << QStringLiteral("");
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::StringId *dataNames(int *count) const Q_DECL_OVERRIDE Q_DECL_FINAL");
- clazz.dataMethods << QStringLiteral("{ *count = %1; return dataIds; }").arg(count);
- clazz.dataMethods << QString();
- }
-
- { // evaluators
- auto evaluators = td->evaluators();
- clazz.classFields << QStringLiteral("static QScxmlExecutableContent::EvaluatorInfo evaluators[];");
- t << QStringLiteral("QScxmlExecutableContent::EvaluatorInfo %1::Data::evaluators[] = {").arg(clazz.className);
- if (isCppDataModel()) {
- t << QStringLiteral("{ -1, -1 }");
- } else {
- generateList(t, [&evaluators](int idx) -> QString {
- if (evaluators.isEmpty() && idx == 0) // prevent generation of empty array
- return QStringLiteral("{ -1, -1 }");
- if (idx >= evaluators.size())
- return QString();
-
- auto eval = evaluators.at(idx);
- return QStringLiteral("{ %1, %2 }").arg(eval.expr).arg(eval.context);
- });
- }
- t << QStringLiteral("};") << QStringLiteral("");
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::EvaluatorInfo evaluatorInfo(QScxmlExecutableContent::EvaluatorId evaluatorId) const Q_DECL_OVERRIDE Q_DECL_FINAL");
- clazz.dataMethods << QStringLiteral("{ Q_ASSERT(evaluatorId >= 0); Q_ASSERT(evaluatorId < %1); return evaluators[evaluatorId]; }").arg(evaluators.size());
- clazz.dataMethods << QString();
-
- if (isCppDataModel()) {
- {
- StringListDumper stringEvals;
- stringEvals << QStringLiteral("QString %1::evaluateToString(QScxmlExecutableContent::EvaluatorId id, bool *ok) {").arg(clazz.dataModelClassName)
- << QStringLiteral(" *ok = true;")
- << QStringLiteral(" switch (id) {");
- auto evals = stringEvaluators();
- for (auto it = evals.constBegin(), eit = evals.constEnd(); it != eit; ++it) {
- stringEvals << QStringLiteral(" case %1:").arg(it.key())
- << QStringLiteral(" return [this]()->QString{ return %1; }();").arg(it.value());
- }
- stringEvals << QStringLiteral(" default:")
- << QStringLiteral(" Q_UNREACHABLE();")
- << QStringLiteral(" *ok = false;")
- << QStringLiteral(" return QString();")
- << QStringLiteral(" }");
- stringEvals << QStringLiteral("}");
- clazz.dataModelMethods.append(Method(stringEvals));
- }
-
- {
- StringListDumper boolEvals;
- boolEvals << QStringLiteral("bool %1::evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok) {").arg(clazz.dataModelClassName)
- << QStringLiteral(" *ok = true;")
- << QStringLiteral(" switch (id) {");
- auto evals = boolEvaluators();
- for (auto it = evals.constBegin(), eit = evals.constEnd(); it != eit; ++it) {
- boolEvals << QStringLiteral(" case %1:").arg(it.key())
- << QStringLiteral(" return [this]()->bool{ return %1; }();").arg(it.value());
- }
- boolEvals << QStringLiteral(" default:")
- << QStringLiteral(" Q_UNREACHABLE();")
- << QStringLiteral(" *ok = false;")
- << QStringLiteral(" return false;")
- << QStringLiteral(" }");
- boolEvals << QStringLiteral("}");
- clazz.dataModelMethods.append(Method(boolEvals));
- }
-
- {
- StringListDumper variantEvals;
- variantEvals << QStringLiteral("QVariant %1::evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok) {").arg(clazz.dataModelClassName)
- << QStringLiteral(" *ok = true;")
- << QStringLiteral(" switch (id) {");
- auto evals = variantEvaluators();
- for (auto it = evals.constBegin(), eit = evals.constEnd(); it != eit; ++it) {
- variantEvals << QStringLiteral(" case %1:").arg(it.key())
- << QStringLiteral(" return [this]()->QVariant{ return %1; }();").arg(it.value());
- }
- variantEvals << QStringLiteral(" default:")
- << QStringLiteral(" Q_UNREACHABLE();")
- << QStringLiteral(" *ok = false;")
- << QStringLiteral(" return QVariant();")
- << QStringLiteral(" }");
- variantEvals << QStringLiteral("}");
- clazz.dataModelMethods.append(Method(variantEvals));
- }
-
- {
- StringListDumper voidEvals;
- voidEvals << QStringLiteral("void %1::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok) {").arg(clazz.dataModelClassName)
- << QStringLiteral(" *ok = true;")
- << QStringLiteral(" switch (id) {");
- auto evals = voidEvaluators();
- for (auto it = evals.constBegin(), eit = evals.constEnd(); it != eit; ++it) {
- voidEvals << QStringLiteral(" case %1:").arg(it.key())
- << QStringLiteral(" [this]()->void{ %1 }();").arg(it.value())
- << QStringLiteral(" break;");
- }
- voidEvals << QStringLiteral(" default:")
- << QStringLiteral(" Q_UNREACHABLE();")
- << QStringLiteral(" *ok = false;")
- << QStringLiteral(" }");
- voidEvals << QStringLiteral("}");
- clazz.dataModelMethods.append(Method(voidEvals));
- }
- }
- }
-
- { // assignments
- auto assignments = td->assignments();
- clazz.classFields << QStringLiteral("static QScxmlExecutableContent::AssignmentInfo assignments[];");
- t << QStringLiteral("QScxmlExecutableContent::AssignmentInfo %1::Data::assignments[] = {").arg(clazz.className);
- if (isCppDataModel()) {
- t << QStringLiteral("{ -1, -1, -1 }");
- } else {
- generateList(t, [&assignments](int idx) -> QString {
- if (assignments.isEmpty() && idx == 0) // prevent generation of empty array
- return QStringLiteral("{ -1, -1, -1 }");
- if (idx >= assignments.size())
- return QString();
-
- auto ass = assignments.at(idx);
- return QStringLiteral("{ %1, %2, %3 }").arg(ass.dest).arg(ass.expr).arg(ass.context);
- });
- }
- t << QStringLiteral("};") << QStringLiteral("");
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::AssignmentInfo assignmentInfo(QScxmlExecutableContent::EvaluatorId assignmentId) const Q_DECL_OVERRIDE Q_DECL_FINAL");
- clazz.dataMethods << QStringLiteral("{ Q_ASSERT(assignmentId >= 0); Q_ASSERT(assignmentId < %1); return assignments[assignmentId]; }").arg(assignments.size());
- clazz.dataMethods << QString();
- }
-
- { // foreaches
- auto foreaches = td->foreaches();
- clazz.classFields << QStringLiteral("static QScxmlExecutableContent::ForeachInfo foreaches[];");
- t << QStringLiteral("QScxmlExecutableContent::ForeachInfo %1::Data::foreaches[] = {").arg(clazz.className);
- generateList(t, [&foreaches](int idx) -> QString {
- if (foreaches.isEmpty() && idx == 0) // prevent generation of empty array
- return QStringLiteral("{ -1, -1, -1, -1 }");
- if (idx >= foreaches.size())
- return QString();
-
- auto foreach = foreaches.at(idx);
- return QStringLiteral("{ %1, %2, %3, %4 }").arg(foreach.array).arg(foreach.item).arg(foreach.index).arg(foreach.context);
- });
- t << QStringLiteral("};") << QStringLiteral("");
- clazz.dataMethods << QStringLiteral("QScxmlExecutableContent::ForeachInfo foreachInfo(QScxmlExecutableContent::EvaluatorId foreachId) const Q_DECL_OVERRIDE Q_DECL_FINAL");
- clazz.dataMethods << QStringLiteral("{ Q_ASSERT(foreachId >= 0); Q_ASSERT(foreachId < %1); return foreaches[foreachId]; }").arg(foreaches.size());
- }
-
- { // strings
- t << QStringLiteral("#define STR_LIT(idx, ofs, len) \\")
- << QStringLiteral(" Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \\")
- << QStringLiteral(" qptrdiff(offsetof(Strings, stringdata) + ofs * sizeof(qunicodechar) - idx * sizeof(QArrayData)) \\")
- << QStringLiteral(" )");
-
- t << QStringLiteral("%1::Data::Strings %1::Data::strings = {{").arg(clazz.className);
- auto strings = td->stringTable();
- if (strings.isEmpty()) // prevent generation of empty array
- strings.append(QStringLiteral(""));
- int ucharCount = 0;
- generateList(t, [&ucharCount, &strings](int idx) -> QString {
- if (idx >= strings.size())
- return QString();
-
- int length = strings.at(idx).size();
- QString str = QStringLiteral("STR_LIT(%1, %2, %3)").arg(QString::number(idx),
- QString::number(ucharCount),
- QString::number(length));
- ucharCount += length + 1;
- return str;
- });
- t << QStringLiteral("},{");
- for (int i = 0, ei = strings.size(); i < ei; ++i) {
- const QString &string = strings.at(i);
- QString result;
- for (int charPos = 0, eCharPos = string.size(); charPos < eCharPos; ++charPos) {
- result.append(QStringLiteral("0x%1,")
- .arg(QString::number(string.at(charPos).unicode(), 16)));
- }
- result.append(QStringLiteral("0%1 // %2: %3")
- .arg(QLatin1String(i < ei - 1 ? "," : ""), QString::number(i),
- cEscape(string)));
- t << result;
- }
- t << QStringLiteral("}};") << QStringLiteral("");
-
- clazz.classFields << QStringLiteral("static struct Strings {")
- << QStringLiteral(" QArrayData data[%1];").arg(strings.size())
- << QStringLiteral(" qunicodechar stringdata[%1];").arg(ucharCount + 1)
- << QStringLiteral("} strings;");
-
- clazz.dataMethods << QStringLiteral("QString string(QScxmlExecutableContent::StringId id) const Q_DECL_OVERRIDE Q_DECL_FINAL");
- clazz.dataMethods << QStringLiteral("{");
- clazz.dataMethods << QStringLiteral(" Q_ASSERT(id >= QScxmlExecutableContent::NoString); Q_ASSERT(id < %1);").arg(strings.size());
- clazz.dataMethods << QStringLiteral(" if (id == QScxmlExecutableContent::NoString) return QString();");
- if (translationUnit->useCxx11) {
- clazz.dataMethods << QStringLiteral(" return QString({static_cast<QStringData*>(strings.data + id)});");
- } else {
- clazz.dataMethods << QStringLiteral(" QStringDataPtr data;");
- clazz.dataMethods << QStringLiteral(" data.ptr = static_cast<QStringData*>(strings.data + id);");
- clazz.dataMethods << QStringLiteral(" return QString(data);");
- }
- clazz.dataMethods << QStringLiteral("}");
- clazz.dataMethods << QString();
+ QString evals;
+ for (auto it = info.voidEvaluators.constBegin(), eit = info.voidEvaluators.constEnd();
+ it != eit; ++it) {
+ evals += QStringLiteral(" case %1:\n").arg(it.key());
+ evals += QStringLiteral(" [this]()->void{ %1 }();\n").arg(it.value());
+ evals += QStringLiteral(" break;\n");
}
+ replacements[QStringLiteral("evaluateToVoidCases")] = evals;
}
+}
- void generateMetaObject()
+int createFactoryId(QStringList &factories, const QString &className,
+ const QString &namespacePrefix,
+ QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
+ QScxmlExecutableContent::StringId id,
+ QScxmlExecutableContent::StringId idPrefix,
+ QScxmlExecutableContent::StringId idlocation,
+ const QVector<QScxmlExecutableContent::StringId> &namelist,
+ bool autoforward,
+ const QVector<QScxmlExecutableContent::Param> &params,
+ QScxmlExecutableContent::ContainerId finalize,
+ bool useCxx11)
+{
+ const int idx = factories.size();
+
+ QString line = QStringLiteral("case %1: return new ").arg(QString::number(idx));
+ if (srcexpr == QScxmlExecutableContent::NoInstruction) {
+ line += QStringLiteral("QScxmlInvokeScxmlFactory<%1::%2>(%3, ")
+ .arg(namespacePrefix, className, QString::number(invokeLocation));
+ } else {
+ line += QStringLiteral("QScxmlDynamicScxmlFactory(%1, %2, ")
+ .arg(invokeLocation).arg(srcexpr);
+ }
+ line += QStringLiteral("%1, ").arg(QString::number(id));
+ line += QStringLiteral("%1, ").arg(QString::number(idPrefix));
+ line += QStringLiteral("%1, ").arg(QString::number(idlocation));
{
- 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;
-
- const QByteArray mangledStateName = mangledName(stateName, StateName).toUtf8();
- const QString mangledSignalName = mangledName(stateName, SignalName);
-
- FunctionDef signal;
- signal.type.name = "void";
- signal.type.rawName = signal.type.name;
- signal.normalizedType = signal.type.name;
- signal.name = mangledSignalName.toUtf8();
- signal.access = FunctionDef::Private;
- signal.isSignal = true;
- if (!m_qtMode) {
- signal.implementation = "QMetaObject::activate(_o, &staticMetaObject, %d, _a);";
- } else {
- clazz.signalMethods << QStringLiteral("void %1(bool active);")
- .arg(mangledSignalName);
- }
- 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->" + mangledStateName + ".active";
- prop.notify = mangledSignalName.toUtf8();
- 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);");
+ QStringList l;
+ foreach (auto name, namelist) {
+ l.append(QString::number(name));
}
- for (const auto &service : m_serviceProps) {
- auto serviceName = service.first;
- const QString mangledServiceName = mangledName(serviceName, PlainName);
- const QString fqServiceClass = service.second;
- const QByteArray serviceClass = fqServiceClass.toUtf8();
- knownQObjectClasses.insert(serviceClass, "");
-
- reg.impl << QStringLiteral(" SET_SERVICE_PROP(%1, %2, %3%2, %4)")
- .arg(addString(serviceName))
- .arg(mangledServiceName, namespacePrefix).arg(classDef.signalList.size());
-
- const QByteArray mangledMachineName = mangledName(serviceName, MachineName).toUtf8();
- const QByteArray mangledSignalName = mangledName(serviceName, SignalName).toUtf8();
-
- FunctionDef signal;
- signal.type.name = "void";
- signal.type.rawName = signal.type.name;
- signal.normalizedType = signal.type.name;
- signal.name = mangledSignalName;
- 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->" + mangledMachineName;
- prop.notify = mangledSignalName;
- 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);
- Generator(&classDef, QList<QByteArray>(), knownQObjectClasses,
- QHash<QByteArray, QByteArray>(), buf).generateCode();
- buf.close();
- }
-
- QString qba(const QString &bytes)
- {
- return QStringLiteral("string(%1)").arg(addString(bytes));
+ line += QStringLiteral("%1, ").arg(
+ createVector(QStringLiteral("QScxmlExecutableContent::StringId"), l, useCxx11));
}
-
- QString scxmlClassName(DocumentModel::ScxmlDocument *doc)
+ line += QStringLiteral("%1, ").arg(autoforward ? QStringLiteral("true")
+ : QStringLiteral("false"));
{
- QString name = mangleIdentifier(translationUnit->classnameForDocument.value(doc));
- Q_ASSERT(!name.isEmpty());
- return namespacePrefix + name;
- }
-
- /*!
- * \internal
- * Mangles \a str to be a unique C++ identifier. Characters that are invalid for C++ identifiers
- * are replaced by the pattern \c _0x<hex>_ where <hex> is the hexadecimal unicode
- * representation of the character. As identifiers with leading underscores followed by either
- * another underscore or a capital letter are reserved in C++, we also escape those, by escaping
- * the first underscore, using the above method.
- *
- * We keep track of all identifiers we have used so far and if we find two different names that
- * map to the same mangled identifier by the above method, we append underscores to the new one
- * until the result is unique.
- *
- * \note
- * Although C++11 allows for non-ascii (unicode) characters to be used in identifiers,
- * many compilers forgot to read the spec and do not implement this. Some also do not
- * implement C99 identifiers, because that is \e {at the implementation's discretion}. So,
- * we are stuck with plain old boring identifiers.
- */
- QString mangleIdentifier(const QString &str) const
- {
- auto isNonDigit = [](QChar c) -> bool {
- return (c >= QLatin1Char('a') && c <= QLatin1Char('z')) ||
- (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) ||
- c == QLatin1Char('_');
- };
-
- Q_ASSERT(!str.isEmpty());
-
- QString mangled;
- mangled.reserve(str.size());
-
- int i = 0;
- if (str.startsWith(QLatin1Char('_')) && str.size() > 1) {
- QChar ch = str.at(1);
- if (ch == QLatin1Char('_')
- || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))) {
- mangled += QLatin1String("_0x5f_");
- ++i;
- }
+ QStringList l;
+ foreach (const auto &param, params) {
+ l += QStringLiteral("QScxmlExecutableContent::Param(%1, %2, %3)")
+ .arg(QString::number(param.name),
+ QString::number(param.expr),
+ QString::number(param.location));
}
-
- for (int ei = str.length(); i != ei; ++i) {
- auto c = str.at(i).unicode();
- if ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) || isNonDigit(c)) {
- mangled += c;
- } else {
- mangled += QLatin1String("_0x") + QString::number(c, 16) + QLatin1Char('_');
- }
- }
-
- while (true) {
- auto it = m_mangledToOriginal.constFind(mangled);
- if (it == m_mangledToOriginal.constEnd()) {
- m_mangledToOriginal.insert(mangled, str);
- break;
- } else if (it.value() == str) {
- break;
- }
- mangled += QStringLiteral("_"); // append underscores until we get a unique name
- }
-
- return mangled;
+ line += QStringLiteral("%1, ").arg(
+ createVector(QStringLiteral("QScxmlExecutableContent::Param"), l,
+ useCxx11));
}
+ line += QStringLiteral("%1);").arg(finalize);
-private:
- QString namespacePrefix;
- ClassDump &clazz;
- TranslationUnit *translationUnit;
- mutable QHash<AbstractState *, QHash<NameForm, QString> > m_mangledNames;
- mutable QHash<QString, QString> m_mangledToOriginal;
- 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;
- QVector<DocumentModel::DataElement *> m_dataElements;
-};
+ factories.append(line);
+ return idx;
+}
} // anonymous namespace
-
void CppDumper::dump(TranslationUnit *unit)
{
Q_ASSERT(unit);
@@ -1316,38 +429,83 @@ void CppDumper::dump(TranslationUnit *unit)
m_translationUnit = unit;
- QStringList classDecls;
- QVector<ClassDump> clazzes;
+ QString namespacePrefix;
+ if (!m_translationUnit->namespaceName.isEmpty()) {
+ namespacePrefix = QStringLiteral("::%1").arg(m_translationUnit->namespaceName);
+ }
+
+ QStringList classNames;
+ QVector<GeneratedTableData> tables;
+ QVector<GeneratedTableData::MetaDataInfo> metaDataInfos;
+ QVector<GeneratedTableData::DataModelInfo> dataModelInfos;
+ QVector<QStringList> factories;
auto docs = m_translationUnit->otherDocuments();
- clazzes.resize(docs.size() + 1);
- DumperVisitor(clazzes[0], m_translationUnit).process(unit->mainDocument);
+ docs.prepend(unit->mainDocument);
+ tables.resize(docs.size());
+ metaDataInfos.resize(tables.size());
+ dataModelInfos.resize(tables.size());
+ factories.resize(tables.size());
+ auto classnameForDocument = unit->classnameForDocument;
+
for (int i = 0, ei = docs.size(); i != ei; ++i) {
auto doc = docs.at(i);
- ClassDump &clazz = clazzes[i + 1];
- DumperVisitor(clazz, m_translationUnit).process(doc);
- classDecls.append(clazz.className);
+ auto metaDataInfo = &metaDataInfos[i];
+ GeneratedTableData::build(doc, &tables[i], metaDataInfo, &dataModelInfos[i],
+ [this, &factories, i, &classnameForDocument, &namespacePrefix](
+ QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
+ QScxmlExecutableContent::StringId id,
+ QScxmlExecutableContent::StringId idPrefix,
+ QScxmlExecutableContent::StringId idlocation,
+ const QVector<QScxmlExecutableContent::StringId> &namelist,
+ bool autoforward,
+ const QVector<QScxmlExecutableContent::Param> &params,
+ QScxmlExecutableContent::ContainerId finalize,
+ const QSharedPointer<DocumentModel::ScxmlDocument> &content) -> int {
+ QString className;
+ if (srcexpr == QScxmlExecutableContent::NoInstruction) {
+ className = mangleIdentifier(classnameForDocument.value(content.data()));
+ }
+ return createFactoryId(factories[i], className, namespacePrefix, invokeLocation,
+ srcexpr, id, idPrefix, idlocation, namelist, autoforward, params,
+ finalize, m_translationUnit->useCxx11);
+ });
+ classNames.append(mangleIdentifier(classnameForDocument.value(doc)));
+ std::sort(metaDataInfo->outgoingEvents.begin(), metaDataInfo->outgoingEvents.end());
}
- QString headerName = QFileInfo(unit->outHFileName).fileName();
+ const QString headerName = QFileInfo(unit->outHFileName).fileName();
const QString headerGuard = headerName.toUpper()
.replace(QLatin1Char('.'), QLatin1Char('_'))
.replace(QLatin1Char('-'), QLatin1Char('_'));
- writeHeaderStart(headerGuard, classDecls);
- writeImplStart(clazzes);
+ QStringList forwardDecls = classNames;
+ forwardDecls.pop_front();
+ writeHeaderStart(headerGuard, forwardDecls);
+ writeImplStart();
+
+ for (int i = 0, ei = tables.size(); i != ei; ++i) {
+ const GeneratedTableData &table = tables.at(i);
+ DocumentModel::ScxmlDocument *doc = docs.at(i);
+ writeClass(classNames.at(i), metaDataInfos.at(i));
+ writeImplBody(table, classNames.at(i), doc, factories.at(i), metaDataInfos.at(i));
- foreach (const ClassDump &clazz, clazzes) {
- writeClass(clazz);
- writeImplBody(clazz);
+ if (doc->root->dataModel == DocumentModel::Scxml::CppDataModel) {
+ Replacements r;
+ r[QStringLiteral("datamodel")] = doc->root->cppDataModelClassName;
+ generateCppDataModelEvaluators(dataModelInfos.at(i), r);
+ genTemplate(cpp, QStringLiteral(":/cppdatamodel.t"), r);
+ }
}
- classDecls.append(clazzes.at(0).className);
- writeHeaderEnd(headerGuard, classDecls);
+ writeHeaderEnd(headerGuard, classNames);
writeImplEnd();
}
void CppDumper::writeHeaderStart(const QString &headerGuard, const QStringList &forwardDecls)
{
- h << doNotEditComment.arg(m_translationUnit->scxmlFileName, QString::number(Q_QSCXMLC_OUTPUT_REVISION), QString::fromLatin1(QT_VERSION_STR))
+ h << doNotEditComment.arg(m_translationUnit->scxmlFileName,
+ QString::number(Q_QSCXMLC_OUTPUT_REVISION),
+ QString::fromLatin1(QT_VERSION_STR))
<< endl;
h << QStringLiteral("#ifndef ") << headerGuard << endl
@@ -1358,59 +516,22 @@ void CppDumper::writeHeaderStart(const QString &headerGuard, const QStringList &
h << l("namespace ") << m_translationUnit->namespaceName << l(" {") << endl << endl;
if (!forwardDecls.isEmpty()) {
- foreach (const QString &name, forwardDecls) {
- h << QStringLiteral("class %1;").arg(name) << endl;
+ for (int i = 1, ei = forwardDecls.size(); i != ei; ++i) {
+ h << QStringLiteral("class %1;").arg(forwardDecls.at(i)) << endl;
}
h << endl;
}
}
-void CppDumper::writeClass(const ClassDump &clazz)
+void CppDumper::writeClass(const QString &className, const GeneratedTableData::MetaDataInfo &info)
{
- h << l("class ") << clazz.className << QStringLiteral(": public QScxmlStateMachine\n{") << endl;
- h << QStringLiteral("public:") << endl
- << QStringLiteral(" /* qmake ignore Q_OBJECT */") << endl
- << QStringLiteral(" Q_OBJECT") << endl;
- clazz.properties.write(h, QStringLiteral(" "), QStringLiteral("\n"));
-
- h << endl
- << QStringLiteral("public:") << endl;
- h << l(" ") << clazz.className << l("(QObject *parent = 0);") << endl;
- h << l(" ~") << clazz.className << "();" << endl;
-
- if (!clazz.publicMethods.isEmpty()) {
- h << endl;
- foreach (const Method &m, clazz.publicMethods) {
- h << QStringLiteral(" ") << m.decl << QLatin1Char(';') << endl;
- }
- }
-
- if (!clazz.protectedMethods.isEmpty()) {
- h << endl
- << QStringLiteral("protected:") << endl;
- foreach (const Method &m, clazz.protectedMethods) {
- h << QStringLiteral(" ") << m.decl << QLatin1Char(';') << endl;
- }
- }
-
- if (!clazz.signalMethods.isEmpty()) {
- h << endl
- << QStringLiteral("signals:") << endl;
- clazz.signalMethods.write(h, QStringLiteral(" "), QStringLiteral("\n"));
- }
-
- if (!clazz.publicSlotDeclarations.isEmpty()) {
- h << endl
- << QStringLiteral("public slots:") << endl;
- clazz.publicSlotDeclarations.write(h, QStringLiteral(" "), QStringLiteral("\n"));
- }
-
- h << endl
- << l("private:") << endl
- << l(" struct Data;") << endl
- << l(" friend struct Data;") << endl
- << l(" struct Data *data;") << endl
- << l("};") << endl << endl;
+ const bool qtMode = m_translationUnit->mainDocument->qtMode;
+ Replacements r;
+ r[QStringLiteral("classname")] = className;
+ r[QStringLiteral("signals")] = qtMode ? generateSignalDecls(info) : QString();
+ r[QStringLiteral("slots")] = qtMode ? generateSlotDecls(info) : QString();
+ r[QStringLiteral("getters")] = qtMode ? generateGetterDecls(info) : QString();
+ genTemplate(h, QStringLiteral(":/decl.t"), r);
}
void CppDumper::writeHeaderEnd(const QString &headerGuard, const QStringList &metatypeDecls)
@@ -1430,121 +551,423 @@ void CppDumper::writeHeaderEnd(const QString &headerGuard, const QStringList &me
h << QStringLiteral("#endif // ") << headerGuard << endl;
}
-void CppDumper::writeImplStart(const QVector<ClassDump> &allClazzes)
+void CppDumper::writeImplStart()
{
- cpp << doNotEditComment.arg(m_translationUnit->scxmlFileName, QString::number(Q_QSCXMLC_OUTPUT_REVISION), QString::fromLatin1(QT_VERSION_STR))
+ cpp << doNotEditComment.arg(m_translationUnit->scxmlFileName,
+ QString::number(Q_QSCXMLC_OUTPUT_REVISION),
+ l(QT_VERSION_STR))
<< endl;
- StringListDumper includes;
- foreach (const ClassDump &clazz, allClazzes) {
- includes.text += clazz.implIncludes.text;
+ QStringList includes;
+ foreach (DocumentModel::ScxmlDocument *doc, m_translationUnit->classnameForDocument.keys()) {
+ switch (doc->root->dataModel) {
+ case DocumentModel::Scxml::NullDataModel:
+ includes += l("QScxmlNullDataModel");
+ break;
+ case DocumentModel::Scxml::JSDataModel:
+ includes += l("QScxmlEcmaScriptDataModel");
+ break;
+ case DocumentModel::Scxml::CppDataModel:
+ includes += doc->root->cppDataModelHeaderName;
+ break;
+ }
+
}
- includes.unique();
+ includes.sort();
+ includes.removeDuplicates();
QString headerName = QFileInfo(m_translationUnit->outHFileName).fileName();
cpp << l("#include \"") << headerName << l("\"") << endl;
cpp << endl
- << QStringLiteral("#include <qscxmlqstates.h>") << endl
+ << QStringLiteral("#include <qscxmlinvokableservice.h>") << endl
<< QStringLiteral("#include <qscxmltabledata.h>") << endl;
- if (!includes.isEmpty()) {
- includes.write(cpp, QStringLiteral("#include <"), QStringLiteral(">\n"));
- cpp << endl;
+ foreach (const QString &inc, includes) {
+ cpp << l("#include <") << inc << l(">") << endl;
}
cpp << endl
- << revisionCheck.arg(m_translationUnit->scxmlFileName, QString::number(Q_QSCXMLC_OUTPUT_REVISION), QString::fromLatin1(QT_VERSION_STR))
+ << revisionCheck.arg(m_translationUnit->scxmlFileName,
+ QString::number(Q_QSCXMLC_OUTPUT_REVISION),
+ QString::fromLatin1(QT_VERSION_STR))
<< endl;
if (!m_translationUnit->namespaceName.isEmpty())
cpp << l("namespace ") << m_translationUnit->namespaceName << l(" {") << endl << endl;
}
-void CppDumper::writeImplBody(const ClassDump &clazz)
+void CppDumper::writeImplBody(const GeneratedTableData &table,
+ const QString &className,
+ DocumentModel::ScxmlDocument *doc,
+ const QStringList &factory,
+ const GeneratedTableData::MetaDataInfo &info)
+{
+ const bool qtMode = m_translationUnit->mainDocument->qtMode;
+
+ QString dataModelField, dataModelInitialization;
+ switch (doc->root->dataModel) {
+ case DocumentModel::Scxml::NullDataModel:
+ dataModelField = l("QScxmlNullDataModel dataModel;");
+ dataModelInitialization = l("stateMachine.setDataModel(&dataModel);");
+ break;
+ case DocumentModel::Scxml::JSDataModel:
+ dataModelField = l("QScxmlEcmaScriptDataModel dataModel;");
+ dataModelInitialization = l("stateMachine.setDataModel(&dataModel);");
+ break;
+ case DocumentModel::Scxml::CppDataModel:
+ dataModelField = QStringLiteral("// Data model %1 is set from outside.").arg(
+ doc->root->cppDataModelClassName);
+ dataModelInitialization = dataModelField;
+ break;
+ }
+
+ QString name;
+ if (table.theName == -1) {
+ name = QStringLiteral("QString()");
+ } else {
+ name = QStringLiteral("string(%1)").arg(table.theName);
+ }
+
+ QString serviceFactories = factory.join(QStringLiteral("\n "))
+ + QStringLiteral("\n default: Q_UNREACHABLE();");
+
+ Replacements r;
+ r[QStringLiteral("classname")] = className;
+ r[QStringLiteral("name")] = name;
+ r[QStringLiteral("initialSetup")] = QString::number(table.initialSetup());
+ generateTables(table, info.outgoingEvents, r, m_translationUnit->useCxx11);
+ r[QStringLiteral("dataModelField")] = dataModelField;
+ r[QStringLiteral("dataModelInitialization")] = dataModelInitialization;
+ r[QStringLiteral("theStateMachineTable")] =
+ GeneratedTableData::toString(table.stateMachineTable());
+ r[QStringLiteral("metaObject")] = generateMetaObject(className, info, qtMode);
+ r[QStringLiteral("serviceFactories")] = serviceFactories;
+ r[QStringLiteral("slots")] = qtMode ? generateSlotDefs(className, info) : QString();
+ r[QStringLiteral("getters")] = qtMode ? generateGetterDefs(className, info) : QString();
+ genTemplate(cpp, QStringLiteral(":/data.t"), r);
+}
+
+void CppDumper::writeImplEnd()
{
- cpp << l("struct ") << clazz.className << l("::Data: private QScxmlTableData");
- if (clazz.needsEventFilter) {
- cpp << QStringLiteral(", public QScxmlEventFilter");
+ if (!m_translationUnit->namespaceName.isEmpty()) {
+ cpp << endl
+ << QStringLiteral("} // %1 namespace").arg(m_translationUnit->namespaceName) << endl;
}
- cpp << l(" {") << endl;
-
- cpp << QStringLiteral(" Data(%1 &stateMachine)").arg(clazz.className) << endl
- << QStringLiteral(" : stateMachine(stateMachine)") << endl;
- clazz.constructor.initializer.write(cpp, QStringLiteral(" , "), QStringLiteral("\n"));
- cpp << l(" {") << endl;
- clazz.constructor.impl.write(cpp, QStringLiteral(" "), QStringLiteral("\n"));
- cpp << l(" }") << endl;
-
- cpp << endl;
- cpp << l(" void init() {\n");
- clazz.init.impl.write(cpp, QStringLiteral(" "), QStringLiteral("\n"));
- cpp << l(" }") << endl;
- cpp << endl;
- clazz.dataMethods.write(cpp, QStringLiteral(" "), QStringLiteral("\n"));
+}
- cpp << endl
- << QStringLiteral(" %1 &stateMachine;").arg(clazz.className) << endl;
- clazz.classFields.write(cpp, QStringLiteral(" "), QStringLiteral("\n"));
+/*!
+ * \internal
+ * Mangles \a str to be a unique C++ identifier. Characters that are invalid for C++ identifiers
+ * are replaced by the pattern \c _0x<hex>_ where <hex> is the hexadecimal unicode
+ * representation of the character. As identifiers with leading underscores followed by either
+ * another underscore or a capital letter are reserved in C++, we also escape those, by escaping
+ * the first underscore, using the above method.
+ *
+ * We keep track of all identifiers we have used so far and if we find two different names that
+ * map to the same mangled identifier by the above method, we append underscores to the new one
+ * until the result is unique.
+ *
+ * \note
+ * Although C++11 allows for non-ascii (unicode) characters to be used in identifiers,
+ * many compilers forgot to read the spec and do not implement this. Some also do not
+ * implement C99 identifiers, because that is \e {at the implementation's discretion}. So,
+ * we are stuck with plain old boring identifiers.
+ */
+QString CppDumper::mangleIdentifier(const QString &str)
+{
+ auto isNonDigit = [](QChar c) -> bool {
+ return (c >= QLatin1Char('a') && c <= QLatin1Char('z')) ||
+ (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) ||
+ c == QLatin1Char('_');
+ };
- cpp << l("};") << endl
- << endl;
- clazz.classMethods.write(cpp, QStringLiteral(""), QStringLiteral("\n"));
+ Q_ASSERT(!str.isEmpty());
- cpp << clazz.className << l("::") << clazz.className << l("(QObject *parent)") << endl
- << QStringLiteral(" : QScxmlStateMachine(parent)") << endl
- << QStringLiteral(" , data(new Data(*this))") << endl
- << QStringLiteral("{ qRegisterMetaType<%1 *>(); data->init(); }").arg(clazz.className) << endl
- << endl;
- cpp << clazz.className << l("::~") << clazz.className << l("()") << endl
- << l("{ delete data; }") << endl
- << endl;
- foreach (const Method &m, clazz.publicMethods) {
- m.impl.write(cpp, QStringLiteral(""), QStringLiteral("\n"), clazz.className);
- cpp << endl;
- }
- if (!clazz.protectedMethods.isEmpty()) {
- cpp << "#define SET_SERVICE_PROP(s, n, fq, sig) \\\n"
- " if (id == data->string(s)) { \\\n"
- " QScxmlInvokableScxml *machine = service ? dynamic_cast<QScxmlInvokableScxml *>(service) : Q_NULLPTR; \\\n"
- " fq *casted = machine ? dynamic_cast<fq*>(machine->stateMachine()) : Q_NULLPTR; \\\n"
- " if (data->n != casted) { \\\n"
- " data->n = casted; \\\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"
- << endl;
- foreach (const Method &m, clazz.protectedMethods) {
- m.impl.write(cpp, QStringLiteral(""), QStringLiteral("\n"), clazz.className);
- cpp << endl;
+ QString mangled;
+ mangled.reserve(str.size());
+
+ int i = 0;
+ if (str.startsWith(QLatin1Char('_')) && str.size() > 1) {
+ QChar ch = str.at(1);
+ if (ch == QLatin1Char('_')
+ || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))) {
+ mangled += QLatin1String("_0x5f_");
+ ++i;
}
- cpp << QStringLiteral("#undef SET_SERVICE_PROP") << endl
- << endl;
}
- clazz.publicSlotDefinitions.write(cpp, QStringLiteral("\n"), QStringLiteral("\n"));
- cpp << endl;
- clazz.tables.write(cpp, QStringLiteral(""), QStringLiteral("\n"));
+ for (int ei = str.length(); i != ei; ++i) {
+ auto c = str.at(i).unicode();
+ if ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) || isNonDigit(c)) {
+ mangled += c;
+ } else {
+ mangled += QLatin1String("_0x") + QString::number(c, 16) + QLatin1Char('_');
+ }
+ }
- if (!clazz.dataModelMethods.isEmpty()) {
- bool first = true;
- foreach (const Method &m, clazz.dataModelMethods) {
- if (first) {
- first = false;
- } else {
- cpp << endl;
- }
- m.impl.write(cpp, QStringLiteral(""), QStringLiteral("\n"));
+ while (true) {
+ auto it = m_mangledToOriginal.constFind(mangled);
+ if (it == m_mangledToOriginal.constEnd()) {
+ m_mangledToOriginal.insert(mangled, str);
+ break;
+ } else if (it.value() == str) {
+ break;
}
+ mangled += QStringLiteral("_"); // append underscores until we get a unique name
}
- cpp << endl << clazz.metaData;
+ return mangled;
}
-void CppDumper::writeImplEnd()
+QString CppDumper::generateSignalDecls(const GeneratedTableData::MetaDataInfo &info)
{
- if (!m_translationUnit->namespaceName.isEmpty()) {
- cpp << endl
- << QStringLiteral("} // %1 namespace").arg(m_translationUnit->namespaceName) << endl;
+ QString decls;
+
+ foreach (const QString &stateName, info.stateNames) {
+ decls += QStringLiteral(" void %1Changed(bool active);\n")
+ .arg(mangleIdentifier(stateName));
+ }
+
+ foreach (const QString &machineName, info.subStateMachineNames) {
+ decls += QStringLiteral(" void %1Changed(QScxmlStateMachine *stateMachine);\n")
+ .arg(mangleIdentifier(machineName));
+ }
+
+ foreach (const QString &eventName, info.outgoingEvents) {
+ decls += QStringLiteral(" void %1(const QVariant &data);\n")
+ .arg(mangleIdentifier(eventName));
+ }
+
+ return decls;
+}
+
+QString CppDumper::generateSlotDecls(const GeneratedTableData::MetaDataInfo &info)
+{
+ QString decls;
+
+ foreach (const QString &eventName, info.incomingEvents) {
+ if (!DocumentModel::isEventToBeGenerated(eventName))
+ continue;
+
+ decls += QStringLiteral(" void %1(const QVariant &data = QVariant());\n")
+ .arg(mangleIdentifier(eventName));
+ }
+
+ return decls;
+}
+
+QString CppDumper::generateSlotDefs(const QString &className,
+ const GeneratedTableData::MetaDataInfo &info)
+{
+ QString defs;
+
+ foreach (const QString &eventName, info.incomingEvents) {
+ if (!DocumentModel::isEventToBeGenerated(eventName))
+ continue;
+
+ const auto mangledName = mangleIdentifier(eventName);
+ defs += QStringLiteral("void %1::%2(const QVariant &data)\n").arg(className, mangledName);
+ defs += QStringLiteral("{ submitEvent(QStringLiteral(\"%1\"), data); }\n\n").arg(eventName);
}
+
+ return defs;
+}
+
+QString CppDumper::generateGetterDecls(const GeneratedTableData::MetaDataInfo &info)
+{
+ QString decls;
+
+ foreach (const QString &stateName, info.stateNames) {
+ decls += QStringLiteral(" bool %1() const;\n").arg(mangleIdentifier(stateName));
+ }
+
+ foreach (const QString &machineName, info.subStateMachineNames) {
+ decls += QStringLiteral(" QScxmlStateMachine *%1() const;\n")
+ .arg(mangleIdentifier(machineName));
+ }
+
+ return decls;
+}
+
+QString CppDumper::generateGetterDefs(const QString &className,
+ const GeneratedTableData::MetaDataInfo &info)
+{
+ QString defs;
+
+ int stateIndex = 0;
+ foreach (const QString &stateName, info.stateNames) {
+ defs += QStringLiteral("bool %1::%2() const\n").arg(className, mangleIdentifier(stateName));
+ defs += QStringLiteral("{ return isActive(%1); }\n\n").arg(stateIndex);
+ ++stateIndex;
+ }
+
+ int machineIndex = 0;
+ foreach (const QString &machineName, info.subStateMachineNames) {
+ defs += QStringLiteral("QScxmlStateMachine *%1::%2() const\n")
+ .arg(className, mangleIdentifier(machineName));
+ defs += QStringLiteral("{ return subStateMachine(%1); }\n\n").arg(machineIndex);
+ ++machineIndex;
+ }
+
+ return defs;
+}
+
+QString CppDumper::generateMetaObject(const QString &className,
+ const GeneratedTableData::MetaDataInfo &info,
+ bool m_qtMode)
+{
+ ClassDef classDef;
+ classDef.classname = className.toUtf8();
+ classDef.qualified = classDef.classname;
+ classDef.superclassList << qMakePair(QByteArray("QScxmlStateMachine"), FunctionDef::Public);
+ classDef.hasQObject = true;
+
+ // stateNames:
+ int stateIdx = 0;
+ foreach (const QString &stateName, info.stateNames) {
+ if (stateName.isEmpty())
+ continue;
+
+ QByteArray mangledStateName = 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);";
+ }
+ 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 = "isActive(" + QByteArray::number(stateIdx++) + ")";
+ prop.notify = mangledStateName + "Changed";
+ prop.notifyId = classDef.signalList.size() - 1;
+ prop.gspec = PropertyDef::ValueSpec;
+ prop.scriptable = "true";
+ classDef.propertyList << prop;
+ }
+
+ // sub-statemachines:
+ QHash<QByteArray, QByteArray> knownQObjectClasses;
+ knownQObjectClasses.insert(QByteArray("QScxmlStateMachine"), QByteArray());
+ int machineIdx = 0;
+ for (const auto &service : info.subStateMachineNames) {
+ const auto serviceName = service;
+ const QString fqServiceClass = QStringLiteral("QScxmlStateMachine");
+ const QByteArray serviceClass = fqServiceClass.toUtf8();
+ knownQObjectClasses.insert(serviceClass, "");
+
+ const QByteArray mangledServiceName = mangleIdentifier(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 = "subStateMachine(" + QByteArray::number(machineIdx++) + ")";
+ prop.notify = mangledServiceName + "Changed";
+ prop.notifyId = classDef.signalList.size() - 1;
+ prop.gspec = PropertyDef::ValueSpec;
+ prop.scriptable = "true";
+ classDef.propertyList << prop;
+ }
+
+ // Event signals:
+ foreach (const QString &signalName, info.outgoingEvents) {
+ 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;
+ }
+
+ // event slots:
+ foreach (const QString &eventName, info.incomingEvents) {
+ if (!DocumentModel::isEventToBeGenerated(eventName))
+ continue;
+
+ 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;
+
+ 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;
+ }
+
+ foreach (const QString &eventName, info.incomingEvents) {
+ if (!DocumentModel::isEventToBeGenerated(eventName))
+ continue;
+
+ 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;
+ }
+
+ QBuffer buf;
+ buf.open(QIODevice::WriteOnly);
+ Generator(&classDef, QList<QByteArray>(), knownQObjectClasses,
+ QHash<QByteArray, QByteArray>(), buf).generateCode();
+ buf.close();
+ return QString::fromUtf8(buf.buffer());
}
QT_END_NAMESPACE
diff --git a/tools/qscxmlc/scxmlcppdumper.h b/tools/qscxmlc/scxmlcppdumper.h
index f02bf2f..97011d0 100644
--- a/tools/qscxmlc/scxmlcppdumper.h
+++ b/tools/qscxmlc/scxmlcppdumper.h
@@ -32,13 +32,12 @@
#include "qscxmlglobals.h"
#include <QtScxml/private/qscxmlparser_p.h>
+#include <QtScxml/private/qscxmltabledata_p.h>
#include <QTextStream>
QT_BEGIN_NAMESPACE
-struct ClassDump;
-
struct TranslationUnit
{
TranslationUnit()
@@ -74,13 +73,30 @@ public:
private:
void writeHeaderStart(const QString &headerGuard, const QStringList &forwardDecls);
- void writeClass(const ClassDump &clazz);
+ void writeClass(const QString &className,
+ const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
void writeHeaderEnd(const QString &headerGuard, const QStringList &metatypeDecls);
- void writeImplStart(const QVector<ClassDump> &allClazzes);
- void writeImplBody(const ClassDump &clazz);
+ void writeImplStart();
+ void writeImplBody(const QScxmlInternal::GeneratedTableData &table,
+ const QString &className,
+ DocumentModel::ScxmlDocument *doc,
+ const QStringList &factory,
+ const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
void writeImplEnd();
+ QString mangleIdentifier(const QString &str);
private:
+ QString generateSignalDecls(const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateSlotDecls(const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateSlotDefs(const QString &className,
+ const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateGetterDecls(const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateGetterDefs(const QString &className,
+ const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateMetaObject(const QString &className,
+ const QScxmlInternal::GeneratedTableData::MetaDataInfo &info,
+ bool m_qtMode);
+
QTextStream &h;
QTextStream &cpp;
@@ -88,6 +104,8 @@ private:
static QLatin1String l (const char *str) { return QLatin1String(str); }
TranslationUnit *m_translationUnit;
+
+ mutable QHash<QString, QString> m_mangledToOriginal;
};
QT_END_NAMESPACE
diff --git a/tools/qscxmlc/templates.qrc b/tools/qscxmlc/templates.qrc
new file mode 100644
index 0000000..6f2ccf6
--- /dev/null
+++ b/tools/qscxmlc/templates.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data.t</file>
+ <file>decl.t</file>
+ <file>cppdatamodel.t</file>
+ </qresource>
+</RCC>