summaryrefslogtreecommitdiffstats
path: root/tools/qscxmlc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qscxmlc')
-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>