diff options
Diffstat (limited to 'src/uscxml/interpreter')
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.cpp | 533 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.h | 12 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterRC.cpp | 579 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterRC.cpp.deactivated | 1292 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterRC.h (renamed from src/uscxml/interpreter/InterpreterRC.h.deactivated) | 37 |
5 files changed, 598 insertions, 1855 deletions
diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index aedf516..7dcb768 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -33,460 +33,8 @@ using namespace Arabica::DOM; // see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation -InterpreterState InterpreterDraft6::interpret() { - InterpreterState state; - while(true) { - state = step(-1); - - switch (state) { - case uscxml::USCXML_FINISHED: - case uscxml::USCXML_DESTROYED: - // return as we finished - return state; - default: - - // process invokers on main thread - if(_thread == NULL) { - runOnMainThread(200); - } - - // process next step - break; - } - } - return state; -} - -// setup / fetch the documents initial transitions -NodeSet<std::string> InterpreterDraft6::getDocumentInitialTransitions() { - NodeSet<std::string> initialTransitions; - - if (_startConfiguration.size() > 0) { - // we emulate entering a given configuration by creating a pseudo deep history - Element<std::string> initHistory = _document.createElementNS(_nsInfo.nsURL, "history"); - _nsInfo.setPrefix(initHistory); - - initHistory.setAttribute("id", UUID::getUUID()); - initHistory.setAttribute("type", "deep"); - _scxml.insertBefore(initHistory, _scxml.getFirstChild()); - - std::string histId = ATTR(initHistory, "id"); - NodeSet<std::string> histStates; - for (std::list<std::string>::const_iterator stateIter = _startConfiguration.begin(); stateIter != _startConfiguration.end(); stateIter++) { - histStates.push_back(getState(*stateIter)); - } - _historyValue[histId] = histStates; - - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", histId); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); - - } else { - // try to get initial transition from initial element - initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet(); - if (initialTransitions.size() == 0) { - Arabica::XPath::NodeSet<std::string> initialStates; - // fetch per draft - initialStates = getInitialStates(); - assert(initialStates.size() > 0); - for (int i = 0; i < initialStates.size(); i++) { - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", ATTR_CAST(initialStates[i], "id")); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); - } - } - } - return initialTransitions; -} - -InterpreterState InterpreterDraft6::step(int waitForMS = 0) { - try { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - - if (_state == USCXML_FINISHED || _state == USCXML_DESTROYED) { - return _state; - } - - NodeSet<std::string> enabledTransitions; - - // setup document and interpreter - if (!_isInitialized) { - init(); // will throw - } - - if (_configuration.size() == 0) { - // goto initial configuration - NodeSet<std::string> initialTransitions = getDocumentInitialTransitions(); - assert(initialTransitions.size() > 0); - enterStates(initialTransitions); - setInterpreterState(USCXML_MICROSTEPPED); - } - - assert(isLegalConfiguration(_configuration)); - - // are there spontaneous transitions? - if (!_stable) { - enabledTransitions = selectEventlessTransitions(); - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - - setInterpreterState(USCXML_MICROSTEPPED); - return _state; - } - _stable = true; - } - - // test415 - if (_topLevelFinalReached) - goto EXIT_INTERPRETER; - - // process internal event - if (!_internalQueue.empty()) { - _currEvent = _internalQueue.front(); - _internalQueue.pop_front(); - _stable = false; - - USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent) - - _dataModel.setEvent(_currEvent); - enabledTransitions = selectTransitions(_currEvent.name); - - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - - // test 319 - even if we do not enable transitions, consider it a microstep - setInterpreterState(USCXML_MICROSTEPPED); - return _state; - - } else { - _stable = true; - } - - if (_state != USCXML_MACROSTEPPED && _state != USCXML_IDLE) - USCXML_MONITOR_CALLBACK(onStableConfiguration) - - setInterpreterState(USCXML_MACROSTEPPED); - - if (_topLevelFinalReached) - goto EXIT_INTERPRETER; - - - // when we reach a stable configuration, invoke - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - Element<std::string> invokeElem = Element<std::string>(invokes[j]); - if (!HAS_ATTR(invokeElem, "persist") || !DOMUtils::attributeIsTrue(ATTR(invokeElem, "persist"))) { - invoke(invokeElem); - } - } - } - _statesToInvoke = NodeSet<std::string>(); - - if (_externalQueue.isEmpty()) { - setInterpreterState(USCXML_IDLE); - - if (waitForMS < 0) { - // wait blockingly for an event forever - while(_externalQueue.isEmpty()) { - _condVar.wait(_mutex); - } - } - - if (waitForMS > 0) { - // wait given number of milliseconds max - uint64_t now = tthread::chrono::system_clock::now(); - uint64_t then = now + waitForMS; - while(_externalQueue.isEmpty() && now < then) { - _condVar.wait_for(_mutex, then - now); - now = tthread::chrono::system_clock::now(); - } - } - - if (_externalQueue.isEmpty()) { - return _state; - } - - setInterpreterState(USCXML_MACROSTEPPED); - } - - _currEvent = _externalQueue.pop(); - _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external - _stable = false; - - if (_topLevelFinalReached) - goto EXIT_INTERPRETER; - - USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent) - - if (iequals(_currEvent.name, "cancel.invoke." + _sessionId)) { - goto EXIT_INTERPRETER; - } - - try { - _dataModel.setEvent(_currEvent); - } catch (Event e) { - LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent; - } - - finalizeAndAutoForwardCurrentEvent(); - - // run internal processing until we reach a stable configuration again - enabledTransitions = selectTransitions(_currEvent.name); - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - - if (_topLevelFinalReached) - goto EXIT_INTERPRETER; - - return _state; - -EXIT_INTERPRETER: - USCXML_MONITOR_CALLBACK(beforeCompletion) - - exitInterpreter(); - if (_sendQueue) { - std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin(); - while(sendIter != _sendIds.end()) { - _sendQueue->cancelEvent(sendIter->first); - sendIter++; - } - } - - USCXML_MONITOR_CALLBACK(afterCompletion) - -// assert(hasLegalConfiguration()); - _mutex.unlock(); - - // remove datamodel - if(!_userSuppliedDataModel) - _dataModel = DataModel(); - - setInterpreterState(USCXML_FINISHED); - return _state; - } catch (boost::bad_weak_ptr e) { - LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl; - setInterpreterState(USCXML_DESTROYED); - return _state; - } - - // set datamodel to null from this thread - if(_dataModel) - _dataModel = DataModel(); - -} - -// process transitions until we are in a stable configuration again -void InterpreterDraft6::stabilize() { - - NodeSet<std::string> enabledTransitions; - _stable = false; - - if (_configuration.size() == 0) { - // goto initial configuration - NodeSet<std::string> initialTransitions = getDocumentInitialTransitions(); - assert(initialTransitions.size() > 0); - enterStates(initialTransitions); - } - - do { // process microsteps for enabled transitions until there are no more left - - 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 - - USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent) - - if (_dataModel) - _dataModel.setEvent(_currEvent); - enabledTransitions = selectTransitions(_currEvent.name); - } - } - - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - } while(!_internalQueue.empty() || !_stable); - - USCXML_MONITOR_CALLBACK(onStableConfiguration) - - // when we reach a stable configuration, invoke - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - Element<std::string> invokeElem = Element<std::string>(invokes[j]); - if (!HAS_ATTR(invokeElem, "persist") || !DOMUtils::attributeIsTrue(ATTR(invokeElem, "persist"))) { - invoke(invokeElem); - } - } - } - _statesToInvoke = NodeSet<std::string>(); - -} - -Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectTransitions(const std::string& event) { - Arabica::XPath::NodeSet<std::string> enabledTransitions; - - NodeSet<std::string> states; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(Element<std::string>(_configuration[i]))) - states.push_back(_configuration[i]); - } - states.to_document_order(); - -#if 0 - std::cout << "Atomic states: " << std::endl; - for (int i = 0; i < states.size(); i++) { - std::cout << states[i] << std::endl << "----" << std::endl; - } - std::cout << std::endl; -#endif - - unsigned int index = 0; - while(states.size() > index) { - NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", states[index]); - for (unsigned int k = 0; k < transitions.size(); k++) { - if (isEnabledTransition(Element<std::string>(transitions[k]), event)) { - enabledTransitions.push_back(transitions[k]); - goto LOOP; - } - } - { - Node<std::string> parent = states[index].getParentNode(); - if (parent) { - states.push_back(parent); - } - } -LOOP: - index++; - } - enabledTransitions = filterPreempted(enabledTransitions); - -#if 0 - std::cout << "Enabled transitions: " << std::endl; - for (int i = 0; i < enabledTransitions.size(); i++) { - std::cout << DOMUtils::xPathForNode(enabledTransitions[i]) << std::endl; - } - std::cout << std::endl; -#endif - - return enabledTransitions; -} - -bool InterpreterDraft6::isEnabledTransition(const Element<std::string>& transition, const std::string& event) { - std::string eventName; - if (HAS_ATTR(transition, "event")) { - eventName = ATTR(transition, "event"); - } else if(HAS_ATTR(transition, "eventexpr")) { - if (_dataModel) { - eventName = _dataModel.evalAsString(ATTR(transition, "eventexpr")); - } else { - LOG(ERROR) << "Transition has eventexpr attribute with no datamodel defined"; - return false; - } - } else { - return false; - } - - std::list<std::string> eventNames = tokenizeIdRefs(eventName); - std::list<std::string>::iterator eventIter = eventNames.begin(); - while(eventIter != eventNames.end()) { - if(nameMatch(*eventIter, event) && hasConditionMatch(transition)) { - return true; - } - eventIter++; - } - return false; -} - -Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectEventlessTransitions() { - Arabica::XPath::NodeSet<std::string> enabledTransitions; - - NodeSet<std::string> states; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(Element<std::string>(_configuration[i]))) - states.push_back(_configuration[i]); - } - states.to_document_order(); - -#if 0 - std::cout << "Atomic States: "; - for (int i = 0; i < atomicStates.size(); i++) { - std::cout << ATTR(atomicStates[i], "id") << ", "; - } - std::cout << std::endl; -#endif - - unsigned int index = 0; - while(states.size() > index) { - bool foundTransition = false; - NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", states[index]); - for (unsigned int k = 0; k < transitions.size(); k++) { - Element<std::string> transElem(transitions[k]); - if (!HAS_ATTR(transElem, "event") && hasConditionMatch(transElem)) { - enabledTransitions.push_back(transitions[k]); - foundTransition = true; - goto LOOP; - } - } - if (!foundTransition) { - Node<std::string> parent = states[index].getParentNode(); - if (parent) { - states.push_back(parent); - } - } -LOOP: - index++; - } - -#if 0 - std::cout << "Enabled eventless transitions: " << std::endl; - for (int i = 0; i < enabledTransitions.size(); i++) { - std::cout << enabledTransitions[i] << std::endl << "----" << std::endl; - } - std::cout << std::endl; -#endif - - enabledTransitions = filterPreempted(enabledTransitions); - return enabledTransitions; -} - -Arabica::XPath::NodeSet<std::string> InterpreterDraft6::filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { +Arabica::XPath::NodeSet<std::string> InterpreterDraft6::removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { Arabica::XPath::NodeSet<std::string> filteredTransitions; for (unsigned int i = 0; i < enabledTransitions.size(); i++) { Element<std::string> t(enabledTransitions[i]); @@ -566,7 +114,6 @@ bool InterpreterDraft6::isWithinParallel(const Element<std::string>& transition) _transWithinParallel[transition] = lcpa; return _transWithinParallel[transition]; - } Node<std::string> InterpreterDraft6::findLCPA(const Arabica::XPath::NodeSet<std::string>& states) { @@ -587,64 +134,6 @@ NEXT_ANCESTOR: return ancestor; } -void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { -#if VERBOSE - std::cout << "Transitions: "; - for (int i = 0; i < enabledTransitions.size(); i++) { - std::cout << ((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 << " " << ((Element<std::string>)targetSet[j]).getAttribute("id") << std::endl; - } - } - std::cout << std::endl; -#endif - - USCXML_MONITOR_CALLBACK(beforeMicroStep) - - exitStates(enabledTransitions); - - for (int i = 0; i < enabledTransitions.size(); i++) { - Element<std::string> transition(enabledTransitions[i]); - - USCXML_MONITOR_CALLBACK3(beforeTakingTransition, transition, (i + 1 < enabledTransitions.size())) - - executeContent(transition); - - USCXML_MONITOR_CALLBACK3(afterTakingTransition, transition, (i + 1 < enabledTransitions.size())) - } - - enterStates(enabledTransitions); - - USCXML_MONITOR_CALLBACK(afterMicroStep) - -} - -void InterpreterDraft6::exitInterpreter() { -#if VERBOSE - std::cout << "Exiting interpreter " << _name << std::endl; -#endif - NodeSet<std::string> statesToExit = _configuration; - statesToExit.forward(false); - statesToExit.sort(); - - for (int i = 0; i < statesToExit.size(); i++) { - Arabica::XPath::NodeSet<std::string> onExitElems = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", statesToExit[i]); - for (int j = 0; j < onExitElems.size(); j++) { - executeContent(Element<std::string>(onExitElems[j])); - } - Arabica::XPath::NodeSet<std::string> invokeElems = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); - // TODO: we ought to cancel all remaining invokers just to be sure with the persist extension - for (int j = 0; j < invokeElems.size(); j++) { - cancelInvoke(Element<std::string>(invokeElems[j])); - } - Element<std::string> stateElem(statesToExit[i]); - if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { - returnDoneEvent(statesToExit[i]); - } - } - _configuration = NodeSet<std::string>(); -} void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { @@ -737,7 +226,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e #if VERBOSE std::cout << _name << ": History node " << ATTR(historyElem, "id") << " contains: "; for (int i = 0; i < historyNodes.size(); i++) { - std::cout << ATTR(historyNodes[i], "id") << ", "; + std::cout << ATTR_CAST(historyNodes[i], "id") << ", "; } std::cout << std::endl; #endif @@ -801,7 +290,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& #if VERBOSE std::cout << _name << ": Target States: "; for (int i = 0; i < tStates.size(); i++) { - std::cout << ATTR(tStates[i], "id") << ", "; + std::cout << ATTR_CAST(tStates[i], "id") << ", "; } std::cout << std::endl; #endif @@ -809,7 +298,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& Node<std::string> ancestor; Node<std::string> source = getSourceState(transition); #if VERBOSE - std::cout << _name << ": Source States: " << ATTR(source, "id") << std::endl; + std::cout << _name << ": Source States: " << ATTR_CAST(source, "id") << std::endl; #endif assert(source); @@ -833,7 +322,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& } #if VERBOSE - std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl; + std::cout << _name << ": Ancestor: " << ATTR_CAST(ancestor, "id") << std::endl; #endif for (int j = 0; j < tStates.size(); j++) { @@ -843,7 +332,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& #if VERBOSE std::cout << _name << ": States to enter: "; for (int i = 0; i < statesToEnter.size(); i++) { - std::cout << LOCALNAME(statesToEnter[i]) << ":" << ATTR(statesToEnter[i], "id") << ", "; + std::cout << LOCALNAME(statesToEnter[i]) << ":" << ATTR_CAST(statesToEnter[i], "id") << ", "; } std::cout << std::endl; #endif @@ -852,9 +341,9 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor); #if VERBOSE - std::cout << _name << ": Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": "; + std::cout << _name << ": Proper Ancestors of " << ATTR_CAST(tStates[j], "id") << " and " << ATTR_CAST(ancestor, "id") << ": "; for (int i = 0; i < ancestors.size(); i++) { - std::cout << ATTR(ancestors[i], "id") << ", "; + std::cout << ATTR_CAST(ancestors[i], "id") << ", "; } std::cout << std::endl; #endif @@ -885,7 +374,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& #if VERBOSE std::cout << _name << ": States to enter: "; for (int i = 0; i < statesToEnter.size(); i++) { - std::cout << ATTR(statesToEnter[i], "id") << ", "; + std::cout << ATTR_CAST(statesToEnter[i], "id") << ", "; } std::cout << std::endl; #endif @@ -998,7 +487,7 @@ void InterpreterDraft6::addStatesToEnter(const Element<std::string>& state, #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 << ATTR_CAST(historyValue[i], "id") << ", "; } std::cout << std::endl; #endif @@ -1010,7 +499,7 @@ void InterpreterDraft6::addStatesToEnter(const Element<std::string>& state, #if VERBOSE std::cout << "Proper Ancestors: "; for (int i = 0; i < ancestors.size(); i++) { - std::cout << ATTR(ancestors[i], "id") << ", "; + std::cout << ATTR_CAST(ancestors[i], "id") << ", "; } std::cout << std::endl; #endif diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h index 3414e5e..6a1275b 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.h +++ b/src/uscxml/interpreter/InterpreterDraft6.h @@ -29,11 +29,7 @@ public: virtual ~InterpreterDraft6() {}; protected: - virtual InterpreterState interpret(); - virtual InterpreterState step(int blocking); - void stabilize(); - void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); void addStatesToEnter(const Arabica::DOM::Element<std::string>& state, Arabica::XPath::NodeSet<std::string>& statesToEnter, @@ -41,15 +37,9 @@ protected: Arabica::XPath::NodeSet<std::string>& defaultHistoryContent); void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - void exitInterpreter(); - Arabica::XPath::NodeSet<std::string> selectEventlessTransitions(); - Arabica::XPath::NodeSet<std::string> selectTransitions(const std::string& event); - Arabica::XPath::NodeSet<std::string> filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + Arabica::XPath::NodeSet<std::string> removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); bool isPreemptingTransition(const Arabica::DOM::Element<std::string>& t1, const Arabica::DOM::Element<std::string>& t2); - bool isEnabledTransition(const Arabica::DOM::Element<std::string>& transition, const std::string& event); - - Arabica::XPath::NodeSet<std::string> getDocumentInitialTransitions(); bool isCrossingBounds(const Arabica::DOM::Element<std::string>& transition); bool isWithinParallel(const Arabica::DOM::Element<std::string>& transition); diff --git a/src/uscxml/interpreter/InterpreterRC.cpp b/src/uscxml/interpreter/InterpreterRC.cpp new file mode 100644 index 0000000..6aea740 --- /dev/null +++ b/src/uscxml/interpreter/InterpreterRC.cpp @@ -0,0 +1,579 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "InterpreterRC.h" + +#include "uscxml/Factory.h" +#include "uscxml/concurrency/DelayedEventQueue.h" + +#include <glog/logging.h> +#include "uscxml/UUID.h" +#include "uscxml/DOMUtils.h" + +namespace uscxml { + +using namespace Arabica::XPath; +using namespace Arabica::DOM; + +size_t padding = 0; + +std::string getPadding() { + std::string pad = ""; + for (int i = 0; i < padding; i++) { + pad += " "; + } + return pad; +} + +Arabica::XPath::NodeSet<std::string> InterpreterRC::removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { + Arabica::XPath::NodeSet<std::string> filteredTransitions; + + for (unsigned int i = 0; i < enabledTransitions.size(); i++) { + Element<std::string> t1(enabledTransitions[i]); + bool t1Preempted = false; + Arabica::XPath::NodeSet<std::string> transitionsToRemove; + + for (unsigned int j = 0; j < filteredTransitions.size(); j++) { + Element<std::string> t2(enabledTransitions[j]); + if (hasIntersection(computeExitSet(t1), computeExitSet(t2))) { + if (isDescendant(getSourceState(t1), getSourceState(t2))) { + transitionsToRemove.push_back(t2); + } else { + t1Preempted = true; + break; + } + } + } + + if (!t1Preempted) { + // remove transitionsToRemove from filteredTransitions + std::list<Node<std::string> > tmp; + for (int i = 0; i < filteredTransitions.size(); i++) { + if (!isMember(filteredTransitions[i], transitionsToRemove)) { + tmp.push_back(filteredTransitions[i]); + } + } + filteredTransitions = NodeSet<std::string>(); + filteredTransitions.insert(filteredTransitions.end(), tmp.begin(), tmp.end()); + + filteredTransitions.push_back(t1); + } + } + return filteredTransitions; +} + +bool InterpreterRC::hasIntersection(const Arabica::XPath::NodeSet<std::string>& nodeSet1, const Arabica::XPath::NodeSet<std::string>& nodeSet2) { + for (unsigned int i = 0; i < nodeSet1.size(); i++) { + for (unsigned int j = 0; j < nodeSet2.size(); j++) { + if (nodeSet1[i] == nodeSet2[j]) + return true; + } + } + return false; +} + + +void InterpreterRC::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { + NodeSet<std::string> statesToExit = computeExitSet(enabledTransitions); + + // remove statesToExit from _statesToInvoke + std::list<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.forward(false); + statesToExit.sort(); + + for (int i = 0; i < statesToExit.size(); i++) { + NodeSet<std::string> histories = filterChildElements(_nsInfo.xmlNSPrefix + "history", statesToExit[i]); + for (int j = 0; j < histories.size(); j++) { + Element<std::string> historyElem = (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 (iequals(historyType, "deep")) { + if (isAtomic(Element<std::string>(_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; + } + } + + for (int i = 0; i < statesToExit.size(); i++) { + USCXML_MONITOR_CALLBACK3(beforeExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size())) + + NodeSet<std::string> onExits = filterChildElements(_nsInfo.xmlNSPrefix + "onExit", statesToExit[i]); + for (int j = 0; j < onExits.size(); j++) { + Element<std::string> onExitElem = (Element<std::string>)onExits[j]; + executeContent(onExitElem); + } + + USCXML_MONITOR_CALLBACK3(afterExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size())) + + NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); + for (int j = 0; j < invokes.size(); j++) { + Element<std::string> invokeElem = (Element<std::string>)invokes[j]; + cancelInvoke(invokeElem); + } + + // remove statesToExit[i] from _configuration - test409 + tmp.clear(); + for (int j = 0; j < _configuration.size(); j++) { + if (_configuration[j] != statesToExit[i]) { + tmp.push_back(_configuration[j]); + } + } + _configuration = NodeSet<std::string>(); + _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); + } +} + + +Arabica::XPath::NodeSet<std::string> InterpreterRC::computeExitSet(const Arabica::XPath::NodeSet<std::string>& transitions) { + NodeSet<std::string> statesToExit; + for (unsigned int i = 0; i < transitions.size(); i++) { + Element<std::string> t(transitions[i]); + if (isTargetless(t)) + continue; + Arabica::DOM::Node<std::string> domain = getTransitionDomain(t); + if (!domain) + continue; + for (unsigned int j = 0; j < _configuration.size(); j++) { + const Node<std::string>& s = _configuration[j]; + if (isDescendant(s, domain)) { + statesToExit.push_back(s); + } + } + } +#if 0 + std::cout << "computeExitSet: "; + for (int i = 0; i < statesToExit.size(); i++) { + std::cout << ATTR(statesToExit[i], "id") << " "; + } + std::cout << std::endl; +#endif + return statesToExit; +} + +Arabica::XPath::NodeSet<std::string> InterpreterRC::computeExitSet(const Arabica::DOM::Node<std::string>& transition) { + Arabica::XPath::NodeSet<std::string> transitions; + transitions.push_back(transition); + return computeExitSet(transitions); +} + + +void InterpreterRC::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { + NodeSet<std::string> statesToEnter; + NodeSet<std::string> statesForDefaultEntry; + // initialize the temporary table for default content in history states + std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent; + + computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent); + statesToEnter.to_document_order(); + + for (int i = 0; i < statesToEnter.size(); i++) { + Element<std::string> s = (Element<std::string>)statesToEnter[i]; + + USCXML_MONITOR_CALLBACK3(beforeEnteringState, s, i + 1 < statesToEnter.size()) + + _configuration.push_back(s); + _statesToInvoke.push_back(s); + + // if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) { + if (_binding == LATE && !isMember(s, _alreadyEntered)) { + NodeSet<std::string> dataModelElems = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", s); + if(dataModelElems.size() > 0 && _dataModel) { + Arabica::XPath::NodeSet<std::string> dataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", dataModelElems[0]); + for (int j = 0; j < dataElems.size(); j++) { + if (dataElems[j].getNodeType() == Node_base::ELEMENT_NODE) + initializeData(Element<std::string>(dataElems[j])); + } + } + _alreadyEntered.push_back(s); + // stateElem.setAttribute("isFirstEntry", ""); + } + // execute onentry executable content + NodeSet<std::string> onEntryElems = filterChildElements(_nsInfo.xmlNSPrefix + "onEntry", s); + executeContent(onEntryElems, false); + + USCXML_MONITOR_CALLBACK3(afterEnteringState, s, i + 1 < statesToEnter.size()) + + if (isMember(s, statesForDefaultEntry)) { + // execute initial transition content for compound states + Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", s).asNodeSet(); + executeContent(transitions); + } + if (defaultHistoryContent.find(ATTR(s, "id")) != defaultHistoryContent.end()) { + executeContent(Element<std::string>(defaultHistoryContent[ATTR(s, "id")])); + } + + if (isFinal(s)) { + internalDoneSend(s); + if (parentIsScxmlState(s)) { + _topLevelFinalReached = true; + } else { + Element<std::string> parent = (Element<std::string>)s.getParentNode(); + Element<std::string> grandParent = (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(Element<std::string>(childs[j]))) { + inFinalState = false; + break; + } + } + if (inFinalState) { + internalDoneSend(grandParent); + } + } + } + } + } +} + + +void InterpreterRC::computeEntrySet(const Arabica::XPath::NodeSet<std::string>& transitions, + NodeSet<std::string>& statesToEnter, + NodeSet<std::string>& statesForDefaultEntry, + std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { + +#if 1 + for (int i = 0; i < transitions.size(); i++) { + Element<std::string> t(transitions[i]); + + NodeSet<std::string> targets = getTargetStates(t); + +#if 1 + std::cout << "computeEntrySet: "; + for (int i = 0; i < targets.size(); i++) { + std::cout << ATTR_CAST(targets[i], "id") << " "; + } + std::cout << std::endl; +#endif + + + for (int j = 0; j < targets.size(); j++) { + Element<std::string> s = Element<std::string>(targets[j]); + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + } + + for (int j = 0; j < targets.size(); j++) { + Element<std::string> s = Element<std::string>(targets[j]); + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + } + +#if 1 + std::cout << "after addDescendantStatesToEnter: "; + for (int i = 0; i < statesToEnter.size(); i++) { + std::cout << ATTR_CAST(statesToEnter[i], "id") << " "; + } + std::cout << std::endl; +#endif + + Element<std::string> ancestor = Element<std::string>(getTransitionDomain(t)); + NodeSet<std::string> effectiveTargetStates = getEffectiveTargetStates(t); + + for (int j = 0; j < effectiveTargetStates.size(); j++) { + Element<std::string> s = Element<std::string>(effectiveTargetStates[j]); + addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + +#if 1 + std::cout << "after addAncestorStatesToEnter: "; + for (int i = 0; i < statesToEnter.size(); i++) { + std::cout << ATTR_CAST(statesToEnter[i], "id") << " "; + } + std::cout << std::endl; +#endif + + } + + + + +#else + for (int i = 0; i < transitions.size(); i++) { + Element<std::string> t(transitions[i]); + + NodeSet<std::string> targets = getTargetStates(t); + for (int j = 0; j < targets.size(); j++) { + if (!isMember(targets[j], statesToEnter)) { + std::cout << "adding: " << ATTR_CAST(anc, "id") << std::endl; + statesToEnter.push_back(targets[j]); + } + } + } + +#if 1 + std::cout << "before addDescendantStatesToEnter: "; + for (int i = 0; i < statesToEnter.size(); i++) { + std::cout << ATTR_CAST(statesToEnter[i], "id") << " "; + } + std::cout << std::endl; +#endif + + NodeSet<std::string> tmp = statesToEnter; + for (int i = 0; i < tmp.size(); i++) { + assert(tmp[i]); + addDescendantStatesToEnter(tmp[i],statesToEnter,statesForDefaultEntry, defaultHistoryContent); + } + +#if 1 + std::cout << "after addDescendantStatesToEnter: "; + for (int i = 0; i < statesToEnter.size(); i++) { + std::cout << ATTR_CAST(statesToEnter[i], "id") << " "; + } + std::cout << std::endl; +#endif + + for (int i = 0; i < transitions.size(); i++) { + Element<std::string> t = (Element<std::string>)transitions[i]; + Node<std::string> ancestor = getTransitionDomain(t); + NodeSet<std::string> targets = getTargetStates(t); + for (int j = 0; j < targets.size(); j++) { + const Node<std::string>& s = targets[j]; + addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + } + +#if 1 + std::cout << "after addAncestorStatesToEnter: "; + for (int i = 0; i < statesToEnter.size(); i++) { + std::cout << ATTR_CAST(statesToEnter[i], "id") << " "; + } + std::cout << std::endl; +#endif + +#endif +} + +Arabica::XPath::NodeSet<std::string> InterpreterRC::getEffectiveTargetStates(const Arabica::DOM::Element<std::string>& transition) { + NodeSet<std::string> effectiveTargets; + NodeSet<std::string> targets = getTargetStates(transition); + + for (int j = 0; j < targets.size(); j++) { + Element<std::string> s = Element<std::string>(targets[j]); + if (isHistory(s)) { + if (_historyValue.find(ATTR(s, "id")) != _historyValue.end()) { + targets.push_back(_historyValue["id"]); + } else { + NodeSet<std::string> histTrans = filterChildElements(_nsInfo.xmlNSPrefix + "transition", s); + // TODO: what if there are many history transitions? + if (histTrans.size() > 0) + targets.push_back(getEffectiveTargetStates(Element<std::string>(histTrans[0]))); + } + } else { + effectiveTargets.push_back(s); + } + } + + return effectiveTargets; +} + +void InterpreterRC::computeEntrySet(const Arabica::DOM::Node<std::string>& transition, + NodeSet<std::string>& statesToEnter, + NodeSet<std::string>& statesForDefaultEntry, + std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { + Arabica::XPath::NodeSet<std::string> transitions; + transitions.push_back(transition); + computeEntrySet(transitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent); +} + +void InterpreterRC::addDescendantStatesToEnter(const Arabica::DOM::Element<std::string>& state, + Arabica::XPath::NodeSet<std::string>& statesToEnter, + Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry, + std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { + + std::cout << getPadding() << "addDescendantStatesToEnter: " << ATTR(state, "id") << std::endl; + padding++; + + if (isHistory(state)) { + + std::string stateId = ATTR(state, "id"); + if (_historyValue.find(stateId) != _historyValue.end()) { + const Arabica::XPath::NodeSet<std::string>& historyValue = _historyValue[stateId]; + for (int i = 0; i < historyValue.size(); i++) { + const Element<std::string>& s = Element<std::string>(historyValue[i]); + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + + } else { + NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", state); + if (transitions.size() > 0) { + // TODO: what if there are many history transitions? + defaultHistoryContent[stateId] = transitions[0]; + } + + for (int i = 0; i < transitions.size(); i++) { + NodeSet<std::string> targets = getTargetStates(Element<std::string>(transitions[i])); + for (int j = 0; j < targets.size(); j++) { + const Element<std::string>& s = Element<std::string>(targets[i]); + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + } + } + } else { + + if (!isMember(state, statesToEnter)) { // adding an existing element invalidates old reference + std::cout << getPadding() << "adding: " << ATTR_CAST(state, "id") << std::endl; + statesToEnter.push_back(state); + } + + if (isCompound(state)) { + statesForDefaultEntry.push_back(state); + + NodeSet<std::string> targets = getInitialStates(Element<std::string>(state)); + for (int i = 0; i < targets.size(); i++) { + const Element<std::string>& s = Element<std::string>(targets[i]); + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + } + + for (int i = 0; i < targets.size(); i++) { + const Element<std::string>& s = Element<std::string>(targets[i]); + addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + + } else if(isParallel(state)) { + NodeSet<std::string> childStates = getChildStates(state); + + for (int i = 0; i < childStates.size(); i++) { + const Element<std::string>& child = Element<std::string>(childStates[i]); + + for (int j = 0; j < statesToEnter.size(); j++) { + const Node<std::string>& s = statesToEnter[j]; + if (isDescendant(s, child)) { + goto BREAK_LOOP; + } + + } + addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent); +BREAK_LOOP: + ; + } + } + } + padding--; +} + +void InterpreterRC::addAncestorStatesToEnter(const Arabica::DOM::Element<std::string>& state, + const Arabica::DOM::Element<std::string>& ancestor, + Arabica::XPath::NodeSet<std::string>& statesToEnter, + Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry, + std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { + + std::cout << getPadding() << "addAncestorStatesToEnter: " << ATTR(state, "id") << " - " << ATTR(ancestor, "id") << std::endl; + padding++; + + NodeSet<std::string> ancestors = getProperAncestors(state, ancestor); + for (int i = 0; i < ancestors.size(); i++) { + const Node<std::string>& anc = ancestors[i]; + std::cout << getPadding() << "adding: " << ATTR_CAST(anc, "id") << std::endl; + statesToEnter.push_back(anc); + if (isParallel(Element<std::string>(anc))) { + NodeSet<std::string> childStates = getChildStates(anc); + for (int j = 0; j < childStates.size(); j++) { + const Element<std::string>& child = Element<std::string>(childStates[j]); + for (int k = 0; k < statesToEnter.size(); k++) { + const Node<std::string>& s = statesToEnter[k]; + if (isDescendant(s, child)) { + goto BREAK_LOOP; + } + } + addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent); +BREAK_LOOP: + ; + } + } + } + padding--; +} + + +Arabica::DOM::Node<std::string> InterpreterRC::getTransitionDomain(const Arabica::DOM::Element<std::string>& transition) { +#if 1 + + NodeSet<std::string> tStates = getEffectiveTargetStates(transition); + Node<std::string> source = getSourceState(transition); + + if (tStates.size() == 0) { + return Arabica::DOM::Node<std::string>(); // null + } + std::string transitionType = (HAS_ATTR(transition, "type") ? ATTR(transition, "type") : "external"); + + if (iequals(transitionType, "internal") && isCompound(Element<std::string>(source))) { + for (int i = 0; i < tStates.size(); i++) { + const Node<std::string>& s = tStates[i]; + if (!isDescendant(s, source)) + goto BREAK_LOOP; + } + return source; + } + +BREAK_LOOP: + Arabica::XPath::NodeSet<std::string> states; + states.push_back(source); + states.push_back(tStates); + return findLCCA(states); + +#else + NodeSet<std::string> tStates = getTargetStates(transition); + Node<std::string> source = getSourceState(transition); + +#if 0 + std::cout << "getTransitionDomain: " << std::endl << transition << std::endl; +#endif + + if (tStates.size() == 0) { + return Arabica::DOM::Node<std::string>(); // null + } + std::string transitionType = (HAS_ATTR(transition, "type") ? ATTR(transition, "type") : "external"); + + if (iequals(transitionType, "internal") && isCompound(Element<std::string>(source))) { + for (int i = 0; i < tStates.size(); i++) { + const Node<std::string>& s = tStates[i]; + if (!isDescendant(s, source)) + goto BREAK_LOOP; + } + return source; + } +BREAK_LOOP: + ; + Arabica::XPath::NodeSet<std::string> states; + states.push_back(source); + states.push_back(tStates); + return findLCCA(states); +#endif +} + +}
\ No newline at end of file diff --git a/src/uscxml/interpreter/InterpreterRC.cpp.deactivated b/src/uscxml/interpreter/InterpreterRC.cpp.deactivated deleted file mode 100644 index 9993227..0000000 --- a/src/uscxml/interpreter/InterpreterRC.cpp.deactivated +++ /dev/null @@ -1,1292 +0,0 @@ -/** - * @file - * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#include "InterpreterRC.h" - -#include "uscxml/Factory.h" -#include "uscxml/concurrency/DelayedEventQueue.h" - -#include <glog/logging.h> -#include "uscxml/UUID.h" -#include "uscxml/DOMUtils.h" - -namespace uscxml { - -using namespace Arabica::XPath; -using namespace Arabica::DOM; - -/** -procedure interpret(doc): - if not valid(doc): failWithError() - expandScxmlSource(doc) - configuration = new OrderedSet() - statesToInvoke = new OrderedSet() - internalQueue = new Queue() - externalQueue = new BlockingQueue() - historyValue = new HashTable() - datamodel = new Datamodel(doc) - if doc.binding == "early": - initializeDatamodel(datamodel, doc) - running = true - executeGlobalScriptElement(doc) - enterStates([doc.initial.transition]) - mainEventLoop() - */ -InterpreterState InterpreterRC::interpret() { - try { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - if (!_isInitialized) - init(); - - // dump(); - - // just make sure we have a session id - assert(_sessionId.length() > 0); - - setupIOProcessors(); - - 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"); - if(datamodelName.length() > 0) { - _dataModel = _factory->createDataModel(datamodelName, this); - if (!_dataModel) { - Event e; - e.data.compound["cause"] = Data("Cannot instantiate datamodel", Data::VERBATIM); - throw e; - } - } else { - _dataModel = _factory->createDataModel("null", this); - } - if(datamodelName.length() > 0 && !_dataModel) { - LOG(ERROR) << "No datamodel for " << datamodelName << " registered"; - } - - if (_dataModel) { - _dataModel.assign("_x.args", _cmdLineOptions); - } - - _binding = (HAS_ATTR(_scxml, "binding") && 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("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet(); - for (unsigned int i = 0; i < dataElems.size(); i++) { - // do not process data elements of nested documents from invokers - if (!getAncestorElement(dataElems[i], _nsInfo.xmlNSPrefix + "invoke")) - if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) { - initializeData(Element<std::string>(dataElems[i])); - } - } - } else if(_dataModel) { - // initialize current data elements - NodeSet<std::string> topDataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", _scxml)); - for (unsigned int i = 0; i < topDataElems.size(); i++) { - if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE) - initializeData(Element<std::string>(topDataElems[i])); - } - } - - // executeGlobalScriptElements - NodeSet<std::string> globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml); - for (unsigned int i = 0; i < globalScriptElems.size(); i++) { - if (_dataModel) { - executeContent(Element<std::string>(globalScriptElems[i])); - } - } - - NodeSet<std::string> initialTransitions; - - if (_startConfiguration.size() > 0) { - // we emulate entering a given configuration by creating a pseudo deep history - Element<std::string> initHistory = _document.createElementNS(_nsInfo.nsURL, "history"); - _nsInfo.setPrefix(initHistory); - - initHistory.setAttribute("id", UUID::getUUID()); - initHistory.setAttribute("type", "deep"); - _scxml.insertBefore(initHistory, _scxml.getFirstChild()); - - std::string histId = ATTR(initHistory, "id"); - NodeSet<std::string> histStates; - for (std::list<std::string>::const_iterator stateIter = _startConfiguration.begin(); stateIter != _startConfiguration.end(); stateIter++) { - histStates.push_back(getState(*stateIter)); - } - _historyValue[histId] = histStates; - - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", histId); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); - - } else { - // try to get initial transition from initial element - initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet(); - if (initialTransitions.size() == 0) { - Arabica::XPath::NodeSet<std::string> initialStates; - // fetch per draft - initialStates = getInitialStates(); - assert(initialStates.size() > 0); - for (int i = 0; i < initialStates.size(); i++) { - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", ATTR_CAST(initialStates[i], "id")); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); - } - } - } - - assert(initialTransitions.size() > 0); - - enterStates(initialTransitions); - // _mutex.unlock(); - - // assert(hasLegalConfiguration()); - mainEventLoop(); - } catch (boost::bad_weak_ptr e) { - LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl; - } - // set datamodel to null from this thread - if(_dataModel) - _dataModel = DataModel(); - - return _state; -} - -/** -procedure mainEventLoop(): - while running: - enabledTransitions = null - macrostepDone = false - # Here we handle eventless transitions and transitions - # triggered by internal events until macrostep is complete - while running and not macrostepDone: - enabledTransitions = selectEventlessTransitions() - if enabledTransitions.isEmpty(): - if internalQueue.isEmpty(): - macrostepDone = true - else: - internalEvent = internalQueue.dequeue() - datamodel["_event"] = internalEvent - enabledTransitions = selectTransitions(internalEvent) - if not enabledTransitions.isEmpty(): - microstep(enabledTransitions.toList()) - # either we're in a final state, and we break out of the loop - if not running: - break; - # or we've completed a macrostep, so we start a new macrostep by waiting for an external event - # Here we invoke whatever needs to be invoked. The implementation of 'invoke' is platform-specific - for state in statesToInvoke: - for inv in state.invoke: - invoke(inv) - statesToInvoke.clear() - # Invoking may have raised internal error events and we iterate to handle them - if not internalQueue.isEmpty(): - continue - # A blocking wait for an external event. Alternatively, if we have been invoked - # our parent session also might cancel us. The mechanism for this is platform specific, - # but here we assume it's a special event we receive - externalEvent = externalQueue.dequeue() - if isCancelEvent(externalEvent): - running = false - continue - datamodel["_event"] = externalEvent - for state in configuration: - for inv in state.invoke: - if inv.invokeid == externalEvent.invokeid: - applyFinalize(inv, externalEvent) - if inv.autoforward: - send(inv.id, externalEvent) - enabledTransitions = selectTransitions(externalEvent) - if not enabledTransitions.isEmpty(): - microstep(enabledTransitions.toList()) - # End of outer while running loop. If we get here, we have reached a top-level final state or have been cancelled - exitInterpreter() - */ -void InterpreterRC::mainEventLoop() { - - 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) { - - enabledTransitions = selectEventlessTransitions(); - if (enabledTransitions.size() == 0) { - if (_internalQueue.size() == 0) { - _stable = true; - } else { - _currEvent = _internalQueue.front(); - _internalQueue.pop_front(); - - USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent) - - if (_dataModel) - _dataModel.setEvent(_currEvent); - enabledTransitions = selectTransitions(_currEvent.name); - } - } - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - } - - if (!_running) - goto EXIT_INTERPRETER; - - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = filterChildElements(_nsInfo.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 - if (!hasLegalConfiguration()) { - std::cout << "Illegal configuration!" << std::endl; - for (unsigned int j = 0; j < _configuration.size(); j++) { - std::cout << ATTR_CAST(_configuration[j], "id") << " "; - } - std::cout << std::endl; - } - assert(hasLegalConfiguration()); - - // if (!_sendQueue || _sendQueue->isEmpty()) { - - USCXML_MONITOR_CALLBACK(onStableConfiguration) - - // } - - _mutex.unlock(); - // whenever we have a stable configuration, run the mainThread hooks with 200fps - while(_externalQueue.isEmpty() && _thread == NULL) { - runOnMainThread(200); - } - _mutex.lock(); - - // A blocking wait for an external event. Alternatively, if we have been invoked - // our parent session also might cancel us. The mechanism for this is platform specific, - // but here we assume it's a special event we receive - - while(_externalQueue.isEmpty()) { - _condVar.wait(_mutex); - } - _currEvent = _externalQueue.pop(); -#if 0 - std::cout << "Received externalEvent event " << _currEvent.name << std::endl; -#endif - _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external - if (!_running) - goto EXIT_INTERPRETER; - - USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent) - - if (_dataModel && 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 << _currEvent; - } - } - for (unsigned int i = 0; i < _configuration.size(); i++) { - NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _configuration[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - Element<std::string> invokeElem = (Element<std::string>)invokes[j]; - std::string invokeId; - if (HAS_ATTR(invokeElem, "id")) { - invokeId = ATTR(invokeElem, "id"); - } else { - if (HAS_ATTR(invokeElem, "idlocation") && _dataModel) { - try { - invokeId = _dataModel.evalAsString(ATTR(invokeElem, "idlocation")); - } catch(Event e) { - LOG(ERROR) << "Syntax error while assigning idlocation from invoke:" << std::endl << e << std::endl; - } - } - } - std::string autoForward = invokeElem.getAttribute("autoforward"); - if (iequals(invokeId, _currEvent.invokeid)) { - - Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeElem); - for (int k = 0; k < finalizes.size(); k++) { - Element<std::string> finalizeElem = Element<std::string>(finalizes[k]); - executeContent(finalizeElem); - } - - } - if (iequals(autoForward, "true")) { - try { - // do not autoforward to invokers that send to #_parent from the SCXML IO Processor! - // Yes do so, see test229! - // if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor")) - _invokers[invokeId].send(_currEvent); - } catch(...) { - LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId; - } - } - } - } - enabledTransitions = selectTransitions(_currEvent.name); - if (!enabledTransitions.empty()) { - // test 403b - enabledTransitions.to_document_order(); - microstep(enabledTransitions); - } - } - -EXIT_INTERPRETER: - USCXML_MONITOR_CALLBACK(beforeCompletion) - - exitInterpreter(); - if (_sendQueue) { - std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin(); - while(sendIter != _sendIds.end()) { - _sendQueue->cancelEvent(sendIter->first); - sendIter++; - } - } - - USCXML_MONITOR_CALLBACK(afterCompletion) - -} - -/** -procedure exitInterpreter(): - statesToExit = configuration.toList().sort(exitOrder) - for s in statesToExit: - for content in s.onexit: - executeContent(content) - for inv in s.invoke: - cancelInvoke(inv) - configuration.delete(s) - if isFinalState(s) and isScxmlState(s.parent): - returnDoneEvent(s.donedata) - */ -void InterpreterRC::exitInterpreter() { - NodeSet<std::string> statesToExit = _configuration; - statesToExit.forward(false); - statesToExit.sort(); - - for (int i = 0; i < statesToExit.size(); i++) { - Arabica::XPath::NodeSet<std::string> onExitElems = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", statesToExit[i]); - for (int j = 0; j < onExitElems.size(); j++) { - executeContent(Element<std::string>(onExitElems[j])); - } - Arabica::XPath::NodeSet<std::string> invokeElems = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); - for (int j = 0; j < invokeElems.size(); j++) { - cancelInvoke(invokeElems[j]); - } - Element<std::string> stateElem(statesToExit[i]); - if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { - returnDoneEvent(stateElem); - } - } - _configuration = NodeSet<std::string>(); -} - -/** -function selectEventlessTransitions(): - enabledTransitions = new OrderedSet() - atomicStates = configuration.toList().filter(isAtomicState).sort(documentOrder) - for state in atomicStates: - loop: for s in [state].append(getProperAncestors(state, null)): - for t in s.transition: - if not t.event and conditionMatch(t): - enabledTransitions.add(t) - break loop - enabledTransitions = removeConflictingTransitions(enabledTransitions) - return enabledTransitions - */ -Arabica::XPath::NodeSet<std::string> InterpreterRC::selectEventlessTransitions() { - Arabica::XPath::NodeSet<std::string> enabledTransitions; - - NodeSet<std::string> atomicStates; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(Element<std::string>(_configuration[i]))) - atomicStates.push_back(_configuration[i]); - } - atomicStates.to_document_order(); - - for (unsigned int i = 0; i < atomicStates.size(); i++) { - const Node<std::string>& state = atomicStates[i]; - NodeSet<std::string> withAncestors; - withAncestors.push_back(state); - withAncestors.push_back(getProperAncestors(state, Node<std::string>())); - for (unsigned int j = 0; j < withAncestors.size(); j++) { - const Node<std::string>& ancestor = withAncestors[i]; - NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", ancestor); - for (unsigned int k = 0; k < transitions.size(); k++) { - Element<std::string> transElem(transitions[k]); - if (!HAS_ATTR(transElem, "event") && hasConditionMatch(transElem)) { - enabledTransitions.push_back(transitions[k]); - goto BREAK_LOOP; - } - } - } -BREAK_LOOP: - ; - } - - enabledTransitions = removeConflictingTransitions(enabledTransitions); - return enabledTransitions; -} - -/** -function selectTransitions(event): - enabledTransitions = new OrderedSet() - atomicStates = configuration.toList().filter(isAtomicState).sort(documentOrder) - for state in atomicStates: - loop: for s in [state].append(getProperAncestors(state, null)): - for t in s.transition: - if t.event and nameMatch(t.event, event.name) and conditionMatch(t): - enabledTransitions.add(t) - break loop - enabledTransitions = removeConflictingTransitions(enabledTransitions) - return enabledTransitions - */ -Arabica::XPath::NodeSet<std::string> InterpreterRC::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(Element<std::string>(_configuration[i]))) - atomicStates.push_back(_configuration[i]); - } - atomicStates.to_document_order(); - -#if 0 - std::cout << "selectTransitions for " << event << "========" << std::endl; -#endif - for (unsigned int i = 0; i < atomicStates.size(); i++) { - const Node<std::string>& state = atomicStates[i]; -#if 0 - std::cout << " == from " << ATTR(state, "id") << std::endl; -#endif - - NodeSet<std::string> withAncestors; - withAncestors.push_back(state); - withAncestors.push_back(getProperAncestors(state, Node<std::string>())); - for (unsigned int j = 0; j < withAncestors.size(); j++) { - const Node<std::string>& ancestor = withAncestors[j]; - NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", ancestor); - for (unsigned int k = 0; k < transitions.size(); k++) { - if (isEnabledTransition(Element<std::string>(transitions[k]), event)) { - enabledTransitions.push_back(transitions[k]); - goto BREAK_LOOP; - } - } - } -BREAK_LOOP: - ; - } - - enabledTransitions = removeConflictingTransitions(enabledTransitions); - -#if 0 - std::cout << "enabledTransitions ========" << std::endl; - for (unsigned int k = 0; k < enabledTransitions.size(); k++) { - std::cout << enabledTransitions[k]; - } - std::cout << std::endl; - std::cout << "======== enabledTransitions" << std::endl; -#endif - return enabledTransitions; -} - -bool InterpreterRC::isEnabledTransition(const Element<std::string>& transition, const std::string& event) { - std::string eventName; - if (HAS_ATTR(transition, "event")) { - eventName = ATTR(transition, "event"); - } else if(HAS_ATTR(transition, "eventexpr")) { - if (_dataModel) { - eventName = _dataModel.evalAsString(ATTR(transition, "eventexpr")); - } else { - LOG(ERROR) << "Transition has eventexpr attribute with no datamodel defined"; - return false; - } - } else { - return false; - } - - std::list<std::string> eventNames = tokenizeIdRefs(eventName); - std::list<std::string>::iterator eventIter = eventNames.begin(); - while(eventIter != eventNames.end()) { - if(nameMatch(*eventIter, event) && hasConditionMatch(transition)) { - return true; - } - eventIter++; - } - return false; -} - - -/** -function removeConflictingTransitions(enabledTransitions): - filteredTransitions = new OrderedSet() - // toList sorts the transitions in the order of the states that selected them - for t1 in enabledTransitions.toList(): - t1Preempted = false; - transitionsToRemove = new OrderedSet() - for t2 in filteredTransitions.toList(): - if computeExitSet([t1]).hasIntersection(computeExitSet([t2])): - if isDescendant(t1.source, t2.source): - transitionsToRemove.add(t2) - else: - t1Preempted = true - break - if not t1Preempted: - for t3 in transitionsToRemove.toList(): - filteredTransitions.delete(t3) - filteredTransitions.add(t1) - - return filteredTransitions - */ -Arabica::XPath::NodeSet<std::string> InterpreterRC::removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - Arabica::XPath::NodeSet<std::string> filteredTransitions; - - for (unsigned int i = 0; i < enabledTransitions.size(); i++) { - Element<std::string> t1(enabledTransitions[i]); - bool t1Preempted = false; - Arabica::XPath::NodeSet<std::string> transitionsToRemove; - - for (unsigned int j = 0; j < filteredTransitions.size(); j++) { - Element<std::string> t2(enabledTransitions[j]); - if (hasIntersection(computeExitSet(t1), computeExitSet(t2))) { - if (isDescendant(getSourceState(t1), getSourceState(t2))) { - transitionsToRemove.push_back(t2); - } else { - t1Preempted = true; - break; - } - } - } - - if (!t1Preempted) { - // remove transitionsToRemove from filteredTransitions - std::list<Node<std::string> > tmp; - for (int i = 0; i < filteredTransitions.size(); i++) { - if (!isMember(filteredTransitions[i], transitionsToRemove)) { - tmp.push_back(filteredTransitions[i]); - } - } - filteredTransitions = NodeSet<std::string>(); - filteredTransitions.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); - - filteredTransitions.push_back(t1); - } - } - return filteredTransitions; -} - -bool InterpreterRC::hasIntersection(const Arabica::XPath::NodeSet<std::string>& nodeSet1, const Arabica::XPath::NodeSet<std::string>& nodeSet2) { - for (unsigned int i = 0; i < nodeSet1.size(); i++) { - for (unsigned int j = 0; j < nodeSet2.size(); j++) { - if (nodeSet1[i] == nodeSet2[j]) - return true; - } - } - return false; -} - -/** -procedure microstep(enabledTransitions): - exitStates(enabledTransitions) - executeTransitionContent(enabledTransitions) - enterStates(enabledTransitions) - */ -void InterpreterRC::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - - USCXML_MONITOR_CALLBACK(beforeMicroStep) - - exitStates(enabledTransitions); - - for (int i = 0; i < enabledTransitions.size(); i++) { - Element<std::string> transition(enabledTransitions[i]); - - USCXML_MONITOR_CALLBACK3(beforeTakingTransition, transition, (i + 1 < enabledTransitions.size())) - - executeContent(transition); - - USCXML_MONITOR_CALLBACK3(afterTakingTransition, transition, (i + 1 < enabledTransitions.size())) - } - - enterStates(enabledTransitions); - - USCXML_MONITOR_CALLBACK(afterMicroStep) -} - - -/** -procedure exitStates(enabledTransitions): - statesToExit = computeExitSet(enabledTransitions) - for s in statesToExit: - statesToInvoke.delete(s) - statesToExit = statesToExit.toList().sort(exitOrder) - for s in statesToExit: - for h in s.history: - if h.type == "deep": - f = lambda s0: isAtomicState(s0) and isDescendant(s0,s) - else: - f = lambda s0: s0.parent == s - historyValue[h.id] = configuration.toList().filter(f) - for s in statesToExit: - for content in s.onexit: - executeContent(content) - for inv in s.invoke: - cancelInvoke(inv) - configuration.delete(s) - */ -void InterpreterRC::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - NodeSet<std::string> statesToExit = computeExitSet(enabledTransitions); - - // remove statesToExit from _statesToInvoke - std::list<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.forward(false); - statesToExit.sort(); - - for (int i = 0; i < statesToExit.size(); i++) { - NodeSet<std::string> histories = filterChildElements(_nsInfo.xmlNSPrefix + "history", statesToExit[i]); - for (int j = 0; j < histories.size(); j++) { - Element<std::string> historyElem = (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 (iequals(historyType, "deep")) { - if (isAtomic(Element<std::string>(_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; - } - } - - for (int i = 0; i < statesToExit.size(); i++) { - USCXML_MONITOR_CALLBACK3(beforeExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size())) - - NodeSet<std::string> onExits = filterChildElements(_nsInfo.xmlNSPrefix + "onExit", statesToExit[i]); - for (int j = 0; j < onExits.size(); j++) { - Element<std::string> onExitElem = (Element<std::string>)onExits[j]; - executeContent(onExitElem); - } - - USCXML_MONITOR_CALLBACK3(afterExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size())) - - NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); - for (int j = 0; j < invokes.size(); j++) { - Element<std::string> invokeElem = (Element<std::string>)invokes[j]; - cancelInvoke(invokeElem); - } - - // remove statesToExit[i] from _configuration - test409 - tmp.clear(); - for (int j = 0; j < _configuration.size(); j++) { - if (_configuration[j] != statesToExit[i]) { - tmp.push_back(_configuration[j]); - } - } - _configuration = NodeSet<std::string>(); - _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); - } -} - - -/** -function computeExitSet(transitions) - statesToExit = new OrderedSet - for t in transitions: - if(getTargetSet(t.target)): - domain = getTransitionDomain(t) - for s in configuration: - if isDescendant(s,domain): - statesToExit.add(s) - return statesToExit - */ -Arabica::XPath::NodeSet<std::string> InterpreterRC::computeExitSet(const Arabica::XPath::NodeSet<std::string>& transitions) { - NodeSet<std::string> statesToExit; - for (unsigned int i = 0; i < transitions.size(); i++) { - Element<std::string> t(transitions[i]); - if (isTargetless(t)) - continue; - Arabica::DOM::Node<std::string> domain = getTransitionDomain(t); - if (!domain) - continue; - for (unsigned int j = 0; j < _configuration.size(); j++) { - const Node<std::string>& s = _configuration[j]; - if (isDescendant(s, domain)) { - statesToExit.push_back(s); - } - } - } -#if 0 - std::cout << "computeExitSet: "; - for (int i = 0; i < statesToExit.size(); i++) { - std::cout << ATTR(statesToExit[i], "id") << " "; - } - std::cout << std::endl; -#endif - return statesToExit; -} - -Arabica::XPath::NodeSet<std::string> InterpreterRC::computeExitSet(const Arabica::DOM::Node<std::string>& transition) { - Arabica::XPath::NodeSet<std::string> transitions; - transitions.push_back(transition); - return computeExitSet(transitions); -} - - -/** -procedure enterStates(enabledTransitions): - statesToEnter = new OrderedSet() - statesForDefaultEntry = new OrderedSet() - computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry) - for s in statesToEnter.toList().sort(entryOrder): - configuration.add(s) - statesToInvoke.add(s) - if binding == "late" and s.isFirstEntry: - initializeDataModel(datamodel.s,doc.s) - s.isFirstEntry = false - for content in s.onentry: - executeContent(content) - if statesForDefaultEntry.isMember(s): - executeContent(s.initial.transition) - if isFinalState(s): - if isSCXMLElement(s.parent): - running = false - else: - parent = s.parent - grandparent = parent.parent - internalQueue.enqueue(new Event("done.state." + parent.id, s.donedata)) - if isParallelState(grandparent): - if getChildStates(grandparent).every(isInFinalState): - internalQueue.enqueue(new Event("done.state." + grandparent.id)) - */ -void InterpreterRC::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - NodeSet<std::string> statesToEnter; - NodeSet<std::string> statesForDefaultEntry; - // initialize the temporary table for default content in history states - std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent; - - computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent); - statesToEnter.to_document_order(); - - for (int i = 0; i < statesToEnter.size(); i++) { - Element<std::string> s = (Element<std::string>)statesToEnter[i]; - - USCXML_MONITOR_CALLBACK3(beforeEnteringState, s, i + 1 < statesToEnter.size()) - - _configuration.push_back(s); - _statesToInvoke.push_back(s); - - // if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) { - if (_binding == LATE && !isMember(s, _alreadyEntered)) { - NodeSet<std::string> dataModelElems = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", s); - if(dataModelElems.size() > 0 && _dataModel) { - Arabica::XPath::NodeSet<std::string> dataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", dataModelElems[0]); - for (int j = 0; j < dataElems.size(); j++) { - if (dataElems[j].getNodeType() == Node_base::ELEMENT_NODE) - initializeData(Element<std::string>(dataElems[j])); - } - } - _alreadyEntered.push_back(s); - // stateElem.setAttribute("isFirstEntry", ""); - } - // execute onentry executable content - NodeSet<std::string> onEntryElems = filterChildElements(_nsInfo.xmlNSPrefix + "onEntry", s); - executeContent(onEntryElems, false); - - USCXML_MONITOR_CALLBACK3(afterEnteringState, s, i + 1 < statesToEnter.size()) - - if (isMember(s, statesForDefaultEntry)) { - // execute initial transition content for compound states - Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", s).asNodeSet(); - executeContent(transitions); - } - if (defaultHistoryContent.find(ATTR(s, "id")) != defaultHistoryContent.end()) { - executeContent(Element<std::string>(defaultHistoryContent[ATTR(s, "id")])); - } - - /** - if isFinalState(s): - if isSCXMLElement(s.parent): - running = false - else: - parent = s.parent - grandparent = parent.parent - internalQueue.enqueue(new Event("done.state." + parent.id, s.donedata)) - if isParallelState(grandparent): - if getChildStates(grandparent).every(isInFinalState): - internalQueue.enqueue(new Event("done.state." + grandparent.id)) - */ - //std::cout << _name << ": " << s << std::endl; - - if (isFinal(s)) { - internalDoneSend(s); - if (parentIsScxmlState(s)) { - _running = false; - _topLevelFinalReached = true; - } else { - Element<std::string> parent = (Element<std::string>)s.getParentNode(); - Element<std::string> grandParent = (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); - } - } - } - } - } -} - - -/** -procedure computeEntrySet(transitions, statesToEnter, statesForDefaultEntry) - for t in transitions: - statesToEnter.union(getTargetStates(t.target)) - for s in statesToEnter: - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry) - for t in transitions: - ancestor = getTransitionDomain(t) - for s in getTargetStates(t.target)): - addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry) - */ -void InterpreterRC::computeEntrySet(const Arabica::XPath::NodeSet<std::string>& transitions, - NodeSet<std::string>& statesToEnter, - NodeSet<std::string>& statesForDefaultEntry, - std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { - for (int i = 0; i < transitions.size(); i++) { - Element<std::string> t(transitions[i]); - - NodeSet<std::string> targets = getTargetStates(t); - for (int j = 0; j < targets.size(); j++) { - if (!isMember(targets[j], statesToEnter)) { - statesToEnter.push_back(targets[j]); - } - } - } - -#if 0 - std::cout << "before addDescendantStatesToEnter: "; - for (int i = 0; i < statesToEnter.size(); i++) { - std::cout << ATTR(statesToEnter[i], "id") << " "; - } - std::cout << std::endl; -#endif - - NodeSet<std::string> tmp = statesToEnter; - for (int i = 0; i < tmp.size(); i++) { - assert(tmp[i]); - addDescendantStatesToEnter(tmp[i],statesToEnter,statesForDefaultEntry, defaultHistoryContent); - } - -#if 0 - std::cout << "after addDescendantStatesToEnter: "; - for (int i = 0; i < statesToEnter.size(); i++) { - std::cout << ATTR(statesToEnter[i], "id") << " "; - } - std::cout << std::endl; -#endif - - for (int i = 0; i < transitions.size(); i++) { - Element<std::string> t = (Element<std::string>)transitions[i]; - Node<std::string> ancestor = getTransitionDomain(t); - NodeSet<std::string> targets = getTargetStates(t); - for (int j = 0; j < targets.size(); j++) { - const Node<std::string>& s = targets[j]; - addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent); - } - } - -#if 0 - std::cout << "after addAncestorStatesToEnter: "; - for (int i = 0; i < statesToEnter.size(); i++) { - std::cout << ATTR(statesToEnter[i], "id") << " "; - } - std::cout << std::endl; -#endif -} - -void InterpreterRC::computeEntrySet(const Arabica::DOM::Node<std::string>& transition, - NodeSet<std::string>& statesToEnter, - NodeSet<std::string>& statesForDefaultEntry, - std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { - Arabica::XPath::NodeSet<std::string> transitions; - transitions.push_back(transition); - computeEntrySet(transitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent); -} - - -/** -procedure addDescendantStatesToEnter(state,statesToEnter,statesForDefaultEntry): - if isHistoryState(state): - if historyValue[state.id]: - for s in historyValue[state.id]: - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry) - addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry) - else: - for t in state.transition: - for s in getTargetStates(t.target): - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry) - addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry) - else: - statesToEnter.add(state) - if isCompoundState(state): - statesForDefaultEntry.add(state) - for s in getTargetStates(state.initial): - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry) - addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry) - else: - if isParallelState(state): - for child in getChildStates(state): - if not statesToEnter.some(lambda s: isDescendant(s,child)): - addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry) - */ -void InterpreterRC::addDescendantStatesToEnter(const Arabica::DOM::Node<std::string>& state, - Arabica::XPath::NodeSet<std::string>& statesToEnter, - Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry, - std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { - if (isHistory(Element<std::string>(state))) { - std::string stateId = ATTR(state, "id"); - if (_historyValue.find(stateId) != _historyValue.end()) { - const Arabica::XPath::NodeSet<std::string>& historyValue = _historyValue[stateId]; - for (int i = 0; i < historyValue.size(); i++) { - const Node<std::string>& s = historyValue[i]; - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); - addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); - } - } else { - NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", state); - if (transitions.size() > 0) { - defaultHistoryContent[ATTR(state, "id")] = transitions[0]; - } - if (transitions.size() > 1) { - LOG(ERROR) << "Only one transition allowed in history"; - } - for (int i = 0; i < transitions.size(); i++) { - NodeSet<std::string> targets = getTargetStates(Element<std::string>(transitions[i])); - for (int j = 0; j < targets.size(); j++) { - const Node<std::string>& s = targets[i]; - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); - addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); - } - } - } - } else { - if (!isMember(state, statesToEnter)) // adding an existing element invalidates old reference - statesToEnter.push_back(state); - - if (isCompound(Element<std::string>(state))) { - statesForDefaultEntry.push_back(state); - NodeSet<std::string> targets = getInitialStates(Element<std::string>(state)); - for (int i = 0; i < targets.size(); i++) { - const Node<std::string>& s = targets[i]; - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); - addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); - } - } else if(isParallel(Element<std::string>(state))) { - // if state is a parallel state, recursively call addStatesToEnter on any of its child - // states that don't already have a descendant on statesToEnter. - NodeSet<std::string> childStates = getChildStates(state); - for (int i = 0; i < childStates.size(); i++) { - const Node<std::string>& child = childStates[i]; - for (int j = 0; j < statesToEnter.size(); j++) { - const Node<std::string>& s = statesToEnter[j]; - if (isDescendant(s, child)) { - goto BREAK_LOOP; - } - } - addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent); -BREAK_LOOP: - ; - } - } - } -} - - -/** -procedure addAncestorStatesToEnter(state, ancestor, statesToEnter, statesForDefaultEntry) - for anc in getProperAncestors(state,ancestor): - statesToEnter.add(anc) - if isParallelState(anc): - for child in getChildStates(anc): - if not statesToEnter.some(lambda s: isDescendant(s,child)): - addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry) - */ -void InterpreterRC::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, - std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent) { - NodeSet<std::string> ancestors = getProperAncestors(state,ancestor); - for (int i = 0; i < ancestors.size(); i++) { - const Node<std::string>& anc = ancestors[i]; - statesToEnter.push_back(anc); - if (isParallel(Element<std::string>(anc))) { - NodeSet<std::string> childStates = getChildStates(anc); - for (int j = 0; j < childStates.size(); j++) { - const Node<std::string>& child = childStates[j]; - for (int k = 0; k < statesToEnter.size(); k++) { - const Node<std::string>& s = statesToEnter[k]; - if (isDescendant(s, child)) { - goto BREAK_LOOP; - } - } - addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent); -BREAK_LOOP: - ; - } - } - } -} - -/** -function isInFinalState(s): - if isCompoundState(s): - return getChildStates(s).some(lambda s: isFinalState(s) and configuration.isMember(s)) - elif isParallelState(s): - return getChildStates(s).every(isInFinalState) - else: - return false -*/ -bool InterpreterRC::isInFinalState(const Arabica::DOM::Node<std::string>& state) { - if (isCompound(Element<std::string>(state))) { - Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); - for (int i = 0; i < childs.size(); i++) { - if (isFinal(Element<std::string>(childs[i])) && isMember(childs[i], _configuration)) - return true; - } - } else if (isParallel(Element<std::string>(state))) { - Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); - for (int i = 0; i < childs.size(); i++) { - if (!isInFinalState(childs[i])) - return false; - } - return true; - } - return false; -} - - -/** -function getTransitionDomain(t) - tstates = getTargetStates(t.target) - if not tstates - return t.source - elif t.type == "internal" and isCompoundState(t.source) and tstates.every(lambda s: isDescendant(s,t.source)): - return t.source - else: - return findLCCA([t.source].append(tstates)) - */ -Arabica::DOM::Node<std::string> InterpreterRC::getTransitionDomain(const Arabica::DOM::Element<std::string>& transition) { - NodeSet<std::string> tStates = getTargetStates(transition); - Node<std::string> source = getSourceState(transition); - -#if 0 - std::cout << "getTransitionDomain: " << std::endl << transition << std::endl; -#endif - - if (tStates.size() == 0) { - return Arabica::DOM::Node<std::string>(); // null - } - std::string transitionType = (HAS_ATTR(transition, "type") ? ATTR(transition, "type") : "external"); - - if (iequals(transitionType, "internal") && isCompound(Element<std::string>(source))) { - for (int i = 0; i < tStates.size(); i++) { - const Node<std::string>& s = tStates[i]; - if (!isDescendant(s, source)) - goto BREAK_LOOP; - } - return source; - } -BREAK_LOOP: - ; - Arabica::XPath::NodeSet<std::string> states; - states.push_back(source); - states.push_back(tStates); - return findLCCA(states); -} - - -/** -function findLCCA(stateList): - for anc in getProperAncestors(stateList.head(),null).filter(isCompoundStateOrScxmlElement): - if stateList.tail().every(lambda s: isDescendant(s,anc)): - return anc - */ -Arabica::DOM::Node<std::string> InterpreterRC::findLCCA(const Arabica::XPath::NodeSet<std::string>& states) { - Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>()); - // ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec? - Arabica::DOM::Node<std::string> ancestor; - for (int i = 0; i < ancestors.size(); i++) { - if (!isCompound(Element<std::string>(ancestors[i]))) - continue; - for (int j = 0; j < states.size(); j++) { - if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i])) - goto NEXT_ANCESTOR; - } - ancestor = ancestors[i]; - break; -NEXT_ANCESTOR: - ; - } - - // take uppermost root as ancestor - if (!ancestor) - ancestor = _scxml; - assert(ancestor); - return ancestor; -} - -/** - If state2 is null, returns the set of all ancestors of state1 in ancestry order - (state1's parent followed by the parent's parent, etc. up to an including the - <scxml> element). If state2 is non-null, returns inancestry order the set of all - ancestors of state1, up to but not including state2. (A "proper ancestor" of a - state is its parent, or the parent's parent, or the parent's parent's parent, - etc.)) If state2 is state1's parent, or equal to state1, or a descendant of - state1, this returns the empty set. -*/ -Arabica::XPath::NodeSet<std::string> InterpreterRC::getProperAncestors(const Arabica::DOM::Node<std::string>& state1, const Arabica::DOM::Node<std::string>& state2) { - NodeSet<std::string> ancestors; - - if (!state1 || !isState(Element<std::string>(state1))) - return ancestors; - - if (!state2) { - /** - If state2 is null, returns the set of all ancestors of state1 in ancestry - order (state1's parent followed by the parent's parent, etc. up to an - including the <scxml> element). - */ - Arabica::DOM::Node<std::string> parent = state1.getParentNode(); - while(parent && isState(Element<std::string>(parent))) { - ancestors.push_back(parent); - parent = parent.getParentNode(); - } - return ancestors; - } - - /** - If state2 is state1's parent, or equal to state1, or a descendant of - state1, this returns the empty set - */ - if (state1.getParentNode() == state2 || state1 == state2 || isDescendant(state2, state1)) { - return ancestors; - } - - /** - If state2 is non-null, returns in ancestry order the set of all ancestors - of state1, up to but not including state2. - */ - Arabica::DOM::Node<std::string> parent = state1.getParentNode(); - while(parent && isState(Element<std::string>(parent)) && parent != state2) { - ancestors.push_back(parent); - parent = parent.getParentNode(); - } - return ancestors; -} - -NodeSet<std::string> InterpreterRC::getTargetStates(const Arabica::DOM::Element<std::string>& transition) { - NodeSet<std::string> targetStates; - - std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target"); - std::list<std::string> targetIds = InterpreterImpl::tokenizeIdRefs(ATTR(transition, "target")); - if (targetIds.size() > 0) { - for (std::list<std::string>::const_iterator targetIter = targetIds.begin(); targetIter != targetIds.end(); targetIter++) { - Arabica::DOM::Node<std::string> state = getState(*targetIter); - if (state) { - assert(HAS_ATTR(state, "id")); - targetStates.push_back(state); - } - } - } else { - targetStates.push_back(getSourceState(transition)); // TODO: is this till correct? - } - return targetStates; -} - - -#if 0 -/** -Returns 'true' if state1 is a descendant of state2 (a child, or a child of a child, or a child of a child of a child, etc.) Otherwise returns 'false'. -*/ -bool InterpreterRC::isDescendant(const Arabica::DOM::Node<std::string>& state1, const Arabica::DOM::Node<std::string>& state2) { - return false; -} - -/** -Returns a list containing all <state>, <final>, and <parallel> children of state1. -*/ -Arabica::XPath::NodeSet<std::string> InterpreterRC::getChildStates(const Arabica::DOM::Node<std::string>& state) { - return Arabica::XPath::NodeSet<std::string>(); -} -#endif - - -}
\ No newline at end of file diff --git a/src/uscxml/interpreter/InterpreterRC.h.deactivated b/src/uscxml/interpreter/InterpreterRC.h index 9afc2e6..3dae973 100644 --- a/src/uscxml/interpreter/InterpreterRC.h.deactivated +++ b/src/uscxml/interpreter/InterpreterRC.h @@ -25,19 +25,11 @@ namespace uscxml { class InterpreterRC : public InterpreterImpl { - InterpreterState interpret(); - void mainEventLoop(); - void exitInterpreter(); - - void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - - Arabica::XPath::NodeSet<std::string> selectEventlessTransitions(); - Arabica::XPath::NodeSet<std::string> selectTransitions(const std::string& event); - bool isEnabledTransition(const Arabica::DOM::Element<std::string>& transition, const std::string& event); - bool hasIntersection(const Arabica::XPath::NodeSet<std::string>& nodeSet1, const Arabica::XPath::NodeSet<std::string>& nodeSet2); - void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + Arabica::XPath::NodeSet<std::string> removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + + bool hasIntersection(const Arabica::XPath::NodeSet<std::string>& nodeSet1, const Arabica::XPath::NodeSet<std::string>& nodeSet2); Arabica::XPath::NodeSet<std::string> computeExitSet(const Arabica::XPath::NodeSet<std::string>& transitions); Arabica::XPath::NodeSet<std::string> computeExitSet(const Arabica::DOM::Node<std::string>& transition); @@ -51,35 +43,20 @@ class InterpreterRC : public InterpreterImpl { Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry, std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent); - Arabica::XPath::NodeSet<std::string> removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); Arabica::DOM::Node<std::string> getTransitionDomain(const Arabica::DOM::Element<std::string>& transition); + Arabica::XPath::NodeSet<std::string> getEffectiveTargetStates(const Arabica::DOM::Element<std::string>& transition); - void addDescendantStatesToEnter(const Arabica::DOM::Node<std::string>& state, + void addDescendantStatesToEnter(const Arabica::DOM::Element<std::string>& state, Arabica::XPath::NodeSet<std::string>& statesToEnter, Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry, std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent); - void addAncestorStatesToEnter(const Arabica::DOM::Node<std::string>& state, - const Arabica::DOM::Node<std::string>& ancestor, + void addAncestorStatesToEnter(const Arabica::DOM::Element<std::string>& state, + const Arabica::DOM::Element<std::string>& ancestor, Arabica::XPath::NodeSet<std::string>& statesToEnter, Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry, std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent); - bool isInFinalState(const Arabica::DOM::Node<std::string>& state); - Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states); - - Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, - const Arabica::DOM::Node<std::string>& s2); - - Arabica::XPath::NodeSet<std::string> getTargetStates(const Arabica::DOM::Element<std::string>& transition); - -#if 0 - bool isDescendant(const Arabica::DOM::Node<std::string>& state1, const Arabica::DOM::Node<std::string>& state2); - Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state); -#endif - - bool _running; - }; } |