From 330576fcb4d97504e0d6951067b753499d91b541 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sun, 14 Dec 2014 14:20:04 +0100 Subject: Renamed URI to URL Some fixes for Xincludes --- CMakeLists.txt | 4 + apps/uscxml-browser.cpp | 2 +- apps/uscxml-dot.cpp | 2 +- apps/uscxml-transform.cpp | 2 +- contrib/local/virtualbox.sh | 9 + .../tests/datamodel/TestDataModelAccess.java | 2 +- .../tests/datamodel/TestJavaScriptDataModel.java | 2 +- .../org/uscxml/tests/datamodel/TestW3CECMA.java | 2 +- .../invoker/factory/vxml/TestVoiceXMLInvoker.java | 2 +- src/bindings/swig/java/uscxml.i | 6 +- src/bindings/swig/uscxml_ignores.i | 3 +- src/uscxml/Interpreter.cpp | 98 ++++++----- src/uscxml/Interpreter.h | 76 ++++++--- src/uscxml/debug/DebugSession.cpp | 4 +- src/uscxml/debug/DebuggerServlet.cpp | 2 +- src/uscxml/messages/SendRequest.h | 1 + .../plugins/datamodel/promela/PromelaDataModel.cpp | 64 ++++---- .../plugins/datamodel/promela/PromelaParser.h | 5 +- src/uscxml/plugins/element/fetch/FetchElement.cpp | 2 +- src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp | 2 +- .../invoker/filesystem/dirmon/DirMonInvoker.cpp | 2 +- .../invoker/graphics/openscenegraph/OSGInvoker.cpp | 2 +- .../plugins/invoker/miles/MilesSessionInvoker.cpp | 2 +- src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 6 +- .../plugins/invoker/umundo/UmundoInvoker.cpp | 6 +- src/uscxml/transform/ChartToPromela.cpp | 181 ++++++++++++++++++--- src/uscxml/transform/ChartToPromela.h | 3 +- test/ctest/CTestCustom.ctest.in | 8 +- test/src/test-stress.cpp | 2 +- test/src/test-w3c.cpp | 4 +- .../baseuri/test-xinclude-baseuri1.include | 6 + .../baseuri/test-xinclude-baseuri2.include | 1 + .../xinclude/baseuri/test-xinclude-script.include | 1 + test/uscxml/xinclude/test-xinclude-baseuri.scxml | 13 ++ test/w3c/confPromela.xsl | 6 +- test/w3c/convert-tests.sh | 26 +-- test/w3c/promela/test150.scxml | 86 +++++----- test/w3c/promela/test151.scxml | 6 +- test/w3c/promela/test152.scxml | 6 +- test/w3c/promela/test153.scxml | 6 +- test/w3c/promela/test155.scxml | 6 +- test/w3c/promela/test156.scxml | 6 +- test/w3c/promela/test242.scxml | 97 +++++------ test/w3c/promela/test252.scxml | 2 +- test/w3c/promela/test347.scxml | 80 ++++----- test/w3c/promela/test509.scxml | 2 +- test/w3c/promela/test510.scxml | 2 +- test/w3c/promela/test518.scxml | 2 +- test/w3c/promela/test519.scxml | 2 +- test/w3c/promela/test520.scxml | 2 +- test/w3c/promela/test522.scxml | 2 +- test/w3c/promela/test525.scxml | 6 +- test/w3c/promela/test534.scxml | 2 +- test/w3c/promela/test551.scxml | 6 +- 54 files changed, 529 insertions(+), 351 deletions(-) create mode 100755 contrib/local/virtualbox.sh create mode 100644 test/uscxml/xinclude/baseuri/test-xinclude-baseuri1.include create mode 100644 test/uscxml/xinclude/baseuri/test-xinclude-baseuri2.include create mode 100644 test/uscxml/xinclude/baseuri/test-xinclude-script.include create mode 100644 test/uscxml/xinclude/test-xinclude-baseuri.scxml diff --git a/CMakeLists.txt b/CMakeLists.txt index 268185d..789fb2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,10 @@ if(POLICY CMP0046) # Error on non-existent dependency in add_dependencies cmake_policy(SET CMP0046 NEW) endif() +if(POLICY CMP0054) + # Escape variables in if + cmake_policy(SET CMP0054 OLD) +endif() # specify USCXML version SET(USCXML_VERSION_MAJOR "0") diff --git a/apps/uscxml-browser.cpp b/apps/uscxml-browser.cpp index 359a9a0..87b1b1d 100644 --- a/apps/uscxml-browser.cpp +++ b/apps/uscxml-browser.cpp @@ -190,7 +190,7 @@ int main(int argc, char** argv) { LOG(INFO) << "Processing " << documentURL; try { - Interpreter interpreter = Interpreter::fromURI(documentURL); + Interpreter interpreter = Interpreter::fromURL(documentURL); if (interpreter) { if (options.checking) { diff --git a/apps/uscxml-dot.cpp b/apps/uscxml-dot.cpp index e79c3f9..e72b2d4 100644 --- a/apps/uscxml-dot.cpp +++ b/apps/uscxml-dot.cpp @@ -86,7 +86,7 @@ int main(int argc, char** argv) { try { // current option has to be the interpreter's name URL inputFile(argv[optind]); - Interpreter interpreter = Interpreter::fromURI(inputFile.asString()); + Interpreter interpreter = Interpreter::fromURL(inputFile.asString()); optind++; while(optind < argc) { diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp index 62e9278..3d68242 100644 --- a/apps/uscxml-transform.cpp +++ b/apps/uscxml-transform.cpp @@ -178,7 +178,7 @@ int main(int argc, char** argv) { tmp.toAbsoluteCwd(); interpreter = Interpreter::fromXML(ss.str(), tmp); } else { - interpreter = Interpreter::fromURI(inputFile); + interpreter = Interpreter::fromURL(inputFile); } if (!interpreter) { LOG(ERROR) << "Cannot create interpreter from " << inputFile; diff --git a/contrib/local/virtualbox.sh b/contrib/local/virtualbox.sh new file mode 100755 index 0000000..905217c --- /dev/null +++ b/contrib/local/virtualbox.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# VBoxManage startvm b307622e-6b5e-4e47-a427-84760cf2312b +# +# VBoxManage --nologo guestcontrol b307622e-6b5e-4e47-a427-84760cf2312b execute --image "C:\\Program/ Files\\Internet/ Explorer\\iexplore.exe" --username RailroadGuest --password bnsf1234 --wait-exit --wait-stdout +# +# VBoxManage controlvm b307622e-6b5e-4e47-a427-84760cf2312b savestate +# +# VBoxManage showvminfo b307622e-6b5e-4e47-a427-84760cf2312b | grep State diff --git a/embedding/java/src/org/uscxml/tests/datamodel/TestDataModelAccess.java b/embedding/java/src/org/uscxml/tests/datamodel/TestDataModelAccess.java index 656bdbf..0ed1c2e 100644 --- a/embedding/java/src/org/uscxml/tests/datamodel/TestDataModelAccess.java +++ b/embedding/java/src/org/uscxml/tests/datamodel/TestDataModelAccess.java @@ -72,7 +72,7 @@ public class TestDataModelAccess { ""; Interpreter interpreter = Interpreter.fromXML(xml, ""); - interpreter.setSourceURI(TestDataModelAccess.class.getResource("").toString()); + interpreter.setSourceURL(TestDataModelAccess.class.getResource("").toString()); InterpreterState state; do { state = interpreter.step(); diff --git a/embedding/java/src/org/uscxml/tests/datamodel/TestJavaScriptDataModel.java b/embedding/java/src/org/uscxml/tests/datamodel/TestJavaScriptDataModel.java index 7cfa793..590b0b2 100644 --- a/embedding/java/src/org/uscxml/tests/datamodel/TestJavaScriptDataModel.java +++ b/embedding/java/src/org/uscxml/tests/datamodel/TestJavaScriptDataModel.java @@ -17,7 +17,7 @@ public class TestJavaScriptDataModel { // instantiate interpreter with document from file Interpreter interpreter = Interpreter - .fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/uscxml/java/test-ecmascript-datamodel.scxml"); + .fromURL("/Users/sradomski/Documents/TK/Code/uscxml/test/uscxml/java/test-ecmascript-datamodel.scxml"); // wait until interpreter has finished while (true) diff --git a/embedding/java/src/org/uscxml/tests/datamodel/TestW3CECMA.java b/embedding/java/src/org/uscxml/tests/datamodel/TestW3CECMA.java index c525fd1..89fcddd 100644 --- a/embedding/java/src/org/uscxml/tests/datamodel/TestW3CECMA.java +++ b/embedding/java/src/org/uscxml/tests/datamodel/TestW3CECMA.java @@ -30,7 +30,7 @@ public class TestW3CECMA { for (File file : filesList) { if (file.isFile() && file.getName().endsWith(".scxml")) { System.out.println("### " + file.getName() + " #####"); - Interpreter interpreter = Interpreter.fromURI(file.getAbsolutePath()); + Interpreter interpreter = Interpreter.fromURL(file.getAbsolutePath()); interpreter.setCapabilities(1); interpreter.interpret(); } diff --git a/embedding/java/src/org/uscxml/tests/invoker/factory/vxml/TestVoiceXMLInvoker.java b/embedding/java/src/org/uscxml/tests/invoker/factory/vxml/TestVoiceXMLInvoker.java index 4d14602..3d8a968 100644 --- a/embedding/java/src/org/uscxml/tests/invoker/factory/vxml/TestVoiceXMLInvoker.java +++ b/embedding/java/src/org/uscxml/tests/invoker/factory/vxml/TestVoiceXMLInvoker.java @@ -15,7 +15,7 @@ public class TestVoiceXMLInvoker { HTTPServer http = HTTPServer.getInstance(5080, 5081); URL jVoiceXMLDoc = new URL(new URL("file:"), "../../test/uscxml/test-jvoicexml.scxml"); - Interpreter interpreter = Interpreter.fromURI(jVoiceXMLDoc); + Interpreter interpreter = Interpreter.fromURL(jVoiceXMLDoc); interpreter.interpret(); } diff --git a/src/bindings/swig/java/uscxml.i b/src/bindings/swig/java/uscxml.i index 9a86c28..e9b6bf0 100644 --- a/src/bindings/swig/java/uscxml.i +++ b/src/bindings/swig/java/uscxml.i @@ -96,7 +96,7 @@ using namespace Arabica::DOM; %enddef WRAP_THROW_EXCEPTION(uscxml::Interpreter::fromXML); -WRAP_THROW_EXCEPTION(uscxml::Interpreter::fromURI); +WRAP_THROW_EXCEPTION(uscxml::Interpreter::fromURL); WRAP_THROW_EXCEPTION(uscxml::Interpreter::step); WRAP_THROW_EXCEPTION(uscxml::Interpreter::interpret); @@ -231,8 +231,8 @@ import java.net.URL; %} %typemap(javacode) uscxml::Interpreter %{ - public static Interpreter fromURI(URL uri) throws org.uscxml.InterpreterException { - return Interpreter.fromURI(uri.toString()); + public static Interpreter fromURL(URL uri) throws org.uscxml.InterpreterException { + return Interpreter.fromURL(uri.toString()); } public Map getIOProcessors() { diff --git a/src/bindings/swig/uscxml_ignores.i b/src/bindings/swig/uscxml_ignores.i index e6b7e88..e445bd9 100644 --- a/src/bindings/swig/uscxml_ignores.i +++ b/src/bindings/swig/uscxml_ignores.i @@ -38,7 +38,7 @@ %ignore uscxml::Interpreter::Interpreter(const boost::shared_ptr); %ignore uscxml::Interpreter::Interpreter(const Interpreter&); %ignore uscxml::Interpreter::getDelayQueue(); -%ignore uscxml::Interpreter::fromURI(const URL&); +%ignore uscxml::Interpreter::fromURL(const URL&); %ignore uscxml::Interpreter::fromDOM; %ignore uscxml::Interpreter::fromClone; %ignore uscxml::Interpreter::start(); @@ -51,6 +51,7 @@ %ignore uscxml::Interpreter::getDocument; %ignore uscxml::Interpreter::getImpl; %ignore uscxml::Interpreter::runOnMainThread; +%ignore uscxml::Interpreter::getBaseURL(const Arabica::DOM::Node&); %ignore uscxml::Interpreter::getHTTPServlet(); %ignore uscxml::Interpreter::getNodeSetForXPath(const std::string&); %ignore uscxml::Interpreter::isLegalConfiguration(const Arabica::XPath::NodeSet&); diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 3d068f6..cd6472b 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -308,22 +308,22 @@ void NameSpaceInfo::init(const std::map& namespaceInfo std::map::const_iterator nsIter = namespaceInfo.begin(); while(nsIter != namespaceInfo.end()) { - std::string uri = nsIter->first; + std::string url = nsIter->first; std::string prefix = nsIter->second; - if (iequals(uri, "http://www.w3.org/2005/07/scxml")) { - nsURL = uri; + if (iequals(url, "http://www.w3.org/2005/07/scxml")) { + nsURL = url; if (prefix.size() == 0) { xpathPrefix = "scxml:"; - nsContext->addNamespaceDeclaration(uri, "scxml"); + nsContext->addNamespaceDeclaration(url, "scxml"); } else { xpathPrefix = prefix + ":"; xmlNSPrefix = xpathPrefix; - nsContext->addNamespaceDeclaration(uri, prefix); - nsToPrefix[uri] = prefix; + nsContext->addNamespaceDeclaration(url, prefix); + nsToPrefix[url] = prefix; } } else { - nsContext->addNamespaceDeclaration(uri, prefix); - nsToPrefix[uri] = prefix; + nsContext->addNamespaceDeclaration(url, prefix); + nsToPrefix[url] = prefix; } nsIter++; } @@ -372,7 +372,7 @@ InterpreterImpl::InterpreterImpl() { #endif } -Interpreter Interpreter::fromDOM(const Arabica::DOM::Document& dom, const NameSpaceInfo& nameSpaceInfo, const std::string& sourceURI) { +Interpreter Interpreter::fromDOM(const Arabica::DOM::Document& dom, const NameSpaceInfo& nameSpaceInfo, const std::string& sourceURL) { tthread::lock_guard lock(_instanceMutex); boost::shared_ptr interpreterImpl = boost::shared_ptr(new INTERPRETER_IMPL); Interpreter interpreter(interpreterImpl); @@ -397,19 +397,19 @@ Interpreter Interpreter::fromDOM(const Arabica::DOM::Document& dom, return interpreter; } -Interpreter Interpreter::fromXML(const std::string& xml, const std::string& sourceURI) { +Interpreter Interpreter::fromXML(const std::string& xml, const std::string& sourceURL) { std::stringstream* ss = new std::stringstream(); (*ss) << xml; // we need an auto_ptr for arabica to assume ownership std::auto_ptr ssPtr(ss); Arabica::SAX::InputSource inputSource; inputSource.setByteStream(ssPtr); - return fromInputSource(inputSource, sourceURI); + return fromInputSource(inputSource, sourceURL); } -Interpreter Interpreter::fromURI(const std::string& uri) { - URL absUrl(uri); +Interpreter Interpreter::fromURL(const std::string& url) { + URL absUrl(url); if (!absUrl.isAbsolute()) { if (!absUrl.toAbsoluteCwd()) { ERROR_COMMUNICATION_THROW("URL is not absolute or does not have file schema"); @@ -432,14 +432,14 @@ Interpreter Interpreter::fromURI(const std::string& uri) { interpreter = fromXML(ss.str(), absUrl); } - // try to establish URI root for relative src attributes in document + // try to establish URL root for relative src attributes in document if (!interpreter) { - ERROR_PLATFORM_THROW("Cannot create interpreter from URI '" + absUrl.asString() + "'"); + ERROR_PLATFORM_THROW("Cannot create interpreter from URL '" + absUrl.asString() + "'"); } return interpreter; } -Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource& source, const std::string& sourceUri) { +Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource& source, const std::string& sourceURL) { tthread::lock_guard lock(_instanceMutex); // remove old instances @@ -460,8 +460,7 @@ Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource& if (parser.parse(source) && parser.getDocument() && parser.getDocument().hasChildNodes()) { interpreterImpl->setNameSpaceInfo(parser.nameSpace); interpreterImpl->_document = parser.getDocument(); - interpreterImpl->_baseURI = URL::asBaseURL(sourceUri); - interpreterImpl->_sourceURI = sourceUri; + interpreterImpl->_sourceURL = sourceURL; interpreterImpl->setupDOM(); } else { @@ -505,8 +504,8 @@ void InterpreterImpl::cloneFrom(InterpreterImpl* other) { setNameSpaceInfo(other->_nsInfo); - _baseURI = other->_baseURI; - _sourceURI = other->_sourceURI; + _baseURL = other->_baseURL; + _sourceURL = other->_sourceURL; setupDOM(); } @@ -734,7 +733,7 @@ InterpreterState InterpreterImpl::step(int waitForMS) { setInterpreterState(USCXML_MICROSTEPPED); } - assert(isLegalConfiguration(_configuration)); + //assert(isLegalConfiguration(_configuration)); // are there spontaneous transitions? if (!_stable) { @@ -1241,6 +1240,7 @@ void InterpreterImpl::setupDOM() { } _scxml = (Arabica::DOM::Element)scxmls.item(0); + _baseURL[_scxml] = URL::asBaseURL(_sourceURL); } if (_nsInfo.getNSContext() != NULL) @@ -1296,12 +1296,12 @@ void InterpreterImpl::resolveXIncludes() { std::map mergedNs = _nsInfo.nsInfo; std::list includeChain; - includeChain.push_back(_sourceURI); + includeChain.push_back(_sourceURL); Arabica::XPath::NodeSet xincludes = _xpath.evaluate("//" + xIncludeNS + "include", _document.getDocumentElement()).asNodeSet(); for (int i = 0; i < xincludes.size(); i++) { // recursively resolve includes - resolveXIncludes(includeChain, mergedNs, xIncludeNS, Element(xincludes[i])); + resolveXIncludes(includeChain, mergedNs, xIncludeNS, URL::asBaseURL(_sourceURL), Element(xincludes[i])); } // update NameSpaceInfo and reinit xpath resolver @@ -1310,13 +1310,19 @@ void InterpreterImpl::resolveXIncludes() { } -void InterpreterImpl::resolveXIncludes(std::list includeChain, std::map& mergedNS, const std::string& xIncludeNS, Arabica::DOM::Element xinclude) { +void InterpreterImpl::resolveXIncludes(std::list includeChain, + std::map& mergedNS, + const std::string& xIncludeNS, + const URL& baseURL, + const Arabica::DOM::Element& xinclude) { + URL src = baseURL; NodeSet newNodes; + if (HAS_ATTR(xinclude, "href")) { - URL src(ATTR(xinclude, "href")); + src = URL(ATTR(xinclude, "href")); if (!src.isAbsolute()) { - if (!src.toAbsolute(_baseURI)) { - LOG(ERROR) << "Cannot resolve relative URL '" << ATTR(xinclude, "href") << "' to absolute URL via base URL '" << _baseURI << "', trying xi:fallback"; + if (!src.toAbsolute(baseURL)) { + LOG(ERROR) << "Cannot resolve relative URL '" << ATTR(xinclude, "href") << "' to absolute URL via base URL '" << baseURL << "', trying xi:fallback"; goto TRY_WITH_FALLBACK; } } @@ -1416,9 +1422,10 @@ TRY_WITH_FALLBACK: REMOVE_AND_RECURSE: xinclude.getParentNode().removeChild(xinclude); for (int i = 0; i < newNodes.size(); i++) { + _baseURL[newNodes[i]] = URL::asBaseURL(src); Arabica::XPath::NodeSet xincludes = filterChildElements(xIncludeNS + "include", newNodes[i], true); for (int j = 0; j < xincludes.size(); j++) { - resolveXIncludes(includeChain, mergedNS, xIncludeNS, Element(xincludes[j])); + resolveXIncludes(includeChain, mergedNS, xIncludeNS, URL::asBaseURL(src), Element(xincludes[j])); } } } @@ -1609,8 +1616,8 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Element& (HAS_ATTR(element, "srcexpr"))) { std::stringstream srcContent; URL sourceURL(HAS_ATTR(element, "srcexpr") ? _dataModel.evalAsString(ATTR(element, "srcexpr")) : ATTR(element, "src")); - if (!sourceURL.toAbsolute(_baseURI)) { - LOG(ERROR) << LOCALNAME(element) << " element has relative src or srcexpr URI with no baseURI set."; + if (!sourceURL.toAbsolute(getBaseURLForNode(element))) { + LOG(ERROR) << LOCALNAME(element) << " element has relative src or srcexpr URL with no baseURL set."; return; } if (_cachedURLs.find(sourceURL.asString()) != _cachedURLs.end() && false) { @@ -1735,6 +1742,7 @@ void InterpreterImpl::send(const Arabica::DOM::Element& element) { SendRequest sendReq; // test 331 sendReq.Event::eventType = Event::EXTERNAL; + sendReq.elem = element; try { // event if (HAS_ATTR(element, "eventexpr")) { @@ -1962,12 +1970,12 @@ void InterpreterImpl::invoke(const Arabica::DOM::Element& element) source = ATTR(element, "src"); } if (source.length() > 0) { - URL srcURI(source); - if (!srcURI.toAbsolute(_baseURI)) { - LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; + URL srcURL(source); + if (!srcURL.toAbsolute(getBaseURLForNode(element))) { + LOG(ERROR) << "invoke element has relative src URL with no baseURL set."; return; } - invokeReq.src = srcURI.asString(); + invokeReq.src = srcURL.asString(); } // id @@ -2419,13 +2427,9 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element& c // --- SCRIPT -------------------------- if (HAS_ATTR(content, "src")) { URL scriptUrl(ATTR(content, "src")); - if (!scriptUrl.isAbsolute() && !_baseURI) { - LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter"; - return; - } - if (!scriptUrl.toAbsolute(_baseURI)) { - LOG(ERROR) << "Failed to convert relative script URI " << ATTR(content, "src") << " to absolute with base URI " << _baseURI.asString(); + if (!scriptUrl.toAbsolute(getBaseURLForNode(content))) { + LOG(ERROR) << "Failed to convert relative script URL " << ATTR(content, "src") << " to absolute with base URL " << getBaseURLForNode(content); return; } @@ -3360,6 +3364,20 @@ bool InterpreterImpl::isInState(const std::string& stateId) { return false; } +const URL& InterpreterImpl::getBaseURLForNode(const Arabica::DOM::Node& node) { + Arabica::DOM::Node currNode = node; + while(currNode) { + if (_baseURL.find(currNode) != _baseURL.end()) { + // speed-up subsequent lookups + _baseURL[node] = _baseURL[currNode]; + // return baseurl + return _baseURL[currNode]; + } + currNode = currNode.getParentNode(); + } + return _baseURL[_scxml]; +} + void InterpreterImpl::handleDOMEvent(Arabica::DOM::Events::Event& event) { // clear targets _cachedTargets.clear(); diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 12582cf..abccb0a 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -252,18 +252,33 @@ public: _monitors.erase(monitor); } - void setSourceURI(std::string sourceURI) { - _sourceURI = URL(sourceURI); + void setSourceURL(std::string sourceURL) { + _sourceURL = URL(sourceURL); + if (_scxml) { + URL baseURL(sourceURL); + URL::toBaseURL(baseURL); + _baseURL[_scxml] = baseURL; + } + } + + std::string getSourceURL() { + return _sourceURL.asString(); + } - URL baseURI(sourceURI); - URL::toBaseURL(baseURI); - _baseURI = baseURI; + std::string getBaseURL() { + return getBaseURLForNode(_scxml); } - std::string getBaseURI() { - return _baseURI.asString(); + + std::string getBaseURL(const Arabica::DOM::Node& refNode) { + return getBaseURLForNode(refNode); } - std::string getSourceURI() { - return _sourceURI.asString(); + + std::string getBaseURL(const std::string& xpathExpr) { + Arabica::XPath::NodeSet roots = _xpath.evaluate(xpathExpr, _scxml).asNodeSet(); + if (roots.size() > 0) { + return getBaseURLForNode(roots[0]); + } + return ""; } void setCmdLineOptions(std::map params); @@ -459,7 +474,11 @@ protected: void init(); void setupDOM(); void resolveXIncludes(); - void resolveXIncludes(std::list includeChain, std::map& mergedNS, const std::string& xIncludeNS, Arabica::DOM::Element xinclude); + void resolveXIncludes(std::list includeChain, + std::map& mergedNS, + const std::string& xIncludeNS, + const URL& baseURL, + const Arabica::DOM::Element& xinclude); virtual void setupIOProcessors(); std::list validate(); @@ -473,7 +492,7 @@ protected: virtual Arabica::XPath::NodeSet selectEventlessTransitions(); virtual Arabica::XPath::NodeSet selectTransitions(const std::string& event); virtual bool isEnabledTransition(const Arabica::DOM::Element& transition, const std::string& event); - + void setInterpreterState(InterpreterState newState); bool _stable; @@ -490,8 +509,9 @@ protected: } InterpreterState _state; - URL _baseURI; - URL _sourceURI; + + URL _sourceURL; + std::map, URL> _baseURL; // with xi:include, we might have different base URLs Arabica::DOM::Document _document; Arabica::DOM::Element _scxml; Arabica::XPath::XPath _xpath; @@ -563,7 +583,8 @@ protected: bool parentIsScxmlState(const Arabica::DOM::Element& state); IOProcessor getIOProcessor(const std::string& type); - + const URL& getBaseURLForNode(const Arabica::DOM::Node& node); + std::map _ioProcessors; std::map > _sendIds; std::map _invokers; @@ -586,10 +607,10 @@ class USCXML_API Interpreter { public: static Interpreter fromDOM(const Arabica::DOM::Document& dom, const NameSpaceInfo& nameSpaceInfo, - const std::string& sourceURI); + const std::string& sourceURL); static Interpreter fromXML(const std::string& xml, - const std::string& sourceURI); - static Interpreter fromURI(const std::string& uri); + const std::string& sourceURL); + static Interpreter fromURL(const std::string& URL); static Interpreter fromClone(const Interpreter& other); Interpreter() : _impl() {} // the empty, invalid interpreter @@ -665,14 +686,21 @@ public: return _impl->removeMonitor(monitor); } - void setSourceURI(std::string sourceURI) { - return _impl->setSourceURI(sourceURI); + void setSourceURL(std::string sourceURL) { + return _impl->setSourceURL(sourceURL); + } + std::string getSourceURL() { + return _impl->getSourceURL(); + } + + std::string getBaseURL() { + return _impl->getBaseURL(); } - std::string getSourceURI() { - return _impl->getSourceURI(); + std::string getBaseURL(const std::string& xpathExpr) { + return _impl->getBaseURL(xpathExpr); } - std::string getBaseURI() { - return _impl->getBaseURI(); + std::string getBaseURL(const Arabica::DOM::Node& refNode) { + return _impl->getBaseURL(refNode); } void setNameSpaceInfo(const NameSpaceInfo& nsInfo) { @@ -819,7 +847,7 @@ protected: return _impl->setInvokeRequest(req); } - static Interpreter fromInputSource(Arabica::SAX::InputSource& source, const std::string& sourceUri); + static Interpreter fromInputSource(Arabica::SAX::InputSource& source, const std::string& sourceURL); boost::shared_ptr _impl; static std::map > _instances; diff --git a/src/uscxml/debug/DebugSession.cpp b/src/uscxml/debug/DebugSession.cpp index d81be51..4d8fda5 100644 --- a/src/uscxml/debug/DebugSession.cpp +++ b/src/uscxml/debug/DebugSession.cpp @@ -108,7 +108,7 @@ Data DebugSession::debugPrepare(const Data& data) { if (data.hasKey("xml")) { _interpreter = Interpreter::fromXML(data.at("xml").atom, ""); } else if (data.hasKey("url")) { - _interpreter = Interpreter::fromURI(data.at("url").atom); + _interpreter = Interpreter::fromURL(data.at("url").atom); } else { _interpreter = Interpreter(); } @@ -119,7 +119,7 @@ Data DebugSession::debugPrepare(const Data& data) { _debugger->attachSession(_interpreter, shared_from_this()); if (data.hasKey("url")) { // this allows to resolve relative external reources - _interpreter.setSourceURI(data.at("url").atom); + _interpreter.setSourceURL(data.at("url").atom); } replyData.compound["status"] = Data("success", Data::VERBATIM); } else { diff --git a/src/uscxml/debug/DebuggerServlet.cpp b/src/uscxml/debug/DebuggerServlet.cpp index 49306a2..64426ff 100644 --- a/src/uscxml/debug/DebuggerServlet.cpp +++ b/src/uscxml/debug/DebuggerServlet.cpp @@ -229,7 +229,7 @@ void DebuggerServlet::processListSessions(const HTTPServer::Request& request) { Data sessionData; sessionData.compound["name"] = Data(instance->getName(), Data::VERBATIM); sessionData.compound["id"] = Data(instance->getSessionId(), Data::VERBATIM); - sessionData.compound["source"] = Data(instance->getSourceURI(), Data::VERBATIM); + sessionData.compound["source"] = Data(instance->getSourceURL(), Data::VERBATIM); sessionData.compound["xml"].node = instance->getDocument(); replyData.compound["sessions"].array.push_back(sessionData); diff --git a/src/uscxml/messages/SendRequest.h b/src/uscxml/messages/SendRequest.h index f43b856..369fc65 100644 --- a/src/uscxml/messages/SendRequest.h +++ b/src/uscxml/messages/SendRequest.h @@ -60,6 +60,7 @@ protected: std::string target; std::string type; uint32_t delayMs; + Arabica::DOM::Element elem; friend USCXML_API std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); diff --git a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp index 5b3c79c..9edd505 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp +++ b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp @@ -276,7 +276,6 @@ std::string PromelaDataModel::evalAsString(const std::string& expr) { void PromelaDataModel::assign(const Element& assignElem, const Node& node, const std::string& content) { - std::string expr; std::string key; std::string value; @@ -299,32 +298,18 @@ void PromelaDataModel::assign(const Element& assignElem, value = content; } - if (key.length() > 0) { - PromelaParser parser(key); - - // declaration is an array? - if (parser.ast->operands.size() > 0 && - parser.ast->operands.back()->operands.size() > 0 && - parser.ast->operands.back()->operands.back()->type == PML_VAR_ARRAY) { - evaluateDecl(parser.ast); - expr = content; - } else if (value.length() > 0) { - expr = key + " = " + value + ";"; - } else { - // declaration - expr = key + ";"; - } + if (value.length() == 0) + return; + + Data json = Data::fromJSON(value); + if (!json.empty()) { + // simply assign from json to key + assign(key, json); } else { - expr = content; - } - - PromelaParser parser(expr, 2, PromelaParser::PROMELA_DECL, PromelaParser::PROMELA_STMNT); - if (parser.type == PromelaParser::PROMELA_DECL) - evaluateDecl(parser.ast); - if (parser.type == PromelaParser::PROMELA_STMNT) + std::string expr = key + " = " + value; + PromelaParser parser(expr, 1, PromelaParser::PROMELA_STMNT); evaluateStmnt(parser.ast); -// parser.dump(); -// std::cout << Data::toJSON(_variables) << std::endl; + } } void PromelaDataModel::evaluateDecl(const std::string& expr) { @@ -510,9 +495,9 @@ Data PromelaDataModel::evaluateExpr(void* ast) { PromelaParserNode* lhs = *opIter++; PromelaParserNode* rhs = *opIter++; - std::cout << "-----" << std::endl; - lhs->dump(); - rhs->dump(); +// std::cout << "-----" << std::endl; +// lhs->dump(); +// rhs->dump(); Data left = evaluateExpr(lhs); Data right = evaluateExpr(rhs); @@ -548,7 +533,18 @@ void PromelaDataModel::evaluateStmnt(void* ast) { } break; } + case PML_INCR: { + PromelaParserNode* name = *opIter++; + setVariable(name, strTo(getVariable(name)) + 1); + break; + } + case PML_DECR: { + PromelaParserNode* name = *opIter++; + setVariable(name, strTo(getVariable(name)) - 1); + break; + } default: + node->dump(); ERROR_EXECUTION_THROW("No support for " + PromelaParserNode::typeToDesc(node->type) + " statement implemented"); } } @@ -714,7 +710,6 @@ void PromelaDataModel::init(const Element& dataElem, const std::string& content) { // from if (HAS_ATTR(dataElem, "id")) { - Element dataElemCopy = dataElem; std::string identifier = ATTR(dataElem, "id"); std::string type = (HAS_ATTR(dataElem, "type") ? ATTR(dataElem, "type") : "int"); std::string arrSize; @@ -725,14 +720,11 @@ void PromelaDataModel::init(const Element& dataElem, type = type.substr(0, bracketPos); } - dataElemCopy.setAttribute("id", type + " " + identifier + arrSize); - - assign(dataElemCopy, node, content); - dataElemCopy.setAttribute("id", identifier); - - return; + std::string expr = type + " " + identifier + arrSize; + PromelaParser parser(expr, 1, PromelaParser::PROMELA_DECL); + evaluateDecl(parser.ast); + } - assign(dataElem, node, content); } void PromelaDataModel::init(const std::string& location, const Data& data) { diff --git a/src/uscxml/plugins/datamodel/promela/PromelaParser.h b/src/uscxml/plugins/datamodel/promela/PromelaParser.h index 303b9be..d1683b9 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaParser.h +++ b/src/uscxml/plugins/datamodel/promela/PromelaParser.h @@ -82,7 +82,10 @@ public: Type type; Event pendingException; - + operator bool() const { + return ast != NULL; + } + protected: void init(const std::string& expr); diff --git a/src/uscxml/plugins/element/fetch/FetchElement.cpp b/src/uscxml/plugins/element/fetch/FetchElement.cpp index 9f97ca9..c042802 100644 --- a/src/uscxml/plugins/element/fetch/FetchElement.cpp +++ b/src/uscxml/plugins/element/fetch/FetchElement.cpp @@ -112,7 +112,7 @@ void FetchElement::enterElement(const Arabica::DOM::Element& node) _targetUrl = URL(_target); if (!_targetUrl.isAbsolute()) { - if (!_targetUrl.toAbsolute(_interpreter->getBaseURI())) { + if (!_targetUrl.toAbsolute(_interpreter->getBaseURL(node))) { LOG(ERROR) << "Cannot transform " << _target << " into absolute URL"; return; } diff --git a/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp b/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp index 004eb84..e813f2f 100644 --- a/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp +++ b/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp @@ -94,7 +94,7 @@ void OpenALInvoker::send(const SendRequest& req) { } URL srcURL = req.params.find("src")->second.atom; - if (!srcURL.toAbsolute(_interpreter->getBaseURI())) { + if (!srcURL.toAbsolute(_interpreter->getBaseURL(req.elem))) { LOG(ERROR) << "src URL " << req.params.find("src")->second << " is relative with no base URI set for interpreter"; return; } diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp index c808192..63d1628 100644 --- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp +++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp @@ -138,7 +138,7 @@ void DirMonInvoker::invoke(const InvokeRequest& req) { while(dirIter != req.params.upper_bound("dir")) { // this is simplified - Data might be more elaborate than a simple string atom URL url(dirIter->second.atom); - if (!url.toAbsolute(_interpreter->getBaseURI()) || !iequals(url.scheme(), "file")) { + if (!url.toAbsolute(_interpreter->getBaseURL(req.elem)) || !iequals(url.scheme(), "file")) { LOG(ERROR) << "Given directory '" << dirIter->second << "' cannot be transformed to absolute path"; } else { _dir = url.path(); diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp index dac4f99..9315185 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp @@ -394,7 +394,7 @@ void OSGInvoker::processNode(const Arabica::DOM::Element& element) } URL srcURI(filename); - if (!srcURI.toAbsolute(_interpreter->getBaseURI())) { + if (!srcURI.toAbsolute(_interpreter->getBaseURL(element))) { LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; return; } diff --git a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp index 7b45f2c..7b12ddd 100644 --- a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp +++ b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp @@ -456,7 +456,7 @@ void MilesSessionInvoker::processEventThumbnail(const std::string& origin, const testImageName << "test" << _imageSeq << ".jpeg"; URL imageURL(testImageName.str()); - imageURL.toAbsolute(_interpreter->getBaseURI()); + imageURL.toAbsolute(_interpreter->getBaseURL()); std::stringstream ssImage; ssImage << imageURL; std::string imageContent = ssImage.str(); diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 84e5520..79b1829 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -74,7 +74,7 @@ void USCXMLInvoker::cancel(const std::string sendId) { void USCXMLInvoker::invoke(const InvokeRequest& req) { _cancelled = false; if (req.src.length() > 0) { - _invokedInterpreter = Interpreter::fromURI(req.src); + _invokedInterpreter = Interpreter::fromURL(req.src); } else if (req.dom) { Arabica::DOM::DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); Arabica::DOM::Document dom = domFactory.createDocument(req.dom.getNamespaceURI(), "", 0); @@ -82,9 +82,9 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { Arabica::DOM::Node newNode = dom.importNode(req.dom, true); dom.appendChild(newNode); // TODO: where do we get the namespace from? - _invokedInterpreter = Interpreter::fromDOM(dom, _interpreter->getNameSpaceInfo(), _interpreter->getSourceURI()); + _invokedInterpreter = Interpreter::fromDOM(dom, _interpreter->getNameSpaceInfo(), _interpreter->getSourceURL()); } else if (req.content.size() > 0) { - _invokedInterpreter = Interpreter::fromXML(req.content, _interpreter->getSourceURI()); + _invokedInterpreter = Interpreter::fromXML(req.content, _interpreter->getSourceURL()); } else { LOG(ERROR) << "Cannot invoke nested SCXML interpreter, neither src attribute nor content nor DOM is given"; } diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index 61008ff..5fd325d 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -187,11 +187,11 @@ void UmundoInvoker::invoke(const InvokeRequest& req) { std::list::const_iterator typeIter = type.begin(); while(typeIter != type.end()) { URL typeURI(*typeIter); - if (typeURI.toAbsolute(_interpreter->getBaseURI())) { + if (typeURI.toAbsolute(_interpreter->getBaseURL(req.elem))) { std::string filename = typeURI.asLocalFile(".proto"); umundo::PBSerializer::addProto(filename); } else { - LOG(ERROR) << "umundo invoker has relative type src but nor baseURI set with interpreter."; + LOG(ERROR) << "umundo invoker has relative type src but no baseURI set with interpreter."; } typeIter++; } @@ -202,7 +202,7 @@ void UmundoInvoker::invoke(const InvokeRequest& req) { std::list::const_iterator typesIter = types.begin(); while(typesIter != types.end()) { URL typeURI(*typesIter); - if (typeURI.toAbsolute(_interpreter->getBaseURI())) { + if (typeURI.toAbsolute(_interpreter->getBaseURL(req.elem))) { umundo::PBSerializer::addProto(typeURI.path()); } else { LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp index 7676a37..dba8d90 100644 --- a/src/uscxml/transform/ChartToPromela.cpp +++ b/src/uscxml/transform/ChartToPromela.cpp @@ -308,10 +308,11 @@ PromelaEventSource::PromelaEventSource(const PromelaInline& source, PromelaCodeA } } } - + void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* interpreter) { PromelaParser parser(code); - +// parser.dump(); + // find all strings std::list astNodes; astNodes.push_back(parser.ast); @@ -339,6 +340,10 @@ void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* inter assignedValue = strTo(node->operands.back()->value); } } + if (node->operands.back()->type == PML_STRING) { + // remember strings for later + astNodes.push_back(node->operands.back()); + } if (node->operands.front()->type == PML_CMPND) node = node->operands.front(); if (node->operands.front()->type != PML_NAME) @@ -414,6 +419,11 @@ void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* inter _typeDefs.types[node->value].occurrences.insert(interpreter); _typeDefs.types[node->value].minValue = 0; _typeDefs.types[node->value].maxValue = 1; + // test325 + if (node->value.compare("_ioprocessors") == 0) { + addCode("_ioprocessors.scxml.location", interpreter); + } + break; } @@ -766,6 +776,7 @@ void ChartToPromela::writeTypeDefs(std::ostream& stream) { for (std::list::reverse_iterator rIter = individualDefs.rbegin(); rIter != individualDefs.rend(); rIter++) { PromelaCodeAnalyzer::PromelaTypedef currDef = *rIter; + if (currDef.types.size() == 0 || currDef.name.size() == 0) continue; @@ -1614,17 +1625,10 @@ void ChartToPromela::writeExecutableContent(std::ostream& stream, const Arabica: writeIfBlock(stream, condChain, indent); } else if(TAGNAME(nodeElem) == "assign") { - if (HAS_ATTR(nodeElem, "location")) { - stream << padding << _prefix << ATTR(nodeElem, "location") << " = "; - } - if (HAS_ATTR(nodeElem, "expr")) { - stream << ADAPT_SRC(ATTR(nodeElem, "expr")) << ";" << std::endl; - } else { - NodeSet assignTexts = filterChildType(Node_base::TEXT_NODE, nodeElem, true); - if (assignTexts.size() > 0) { - stream << ADAPT_SRC(boost::trim_copy(assignTexts[0].getNodeValue())) << ";" << std::endl; - } - } + NodeSet assignTexts = filterChildType(Node_base::TEXT_NODE, nodeElem, true); + assert(assignTexts.size() > 0); + stream << ADAPT_SRC(boost::trim_copy(assignTexts[0].getNodeValue())) << std::endl; + } else if(TAGNAME(nodeElem) == "send" || TAGNAME(nodeElem) == "raise") { std::string targetQueue; if (TAGNAME(nodeElem) == "raise") { @@ -2066,11 +2070,14 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) { // get all data elements NodeSet datas = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet(); - // NodeSet dataText = filterChildType(Node_base::TEXT_NODE, datas, true); // write their text content - stream << "/* datamodel variables for " << _prefix << " */" << std::endl; + stream << "/* data model variables" << (_prefix.size() > 0 ? " for " + _prefix : "") << " */" << std::endl; std::set processedIdentifiers; + + // automatic types + PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes(); + for (int i = 0; i < datas.size(); i++) { Node data = datas[i]; @@ -2078,23 +2085,37 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) { continue; std::string identifier = (HAS_ATTR_CAST(data, "id") ? ATTR_CAST(data, "id") : ""); - std::string expression = (HAS_ATTR_CAST(data, "expr") ? ATTR_CAST(data, "expr") : ""); - if (expression.size() == 0 && HAS_ATTR_CAST(data, "src")) { - URL dataSrc(ATTR_CAST(data, "src")); - dataSrc.toAbsolute(_baseURI); - expression = dataSrc.getInContent(); - } std::string type = boost::trim_copy(HAS_ATTR_CAST(data, "type") ? ATTR_CAST(data, "type") : ""); _dataModelVars.insert(identifier); if (processedIdentifiers.find(identifier) != processedIdentifiers.end()) continue; + processedIdentifiers.insert(identifier); if (boost::starts_with(type, "string")) { type = "int" + type.substr(6, type.length() - 6); } + + if (type.length() == 0 || type == "auto") { + if (allTypes.types.find(identifier) != allTypes.types.end()) { + type = allTypes.types[identifier].name; + } else { + LOG(ERROR) << "Automatic or no type for '" << identifier << "' but no type resolved"; + continue; + } + } + std::string arrSize; + size_t bracketPos = type.find("["); + if (bracketPos != std::string::npos) { + arrSize = type.substr(bracketPos, type.length() - bracketPos); + type = type.substr(0, bracketPos); + } + std::string decl = type + " " + _prefix + identifier + arrSize; + stream << decl << ";" << std::endl; + +#if 0 NodeSet dataText = filterChildType(Node_base::TEXT_NODE, data, true); std::string value; @@ -2128,9 +2149,11 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) { // no id but text content given stream << beautifyIndentation(value) << std::endl; } +#endif } - PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes(); + + // implicit and dynamic types std::map::iterator typeIter = allTypes.types.begin(); while(typeIter != allTypes.types.end()) { if (typeIter->second.occurrences.find(this) == typeIter->second.occurrences.end()) { @@ -2231,6 +2254,13 @@ void ChartToPromela::writeFSM(std::ostream& stream) { // transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _startState); // assert(transitions.size() == 1); + stream << std::endl << "/* global scripts */" << std::endl; + NodeSet scripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml, false); + for (int i = 0; i < scripts.size(); i++) { + writeExecutableContent(stream, scripts[i], 1); + } + stream << std::endl; + stream << "/* transition to initial state */" << std::endl; assert(_start->sortedOutgoing.size() == 1); // initial transition has to be first one for control flow at start @@ -2620,9 +2650,10 @@ void ChartToPromela::writeMain(std::ostream& stream) { stream << std::endl; stream << "init {" << std::endl; if (_varInitializers.size() > 0) { + stream << "/* initialize data model variables */" << std::endl; std::list::iterator initIter = _varInitializers.begin(); while(initIter != _varInitializers.end()) { - stream << ADAPT_SRC(beautifyIndentation(*initIter)) << std::endl; + stream << ADAPT_SRC(beautifyIndentation(*initIter, 1)) << std::endl; initIter++; } stream << std::endl; @@ -2700,8 +2731,8 @@ void ChartToPromela::initNodes() { Interpreter nested; if (HAS_ATTR_CAST(invokes[i], "src")) { URL absUrl(ATTR_CAST(invokes[i], "src")); - absUrl.toAbsolute(_baseURI); - nested = Interpreter::fromURI(absUrl); + absUrl.toAbsolute(_baseURL[_scxml]); + nested = Interpreter::fromURL(absUrl); } else { NodeSet nestedContent = InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "content", invokes[i]); @@ -2714,7 +2745,7 @@ void ChartToPromela::initNodes() { Node importRoot = nestedDoc.importNode(nestedRoot[0], true); nestedDoc.appendChild(importRoot); - nested = Interpreter::fromDOM(nestedDoc, _nsInfo, _sourceURI); + nested = Interpreter::fromDOM(nestedDoc, _nsInfo, _sourceURL); } // std::cout << invokes[i] << std::endl; @@ -2784,6 +2815,69 @@ void ChartToPromela::initNodes() { } } + // transform data / assign json into PROMELA statements + { + NodeSet asgn; + asgn.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true)); + asgn.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "assign", _scxml, true)); + + for (int i = 0; i < asgn.size(); i++) { + if (isInEmbeddedDocument(asgn[i])) + continue; + + Element asgnElem(asgn[i]); + + std::string key; + if (HAS_ATTR(asgnElem, "id")) { + key = ATTR(asgnElem, "id"); + } else if (HAS_ATTR(asgnElem, "location")) { + key = ATTR(asgnElem, "location"); + } + + if (key.length() == 0) + continue; + + std::string value; + if (HAS_ATTR(asgnElem, "expr")) { + value = ATTR(asgnElem, "expr"); + } else if (HAS_ATTR(asgnElem, "src")) { + URL absUrl(ATTR_CAST(asgnElem, "src")); + absUrl.toAbsolute(_baseURL[_scxml]); + value = absUrl.getInContent(); + } else { + NodeSet textChilds = filterChildType(Node_base::TEXT_NODE, asgnElem); + if (textChilds.size() > 0) { + for (int j = 0; j < textChilds.size(); j++) { + value += textChilds[j].getNodeValue(); + } + } + } + + boost::trim(value); + if (value.size() == 0) + continue; + + // remove all children, we will replae by suitable promela statements + while(asgnElem.hasChildNodes()) + asgnElem.removeChild(asgnElem.getFirstChild()); + + std::string newValue; + Data json = Data::fromJSON(value); + if (!json.empty()) { + newValue = dataToAssignments(key, json); + } else { + newValue = key + " = " + value + ";"; + } + newValue = sanitizeCode(newValue); + _analyzer->addCode(newValue, this); + + if (asgnElem.getLocalName() == "data") + _varInitializers.push_back(newValue); + Text newText = _document.createTextNode(newValue); + asgnElem.insertBefore(newText, Node()); + } + } + // do we need sendid / invokeid? { NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); @@ -2926,7 +3020,7 @@ void ChartToPromela::initNodes() { { NodeSet withText; withText.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml, true)); - withText.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true)); +// withText.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true)); for (int i = 0; i < withText.size(); i++) { NodeSet texts = filterChildType(Node_base::TEXT_NODE, withText[i], true); for (int j = 0; j < texts.size(); j++) { @@ -2940,6 +3034,17 @@ void ChartToPromela::initNodes() { } } } + { + NodeSet foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true); + for (int i = 0; i < foreachs.size(); i++) { + if (HAS_ATTR_CAST(foreachs[i], "index")) { + allCode.insert(ATTR_CAST(foreachs[i], "index")); + } + if (HAS_ATTR_CAST(foreachs[i], "item")) { + allCode.insert(ATTR_CAST(foreachs[i], "item")); + } + } + } for (std::set::const_iterator codeIter = allCode.begin(); codeIter != allCode.end(); codeIter++) { _analyzer->addCode(*codeIter, this); } @@ -2961,6 +3066,25 @@ void ChartToPromela::initNodes() { } } + +std::string ChartToPromela::dataToAssignments(const std::string& prefix, const Data& data) { + std::stringstream retVal; + if (data.atom.size() > 0) { + retVal << prefix << " = " << data.atom << ";" << std::endl; + } else if (data.compound.size() > 0) { + for (std::map::const_iterator cIter = data.compound.begin(); cIter != data.compound.end(); cIter++) { + retVal << dataToAssignments(prefix + "." + cIter->first, cIter->second); + } + } else if (data.array.size() > 0) { + size_t index = 0; + for(std::list::const_iterator aIter = data.array.begin(); aIter != data.array.end(); aIter++) { + retVal << dataToAssignments(prefix + "[" + toStr(index) + "]", *aIter); + index++; + } + } + return retVal.str(); +} + std::string ChartToPromela::sanitizeCode(const std::string& code) { std::string replaced = code; boost::replace_all(replaced, "\"", "'"); @@ -3000,6 +3124,9 @@ void ChartToPromela::writeProgram(std::ostream& stream) { // std::cerr << _scxml << std::endl; + stream << "/* " << _sourceURL.asString() << " */" << std::endl; + stream << std::endl; + initNodes(); for (std::map, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { diff --git a/src/uscxml/transform/ChartToPromela.h b/src/uscxml/transform/ChartToPromela.h index 2523bf6..2ee0b1a 100644 --- a/src/uscxml/transform/ChartToPromela.h +++ b/src/uscxml/transform/ChartToPromela.h @@ -324,7 +324,8 @@ protected: // std::string replaceStringsInExpression(const std::string& expr); std::string sanitizeCode(const std::string& code); - + std::string dataToAssignments(const std::string& prefix, const Data& data); + // Arabica::XPath::NodeSet _globalStates; // Arabica::DOM::Node _startState; // std::map > _states; diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in index 07ade54..c4fc9c9 100644 --- a/test/ctest/CTestCustom.ctest.in +++ b/test/ctest/CTestCustom.ctest.in @@ -67,8 +67,8 @@ set(CTEST_CUSTOM_TESTS_IGNORE # "spin/promela/test513.txt" # manual test # fail for syntax - "spin/promela/test150.scxml" # test that foreach causes a new variable to be declared - "spin/promela/test151.scxml" # test that foreach causes a new variable to be declared +# "spin/promela/test150.scxml" # test that foreach causes a new variable to be declared +# "spin/promela/test151.scxml" # test that foreach causes a new variable to be declared "spin/promela/test152.scxml" # test that an illegal array or item value causes error.execution "spin/promela/test156.scxml" # test that an error causes the foreach to stop execution "spin/promela/test224.scxml" # string operation startWith @@ -76,8 +76,8 @@ set(CTEST_CUSTOM_TESTS_IGNORE "spin/promela/test280.scxml" # late data binding / undeclared variable "spin/promela/test286.scxml" # assignment to a non-declared var causes an error "spin/promela/test294.scxml" # mixed types for event.data via donedata - "spin/promela/test302.scxml" # variable not declared - "spin/promela/test304.scxml" # variable not declared +# "spin/promela/test302.scxml" # variable not declared +# "spin/promela/test304.scxml" # variable not declared "spin/promela/test309.scxml" # 'return' as an invalid boolean expression ought to eval to false "spin/promela/test311.scxml" # assignment to a non-declared var "spin/promela/test312.scxml" # assignment of 'return' diff --git a/test/src/test-stress.cpp b/test/src/test-stress.cpp index 06c1aa6..d0b4a5c 100644 --- a/test/src/test-stress.cpp +++ b/test/src/test-stress.cpp @@ -172,7 +172,7 @@ int main(int argc, char** argv) { lastTransitionAt = time(NULL); LOG(INFO) << "Processing " << entryIter->first; - Interpreter interpreter = Interpreter::fromURI(std::string(argv[optind]) + PATH_SEPERATOR + entryIter->first); + Interpreter interpreter = Interpreter::fromURL(std::string(argv[optind]) + PATH_SEPERATOR + entryIter->first); if (interpreter) { // interpreter.setCmdLineOptions(argc, argv); diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp index e7caf6e..e2efa59 100644 --- a/test/src/test-w3c.cpp +++ b/test/src/test-w3c.cpp @@ -136,12 +136,12 @@ int main(int argc, char** argv) { Interpreter interpreter; LOG(INFO) << "Processing " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor)); if (withFlattening) { - interpreter = Interpreter::fromURI(documentURI); + interpreter = Interpreter::fromURL(documentURI); Transformer flattener = ChartToFlatSCXML::transform(interpreter); interpreter = flattener; // std::cout << interpreter.getDocument() << std::endl; } else { - interpreter = Interpreter::fromURI(documentURI); + interpreter = Interpreter::fromURL(documentURI); } if (delayFactor != 1) { diff --git a/test/uscxml/xinclude/baseuri/test-xinclude-baseuri1.include b/test/uscxml/xinclude/baseuri/test-xinclude-baseuri1.include new file mode 100644 index 0000000..4095fa8 --- /dev/null +++ b/test/uscxml/xinclude/baseuri/test-xinclude-baseuri1.include @@ -0,0 +1,6 @@ + + +