summaryrefslogtreecommitdiffstats
path: root/src/uscxml/Interpreter.cpp
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2015-12-04 08:00:18 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2015-12-04 08:00:18 (GMT)
commitb8ba0e7c31f397a66f9d509ff20a85b33619475a (patch)
tree9a5adb4f891cdc29eb80f597510e0cef8ee0a47f /src/uscxml/Interpreter.cpp
parent57ba362eae6e8209cf560555fd4cc4bb76dbe2a1 (diff)
downloaduscxml-b8ba0e7c31f397a66f9d509ff20a85b33619475a.zip
uscxml-b8ba0e7c31f397a66f9d509ff20a85b33619475a.tar.gz
uscxml-b8ba0e7c31f397a66f9d509ff20a85b33619475a.tar.bz2
All changes up to my dissertation
Diffstat (limited to 'src/uscxml/Interpreter.cpp')
-rw-r--r--src/uscxml/Interpreter.cpp164
1 files changed, 150 insertions, 14 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 72232b8..169d9f6 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -330,16 +330,19 @@ void NameSpaceInfo::init(const std::map<std::string, std::string>& namespaceInfo
}
void StateTransitionMonitor::beforeTakingTransition(uscxml::Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
std::cerr << "Transition: " << uscxml::DOMUtils::xPathForNode(transition) << std::endl;
}
void StateTransitionMonitor::onStableConfiguration(uscxml::Interpreter interpreter) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
std::cerr << "Config: {";
printNodeSet(interpreter.getConfiguration());
std::cerr << "}" << std::endl;
}
void StateTransitionMonitor::beforeProcessingEvent(uscxml::Interpreter interpreter, const uscxml::Event& event) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
switch (event.eventType) {
case uscxml::Event::INTERNAL:
std::cerr << "Internal Event: " << event.name << std::endl;
@@ -354,10 +357,12 @@ void StateTransitionMonitor::beforeProcessingEvent(uscxml::Interpreter interpret
}
void StateTransitionMonitor::beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
std::cerr << "Executable Content: " << DOMUtils::xPathForNode(element) << std::endl;
}
void StateTransitionMonitor::beforeExitingState(uscxml::Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
exitingStates.push_back(state);
if (!moreComing) {
std::cerr << "Exiting: {";
@@ -368,6 +373,7 @@ void StateTransitionMonitor::beforeExitingState(uscxml::Interpreter interpreter,
}
void StateTransitionMonitor::beforeEnteringState(uscxml::Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
enteringStates.push_back(state);
if (!moreComing) {
std::cerr << "Entering: {";
@@ -385,7 +391,8 @@ void StateTransitionMonitor::printNodeSet(const Arabica::XPath::NodeSet<std::str
seperator = ", ";
}
}
-
+tthread::recursive_mutex StateTransitionMonitor::_mutex;
+
std::map<std::string, boost::weak_ptr<InterpreterImpl> > Interpreter::_instances;
tthread::recursive_mutex Interpreter::_instanceMutex;
@@ -740,7 +747,7 @@ NodeSet<std::string> InterpreterImpl::getDocumentInitialTransitions() {
} else {
// try to get initial transition from initial element
- initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet();
+ initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "scxml/"+ _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet();
if (initialTransitions.size() == 0) {
Arabica::XPath::NodeSet<std::string> initialStates;
// fetch per draft
@@ -791,6 +798,14 @@ InterpreterState InterpreterImpl::step(int waitForMS) {
std::cerr << std::endl;
#endif
+ // this is not mentionend in the standard, though it makes sense
+ for (int i = 0; i < initialTransitions.size(); i++) {
+ Element<std::string> transition(initialTransitions[i]);
+ USCXML_MONITOR_CALLBACK3(beforeTakingTransition, transition, (i + 1 < enabledTransitions.size()))
+ executeContent(transition);
+ USCXML_MONITOR_CALLBACK3(afterTakingTransition, transition, (i + 1 < enabledTransitions.size()))
+ }
+
enterStates(initialTransitions);
setInterpreterState(USCXML_MICROSTEPPED);
}
@@ -1050,6 +1065,8 @@ void InterpreterImpl::stabilize() {
_statesToInvoke = NodeSet<std::string>();
}
+#if 0
+
Arabica::XPath::NodeSet<std::string> InterpreterImpl::selectTransitions(const std::string& event) {
Arabica::XPath::NodeSet<std::string> enabledTransitions;
@@ -1128,6 +1145,104 @@ LOOP:
return enabledTransitions;
}
+#else
+
+Arabica::XPath::NodeSet<std::string> InterpreterImpl::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();
+
+ for (unsigned int i = 0; i < atomicStates.size(); i++) {
+ Element<std::string> state(atomicStates[i]);
+ while(true) {
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", state);
+ for (unsigned int k = 0; k < transitions.size(); k++) {
+ if (isEnabledTransition(Element<std::string>(transitions[k]), event)) {
+ enabledTransitions.push_back(transitions[k]);
+ goto NEXT_ATOMIC;
+ }
+ }
+ if (state.getParentNode() && state.getParentNode().getNodeType() == Node_base::ELEMENT_NODE) {
+ state = Element<std::string>(state.getParentNode());
+ } else {
+ goto NEXT_ATOMIC;
+ }
+ }
+ NEXT_ATOMIC:;
+ }
+
+#if 0
+ std::cerr << "Enabled transitions for '" << event << "': " << std::endl;
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ std::cerr << enabledTransitions[i] << std::endl << "----" << std::endl;
+ }
+ std::cerr << std::endl;
+#endif
+
+ enabledTransitions = removeConflictingTransitions(enabledTransitions);
+
+#if 0
+ std::cerr << "Non-conflicting transitions for '" << event << "': " << std::endl;
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ std::cerr << enabledTransitions[i] << std::endl << "----" << std::endl;
+ }
+ std::cerr << std::endl;
+#endif
+
+ return enabledTransitions;
+}
+
+
+Arabica::XPath::NodeSet<std::string> InterpreterImpl::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++) {
+ Element<std::string> state(atomicStates[i]);
+ while(true) {
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", state);
+ 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 NEXT_ATOMIC;
+ }
+ }
+ if (state.getParentNode() && state.getParentNode().getNodeType() == Node_base::ELEMENT_NODE) {
+ state = Element<std::string>(state.getParentNode());
+ } else {
+ goto NEXT_ATOMIC;
+ }
+ }
+ NEXT_ATOMIC:;
+ }
+
+#if 0
+ std::cerr << "Enabled eventless transitions: " << std::endl;
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ std::cerr << enabledTransitions[i] << std::endl << "----" << std::endl;
+ }
+ std::cerr << std::endl;
+#endif
+
+ enabledTransitions = removeConflictingTransitions(enabledTransitions);
+ return enabledTransitions;
+}
+
+
+#endif
bool InterpreterImpl::isEnabledTransition(const Element<std::string>& transition, const std::string& event) {
std::string eventName;
@@ -2151,9 +2266,15 @@ void InterpreterImpl::invoke(const Arabica::DOM::Element<std::string>& element)
USCXML_MONITOR_CALLBACK3(afterInvoking, Arabica::DOM::Element<std::string>(element), invokeReq.invokeid)
// this is out of draft but so useful to know when an invoker started
-// Event invSuccess;
-// invSuccess.name = "invoke.success." + invokeReq.invokeid;
-// receive(invSuccess);
+ if (HAS_ATTR(element, "callback")) {
+ std::string callback = ATTR(element, "callback");
+ if (callback.size() > 0) {
+ Event invSuccess;
+ invSuccess.name = callback + "." + invokeReq.invokeid;
+ receive(invSuccess);
+ }
+ }
+
} catch(boost::bad_lexical_cast e) {
LOG(ERROR) << "Exception caught while sending invoke request to invoker " << invokeReq.invokeid << ": " << e.what();
@@ -2594,7 +2715,8 @@ void InterpreterImpl::finalizeAndAutoForwardCurrentEvent() {
// 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"))
- invokeIter->second.send(_currEvent);
+// LOG(ERROR) << _sessionId << " auto forwards " << _currEvent.name << " to " << invokeIter->first << std::endl;
+ invokeIter->second.send(_currEvent);
} catch (const std::exception &e) {
LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first << ": " << e.what();
} catch(...) {
@@ -2696,6 +2818,7 @@ Arabica::DOM::Node<std::string> InterpreterImpl::getAncestorElement(const Arabic
we are speaking of proper ancestor (parent or parent of a parent, etc.) the LCCA is never a member of stateList.
*/
+#define VERBOSE_FIND_LCCA 0
Arabica::DOM::Node<std::string> InterpreterImpl::findLCCA(const Arabica::XPath::NodeSet<std::string>& states) {
#if VERBOSE_FIND_LCCA
std::cerr << "findLCCA: ";
@@ -2729,7 +2852,7 @@ NEXT_ANCESTOR:
// take uppermost root as ancestor
if (!ancestor)
ancestor = _scxml;
- assert(ancestor);
+
#if VERBOSE_FIND_LCCA
std::cerr << " -> " << ATTR_CAST(ancestor, "id") << " " << ancestor.getLocalName() << std::endl;
#endif
@@ -2838,10 +2961,12 @@ Arabica::XPath::NodeSet<std::string> InterpreterImpl::getInitialStates(Arabica::
// initial element as child - but not the implicit generated one
NodeSet<std::string> initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state);
- if(initElems.size() == 1 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) {
+ if(initElems.size() > 0 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) {
NodeSet<std::string> initTrans = filterChildElements(_nsInfo.xmlNSPrefix + "transition", initElems[0]);
- return getTargetStates(Element<std::string>(initTrans[0]));
- }
+ if (initTrans.size() > 0) {
+ return getTargetStates(Element<std::string>(initTrans[0]));
+ }
+ }
// first child state
Arabica::XPath::NodeSet<std::string> initStates;
@@ -3096,6 +3221,14 @@ NodeSet<std::string> InterpreterImpl::filterChildType(const Node_base::Type type
return filteredChildTypes;
}
+/*
+ * 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 in ancestry 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.
+ */
NodeSet<std::string> InterpreterImpl::getProperAncestors(const Arabica::DOM::Node<std::string>& s1,
const Arabica::DOM::Node<std::string>& s2) {
@@ -3109,13 +3242,13 @@ NodeSet<std::string> InterpreterImpl::getProperAncestors(const Arabica::DOM::Nod
Arabica::DOM::Node<std::string> node = s1;
while((node = node.getParentNode())) {
if (node.getNodeType() != Node_base::ELEMENT_NODE)
- continue;
+ break;
Element<std::string> nodeElem(node);
if (!isState(nodeElem))
break;
- if (iequals(TAGNAME(nodeElem), _nsInfo.xmlNSPrefix + "scxml")) // do not return scxml root itself - this is somewhat ill-defined
- break;
+// if (iequals(TAGNAME(nodeElem), _nsInfo.xmlNSPrefix + "scxml")) // do not return scxml root itself - this is somewhat ill-defined
+// break;
if (!iequals(TAGNAME(nodeElem), _nsInfo.xmlNSPrefix + "parallel") &&
!iequals(TAGNAME(nodeElem), _nsInfo.xmlNSPrefix + "state") &&
!iequals(TAGNAME(nodeElem), _nsInfo.xmlNSPrefix + "scxml"))
@@ -3131,7 +3264,10 @@ NodeSet<std::string> InterpreterImpl::getProperAncestors(const Arabica::DOM::Nod
bool InterpreterImpl::isDescendant(const Arabica::DOM::Node<std::string>& s1,
const Arabica::DOM::Node<std::string>& s2) {
- Arabica::DOM::Node<std::string> parent = s1.getParentNode();
+ if (!s1 || !s2)
+ return false;
+
+ Arabica::DOM::Node<std::string> parent = s1.getParentNode();
while(parent) {
if (s2 == parent)
return true;