summaryrefslogtreecommitdiffstats
path: root/src/uscxml/Interpreter.cpp
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-03-28 23:28:46 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-03-28 23:28:46 (GMT)
commit2317f2bf8beb03c60463a9482dbef23540f5c1e0 (patch)
tree9983553e5289cf622e782d0132bb1810276364d2 /src/uscxml/Interpreter.cpp
parent7279ab2caf72b68126bf0c1d7e62c7d89024f9a0 (diff)
downloaduscxml-2317f2bf8beb03c60463a9482dbef23540f5c1e0.zip
uscxml-2317f2bf8beb03c60463a9482dbef23540f5c1e0.tar.gz
uscxml-2317f2bf8beb03c60463a9482dbef23540f5c1e0.tar.bz2
Refactoring and W3C tests
- Moved core of interpreter to support various versions - Added experimental setConfiguration() - There can be more than one initial state
Diffstat (limited to 'src/uscxml/Interpreter.cpp')
-rw-r--r--src/uscxml/Interpreter.cpp1350
1 files changed, 133 insertions, 1217 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 8e9165e..e59ef5f 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -19,6 +19,8 @@
#include <assert.h>
#include <algorithm>
+#include "uscxml/interpreter/InterpreterDraft6.h"
+
#define VERBOSE 0
namespace uscxml {
@@ -31,7 +33,7 @@ const std::string Interpreter::getUUID() {
return boost::lexical_cast<std::string>(uuidGen());
}
-Interpreter::Interpreter() : Arabica::SAX2DOM::Parser<std::string>() {
+Interpreter::Interpreter() {
_lastRunOnMainThread = 0;
_nsURL = "*";
_thread = NULL;
@@ -51,11 +53,9 @@ Interpreter::Interpreter() : Arabica::SAX2DOM::Parser<std::string>() {
Interpreter* Interpreter::fromDOM(const Arabica::DOM::Node<std::string>& node) {
Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
- Interpreter* interpreter = new Interpreter();
+ Interpreter* interpreter = new InterpreterDraft6();
interpreter->_document = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "scxml", 0);
interpreter->_document.appendChild(node);
- interpreter->init();
-
return interpreter;
}
@@ -80,7 +80,6 @@ Interpreter* Interpreter::fromURI(const std::string& uri) {
Interpreter* interpreter = NULL;
- // this is required for windows filenames and does not harm on unices
if (boost::iequals(absUrl.scheme(), "file")) {
Arabica::SAX::InputSource<std::string> inputSource;
inputSource.setSystemId(absUrl.path());
@@ -107,6 +106,59 @@ Interpreter* Interpreter::fromURI(const std::string& uri) {
return interpreter;
}
+Interpreter* Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& source) {
+ Interpreter* interpreter = new InterpreterDraft6();
+
+ SCXMLParser* parser = new SCXMLParser(interpreter);
+ if(!parser->parse(source) || !parser->getDocument().hasChildNodes()) {
+ if(parser->_errorHandler.errorsReported()) {
+ LOG(ERROR) << "could not parse input:";
+ LOG(ERROR) << parser->_errorHandler.errors() << std::endl;
+ } else {
+ Arabica::SAX::InputSourceResolver resolver(source, Arabica::default_string_adaptor<std::string>());
+ if (!resolver.resolve()) {
+ LOG(ERROR) << source.getSystemId() << ": no such file";
+ }
+ }
+ delete parser;
+ delete interpreter;
+ return NULL;
+ } else {
+ interpreter->_document = parser->getDocument();
+ }
+ // interpreter->init();
+ delete parser;
+ return interpreter;
+}
+
+SCXMLParser::SCXMLParser(Interpreter* interpreter) : _interpreter(interpreter) {
+ Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
+ setErrorHandler(errorHandler);
+}
+
+void SCXMLParser::startPrefixMapping(const std::string& prefix, const std::string& uri) {
+#if 0
+ std::cout << "starting prefix mapping " << prefix << ": " << uri << std::endl;
+#endif
+ if (boost::iequals(uri, "http://www.w3.org/2005/07/scxml")) {
+ _interpreter->_nsURL = uri;
+ if (prefix.size() == 0) {
+ LOG(INFO) << "Mapped default namespace to 'scxml:'";
+ _interpreter->_xpathPrefix = "scxml:";
+ _interpreter->_nsContext.addNamespaceDeclaration(uri, "scxml");
+ _interpreter->_nsToPrefix[uri] = "scxml";
+ } else {
+ _interpreter->_xpathPrefix = prefix + ":";
+ _interpreter->_xmlNSPrefix = _interpreter->_xpathPrefix;
+ _interpreter->_nsContext.addNamespaceDeclaration(uri, prefix);
+ _interpreter->_nsToPrefix[uri] = prefix;
+ }
+ } else {
+ _interpreter->_nsContext.addNamespaceDeclaration(uri, prefix);
+ _interpreter->_nsToPrefix[uri] = prefix;
+ }
+}
+
void Interpreter::setName(const std::string& name) {
if (!_running) {
_name = name;
@@ -147,83 +199,6 @@ bool Interpreter::toAbsoluteURI(URL& uri) {
return false;
}
-void Interpreter::startPrefixMapping(const std::string& prefix, const std::string& uri) {
-#if 0
- std::cout << "starting prefix mapping " << prefix << ": " << uri << std::endl;
-#endif
- if (boost::iequals(uri, "http://www.w3.org/2005/07/scxml")) {
- _nsURL = uri;
- if (prefix.size() == 0) {
- LOG(INFO) << "Mapped default namespace to 'scxml:'";
- _xpathPrefix = "scxml:";
- _nsContext.addNamespaceDeclaration(uri, "scxml");
- _nsToPrefix[uri] = "scxml";
- } else {
- _xpathPrefix = prefix + ":";
- _xmlNSPrefix = _xpathPrefix;
- _nsContext.addNamespaceDeclaration(uri, prefix);
- _nsToPrefix[uri] = prefix;
- }
- } else {
- _nsContext.addNamespaceDeclaration(uri, prefix);
- _nsToPrefix[uri] = prefix;
- }
-}
-
-Interpreter* Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& source) {
- Interpreter* interpreter = new Interpreter();
-
- Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
- interpreter->setErrorHandler(errorHandler);
- if(!interpreter->parse(source) || !interpreter->Arabica::SAX2DOM::Parser<std::string>::getDocument().hasChildNodes()) {
- if(errorHandler.errorsReported()) {
- LOG(ERROR) << "could not parse input:";
- LOG(ERROR) << errorHandler.errors() << std::endl;
- } else {
- Arabica::SAX::InputSourceResolver resolver(source, Arabica::default_string_adaptor<std::string>());
- if (!resolver.resolve()) {
- LOG(ERROR) << source.getSystemId() << ": no such file";
- }
- }
- delete interpreter;
- return NULL;
- } else {
- interpreter->_document = interpreter->Arabica::SAX2DOM::Parser<std::string>::getDocument();
- }
-// interpreter->init();
- return interpreter;
-}
-
-void Interpreter::init() {
- if (_document) {
- NodeList<std::string> scxmls = _document.getElementsByTagNameNS(_nsURL, "scxml");
- if (scxmls.getLength() > 0) {
- _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
-
- // setup xpath and check that it works
- _xpath.setNamespaceContext(_nsContext);
- Arabica::XPath::NodeSet<std::string> scxmls = _xpath.evaluate("/" + _xpathPrefix + "scxml", _document).asNodeSet();
- assert(scxmls.size() > 0);
- assert(scxmls[0] == _scxml);
-
- if (_name.length() == 0)
- _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID());
-
- normalize(_document);
-
- if (_capabilities & CAN_GENERIC_HTTP)
- _httpServlet = new InterpreterServlet(this);
-
- _sendQueue = new DelayedEventQueue();
- _sendQueue->start();
-
- } else {
- LOG(ERROR) << "Cannot find SCXML element" << std::endl;
- }
- }
- _isInitialized = true;
-}
-
Interpreter::~Interpreter() {
if (_thread) {
_running = false;
@@ -280,140 +255,34 @@ bool Interpreter::runOnMainThread(int fps, bool blocking) {
return (_thread != NULL);
}
-// see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation
-void Interpreter::interpret() {
- if (!_isInitialized)
- init();
-
- if (!_scxml)
- return;
-// dump();
-
- _sessionId = getUUID();
-
- std::string datamodelName;
- if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel"))
- datamodelName = ATTR(_scxml, "datamodel");
- if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "profile")) // SCION SCXML uses profile to specify datamodel
- datamodelName = ATTR(_scxml, "profile");
- _dataModel = Factory::createDataModel(datamodelName, this);
- if(datamodelName.length() > 0 && !_dataModel) {
- LOG(ERROR) << "No datamodel for " << datamodelName << " registered";
- }
-
- if (_dataModel) {
- _dataModel.assign("_x.args", _cmdLineOptions);
- if (_httpServlet) {
- Data data;
- data.compound["location"] = Data(_httpServlet->getURL(), Data::VERBATIM);
- _dataModel.assign("_ioprocessors['http']", data);
- }
- }
-
- setupIOProcessors();
-
- _running = true;
- _binding = (HAS_ATTR(_scxml, "binding") && boost::iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
-
- // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
-
- if (_dataModel && _binding == EARLY) {
- // initialize all data elements
- NodeSet<std::string> dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _document).asNodeSet();
- for (unsigned int i = 0; i < dataElems.size(); i++) {
- initializeData(dataElems[i]);
- }
- } else if(_dataModel) {
- // initialize current data elements
- NodeSet<std::string> topDataElems = filterChildElements(_xmlNSPrefix + "data", filterChildElements(_xmlNSPrefix + "datamodel", _scxml));
- for (unsigned int i = 0; i < topDataElems.size(); i++) {
- initializeData(topDataElems[i]);
- }
- }
-
- // executeGlobalScriptElements
- NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "script", _document).asNodeSet();
- for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
- if (_dataModel)
- executeContent(globalScriptElems[i]);
- }
-
- // initial transition might be implict
- NodeSet<std::string> initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _document).asNodeSet();
- if (initialTransitions.size() == 0) {
- Arabica::DOM::Element<std::string> initialState = (Arabica::DOM::Element<std::string>)getInitialState();
- Arabica::DOM::Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial");
- initialElem.setAttribute("generated", "true");
- Arabica::DOM::Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition");
- transitionElem.setAttribute("target", initialState.getAttribute("id"));
- initialElem.appendChild(transitionElem);
- _scxml.appendChild(initialElem);
- initialTransitions.push_back(transitionElem);
- }
- enterStates(initialTransitions);
-
-// assert(hasLegalConfiguration());
- mainEventLoop();
-
- if (_parentQueue) {
- // send one final event to unblock eventual listeners
- Event quit;
- quit.name = "done.state.scxml";
- _parentQueue->push(quit);
- }
-
- // set datamodel to null from this thread
- if(_dataModel)
- _dataModel = DataModel();
-
-}
-
-/**
- * Called with a single data element from the topmost datamodel element.
- */
-void Interpreter::initializeData(const Arabica::DOM::Node<std::string>& data) {
- if (!_dataModel) {
- LOG(ERROR) << "Cannot initialize data when no datamodel is given!";
- return;
- }
- try {
- if (!HAS_ATTR(data, "id")) {
- LOG(ERROR) << "Data element has no id!";
- return;
- }
-
- if (HAS_ATTR(data, "expr")) {
- std::string value = ATTR(data, "expr");
- _dataModel.assign(ATTR(data, "id"), value);
- } else if (HAS_ATTR(data, "src")) {
- URL srcURL(ATTR(data, "src"));
- if (!srcURL.isAbsolute())
- toAbsoluteURI(srcURL);
-
- std::stringstream ss;
- if (_cachedURLs.find(srcURL.asString()) != _cachedURLs.end()) {
- ss << _cachedURLs[srcURL.asString()];
- } else {
- ss << srcURL;
- _cachedURLs[srcURL.asString()] = srcURL;
- }
- _dataModel.assign(ATTR(data, "id"), ss.str());
-
- } else if (data.hasChildNodes()) {
- // search for the text node with the actual script
- NodeList<std::string> dataChilds = data.getChildNodes();
- for (int i = 0; i < dataChilds.getLength(); i++) {
- if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) {
- Data value = Data(dataChilds.item(i).getNodeValue());
- _dataModel.assign(ATTR(data, "id"), value);
- break;
- }
- }
+void Interpreter::init() {
+ if (_document) {
+ NodeList<std::string> scxmls = _document.getElementsByTagNameNS(_nsURL, "scxml");
+ if (scxmls.getLength() > 0) {
+ _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
+
+ // setup xpath and check that it works
+ _xpath.setNamespaceContext(_nsContext);
+ Arabica::XPath::NodeSet<std::string> scxmls = _xpath.evaluate("/" + _xpathPrefix + "scxml", _document).asNodeSet();
+ assert(scxmls.size() > 0);
+ assert(scxmls[0] == _scxml);
+
+ if (_name.length() == 0)
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID());
+
+ normalize(_document);
+
+ if (_capabilities & CAN_GENERIC_HTTP)
+ _httpServlet = new InterpreterServlet(this);
+
+ _sendQueue = new DelayedEventQueue();
+ _sendQueue->start();
+
+ } else {
+ LOG(ERROR) << "Cannot find SCXML element" << std::endl;
}
-
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl;
}
+ _isInitialized = true;
}
void Interpreter::normalize(const Arabica::DOM::Document<std::string>& node) {
@@ -476,176 +345,6 @@ void Interpreter::normalize(const Arabica::DOM::Document<std::string>& node) {
#endif
}
-void Interpreter::mainEventLoop() {
- std::set<InterpreterMonitor*>::iterator monIter;
-
- while(_running) {
- NodeSet<std::string> enabledTransitions;
- _stable = false;
-
- // Here we handle eventless transitions and transitions
- // triggered by internal events until machine is stable
- while(_running && !_stable) {
-#if 0
- std::cout << "Configuration: ";
- for (int i = 0; i < _configuration.size(); i++) {
- std::cout << ATTR(_configuration[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeMicroStep(this);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeMicroStep on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeMicroStep on monitors";
- }
- monIter++;
- }
-
- enabledTransitions = selectEventlessTransitions();
- if (enabledTransitions.size() == 0) {
- if (_internalQueue.size() == 0) {
- _stable = true;
- } else {
- _currEvent = _internalQueue.front();
- _internalQueue.pop_front();
-#if VERBOSE
- std::cout << "Received internal event " << _currEvent.name << std::endl;
-#endif
- if (_dataModel)
- _dataModel.setEvent(_currEvent);
- enabledTransitions = selectTransitions(_currEvent.name);
- }
- }
- if (!enabledTransitions.empty()) {
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeTakingTransitions(this, enabledTransitions);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeTakingTransitions on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeTakingTransitions on monitors";
- }
- monIter++;
- }
- microstep(enabledTransitions);
- }
- }
-
- for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
- NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", _statesToInvoke[i]);
- for (unsigned int j = 0; j < invokes.size(); j++) {
- invoke(invokes[j]);
- }
- }
-
- _statesToInvoke = NodeSet<std::string>();
- if (!_internalQueue.empty())
- continue;
-
- // assume that we have a legal configuration as soon as the internal queue is empty
-// assert(hasLegalConfiguration());
-
- monIter = _monitors.begin();
-// if (!_sendQueue || _sendQueue->isEmpty()) {
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->onStableConfiguration(this);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling onStableConfiguration on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling onStableConfiguration on monitors";
- }
- monIter++;
- }
-// }
-
- // whenever we have a stable configuration, run the mainThread hooks with 200fps
- while(_externalQueue.isEmpty() && _thread == NULL) {
- runOnMainThread(200);
- }
-
- _currEvent = _externalQueue.pop();
-#if VERBOSE
- std::cout << "Received externalEvent event " << _currEvent.name << std::endl;
-#endif
- _currEvent.type = Event::EXTERNAL; // make sure it is set to external
- if (!_running)
- exitInterpreter();
-
- if (_dataModel && boost::iequals(_currEvent.name, "cancel.invoke." + _sessionId))
- break;
-
- if (_dataModel)
- try {
- _dataModel.setEvent(_currEvent);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl;
- }
- for (unsigned int i = 0; i < _configuration.size(); i++) {
- NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", _configuration[i]);
- for (unsigned int j = 0; j < invokes.size(); j++) {
- Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j];
- std::string invokeId;
- if (HAS_ATTR(invokeElem, "id"))
- invokeId = ATTR(invokeElem, "id");
- if (HAS_ATTR(invokeElem, "idlocation") && _dataModel)
- invokeId = _dataModel.evalAsString(ATTR(invokeElem, "idlocation"));
-
- std::string autoForward = invokeElem.getAttribute("autoforward");
- if (boost::iequals(invokeId, _currEvent.invokeid)) {
-
- Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_xmlNSPrefix + "finalize", invokeElem);
- for (int k = 0; k < finalizes.size(); k++) {
- Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]);
- executeContent(finalizeElem);
- }
-
- }
- if (boost::iequals(autoForward, "true")) {
- try {
- _invokers[invokeId].send(_currEvent);
- } catch(...) {
- LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId;
- }
- }
- }
- }
- enabledTransitions = selectTransitions(_currEvent.name);
- if (!enabledTransitions.empty())
- microstep(enabledTransitions);
- }
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeCompletion(this);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeCompletion on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeCompletion on monitors";
- }
- monIter++;
- }
-
- exitInterpreter();
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->afterCompletion(this);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling afterCompletion on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling afterCompletion on monitors";
- }
- monIter++;
- }
-
-}
void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) {
if (!isState(state))
@@ -1075,55 +774,6 @@ void Interpreter::cancelInvoke(const Arabica::DOM::Node<std::string>& element) {
}
}
-Arabica::XPath::NodeSet<std::string> Interpreter::selectTransitions(const std::string& event) {
- Arabica::XPath::NodeSet<std::string> enabledTransitions;
-
- NodeSet<std::string> atomicStates;
- for (unsigned int i = 0; i < _configuration.size(); i++) {
- if (isAtomic(_configuration[i]))
- atomicStates.push_back(_configuration[i]);
- }
- atomicStates.to_document_order();
-
- for (unsigned int i = 0; i < atomicStates.size(); i++) {
- NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
-
- NodeSet<std::string> sortedAncestors;
- sortedAncestors.push_back(atomicStates[i]);
- sortedAncestors.insert(sortedAncestors.end(), ancestors.begin(), ancestors.end());
-
- for (unsigned int j = 0; j < sortedAncestors.size(); j++) {
- NodeSet<std::string> transitions = filterChildElements(_xmlNSPrefix + "transition", sortedAncestors[j]);
- for (unsigned int k = 0; k < transitions.size(); k++) {
- std::string eventName;
- if (HAS_ATTR(transitions[k], "event")) {
- eventName = ATTR(transitions[k], "event");
- } else if(HAS_ATTR(transitions[k], "eventexpr")) {
- if (_dataModel) {
- eventName = _dataModel.evalAsString(ATTR(transitions[k], "eventexpr"));
- } else {
- LOG(ERROR) << "Transition has eventexpr attribute with no datamodel defined";
- goto LOOP;
- }
- } else {
- goto LOOP;
- }
-
- if (eventName.length() > 0 &&
- nameMatch(eventName, event) &&
- hasConditionMatch(transitions[k])) {
- enabledTransitions.push_back(transitions[k]);
- goto LOOP;
- }
- }
- }
-LOOP:
- ;
- }
-
- enabledTransitions = filterPreempted(enabledTransitions);
- return enabledTransitions;
-}
// see: http://www.w3.org/TR/scxml/#EventDescriptors
bool Interpreter::nameMatch(const std::string& transitionEvent, const std::string& event) {
@@ -1167,49 +817,10 @@ bool Interpreter::nameMatch(const std::string& transitionEvent, const std::strin
return false;
}
-Arabica::XPath::NodeSet<std::string> Interpreter::selectEventlessTransitions() {
- Arabica::XPath::NodeSet<std::string> enabledTransitions;
-
- NodeSet<std::string> atomicStates;
- for (unsigned int i = 0; i < _configuration.size(); i++) {
- if (isAtomic(_configuration[i]))
- atomicStates.push_back(_configuration[i]);
- }
- atomicStates.to_document_order();
-
- for (unsigned int i = 0; i < atomicStates.size(); i++) {
- NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
- ancestors.push_back(atomicStates[i]);
- for (unsigned int j = 0; j < ancestors.size(); j++) {
- NodeSet<std::string> transitions = filterChildElements(_xmlNSPrefix + "transition", ancestors[j]);
- for (unsigned int k = 0; k < transitions.size(); k++) {
- if (!HAS_ATTR(transitions[k], "event") && hasConditionMatch(transitions[k])) {
- enabledTransitions.push_back(transitions[k]);
- goto LOOP;
- }
- }
-
-#if 0
- NodeSet<std::string> transitions = filterChildElements(_xmlNSPrefix + "transition", ancestors[j]);
- for (unsigned int k = 0; k < transitions.size(); k++) {
- if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) {
- enabledTransitions.push_back(transitions[k]);
- goto LOOP;
- }
- }
-#endif
- }
-LOOP:
- ;
- }
-
- enabledTransitions = filterPreempted(enabledTransitions);
- return enabledTransitions;
-}
bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional) {
- if (HAS_ATTR(conditional, "cond")) {
+ if (HAS_ATTR(conditional, "cond") && ATTR(conditional, "cond").length() > 0) {
if (!_dataModel) {
LOG(ERROR) << "Cannot check a condition without a datamodel";
return false;
@@ -1224,129 +835,6 @@ bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& condi
return true; // no condition is always true
}
-Arabica::XPath::NodeSet<std::string> Interpreter::filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- Arabica::XPath::NodeSet<std::string> filteredTransitions;
- for (unsigned int i = 0; i < enabledTransitions.size(); i++) {
- Arabica::DOM::Node<std::string> t = enabledTransitions[i];
- for (unsigned int j = i+1; j < enabledTransitions.size(); j++) {
- Arabica::DOM::Node<std::string> t2 = enabledTransitions[j];
- if (isPreemptingTransition(t2, t)) {
-#if VERBOSE
- std::cout << "Transition preempted!: " << std::endl << t2 << std::endl << t << std::endl;
-#endif
- goto LOOP;
- }
- }
- filteredTransitions.push_back(t);
-LOOP:
- ;
- }
- return filteredTransitions;
-}
-
-bool Interpreter::isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2) {
- assert(t1);
- assert(t2);
-
-#if VERBOSE
- std::cout << "Checking preemption: " << std::endl << t1 << std::endl << t2 << std::endl;
-#endif
-
-#if 1
- if (t1 == t2)
- return false;
- if (isWithinSameChild(t1) && (!isTargetless(t2) && !isWithinSameChild(t2)))
- return true;
- if (!isTargetless(t1) && !isWithinSameChild(t1))
- return true;
- return false;
-#endif
-
-#if 0
- // isPreempted from chris nuernberger
- if (isTargetless(t1))
- return false;
-
- Arabica::DOM::Node<std::string> existingRoot = getTransitionSubgraph(t1);
- Arabica::DOM::Node<std::string> nextRoot = getTransitionSubgraph(t2);
-
- if (existingRoot == nextRoot || isDescendant(existingRoot, nextRoot) || isDescendant(nextRoot, existingRoot))
- return true;
-
- return false;
-#endif
-}
-
-/**
- * filterPreempted approach from chris nuernberger
- */
-#if 0
-Arabica::DOM::Node<std::string> Interpreter::getTransitionSubgraph(const Arabica::DOM::Node<std::string>& transition) {
- Arabica::XPath::NodeSet<std::string> targets = getTargetStates(transition);
- Arabica::DOM::Node<std::string> source = getSourceState(transition);
-
- if (!targets.size() == 0)
- return source;
-
- if (boost::iequals(ATTR(transition, "type"), "internal") && isCompound(source)) {
- bool allDescendants = true;
- for (int i = 0; i < targets.size(); i++) {
- if (!isDescendant(targets[i], source)) {
- allDescendants = false;
- break;
- }
- }
- if (allDescendants)
- return source;
- }
-
- targets.push_back(source);
- return findLCCA(targets);
-}
-#endif
-
-void Interpreter::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
-#if 0
- std::cout << "Transitions: ";
- for (int i = 0; i < enabledTransitions.size(); i++) {
- std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl;
- NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]);
- for (int j = 0; j < targetSet.size(); j++) {
- std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl;
- }
- }
- std::cout << std::endl;
-#endif
-
- exitStates(enabledTransitions);
- executeTransitionContent(enabledTransitions);
- enterStates(enabledTransitions);
-}
-
-void Interpreter::exitInterpreter() {
- NodeSet<std::string> statesToExit = _configuration;
- statesToExit.to_document_order();
- statesToExit.reverse();
-
- for (int i = 0; i < statesToExit.size(); i++) {
- Arabica::XPath::NodeSet<std::string> onExitElems = filterChildElements(_xmlNSPrefix + "onexit", statesToExit[i]);
- for (int j = 0; j < onExitElems.size(); j++) {
- executeContent(onExitElems[j]);
- }
- Arabica::XPath::NodeSet<std::string> invokeElems = filterChildElements(_xmlNSPrefix + "invoke", statesToExit[i]);
- for (int j = 0; j < invokeElems.size(); j++) {
- cancelInvoke(invokeElems[j]);
- }
- if (isFinal(statesToExit[i]) && parentIsScxmlState(statesToExit[i])) {
- returnDoneEvent(statesToExit[i]);
- }
- }
- _configuration = NodeSet<std::string>();
-}
-
-void Interpreter::executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- executeContent(enabledTransitions);
-}
void Interpreter::executeContent(const NodeList<std::string>& content) {
for (unsigned int i = 0; i < content.getLength(); i++) {
@@ -1392,40 +880,32 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content)
if (HAS_ATTR(ifElem, "cond"))
std::cout << ATTR(ifElem, "cond") << std::endl;
#endif
- if(hasConditionMatch(ifElem)) {
- // condition is true, execute all content up to an elseif, else or end
- if (ifElem.hasChildNodes()) {
- NodeList<std::string> childs = ifElem.getChildNodes();
- for (unsigned int i = 0; i < childs.getLength(); i++) {
- if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "elseif") ||
- boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "else"))
+ /**
+ * A block is everything up to or between elseifs and else. Those element
+ * determine whether the block is true and its executable content executed.
+ */
+ if (ifElem.hasChildNodes()) {
+ bool blockIsTrue = hasConditionMatch(ifElem);
+ NodeList<std::string> childs = ifElem.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "elseif") ||
+ boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "else")) {
+ if (blockIsTrue) {
+ // last block was true, break here
break;
- executeContent(childs.item(i));
- }
- }
- } else {
- // condition does not match - do we have an elsif?
- if (ifElem.hasChildNodes()) {
- NodeSet<std::string> elseifElem = filterChildElements(_xmlNSPrefix + "elseif", ifElem);
- for (unsigned int i = 0; i < elseifElem.size(); i++) {
-#if 0
- if (HAS_ATTR(elseifElem[i], "cond"))
- std::cout << ATTR(elseifElem[i], "cond") << std::endl;
-#endif
- if (hasConditionMatch(elseifElem[i])) {
- executeContent(elseifElem[i].getChildNodes());
- goto ELSIF_ELEM_MATCH;
+ } else {
+ // is this block the one to execute?
+ blockIsTrue = hasConditionMatch(childs.item(i));
+ }
+ } else {
+ if (blockIsTrue) {
+ executeContent(childs.item(i));
}
}
- NodeSet<std::string> elseElem = filterChildElements(_xmlNSPrefix + "else", ifElem);
- if (elseElem.size() > 0)
- executeContent(elseElem[0].getChildNodes());
}
}
-ELSIF_ELEM_MATCH:
- ;
} else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "elseif")) {
std::cerr << "Found single elsif to evaluate!" << std::endl;
} else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "else")) {
@@ -1578,589 +1058,6 @@ ELSIF_ELEM_MATCH:
void Interpreter::returnDoneEvent(const Arabica::DOM::Node<std::string>& state) {
}
-void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- NodeSet<std::string> statesToExit;
- std::set<InterpreterMonitor*>::iterator monIter;
-
-#if VERBOSE
- std::cout << "Enabled exit transitions: " << std::endl;
- for (int i = 0; i < enabledTransitions.size(); i++) {
- std::cout << enabledTransitions[i] << std::endl;
- }
- std::cout << std::endl;
-#endif
-
- for (int i = 0; i < enabledTransitions.size(); i++) {
- Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
- if (!isTargetless(transition)) {
- std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
- NodeSet<std::string> tStates = getTargetStates(transition);
- Arabica::DOM::Node<std::string> ancestor;
- Arabica::DOM::Node<std::string> source = getSourceState(transition);
-
- bool allDescendants = true;
- for (int j = 0; j < tStates.size(); j++) {
- if (!isDescendant(tStates[j], source)) {
- allDescendants = false;
- break;
- }
- }
- if (boost::iequals(transitionType, "internal") &&
- isCompound(source) &&
- allDescendants) {
- ancestor = source;
- } else {
- NodeSet<std::string> tmpStates;
- tmpStates.push_back(source);
- tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
-
-#if VERBOSE
- std::cout << "tmpStates: ";
- for (int i = 0; i < tmpStates.size(); i++) {
- std::cout << ATTR(tmpStates[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
- ancestor = findLCCA(tmpStates);
- }
-
-#if VERBOSE
- std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl;;
-#endif
-
- for (int j = 0; j < _configuration.size(); j++) {
- if (isDescendant(_configuration[j], ancestor))
- statesToExit.push_back(_configuration[j]);
- }
- }
- }
-
-#if VERBOSE
- std::cout << "States to exit: ";
- for (int i = 0; i < statesToExit.size(); i++) {
- std::cout << LOCALNAME(statesToExit[i]) << ":" << ATTR(statesToExit[i], "id") << ", ";
- }
- std::cout << std::endl;
-
-#endif
-
- // remove statesToExit from _statesToInvoke
- std::list<Arabica::DOM::Node<std::string> > tmp;
- for (int i = 0; i < _statesToInvoke.size(); i++) {
- if (!isMember(_statesToInvoke[i], statesToExit)) {
- tmp.push_back(_statesToInvoke[i]);
- }
- }
- _statesToInvoke = NodeSet<std::string>();
- _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end());
-
- statesToExit.to_document_order();
- statesToExit.reverse();
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeExitingStates(this, statesToExit);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeExitingStates on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeExitingStates on monitors";
- }
- monIter++;
- }
-
- for (int i = 0; i < statesToExit.size(); i++) {
- NodeSet<std::string> histories = filterChildElements(_xmlNSPrefix + "history", statesToExit[i]);
- for (int j = 0; j < histories.size(); j++) {
- Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)histories[j];
- std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow");
- NodeSet<std::string> historyNodes;
- for (int k = 0; k < _configuration.size(); k++) {
- if (boost::iequals(historyType, "deep")) {
- if (isAtomic(_configuration[k]) && isDescendant(_configuration[k], statesToExit[i]))
- historyNodes.push_back(_configuration[k]);
- } else {
- if (_configuration[k].getParentNode() == statesToExit[i])
- historyNodes.push_back(_configuration[k]);
- }
- }
- _historyValue[historyElem.getAttribute("id")] = historyNodes;
-#if 0
- std::cout << "History node " << ATTR(historyElem, "id") << " contains: ";
- for (int i = 0; i < historyNodes.size(); i++) {
- std::cout << ATTR(historyNodes[i], "id") << ", ";
- }
- std::cout << std::endl;
-
-#endif
-
- }
- }
-
- for (int i = 0; i < statesToExit.size(); i++) {
- NodeSet<std::string> onExits = filterChildElements(_xmlNSPrefix + "onExit", statesToExit[i]);
- for (int j = 0; j < onExits.size(); j++) {
- Arabica::DOM::Element<std::string> onExitElem = (Arabica::DOM::Element<std::string>)onExits[j];
- executeContent(onExitElem);
- }
- NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", statesToExit[i]);
- for (int j = 0; j < invokes.size(); j++) {
- Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j];
- cancelInvoke(invokeElem);
- }
- }
-
- // remove statesToExit from _configuration
- tmp.clear();
- for (int i = 0; i < _configuration.size(); i++) {
- if (!isMember(_configuration[i], statesToExit)) {
- tmp.push_back(_configuration[i]);
- }
- }
- _configuration = NodeSet<std::string>();
- _configuration.insert(_configuration.end(), tmp.begin(), tmp.end());
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->afterExitingStates(this);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling afterExitingStates on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling afterExitingStates on monitors";
- }
- monIter++;
- }
-
-}
-
-#ifdef ORIG_ENTERSTATES
-void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- NodeSet<std::string> statesToEnter;
- NodeSet<std::string> statesForDefaultEntry;
- std::set<InterpreterMonitor*>::iterator monIter;
-
-#if VERBOSE
- std::cout << "Enabled enter transitions: " << std::endl;
- for (int i = 0; i < enabledTransitions.size(); i++) {
- std::cout << enabledTransitions[i] << std::endl;
- }
- std::cout << std::endl;
-#endif
-
- for (int i = 0; i < enabledTransitions.size(); i++) {
- Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
- if (!isTargetless(transition)) {
- std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
- NodeSet<std::string> tStates = getTargetStates(transition);
-
-#if VERBOSE
- std::cout << "Target States: ";
- for (int i = 0; i < tStates.size(); i++) {
- std::cout << ATTR(tStates[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
-
- Arabica::DOM::Node<std::string> ancestor;
- Arabica::DOM::Node<std::string> source = getSourceState(transition);
-#if VERBOSE
- std::cout << "Source States: " << ATTR(source, "id") << std::endl;
-#endif
- assert(source);
-
- bool allDescendants = true;
- for (int j = 0; j < tStates.size(); j++) {
- if (!isDescendant(tStates[j], source)) {
- allDescendants = false;
- break;
- }
- }
- if (boost::iequals(transitionType, "internal") &&
- isCompound(source) &&
- allDescendants) {
- ancestor = source;
- } else {
- NodeSet<std::string> tmpStates;
- tmpStates.push_back(source);
- tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
-
- ancestor = findLCCA(tmpStates);
- }
-
-#if VERBOSE
- std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl;
-#endif
-
- for (int j = 0; j < tStates.size(); j++) {
- addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry);
- }
-
-#if VERBOSE
- std::cout << "States to enter: ";
- for (int i = 0; i < statesToEnter.size(); i++) {
- std::cout << LOCALNAME(statesToEnter[i]) << ":" << ATTR(statesToEnter[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
-
- for (int j = 0; j < tStates.size(); j++) {
- NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor);
-
-#if VERBOSE
- std::cout << "Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": ";
- for (int i = 0; i < ancestors.size(); i++) {
- std::cout << ATTR(ancestors[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
-
- for (int k = 0; k < ancestors.size(); k++) {
- statesToEnter.push_back(ancestors[k]);
- if(isParallel(ancestors[k])) {
- NodeSet<std::string> childs = getChildStates(ancestors[k]);
- for (int l = 0; l < childs.size(); l++) {
- bool someIsDescendant = false;
- for (int m = 0; m < statesToEnter.size(); m++) {
- if (isDescendant(statesToEnter[m], childs[l])) {
- someIsDescendant = true;
- break;
- }
- }
- if (!someIsDescendant) {
- addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry);
- }
- }
- }
- }
- }
- }
- }
- statesToEnter.to_document_order();
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeEnteringStates(this, statesToEnter);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeEnteringStates on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeEnteringStates on monitors";
- }
- monIter++;
- }
-
- for (int i = 0; i < statesToEnter.size(); i++) {
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i];
- _configuration.push_back(stateElem);
- _statesToInvoke.push_back(stateElem);
- if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
- NodeSet<std::string> dataModelElems = filterChildElements(_xmlNSPrefix + "datamodel", stateElem);
- if(dataModelElems.size() > 0 && _dataModel) {
- Arabica::XPath::NodeSet<std::string> dataElems = filterChildElements(_xmlNSPrefix + "data", dataModelElems[0]);
- for (int j = 0; j < dataElems.size(); j++) {
- initializeData(dataElems[j]);
- }
- }
- stateElem.setAttribute("isFirstEntry", "");
- }
- // execute onentry executable content
- NodeSet<std::string> onEntryElems = filterChildElements(_xmlNSPrefix + "onEntry", stateElem);
- executeContent(onEntryElems);
-
- if (isMember(stateElem, statesForDefaultEntry)) {
- // execute initial transition content for compund states
- Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", stateElem).asNodeSet();
- for (int j = 0; j < transitions.size(); j++) {
- executeContent(transitions[j]);
- }
- }
-
- if (isFinal(stateElem)) {
- internalDoneSend(stateElem);
- Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode();
-
- if (isParallel(parent.getParentNode())) {
- Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode();
-
- Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent);
- bool inFinalState = true;
- for (int j = 0; j < childs.size(); j++) {
- if (!isInFinalState(childs[j])) {
- inFinalState = false;
- break;
- }
- }
- if (inFinalState) {
- internalDoneSend(parent);
- }
- }
- }
- }
- for (int i = 0; i < _configuration.size(); i++) {
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i];
- if (isFinal(stateElem) && parentIsScxmlState(stateElem)) {
- _running = false;
- _done = true;
- }
- }
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->afterEnteringStates(this);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling afterEnteringStates on monitors: " << std::endl << e << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling afterEnteringStates on monitors";
- }
- monIter++;
- }
-
-}
-
-void Interpreter::addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
- std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id");
-
-#if VERBOSE
- std::cout << "Adding state to enter: " << stateId << std::endl;
-#endif
- if (isHistory(state)) {
- if (_historyValue.find(stateId) != _historyValue.end()) {
- Arabica::XPath::NodeSet<std::string> historyValue = _historyValue[stateId];
-
-#if VERBOSE
- std::cout << "History State " << ATTR(state, "id") << ": ";
- for (int i = 0; i < historyValue.size(); i++) {
- std::cout << ATTR(historyValue[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
-
- for (int i = 0; i < historyValue.size(); i++) {
- addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry);
- NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state);
-
-#if VERBOSE
- std::cout << "Proper Ancestors: ";
- for (int i = 0; i < ancestors.size(); i++) {
- std::cout << ATTR(ancestors[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
-
- for (int j = 0; j < ancestors.size(); j++) {
- statesToEnter.push_back(ancestors[j]);
- }
- }
- } else {
- NodeSet<std::string> transitions = filterChildElements(_xmlNSPrefix + "transition", state);
- for (int i = 0; i < transitions.size(); i++) {
- NodeSet<std::string> targets = getTargetStates(transitions[i]);
- for (int j = 0; j < targets.size(); j++) {
- addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry);
-
- // Modifications from chris nuernberger
- NodeSet<std::string> ancestors = getProperAncestors(targets[j], state);
- for (int k = 0; k < ancestors.size(); k++) {
- statesToEnter.push_back(ancestors[k]);
- }
- }
- }
- }
- } else {
- statesToEnter.push_back(state);
- if (isCompound(state)) {
- statesForDefaultEntry.push_back(state);
-
- addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry);
-
-# if 0
- NodeSet<std::string> tStates = getTargetStates(getInitialState(state));
- for (int i = 0; i < tStates.size(); i++) {
- addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry);
- }
-# endif
- // addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry);
- // NodeSet<std::string> tStates = getTargetStates(getInitialState(state));
-
- } else if(isParallel(state)) {
- NodeSet<std::string> childStates = getChildStates(state);
- for (int i = 0; i < childStates.size(); i++) {
- addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry);
- }
- }
- }
-}
-#endif
-
-#ifdef ENTERSTATES_02_2013
-void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- NodeSet<std::string> statesToEnter;
- NodeSet<std::string> statesForDefaultEntry;
- std::set<InterpreterMonitor*>::iterator monIter;
-
- computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry);
- statesToEnter.sort(); // entry order is document order
- for (int i = 0; i < statesToEnter.size(); i++) {
- Arabica::DOM::Element<std::string> s = (Arabica::DOM::Element<std::string>)statesToEnter[i];
- _configuration.push_back(s);
- _statesToInvoke.push_back(s);
-
- if (_binding == LATE && ATTR(s, "isFirstEntry").size() > 0) {
- NodeSet<std::string> dataModelElems = filterChildElements(_xmlNSPrefix + "datamodel", s);
- if(dataModelElems.size() > 0 && _dataModel) {
- Arabica::XPath::NodeSet<std::string> dataElems = filterChildElements(_xmlNSPrefix + "data", dataModelElems[0]);
- for (int j = 0; j < dataElems.size(); j++) {
- initializeData(dataElems[j]);
- }
- }
- s.setAttribute("isFirstEntry", "");
- }
- executeContent(filterChildElements(_xmlNSPrefix + "onEntry", s));
- if (isMember(s, statesForDefaultEntry)) {
- executeContent(getInitialState(s)); // TODO: This part is unclear
- }
-
-#if VERBOSE
- std::cout << "Is state " << ATTR(s, "id") << " final?";
-#endif
- if (isFinal(s)) {
- if (parentIsScxmlState(s)) {
- _running = false;
- _done = true;
- } else {
- Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)s.getParentNode();
- Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode();
- internalDoneSend(parent);
-
- if (isParallel(grandParent)) {
- Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent);
- bool inFinalState = true;
- for (int j = 0; j < childs.size(); j++) {
- if (!isInFinalState(childs[j])) {
- inFinalState = false;
- break;
- }
- }
- if (inFinalState) {
- internalDoneSend(grandParent);
- }
- }
- }
- }
- }
-}
-void Interpreter::computeEntrySet(const Arabica::XPath::NodeSet<std::string>& transitions,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
- for (int i = 0; i < transitions.size(); i++) {
- NodeSet<std::string> targets = getTargetStates(transitions[i]);
- for (int j = 0; j < targets.size(); j++) {
- statesToEnter.push_back(targets[i]);
- }
- }
- for (int i = 0; i < transitions.size(); i++) {
- Arabica::DOM::Node<std::string> ancestor = getTransitionDomain(transitions[i]);
- NodeSet<std::string> targets = getTargetStates(transitions[i]);
- for (int j = 0; j < targets.size(); j++) {
- addAncestorStatesToEnter(targets[j], ancestor, statesToEnter, statesForDefaultEntry);
- }
- }
-}
-void Interpreter::addDescendentStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
- if (isHistory(state)) {
- if (_historyValue.find(ATTR(state, "id")) != _historyValue.end()) {
- Arabica::XPath::NodeSet<std::string> history = _historyValue[ATTR(state, "id")];
- for (int i = 0; i < history.size(); i++) {
- addDescendentStatesToEnter(history[i], statesToEnter, statesForDefaultEntry);
- addAncestorStatesToEnter(history[i], state.getParentNode(), statesToEnter, statesForDefaultEntry);
- }
- } else {
- NodeSet<std::string> transitions = filterChildElements(_xmlNSPrefix + "transition", state);
- for (int i = 0; i < transitions.size(); i++) {
- NodeSet<std::string> targets = getTargetStates(transitions[i]);
- for (int j = 0; j < targets.size(); j++) {
- addDescendentStatesToEnter(targets[j],statesToEnter,statesForDefaultEntry);
- addAncestorStatesToEnter(targets[j], state.getParentNode(), statesToEnter, statesForDefaultEntry);
- }
- }
- }
- } else {
- statesToEnter.push_back(state);
- if (isCompound(state)) {
- statesForDefaultEntry.push_back(state);
- Node<std::string> initial = getInitialState(state);
- addDescendentStatesToEnter(initial, statesToEnter, statesForDefaultEntry);
- addAncestorStatesToEnter(initial, state.getParentNode(), statesToEnter, statesForDefaultEntry);
- } else if (isParallel(state)) {
- NodeSet<std::string> childs = getChildStates(state);
- for (int i = 0; i < childs.size(); i++) {
- bool someAreDescendants = false;
- for (int j = 0; i < statesToEnter.size(); j++) {
- if (isDescendant(statesToEnter[j], childs[i]))
- someAreDescendants = true;
- }
- if (!someAreDescendants) {
- addDescendentStatesToEnter(childs[i], statesToEnter, statesForDefaultEntry);
- }
- }
- }
- }
-}
-
-void Interpreter::addAncestorStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- const Arabica::DOM::Node<std::string>& ancestor,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
- NodeSet<std::string> properAncs = getProperAncestors(state, ancestor);
- for (int k = 0; k < properAncs.size(); k++) {
- statesToEnter.push_back(properAncs[k]);
- if (isParallel(properAncs[k])) {
- NodeSet<std::string> childs = getChildStates(properAncs[k]);
- for (int i = 0; i < childs.size(); i++) {
- bool someAreDescendants = false;
- for (int j = 0; i < statesToEnter.size(); j++) {
- if (isDescendant(statesToEnter[j], childs[i]))
- someAreDescendants = true;
- }
- if (!someAreDescendants) {
- addDescendentStatesToEnter(childs[i], statesToEnter, statesForDefaultEntry);
- }
- }
- }
- }
-}
-
-Arabica::DOM::Node<std::string> Interpreter::getTransitionDomain(const Arabica::DOM::Node<std::string>& transition) {
- Arabica::DOM::Node<std::string> source = getSourceState(transition);
- if (isTargetless(transition)) {
- return source;
- }
-
- Arabica::XPath::NodeSet<std::string> targets = getTargetStates(transition);
- if (boost::iequals(ATTR(transition, "type"), "internal") && isCompound(source)) {
- bool allDescendants = true;
- for (int i = 0; i < targets.size(); i++) {
- if (!isDescendant(targets[i], source)) {
- allDescendants = false;
- break;
- }
- }
- if (allDescendants)
- return source;
- }
-
- targets.push_back(source);
- return findLCCA(targets);
-}
-
-#endif
-
bool Interpreter::parentIsScxmlState(Arabica::DOM::Node<std::string> state) {
Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode();
@@ -2253,6 +1150,16 @@ NEXT_ANCESTOR:
return ancestor;
}
+Arabica::XPath::NodeSet<std::string> Interpreter::getStates(const std::vector<std::string>& stateIds) {
+ Arabica::XPath::NodeSet<std::string> states;
+ std::vector<std::string>::const_iterator tokenIter = stateIds.begin();
+ while(tokenIter != stateIds.end()) {
+ states.push_back(getState(*tokenIter));
+ tokenIter++;
+ }
+ return states;
+}
+
Arabica::DOM::Node<std::string> Interpreter::getState(const std::string& stateId) {
if (_cachedStates.find(stateId) != _cachedStates.end()) {
@@ -2304,7 +1211,7 @@ Arabica::DOM::Node<std::string> Interpreter::getSourceState(const Arabica::DOM::
* attribute nor an <initial> element is specified, the SCXML Processor must use
* the first child state in document order as the default initial state.
*/
-Arabica::DOM::Node<std::string> Interpreter::getInitialState(Arabica::DOM::Node<std::string> state) {
+Arabica::XPath::NodeSet<std::string> Interpreter::getInitialStates(Arabica::DOM::Node<std::string> state) {
if (!state) {
state = _document.getFirstChild();
while(state && !isState(state))
@@ -2317,25 +1224,34 @@ Arabica::DOM::Node<std::string> Interpreter::getInitialState(Arabica::DOM::Node<
assert(isCompound(state) || isParallel(state));
+ Arabica::XPath::NodeSet<std::string> initialStates;
+
// initial attribute at element
Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
if (stateElem.hasAttribute("initial")) {
- return getState(stateElem.getAttribute("initial"));
+ return getStates(tokenizeIdRefs(stateElem.getAttribute("initial")));
}
+ Arabica::XPath::NodeSet<std::string> initStates;
+
// initial element as child - but not the implicit generated one
- NodeSet<std::string> initialStates = filterChildElements(_xmlNSPrefix + "initial", state);
- if(initialStates.size() == 1 && !boost::iequals(ATTR(initialStates[0], "generated"), "true"))
- return initialStates[0];
+ NodeSet<std::string> initElems = filterChildElements(_xmlNSPrefix + "initial", state);
+ if(initElems.size() == 1 && !boost::iequals(ATTR(initElems[0], "generated"), "true")) {
+ initStates.push_back(initialStates[0]);
+ return initStates;
+ }
// first child state
NodeList<std::string> childs = state.getChildNodes();
for (int i = 0; i < childs.getLength(); i++) {
- if (isState(childs.item(i)))
- return childs.item(i);
+ if (isState(childs.item(i))) {
+ initStates.push_back(childs.item(i));
+ return initStates;
+ }
+
}
// nothing found
- return Arabica::DOM::Node<std::string>();
+ return Arabica::XPath::NodeSet<std::string>();
}
NodeSet<std::string> Interpreter::getTargetStates(const Arabica::DOM::Node<std::string>& transition) {
@@ -2488,7 +1404,7 @@ bool Interpreter::isInitial(const Arabica::DOM::Node<std::string>& state) {
if (!isState(parent))
return true; // scxml element
- if (getInitialState(parent) == state)
+ if (isMember(state, getInitialStates(parent)))
return true; // every nested node
return false;