summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@theqtcompany.com>2016-05-31 16:21:29 +0200
committerJarek Kobus <jaroslaw.kobus@qt.io>2016-06-07 08:43:43 +0000
commit4a0d14bfcc49edc60127e0833f6cc8d4edad9027 (patch)
tree250b9730d25a9c01a4563ad25e18445f6e11e59d
parent2906a351df804c0e8d5e4377b9ecd48d293ddf41 (diff)
Implement srcexpr in <invoke>
Change-Id: I572342eb4952a6a0777a7503d374da6536ba052d Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/scxml/qscxmlinvokableservice.cpp55
-rw-r--r--src/scxml/qscxmlinvokableservice.h11
-rw-r--r--src/scxml/qscxmlparser.cpp66
-rw-r--r--src/scxml/qscxmlparser_p.h2
-rw-r--r--src/scxml/qscxmlqstates.h20
-rw-r--r--src/scxml/qscxmlstatemachine.cpp16
-rw-r--r--src/scxml/qscxmlstatemachine.h5
-rw-r--r--src/scxml/qscxmlstatemachine_p.h2
-rw-r--r--tests/3rdparty/scion-tests/scxml-test-framework/test/test216sub1.scxml5
-rw-r--r--tests/auto/scion/scion.pro1
-rw-r--r--tests/auto/scion/tst_scion.cpp5
-rw-r--r--tools/qscxmlc/scxmlcppdumper.cpp3
12 files changed, 175 insertions, 16 deletions
diff --git a/src/scxml/qscxmlinvokableservice.cpp b/src/scxml/qscxmlinvokableservice.cpp
index d473915..bb29635 100644
--- a/src/scxml/qscxmlinvokableservice.cpp
+++ b/src/scxml/qscxmlinvokableservice.cpp
@@ -97,12 +97,17 @@ QScxmlInvokableServiceFactory *QScxmlInvokableService::service() const
class QScxmlInvokableServiceFactory::Data
{
public:
- Data(QScxmlExecutableContent::StringId invokeLocation, QScxmlExecutableContent::StringId id,
- QScxmlExecutableContent::StringId idPrefix, QScxmlExecutableContent::StringId idlocation,
- const QVector<QScxmlExecutableContent::StringId> &namelist, bool autoforward,
+ Data(QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
+ QScxmlExecutableContent::StringId id,
+ QScxmlExecutableContent::StringId idPrefix,
+ QScxmlExecutableContent::StringId idlocation,
+ const QVector<QScxmlExecutableContent::StringId> &namelist,
+ bool autoforward,
const QVector<QScxmlInvokableServiceFactory::Param> &params,
QScxmlExecutableContent::ContainerId finalize)
: invokeLocation(invokeLocation)
+ , srcexpr(srcexpr)
, id(id)
, idPrefix(idPrefix)
, idlocation(idlocation)
@@ -113,6 +118,7 @@ public:
{}
QScxmlExecutableContent::StringId invokeLocation;
+ QScxmlExecutableContent::EvaluatorId srcexpr;
QScxmlExecutableContent::StringId id;
QScxmlExecutableContent::StringId idPrefix;
QScxmlExecutableContent::StringId idlocation;
@@ -123,11 +129,24 @@ public:
};
QScxmlInvokableServiceFactory::QScxmlInvokableServiceFactory(
- QScxmlExecutableContent::StringId invokeLocation, QScxmlExecutableContent::StringId id,
- QScxmlExecutableContent::StringId idPrefix, QScxmlExecutableContent::StringId idlocation,
- const QVector<QScxmlExecutableContent::StringId> &namelist, bool autoforward,
- const QVector<Param> &params, QScxmlExecutableContent::ContainerId finalize)
- : d(new Data(invokeLocation, id, idPrefix, idlocation, namelist, autoforward, params, finalize))
+ QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
+ QScxmlExecutableContent::StringId id,
+ QScxmlExecutableContent::StringId idPrefix,
+ QScxmlExecutableContent::StringId idlocation,
+ const QVector<QScxmlExecutableContent::StringId> &namelist,
+ bool autoforward,
+ const QVector<Param> &params,
+ QScxmlExecutableContent::ContainerId finalize)
+ : d(new Data(invokeLocation,
+ srcexpr,
+ id,
+ idPrefix,
+ idlocation,
+ namelist,
+ autoforward,
+ params,
+ finalize))
{}
QScxmlInvokableServiceFactory::~QScxmlInvokableServiceFactory()
@@ -135,6 +154,23 @@ QScxmlInvokableServiceFactory::~QScxmlInvokableServiceFactory()
delete d;
}
+QString QScxmlInvokableServiceFactory::calculateSrcexpr(QScxmlStateMachine *parent, bool *ok) const
+{
+ Q_ASSERT(ok);
+ *ok = true;
+ auto dataModel = parent->dataModel();
+
+ if (d->srcexpr != QScxmlExecutableContent::NoEvaluator) {
+ *ok = false;
+ auto v = dataModel->evaluateToString(d->srcexpr, ok);
+ if (!*ok)
+ return QString();
+ return v;
+ }
+
+ return QString();
+}
+
QString QScxmlInvokableServiceFactory::calculateId(QScxmlStateMachine *parent, bool *ok) const
{
Q_ASSERT(ok);
@@ -284,6 +320,7 @@ QScxmlStateMachine *QScxmlInvokableScxml::stateMachine() const
QScxmlInvokableScxmlServiceFactory::QScxmlInvokableScxmlServiceFactory(
QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
QScxmlExecutableContent::StringId id,
QScxmlExecutableContent::StringId idPrefix,
QScxmlExecutableContent::StringId idlocation,
@@ -291,7 +328,7 @@ QScxmlInvokableScxmlServiceFactory::QScxmlInvokableScxmlServiceFactory(
bool doAutoforward,
const QVector<QScxmlInvokableServiceFactory::Param> &params,
QScxmlExecutableContent::ContainerId finalize)
- : QScxmlInvokableServiceFactory(invokeLocation, id, idPrefix, idlocation, namelist,
+ : QScxmlInvokableServiceFactory(invokeLocation, srcexpr, id, idPrefix, idlocation, namelist,
doAutoforward, params, finalize)
{}
diff --git a/src/scxml/qscxmlinvokableservice.h b/src/scxml/qscxmlinvokableservice.h
index 21ba707..850047a 100644
--- a/src/scxml/qscxmlinvokableservice.h
+++ b/src/scxml/qscxmlinvokableservice.h
@@ -100,6 +100,7 @@ public:
};
QScxmlInvokableServiceFactory(QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
QScxmlExecutableContent::StringId id,
QScxmlExecutableContent::StringId idPrefix,
QScxmlExecutableContent::StringId idlocation,
@@ -112,6 +113,7 @@ public:
virtual QScxmlInvokableService *invoke(QScxmlStateMachine *parent) = 0;
public: // callbacks from the service:
+ QString calculateSrcexpr(QScxmlStateMachine *parent, bool *ok) const;
QString calculateId(QScxmlStateMachine *parent, bool *ok) const;
QVariantMap calculateData(QScxmlStateMachine *parent, bool *ok) const;
bool autoforward() const;
@@ -145,6 +147,7 @@ class Q_SCXML_EXPORT QScxmlInvokableScxmlServiceFactory: public QScxmlInvokableS
{
public:
QScxmlInvokableScxmlServiceFactory(QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
QScxmlExecutableContent::StringId id,
QScxmlExecutableContent::StringId idPrefix,
QScxmlExecutableContent::StringId idlocation,
@@ -154,7 +157,13 @@ public:
QScxmlExecutableContent::ContainerId finalize);
protected:
- QScxmlInvokableService *finishInvoke(QScxmlStateMachine *child, QScxmlStateMachine *parent);
+#ifndef BUILD_QSCXMLC
+
+ QScxmlInvokableService *loadAndInvokeDynamically(QScxmlStateMachine *parent,
+ const QString &sourceUrl);
+#endif // BUILD_QSCXMLC
+ QScxmlInvokableService *finishInvoke(QScxmlStateMachine *child,
+ QScxmlStateMachine *parent);
};
QT_END_NAMESPACE
diff --git a/src/scxml/qscxmlparser.cpp b/src/scxml/qscxmlparser.cpp
index 55b1368..c22d617 100644
--- a/src/scxml/qscxmlparser.cpp
+++ b/src/scxml/qscxmlparser.cpp
@@ -1005,6 +1005,7 @@ class InvokeDynamicScxmlFactory: public QScxmlInvokableScxmlServiceFactory
{
public:
InvokeDynamicScxmlFactory(QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
QScxmlExecutableContent::StringId id,
QScxmlExecutableContent::StringId idPrefix,
QScxmlExecutableContent::StringId idlocation,
@@ -1012,7 +1013,15 @@ public:
bool autoforward,
const QVector<Param> &params,
QScxmlExecutableContent::ContainerId finalize)
- : QScxmlInvokableScxmlServiceFactory(invokeLocation, id, idPrefix, idlocation, namelist, autoforward, params, finalize)
+ : QScxmlInvokableScxmlServiceFactory(invokeLocation,
+ srcexpr,
+ id,
+ idPrefix,
+ idlocation,
+ namelist,
+ autoforward,
+ params,
+ finalize)
{}
void setContent(const QSharedPointer<DocumentModel::ScxmlDocument> &content)
@@ -1184,6 +1193,9 @@ private:
endSequence();
}
auto factory = new InvokeDynamicScxmlFactory(ctxt,
+ createEvaluatorString(QStringLiteral("invoke"),
+ QStringLiteral("srcexpr"),
+ invoke->srcexpr),
addString(invoke->id),
addString(node->id + QStringLiteral(".session-")),
addString(invoke->idLocation),
@@ -1363,6 +1375,14 @@ private:
inline QScxmlInvokableService *InvokeDynamicScxmlFactory::invoke(QScxmlStateMachine *parent)
{
+ bool ok = true;
+ auto srcexpr = calculateSrcexpr(parent, &ok);
+ if (!ok)
+ return Q_NULLPTR;
+
+ if (!srcexpr.isEmpty())
+ return loadAndInvokeDynamically(parent, srcexpr);
+
auto child = QStateMachineBuilder().build(m_content.data());
auto dm = QScxmlDataModelPrivate::instantiateDataModel(m_content->root->dataModel);
@@ -1375,6 +1395,50 @@ inline QScxmlInvokableService *InvokeDynamicScxmlFactory::invoke(QScxmlStateMach
} // anonymous namespace
+#ifndef BUILD_QSCXMLC
+QScxmlInvokableService *QScxmlInvokableScxmlServiceFactory::loadAndInvokeDynamically(QScxmlStateMachine *parent,
+ const QString &sourceUrl)
+{
+ QScxmlParser::Loader *loader = parent->loader();
+
+ QStringList errs;
+ const QByteArray data = loader->load(sourceUrl, sourceUrl.isEmpty() ?
+ QString() : QFileInfo(sourceUrl).path(), &errs);
+
+ if (!errs.isEmpty()) {
+ qWarning() << errs;
+ return Q_NULLPTR;
+ }
+
+ QXmlStreamReader reader(data);
+ QScxmlParser parser(&reader);
+ parser.setFileName(sourceUrl);
+ parser.setLoader(parent->loader());
+ parser.parse();
+ if (!parser.errors().isEmpty()) {
+ foreach (const QScxmlError &error, parser.errors())
+ qWarning() << error.toString();
+ return Q_NULLPTR;
+ }
+
+ auto mainDoc = QScxmlParserPrivate::get(&parser)->scxmlDocument();
+ if (mainDoc == nullptr) {
+ Q_ASSERT(!parser.errors().isEmpty());
+ foreach (const QScxmlError &error, parser.errors())
+ qWarning() << error.toString();
+ return Q_NULLPTR;
+ }
+
+ auto child = QStateMachineBuilder().build(mainDoc);
+
+ auto dm = QScxmlDataModelPrivate::instantiateDataModel(mainDoc->root->dataModel);
+ dm->setParent(child);
+ child->setDataModel(dm);
+
+ return finishInvoke(child, parent);
+}
+#endif // BUILD_QSCXMLC
+
/*!
* \class QScxmlParser
* \brief The QScxmlParser class is a parser for SCXML files.
diff --git a/src/scxml/qscxmlparser_p.h b/src/scxml/qscxmlparser_p.h
index 98867a8..42b61f8 100644
--- a/src/scxml/qscxmlparser_p.h
+++ b/src/scxml/qscxmlparser_p.h
@@ -702,6 +702,7 @@ private:
static QStringList optionalAttributes(Kind kind);
};
+public:
class DefaultLoader: public QScxmlParser::Loader
{
public:
@@ -711,6 +712,7 @@ private:
QStringList *errors) Q_DECL_OVERRIDE Q_DECL_FINAL;
};
+private:
bool checkAttributes(const QXmlStreamAttributes &attributes, QScxmlParserPrivate::ParserState::Kind kind);
ParserState &current();
ParserState &previous();
diff --git a/src/scxml/qscxmlqstates.h b/src/scxml/qscxmlqstates.h
index 7280a0f..7014861 100644
--- a/src/scxml/qscxmlqstates.h
+++ b/src/scxml/qscxmlqstates.h
@@ -55,6 +55,7 @@ class QScxmlInvokeScxmlFactory: public QScxmlInvokableScxmlServiceFactory
{
public:
QScxmlInvokeScxmlFactory(QScxmlExecutableContent::StringId invokeLocation,
+ QScxmlExecutableContent::EvaluatorId srcexpr,
QScxmlExecutableContent::StringId id,
QScxmlExecutableContent::StringId idPrefix,
QScxmlExecutableContent::StringId idlocation,
@@ -62,12 +63,27 @@ public:
bool doAutoforward,
const QVector<Param> &params,
QScxmlExecutableContent::ContainerId finalize)
- : QScxmlInvokableScxmlServiceFactory(invokeLocation, id, idPrefix, idlocation, namelist,
- doAutoforward, params, finalize)
+ : QScxmlInvokableScxmlServiceFactory(invokeLocation,
+ srcexpr,
+ id,
+ idPrefix,
+ idlocation,
+ namelist,
+ doAutoforward,
+ params,
+ finalize)
{}
QScxmlInvokableService *invoke(QScxmlStateMachine *parent) Q_DECL_OVERRIDE
{
+ bool ok = true;
+ auto srcexpr = calculateSrcexpr(parent, &ok);
+ if (!ok)
+ return Q_NULLPTR;
+
+ if (!srcexpr.isEmpty())
+ return loadAndInvokeDynamically(parent, srcexpr);
+
return finishInvoke(new T, parent);
}
};
diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp
index 6603703..2b25eb9 100644
--- a/src/scxml/qscxmlstatemachine.cpp
+++ b/src/scxml/qscxmlstatemachine.cpp
@@ -234,6 +234,7 @@ QScxmlStateMachinePrivate::QScxmlStateMachinePrivate()
, m_isInvoked(false)
, m_isInitialized(false)
, m_dataModel(Q_NULLPTR)
+ , m_loader(&m_defaultLoader)
, m_dataBinding(QScxmlStateMachine::EarlyBinding)
, m_executionEngine(Q_NULLPTR)
, m_tableData(Q_NULLPTR)
@@ -597,6 +598,21 @@ QScxmlDataModel *QScxmlStateMachine::dataModel() const
return d->m_dataModel;
}
+
+void QScxmlStateMachine::setLoader(QScxmlParser::Loader *loader)
+{
+ Q_D(QScxmlStateMachine);
+
+ d->m_loader = loader;
+}
+
+QScxmlParser::Loader *QScxmlStateMachine::loader() const
+{
+ Q_D(const QScxmlStateMachine);
+
+ return d->m_loader;
+}
+
/*!
* \internal
* Sets the binding method to the specified value.
diff --git a/src/scxml/qscxmlstatemachine.h b/src/scxml/qscxmlstatemachine.h
index 5a800d5..2ab7880 100644
--- a/src/scxml/qscxmlstatemachine.h
+++ b/src/scxml/qscxmlstatemachine.h
@@ -44,6 +44,7 @@
#include <QtScxml/qscxmlexecutablecontent.h>
#include <QtScxml/qscxmlerror.h>
#include <QtScxml/qscxmlevent.h>
+#include <QtScxml/qscxmlparser.h>
#include <QString>
#include <QVector>
@@ -57,7 +58,6 @@ class QTextStream;
class QScxmlEventBuilder;
class QScxmlInvokableServiceFactory;
class QScxmlInvokableService;
-class QScxmlParser;
class QScxmlStateMachine;
class QScxmlTableData;
@@ -105,6 +105,9 @@ public:
void setDataModel(QScxmlDataModel *model);
QScxmlDataModel *dataModel() const;
+ void setLoader(QScxmlParser::Loader *loader);
+ QScxmlParser::Loader *loader() const;
+
BindingMethod dataBinding() const;
bool isRunning() const;
diff --git a/src/scxml/qscxmlstatemachine_p.h b/src/scxml/qscxmlstatemachine_p.h
index 99334cf..ae68ce5 100644
--- a/src/scxml/qscxmlstatemachine_p.h
+++ b/src/scxml/qscxmlstatemachine_p.h
@@ -142,6 +142,8 @@ public: // types & data fields:
bool m_isInitialized;
QVariantMap m_initialValues;
QScxmlDataModel *m_dataModel;
+ QScxmlParserPrivate::DefaultLoader m_defaultLoader;
+ QScxmlParser::Loader *m_loader;
QScxmlStateMachine::BindingMethod m_dataBinding;
QScxmlExecutableContent::QScxmlExecutionEngine *m_executionEngine;
QScxmlTableData *m_tableData;
diff --git a/tests/3rdparty/scion-tests/scxml-test-framework/test/test216sub1.scxml b/tests/3rdparty/scion-tests/scxml-test-framework/test/test216sub1.scxml
new file mode 100644
index 0000000..cf9a3c4
--- /dev/null
+++ b/tests/3rdparty/scion-tests/scxml-test-framework/test/test216sub1.scxml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- when invoked, terminate returning done.invoke. This proves that the invocation succeeded. --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="final" version="1.0" datamodel="ecmascript">
+
+<final id="final"/>
+
+</scxml>
diff --git a/tests/auto/scion/scion.pro b/tests/auto/scion/scion.pro
index eccc02d..1b58a21 100644
--- a/tests/auto/scion/scion.pro
+++ b/tests/auto/scion/scion.pro
@@ -52,6 +52,7 @@ ALLSCXMLS = $$files($$SCXMLS_DIR/*.scxml, true)
# For a better explanation about the "blacklisted" tests, see tst_scion.cpp
# <invoke>
BLACKLISTED = \
+ test216sub1.scxml \
test226sub1.txml \
test239sub1.scxml \
test242sub1.scxml \
diff --git a/tests/auto/scion/tst_scion.cpp b/tests/auto/scion/tst_scion.cpp
index b5e0d0f..c06ac1b 100644
--- a/tests/auto/scion/tst_scion.cpp
+++ b/tests/auto/scion/tst_scion.cpp
@@ -67,8 +67,6 @@ static QSet<QString> testFailOnRun = QSet<QString>()
<< QLatin1String("w3c-ecma/test456.txml") // replaced by modified_test456
// FIXME: qscxmlc fails on improper scxml file, currently no way of testing it properly for compiled case
<< QLatin1String("w3c-ecma/test301.txml")
- // FIXME: Currently we do not support loading scripts from a srcexpr.
- << QLatin1String("w3c-ecma/test216.txml")
// FIXME: Currently we do not support nested scxml as a child of assign.
<< QLatin1String("w3c-ecma/test530.txml")
;
@@ -217,6 +215,7 @@ void TestScion::dynamic()
QScopedPointer<QScxmlStateMachine> stateMachine(parser.instantiateStateMachine());
QVERIFY(stateMachine != Q_NULLPTR);
+ stateMachine->setLoader(&loader);
parser.instantiateDataModel(stateMachine.data());
const bool runResult = runTest(stateMachine.data(), testDescription.object());
@@ -262,6 +261,8 @@ void TestScion::compiled()
QEXPECT_FAIL("", "This is expected to fail", Abort);
}
QVERIFY(stateMachine != Q_NULLPTR);
+ DynamicLoader loader;
+ stateMachine->setLoader(&loader);
const bool runResult = runTest(stateMachine.data(), testDescription.object());
if (runResult == false && testStatus == TestFailsOnRun)
diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp
index a48a6b6..6efa5f6 100644
--- a/tools/qscxmlc/scxmlcppdumper.cpp
+++ b/tools/qscxmlc/scxmlcppdumper.cpp
@@ -400,6 +400,9 @@ protected:
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));