From 6e1a4a67d5b17e92135cd3f5daf51bf044d76e40 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sun, 3 Aug 2014 14:10:57 +0200 Subject: Got rid of more dynamic_casts --- apps/uscxml-browser.cpp | 2 +- apps/uscxml-transform.cpp | 2 +- src/bindings/swig/wrapped/WrappedDataModel.h | 2 +- .../swig/wrapped/WrappedExecutableContent.h | 4 +- .../swig/wrapped/WrappedInterpreterMonitor.h | 8 +- src/uscxml/DOMUtils.cpp | 13 +- src/uscxml/DOMUtils.h | 16 +- src/uscxml/Interpreter.cpp | 149 ++- src/uscxml/Interpreter.h | 17 +- src/uscxml/debug/SCXMLDotWriter.cpp | 163 +-- src/uscxml/interpreter/InterpreterDraft6.cpp | 41 +- src/uscxml/interpreter/InterpreterDraft6.h | 3 + src/uscxml/interpreter/InterpreterRC.cpp | 1292 -------------------- .../interpreter/InterpreterRC.cpp.deactivated | 1292 ++++++++++++++++++++ src/uscxml/interpreter/InterpreterRC.h | 87 -- src/uscxml/interpreter/InterpreterRC.h.deactivated | 87 ++ src/uscxml/messages/Data.cpp | 2 +- src/uscxml/messages/Event.cpp | 4 +- src/uscxml/plugins/DataModel.h | 6 +- src/uscxml/plugins/ExecutableContent.h | 8 +- .../ecmascript/JavaScriptCore/JSCDataModel.cpp | 2 +- .../ecmascript/JavaScriptCore/JSCDataModel.h | 2 +- src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp | 2 +- src/uscxml/plugins/datamodel/lua/LuaDataModel.h | 2 +- .../plugins/datamodel/null/NULLDataModel.cpp | 2 +- src/uscxml/plugins/datamodel/null/NULLDataModel.h | 2 +- .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 4 +- .../plugins/datamodel/prolog/swi/SWIDataModel.h | 2 +- .../plugins/datamodel/promela/PromelaDataModel.cpp | 4 +- .../plugins/datamodel/promela/PromelaDataModel.h | 2 +- .../plugins/datamodel/xpath/XPathDataModel.cpp | 6 +- .../plugins/datamodel/xpath/XPathDataModel.h | 2 +- src/uscxml/plugins/element/fetch/FetchElement.cpp | 4 +- src/uscxml/plugins/element/fetch/FetchElement.h | 4 +- src/uscxml/plugins/element/file/FileElement.cpp | 4 +- src/uscxml/plugins/element/file/FileElement.h | 4 +- .../plugins/element/postpone/PostponeElement.cpp | 4 +- .../plugins/element/postpone/PostponeElement.h | 4 +- .../plugins/element/respond/RespondElement.cpp | 35 +- .../plugins/element/respond/RespondElement.h | 4 +- .../invoker/graphics/openscenegraph/OSGInvoker.cpp | 43 +- .../invoker/graphics/openscenegraph/OSGInvoker.h | 34 +- src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp | 11 +- src/uscxml/transform/ChartToFSM.cpp | 53 +- src/uscxml/transform/ChartToFSM.h | 20 +- src/uscxml/transform/FSMToCPP.cpp | 59 +- src/uscxml/transform/FSMToCPP.h | 14 +- src/uscxml/transform/FSMToPromela.cpp | 64 +- src/uscxml/transform/FSMToPromela.h | 10 +- test/src/test-w3c.cpp | 8 +- test/uscxml/test-performance-events.scxml | 28 + 51 files changed, 1880 insertions(+), 1757 deletions(-) delete mode 100644 src/uscxml/interpreter/InterpreterRC.cpp create mode 100644 src/uscxml/interpreter/InterpreterRC.cpp.deactivated delete mode 100644 src/uscxml/interpreter/InterpreterRC.h create mode 100644 src/uscxml/interpreter/InterpreterRC.h.deactivated create mode 100644 test/uscxml/test-performance-events.scxml diff --git a/apps/uscxml-browser.cpp b/apps/uscxml-browser.cpp index 4e21ec6..1b9df1b 100644 --- a/apps/uscxml-browser.cpp +++ b/apps/uscxml-browser.cpp @@ -39,7 +39,7 @@ class VerboseMonitor : public uscxml::InterpreterMonitor { std::string seperator; std::cout << "Config: {"; for (int i = 0; i < config.size(); i++) { - std::cout << seperator << ATTR(config[i], "id"); + std::cout << seperator << ATTR_CAST(config[i], "id"); seperator = ", "; } std::cout << "}" << std::endl; diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp index fc33617..401ba87 100644 --- a/apps/uscxml-transform.cpp +++ b/apps/uscxml-transform.cpp @@ -40,7 +40,7 @@ class VerboseMonitor : public uscxml::InterpreterMonitor { std::string seperator; std::cerr << "Config: {"; for (int i = 0; i < config.size(); i++) { - std::cerr << seperator << ATTR(config[i], "id"); + std::cerr << seperator << ATTR_CAST(config[i], "id"); seperator = ", "; } std::cerr << "}" << std::endl; diff --git a/src/bindings/swig/wrapped/WrappedDataModel.h b/src/bindings/swig/wrapped/WrappedDataModel.h index 481f0ea..e988dc0 100644 --- a/src/bindings/swig/wrapped/WrappedDataModel.h +++ b/src/bindings/swig/wrapped/WrappedDataModel.h @@ -89,7 +89,7 @@ public: return evalAsBool("", expr); } - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { std::ostringstream ssNode; ssNode << node; return evalAsBool(ssNode.str(), expr); diff --git a/src/bindings/swig/wrapped/WrappedExecutableContent.h b/src/bindings/swig/wrapped/WrappedExecutableContent.h index b1ce4f9..d194f0d 100644 --- a/src/bindings/swig/wrapped/WrappedExecutableContent.h +++ b/src/bindings/swig/wrapped/WrappedExecutableContent.h @@ -55,13 +55,13 @@ public: return "http://www.w3.org/2005/07/scxml"; } - virtual void enterElement(const Arabica::DOM::Node& node) { + virtual void enterElement(const Arabica::DOM::Element& node) { std::ostringstream ssElement; ssElement << node; enterElement(ssElement.str()); } - virtual void exitElement(const Arabica::DOM::Node& node) { + virtual void exitElement(const Arabica::DOM::Element& node) { std::ostringstream ssElement; ssElement << node; exitElement(ssElement.str()); diff --git a/src/bindings/swig/wrapped/WrappedInterpreterMonitor.h b/src/bindings/swig/wrapped/WrappedInterpreterMonitor.h index 0aac660..60fa5a5 100644 --- a/src/bindings/swig/wrapped/WrappedInterpreterMonitor.h +++ b/src/bindings/swig/wrapped/WrappedInterpreterMonitor.h @@ -129,10 +129,10 @@ public: std::list targets; for (int i = 0; i < targetStates.size(); i++) { - targets.push_back(ATTR(targetStates[i], "id")); + targets.push_back(ATTR_CAST(targetStates[i], "id")); } - beforeTakingTransition(interpreter, DOMUtils::xPathForNode(transition), ATTR(sourceState, "id"), targets, ss.str(), moreComing); + beforeTakingTransition(interpreter, DOMUtils::xPathForNode(transition), ATTR_CAST(sourceState, "id"), targets, ss.str(), moreComing); } virtual void beforeTakingTransition(Interpreter interpreter, const std::string& xpath, @@ -152,10 +152,10 @@ public: std::list targets; for (int i = 0; i < targetStates.size(); i++) { - targets.push_back(ATTR(targetStates[i], "id")); + targets.push_back(ATTR_CAST(targetStates[i], "id")); } - afterTakingTransition(interpreter, DOMUtils::xPathForNode(transition), ATTR(sourceState, "id"), targets, ss.str(), moreComing); + afterTakingTransition(interpreter, DOMUtils::xPathForNode(transition), ATTR_CAST(sourceState, "id"), targets, ss.str(), moreComing); } virtual void afterTakingTransition(Interpreter interpreter, const std::string& xpath, diff --git a/src/uscxml/DOMUtils.cpp b/src/uscxml/DOMUtils.cpp index 0a6e350..aebe943 100644 --- a/src/uscxml/DOMUtils.cpp +++ b/src/uscxml/DOMUtils.cpp @@ -48,12 +48,13 @@ std::string DOMUtils::xPathForNode(const Arabica::DOM::Node& node, while(curr) { switch (curr.getNodeType()) { case Arabica::DOM::Node_base::ELEMENT_NODE: { - if (HAS_ATTR(curr, "id")) { + Arabica::DOM::Element elem = Arabica::DOM::Element(curr); + if (HAS_ATTR(elem, "id")) { // we assume ids to be unique and return immediately if (ns == "*") { - xPath.insert(0, "//*[local-name() = \"" + TAGNAME(curr) + "\"][@id=\"" + ATTR(curr, "id") + "\"]"); + xPath.insert(0, "//*[local-name() = \"" + TAGNAME(elem) + "\"][@id=\"" + ATTR(elem, "id") + "\"]"); } else { - xPath.insert(0, "//" + nsPrefix + TAGNAME(curr) + "[@id=\"" + ATTR(curr, "id") + "\"]"); + xPath.insert(0, "//" + nsPrefix + TAGNAME(elem) + "[@id=\"" + ATTR(elem, "id") + "\"]"); } return xPath; } else { @@ -62,16 +63,16 @@ std::string DOMUtils::xPathForNode(const Arabica::DOM::Node& node, int index = 1; // xpath indices start at 1 while(sibling) { if (sibling.getNodeType() == Arabica::DOM::Node_base::ELEMENT_NODE) { - if (iequals(TAGNAME(sibling), TAGNAME(curr))) { + if (iequals(TAGNAME_CAST(sibling), TAGNAME(elem))) { index++; } } sibling = sibling.getPreviousSibling(); } if (ns == "*") { - xPath.insert(0, "/*[local-name() = \"" + TAGNAME(curr) + "\"][" + toStr(index) + "]"); + xPath.insert(0, "/*[local-name() = \"" + TAGNAME(elem) + "\"][" + toStr(index) + "]"); } else { - xPath.insert(0, "/" + nsPrefix + TAGNAME(curr) + "[" + toStr(index) + "]"); + xPath.insert(0, "/" + nsPrefix + TAGNAME(elem) + "[" + toStr(index) + "]"); } } break; diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h index 7748f48..7fd291c 100644 --- a/src/uscxml/DOMUtils.h +++ b/src/uscxml/DOMUtils.h @@ -26,11 +26,17 @@ #include #include // operator<< for nodes -#define TAGNAME(elem) ((Arabica::DOM::Element)elem).getTagName() -#define LOCALNAME(elem) ((Arabica::DOM::Element)elem).getLocalName() -#define ATTR(elem, attr) ((Arabica::DOM::Element)elem).getAttribute(attr) -#define ATTR_NODE(elem, attr) ((Arabica::DOM::Element)elem).getAttributeNode(attr) -#define HAS_ATTR(elem, attr) ((Arabica::DOM::Element)elem).hasAttribute(attr) +#define TAGNAME_CAST(elem) ((Arabica::DOM::Element)elem).getTagName() +#define LOCALNAME_CAST(elem) ((Arabica::DOM::Element)elem).getLocalName() +#define ATTR_CAST(elem, attr) ((Arabica::DOM::Element)elem).getAttribute(attr) +#define ATTR_NODE_CAST(elem, attr) ((Arabica::DOM::Element)elem).getAttributeNode(attr) +#define HAS_ATTR_CAST(elem, attr) ((Arabica::DOM::Element)elem).hasAttribute(attr) + +#define TAGNAME(elem) elem.getTagName() +#define LOCALNAME(elem) elem.getLocalName() +#define ATTR(elem, attr) elem.getAttribute(attr) +#define ATTR_NODE(elem, attr) elem.getAttributeNode(attr) +#define HAS_ATTR(elem, attr) elem.hasAttribute(attr) namespace uscxml { diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index c202246..ba20981 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -902,14 +902,14 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Element& Arabica::XPath::NodeSet doneDatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", state); if (doneDatas.size() > 0) { // only process first donedata element - Arabica::DOM::Node doneData = doneDatas[0]; + Arabica::DOM::Element doneData = Element(doneDatas[0]); processParamChilds(doneData, event.params); Arabica::XPath::NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", doneDatas[0]); if (contents.size() > 1) LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; if (contents.size() > 0) { std::string expr; - processContentElement(contents[0], event.dom, event.content, expr); + processContentElement(Element(contents[0]), event.dom, event.content, expr); if (expr.length() > 0) { try { event.content =_dataModel.evalAsString(expr); @@ -922,12 +922,12 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Element& } } - event.name = "done.state." + ATTR(state.getParentNode(), "id"); // parent?! + event.name = "done.state." + ATTR_CAST(state.getParentNode(), "id"); // parent?! receiveInternal(event); } -void InterpreterImpl::processContentElement(const Arabica::DOM::Node& content, +void InterpreterImpl::processContentElement(const Arabica::DOM::Element& content, Arabica::DOM::Node& dom, std::string& text, std::string& expr) { @@ -940,7 +940,7 @@ void InterpreterImpl::processContentElement(const Arabica::DOM::Node& element, +void InterpreterImpl::processDOMorText(const Arabica::DOM::Element& element, Arabica::DOM::Node& dom, std::string& text) { // do we need to download? @@ -1036,24 +1036,25 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node& el } } -void InterpreterImpl::processParamChilds(const Arabica::DOM::Node& element, std::multimap& params) { +void InterpreterImpl::processParamChilds(const Arabica::DOM::Element& element, std::multimap& params) { NodeSet paramElems = filterChildElements(_nsInfo.xmlNSPrefix + "param", element); for (int i = 0; i < paramElems.size(); i++) { try { - if (!HAS_ATTR(paramElems[i], "name")) { + Element paramElem = Element(paramElems[i]); + if (!HAS_ATTR(paramElem, "name")) { LOG(ERROR) << "param element is missing name attribute"; continue; } Data paramValue; - if (HAS_ATTR(paramElems[i], "expr")) { - paramValue = _dataModel.getStringAsData(ATTR(paramElems[i], "expr")); - } else if(HAS_ATTR(paramElems[i], "location")) { - paramValue = _dataModel.getStringAsData(ATTR(paramElems[i], "location")); + if (HAS_ATTR(paramElem, "expr")) { + paramValue = _dataModel.getStringAsData(ATTR(paramElem, "expr")); + } else if(HAS_ATTR(paramElem, "location")) { + paramValue = _dataModel.getStringAsData(ATTR(paramElem, "location")); } else { LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; continue; } - std::string paramKey = ATTR(paramElems[i], "name"); + std::string paramKey = ATTR(paramElem, "name"); params.insert(std::make_pair(paramKey, paramValue)); } catch(Event e) { LOG(ERROR) << "Syntax error while processing params " << DOMUtils::xPathForNode(paramElems[i]) << ":" << std::endl << e << std::endl; @@ -1069,7 +1070,7 @@ void InterpreterImpl::processParamChilds(const Arabica::DOM::Node& } } -void InterpreterImpl::send(const Arabica::DOM::Node& element) { +void InterpreterImpl::send(const Arabica::DOM::Element& element) { SendRequest sendReq; // test 331 sendReq.Event::eventType = Event::EXTERNAL; @@ -1204,7 +1205,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node& element) { LOG(ERROR) << "Only a single content element is allowed for send elements " << DOMUtils::xPathForNode(element) << " - using first one"; if (contents.size() > 0) { std::string expr; - processContentElement(contents[0], sendReq.dom, sendReq.content, expr); + processContentElement(Element(contents[0]), sendReq.dom, sendReq.content, expr); if (expr.length() > 0) { try { sendReq.data = _dataModel.getStringAsData(expr); @@ -1277,7 +1278,7 @@ void InterpreterImpl::delayedSend(void* userdata, std::string eventName) { INSTANCE->_sendIds.erase(sendReq.sendid); } -void InterpreterImpl::invoke(const Arabica::DOM::Node& element) { +void InterpreterImpl::invoke(const Arabica::DOM::Element& element) { InvokeRequest invokeReq; invokeReq.Event::eventType = Event::EXTERNAL; try { @@ -1354,7 +1355,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node& element) { LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; if (contents.size() > 0) { std::string expr; - processContentElement(contents[0], invokeReq.dom, invokeReq.content, expr); + processContentElement(Element(contents[0]), invokeReq.dom, invokeReq.content, expr); if (expr.length() > 0) { try { invokeReq.data =_dataModel.getStringAsData(expr); @@ -1444,7 +1445,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node& element) { } } -void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node& element) { +void InterpreterImpl::cancelInvoke(const Arabica::DOM::Element& element) { std::string invokeId; if (HAS_ATTR(element, "idlocation")) { invokeId = _dataModel.evalAsString(ATTR(element, "idlocation")); @@ -1581,7 +1582,7 @@ bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::s bool InterpreterImpl::hasConditionMatch(const Arabica::DOM::Element& conditional) { if (HAS_ATTR(conditional, "cond") && ATTR(conditional, "cond").length() > 0) { try { - return _dataModel.evalAsBool(ATTR_NODE(conditional, "cond"), ATTR(conditional, "cond")); + return _dataModel.evalAsBool(conditional, ATTR(conditional, "cond")); } catch (Event e) { LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element " << DOMUtils::xPathForNode(conditional) << ":" << std::endl << e << std::endl; e.name = "error.execution"; @@ -1618,8 +1619,6 @@ void InterpreterImpl::executeContent(const NodeSet& content, bool r } void InterpreterImpl::executeContent(const Arabica::DOM::Element& content, bool rethrow) { - if (content.getNodeType() != Node_base::ELEMENT_NODE) - return; if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "onentry") || iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "onexit") || @@ -1628,9 +1627,10 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element& c // --- CONVENIENCE LOOP -------------------------- NodeList executable = content.getChildNodes(); for (int i = 0; i < executable.getLength(); i++) { - if (executable.item(i).getNodeType() != Node_base::ELEMENT_NODE) + const Arabica::DOM::Node& childNode = executable.item(i); + if (childNode.getNodeType() != Node_base::ELEMENT_NODE) continue; - executeContent(Element(executable.item(i)), rethrow); + executeContent(Element(childNode), rethrow); } return; } @@ -1656,7 +1656,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element& c LOG(ERROR) << "Only a single content element is allowed for raise elements " << DOMUtils::xPathForNode(content) << " - using first one"; if (contents.size() > 0) { std::string expr; - processContentElement(contents[0], raised.dom, raised.content, expr); + processContentElement(Element(contents[0]), raised.dom, raised.content, expr); if (expr.length() > 0) { try { raised.data = _dataModel.getStringAsData(expr); @@ -1704,8 +1704,8 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element& c if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; Element childElem(childs.item(i)); - if (iequals(TAGNAME(childs.item(i)), _nsInfo.xmlNSPrefix + "elseif") || - iequals(TAGNAME(childs.item(i)), _nsInfo.xmlNSPrefix + "else")) { + if (iequals(TAGNAME_CAST(childs.item(i)), _nsInfo.xmlNSPrefix + "elseif") || + iequals(TAGNAME_CAST(childs.item(i)), _nsInfo.xmlNSPrefix + "else")) { if (blockIsTrue) { // last block was true, break here break; @@ -1989,7 +1989,7 @@ Arabica::DOM::Node InterpreterImpl::getAncestorElement(const Arabic Arabica::DOM::Node parent = node.getParentNode(); while(parent) { if (parent.getNodeType() == Node_base::ELEMENT_NODE && - iequals(TAGNAME(parent), tagName)) { + iequals(TAGNAME_CAST(parent), tagName)) { return parent; } parent = parent.getParentNode(); @@ -2106,7 +2106,7 @@ Arabica::XPath::NodeSet InterpreterImpl::getAllStates() { } Arabica::DOM::Node InterpreterImpl::getSourceState(const Arabica::DOM::Element& transition) { - if (iequals(TAGNAME(transition.getParentNode()), _nsInfo.xmlNSPrefix + "initial")) + if (iequals(TAGNAME_CAST(transition.getParentNode()), _nsInfo.xmlNSPrefix + "initial")) return transition.getParentNode().getParentNode(); return transition.getParentNode(); } @@ -2137,7 +2137,7 @@ Arabica::XPath::NodeSet InterpreterImpl::getInitialStates(Arabica:: // initial element as child - but not the implicit generated one NodeSet initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state); - if(initElems.size() == 1 && !iequals(ATTR(initElems[0], "generated"), "true")) { + if(initElems.size() == 1 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) { NodeSet initTrans = filterChildElements(_nsInfo.xmlNSPrefix + "transition", initElems[0]); return getTargetStates(Element(initTrans[0])); } @@ -2159,6 +2159,9 @@ Arabica::XPath::NodeSet InterpreterImpl::getInitialStates(Arabica:: } NodeSet InterpreterImpl::getTargetStates(const Arabica::DOM::Element& transition) { + if (_cachedTargets.find(transition) != _cachedTargets.end()) + return _cachedTargets[transition]; + NodeSet targetStates; assert(boost::ends_with(TAGNAME(transition), "transition")); @@ -2169,10 +2172,12 @@ NodeSet InterpreterImpl::getTargetStates(const Arabica::DOM::Elemen for (int i = 0; i < childs.getLength(); i++) { if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; - if (iequals(TAGNAME(childs.item(i)), _nsInfo.xmlNSPrefix + "transition")) { - targetStates.push_back(getTargetStates(Element(childs.item(i)))); + Element childElem = Element(childs.item(i)); + if (iequals(TAGNAME(childElem), _nsInfo.xmlNSPrefix + "transition")) { + targetStates.push_back(getTargetStates(childElem)); } } + _cachedTargets[transition] = targetStates; return targetStates; } @@ -2181,10 +2186,11 @@ NodeSet InterpreterImpl::getTargetStates(const Arabica::DOM::Elemen for (std::list::const_iterator targetIter = targetIds.begin(); targetIter != targetIds.end(); targetIter++) { Arabica::DOM::Node state = getState(*targetIter); if (state) { - assert(HAS_ATTR(state, "id")); + assert(HAS_ATTR_CAST(state, "id")); targetStates.push_back(state); } } + _cachedTargets[transition] = targetStates; return targetStates; } @@ -2203,7 +2209,7 @@ std::list InterpreterImpl::tokenizeIdRefs(const std::string& idRefs size_t start = 0; for (int i = 0; i < idRefs.size(); i++) { if (isspace(idRefs[i])) { - if (i > 0 && start < i - 1) { + if (i > 0 && start < i) { ids.push_back(idRefs.substr(start, i - start)); } while(isspace(idRefs[++i])); // skip whitespaces @@ -2236,8 +2242,31 @@ std::list InterpreterImpl::tokenizeIdRefs(const std::string& idRefs } std::string InterpreterImpl::spaceNormalize(const std::string& text) { - std::istringstream iss(text); std::stringstream content; + +#if 1 + // 195ms with test-performance-events.scml + std::string seperator; + + size_t start = 0; + for (int i = 0; i < text.size(); i++) { + if (isspace(text[i])) { + if (i > 0 && start < i) { + content << seperator << text.substr(start, i - start); + seperator = " "; + } + while(isspace(text[++i])); // skip whitespaces + start = i; + } else if (i + 1 == text.size()) { + content << seperator << text.substr(start, i + 1 - start); + } + } +// std::cout << ">>" << content.str() << "<<" << std::endl; + +#else + +// 291ms with test-performance-events.scml + std::istringstream iss(text); std::string seperator; do { std::string token; @@ -2247,6 +2276,8 @@ std::string InterpreterImpl::spaceNormalize(const std::string& text) { seperator = " "; } } while (iss); + +#endif return content.str(); } @@ -2270,7 +2301,7 @@ NodeSet InterpreterImpl::filterChildElements(const std::string& tag if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; // std::cout << TAGNAME(childs.item(i)) << std::endl; - if(iequals(TAGNAME(childs.item(i)), tagName)) { + if(iequals(TAGNAME_CAST(childs.item(i)), tagName)) { filteredChildElems.push_back(childs.item(i)); } if (recurse) { @@ -2308,6 +2339,11 @@ NodeSet InterpreterImpl::filterChildType(const Node_base::Type type NodeSet InterpreterImpl::getProperAncestors(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2) { + + std::pair, Arabica::DOM::Node > ancPair = std::make_pair(s1, s2); + if (_cachedProperAncestors.find(ancPair) != _cachedProperAncestors.end()) + return _cachedProperAncestors[ancPair]; + NodeSet ancestors; if (isState(Element(s1))) { Arabica::DOM::Node node = s1; @@ -2329,6 +2365,7 @@ NodeSet InterpreterImpl::getProperAncestors(const Arabica::DOM::Nod ancestors.push_back(node); } } + _cachedProperAncestors[ancPair] = ancestors; return ancestors; } @@ -2433,6 +2470,18 @@ bool InterpreterImpl::isAtomic(const Arabica::DOM::Element& state) if (iequals("parallel", LOCALNAME(state))) return false; +#if 0 + Arabica::DOM::Node child = state.getFirstChild(); + while(child) { + if (child.getNodeType() == Node_base::ELEMENT_NODE) { + if (isState(Element(child))) + return false; + } + child = child.getNextSibling(); + } + +#else + Arabica::DOM::NodeList childs = state.getChildNodes(); for (unsigned int i = 0; i < childs.getLength(); i++) { if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) @@ -2441,6 +2490,8 @@ bool InterpreterImpl::isAtomic(const Arabica::DOM::Element& state) if (isState(Element(childs.item(i)))) return false; } +#endif + return true; } @@ -2665,9 +2716,9 @@ bool InterpreterImpl::isLegalConfiguration(const NodeSet& config) { bool InterpreterImpl::isInState(const std::string& stateId) { if (HAS_ATTR(_scxml, "flat") && DOMUtils::attributeIsTrue(ATTR(_scxml, "flat"))) { // extension for flattened SCXML documents - if (_configuration.size() > 0 && HAS_ATTR(_configuration[0], "id")) { + if (_configuration.size() > 0 && HAS_ATTR_CAST(_configuration[0], "id")) { // all states are encoded in the current statename - std::string encStateList = ATTR(_configuration[0], "id"); + std::string encStateList = ATTR_CAST(_configuration[0], "id"); size_t startActive = encStateList.find_first_of("-"); size_t endActive = encStateList.find_first_of(";"); encStateList = encStateList.substr(startActive, endActive - startActive); @@ -2685,8 +2736,8 @@ bool InterpreterImpl::isInState(const std::string& stateId) { } else { for (int i = 0; i < _configuration.size(); i++) { - if (HAS_ATTR(_configuration[i], "id") && - iequals(ATTR(_configuration[i], "id"), stateId)) { + if (HAS_ATTR_CAST(_configuration[i], "id") && + iequals(ATTR_CAST(_configuration[i], "id"), stateId)) { return true; } } @@ -2694,17 +2745,27 @@ bool InterpreterImpl::isInState(const std::string& stateId) { return false; } -void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event& event) { - // remove modified states from cache - if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes +void InterpreterImpl::handleDOMEvent(Arabica::DOM::Events::Event& event) { + // clear targets + _cachedTargets.clear(); + + if (event.getType().compare("DOMAttrModified") == 0) // we do not care about other attributes return; + + // remove modified states from cache Node target = Arabica::DOM::Node(event.getTarget()); - NodeSet childs = InterpreterImpl::filterChildElements(_interpreter->_nsInfo.xmlNSPrefix + "state", target); + NodeSet childs = InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "state", target); for (int i = 0; i < childs.size(); i++) { - if (HAS_ATTR(childs[i], "id")) { - _interpreter->_cachedStates.erase(ATTR(childs[i], "id")); + if (HAS_ATTR_CAST(childs[i], "id")) { + _cachedStates.erase(ATTR_CAST(childs[i], "id")); } } + // it's more stress to search through all pairs, just have them recalculated + _cachedProperAncestors.clear(); +} + +void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event& event) { + _interpreter->handleDOMEvent(event); } std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState) { diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 3cd6016..c3acc98 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -435,6 +435,8 @@ public: Arabica::DOM::Node findLCCA(const Arabica::XPath::NodeSet& states); virtual Arabica::XPath::NodeSet getProperAncestors(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2); + virtual void handleDOMEvent(Arabica::DOM::Events::Event& event); + protected: static void run(void*); // static method for thread to run @@ -512,19 +514,19 @@ protected: virtual void executeContent(const Arabica::DOM::NodeList& content, bool rethrow = false); virtual void executeContent(const Arabica::XPath::NodeSet& content, bool rethrow = false); - void processContentElement(const Arabica::DOM::Node& element, + void processContentElement(const Arabica::DOM::Element& element, Arabica::DOM::Node& dom, std::string& text, std::string& expr); - void processParamChilds(const Arabica::DOM::Node& element, + void processParamChilds(const Arabica::DOM::Element& element, std::multimap& params); - void processDOMorText(const Arabica::DOM::Node& element, + void processDOMorText(const Arabica::DOM::Element& element, Arabica::DOM::Node& dom, std::string& text); - virtual void send(const Arabica::DOM::Node& element); - virtual void invoke(const Arabica::DOM::Node& element); - virtual void cancelInvoke(const Arabica::DOM::Node& element); + virtual void send(const Arabica::DOM::Element& element); + virtual void invoke(const Arabica::DOM::Element& element); + virtual void cancelInvoke(const Arabica::DOM::Element& element); virtual void internalDoneSend(const Arabica::DOM::Element& state); static void delayedSend(void* userdata, std::string eventName); void returnDoneEvent(const Arabica::DOM::Node& state); @@ -540,7 +542,8 @@ protected: std::map _invokers; std::map, ExecutableContent> _executableContent; - /// TODO: We need to adapt them when the DOM is operated upon + std::map, Arabica::DOM::Node >, Arabica::XPath::NodeSet > _cachedProperAncestors; + std::map, Arabica::XPath::NodeSet > _cachedTargets; std::map > _cachedStates; std::map _cachedURLs; diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp index e833a10..be053d7 100644 --- a/src/uscxml/debug/SCXMLDotWriter.cpp +++ b/src/uscxml/debug/SCXMLDotWriter.cpp @@ -401,7 +401,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element histories = InterpreterImpl::filterChildElements(_xmlNSPrefix + "history", stateElem); for (int i = 0; i < histories.size(); i++) { - os << " history: " << ATTR(histories[i], "id") << "" << std::endl; + os << " history: " << ATTR_CAST(histories[i], "id") << "" << std::endl; } @@ -548,41 +548,42 @@ std::string SCXMLDotWriter::getDetailedLabel(const Element& elem, i for (int i = 0; i < childElems.getLength(); i++) { if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; + Element elem = Element(childElems.item(i)); - if (InterpreterImpl::isState(Element(childElems.item(i))) || - iequals(TAGNAME(childElems.item(i)), "transition") || - iequals(TAGNAME(childElems.item(i)), "initial") || + if (InterpreterImpl::isState(elem) || + iequals(TAGNAME(elem), "transition") || + iequals(TAGNAME(elem), "initial") || false) continue; struct ElemDetails details; - details.name = "" + TAGNAME(childElems.item(i)) + ":"; + details.name = "" + TAGNAME(elem) + ":"; - if (iequals(TAGNAME(childElems.item(i)), "history")) { + if (iequals(TAGNAME(elem), "history")) { continue; } // provide details for special elements here // param --------- - if (iequals(TAGNAME(childElems.item(i)), "param")) { - if (HAS_ATTR(childElems.item(i), "name")) - details.name += " " + ATTR(childElems.item(i), "name") + " = "; - if (HAS_ATTR(childElems.item(i), "expr")) - details.name += ATTR(childElems.item(i), "expr"); - if (HAS_ATTR(childElems.item(i), "location")) - details.name += ATTR(childElems.item(i), "location"); + if (iequals(TAGNAME(elem), "param")) { + if (HAS_ATTR(elem, "name")) + details.name += " " + ATTR(elem, "name") + " = "; + if (HAS_ATTR(elem, "expr")) + details.name += ATTR(elem, "expr"); + if (HAS_ATTR(elem, "location")) + details.name += ATTR(elem, "location"); } // data --------- - if (iequals(TAGNAME(childElems.item(i)), "data")) { - if (HAS_ATTR(childElems.item(i), "id")) - details.name += " " + ATTR(childElems.item(i), "id"); - if (HAS_ATTR(childElems.item(i), "src")) - details.name += ATTR(childElems.item(i), "src"); - if (HAS_ATTR(childElems.item(i), "expr")) - details.name += " = " + ATTR(childElems.item(i), "expr"); - NodeList grandChildElems = childElems.item(i).getChildNodes(); + if (iequals(TAGNAME(elem), "data")) { + if (HAS_ATTR(elem, "id")) + details.name += " " + ATTR(elem, "id"); + if (HAS_ATTR(elem, "src")) + details.name += ATTR(elem, "src"); + if (HAS_ATTR(elem, "expr")) + details.name += " = " + ATTR(elem, "expr"); + NodeList grandChildElems = elem.getChildNodes(); for (int j = 0; j < grandChildElems.getLength(); j++) { if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) { details.name += dotEscape(grandChildElems.item(j).getNodeValue()); @@ -591,60 +592,60 @@ std::string SCXMLDotWriter::getDetailedLabel(const Element& elem, i } // invoke --------- - if (iequals(TAGNAME(childElems.item(i)), "invoke")) { - if (HAS_ATTR(childElems.item(i), "type")) - details.name += "
type = " + ATTR(childElems.item(i), "type"); - if (HAS_ATTR(childElems.item(i), "typeexpr")) - details.name += "
type = " + ATTR(childElems.item(i), "typeexpr"); - if (HAS_ATTR(childElems.item(i), "src")) - details.name += "
src = " + ATTR(childElems.item(i), "src"); - if (HAS_ATTR(childElems.item(i), "srcexpr")) - details.name += "
src = " + ATTR(childElems.item(i), "srcexpr"); - if (HAS_ATTR(childElems.item(i), "id")) - details.name += "
id = " + ATTR(childElems.item(i), "id"); - if (HAS_ATTR(childElems.item(i), "idlocation")) - details.name += "
id = " + ATTR(childElems.item(i), "idlocation"); + if (iequals(TAGNAME(elem), "invoke")) { + if (HAS_ATTR(elem, "type")) + details.name += "
type = " + ATTR(elem, "type"); + if (HAS_ATTR(elem, "typeexpr")) + details.name += "
type = " + ATTR(elem, "typeexpr"); + if (HAS_ATTR(elem, "src")) + details.name += "
src = " + ATTR(elem, "src"); + if (HAS_ATTR(elem, "srcexpr")) + details.name += "
src = " + ATTR(elem, "srcexpr"); + if (HAS_ATTR(elem, "id")) + details.name += "
id = " + ATTR(elem, "id"); + if (HAS_ATTR(elem, "idlocation")) + details.name += "
id = " + ATTR(elem, "idlocation"); } // send --------- - if (iequals(TAGNAME(childElems.item(i)), "raise")) { - if (HAS_ATTR(childElems.item(i), "event ")) - details.name += "
event = " + ATTR(childElems.item(i), "event"); + if (iequals(TAGNAME(elem), "raise")) { + if (HAS_ATTR(elem, "event ")) + details.name += "
event = " + ATTR(elem, "event"); } // send --------- - if (iequals(TAGNAME(childElems.item(i)), "send")) { - if (HAS_ATTR(childElems.item(i), "id")) - details.name += "
id = " + ATTR(childElems.item(i), "id"); - if (HAS_ATTR(childElems.item(i), "type")) - details.name += "
type = " + ATTR(childElems.item(i), "type"); - if (HAS_ATTR(childElems.item(i), "typeexpr")) - details.name += "
type = " + ATTR(childElems.item(i), "typeexpr"); - if (HAS_ATTR(childElems.item(i), "event")) - details.name += "
event = " + ATTR(childElems.item(i), "event"); - if (HAS_ATTR(childElems.item(i), "eventexpr")) - details.name += "
event = " + ATTR(childElems.item(i), "eventexpr"); - if (HAS_ATTR(childElems.item(i), "target")) - details.name += "
target = " + ATTR(childElems.item(i), "target"); - if (HAS_ATTR(childElems.item(i), "targetexpr")) - details.name += "
target = " + ATTR(childElems.item(i), "targetexpr"); - if (HAS_ATTR(childElems.item(i), "delay")) - details.name += "
delay = " + ATTR(childElems.item(i), "delay"); - if (HAS_ATTR(childElems.item(i), "delayexpr")) - details.name += "
delay = " + ATTR(childElems.item(i), "delayexpr"); + if (iequals(TAGNAME(elem), "send")) { + if (HAS_ATTR(elem, "id")) + details.name += "
id = " + ATTR(elem, "id"); + if (HAS_ATTR(elem, "type")) + details.name += "
type = " + ATTR(elem, "type"); + if (HAS_ATTR(elem, "typeexpr")) + details.name += "
type = " + ATTR(elem, "typeexpr"); + if (HAS_ATTR(elem, "event")) + details.name += "
event = " + ATTR(elem, "event"); + if (HAS_ATTR(elem, "eventexpr")) + details.name += "
event = " + ATTR(elem, "eventexpr"); + if (HAS_ATTR(elem, "target")) + details.name += "
target = " + ATTR(elem, "target"); + if (HAS_ATTR(elem, "targetexpr")) + details.name += "
target = " + ATTR(elem, "targetexpr"); + if (HAS_ATTR(elem, "delay")) + details.name += "
delay = " + ATTR(elem, "delay"); + if (HAS_ATTR(elem, "delayexpr")) + details.name += "
delay = " + ATTR(elem, "delayexpr"); } // cancel --------- - if (iequals(TAGNAME(childElems.item(i)), "cancel")) { - if (HAS_ATTR(childElems.item(i), "sendid")) - details.name += " " + ATTR(childElems.item(i), "sendid"); + if (iequals(TAGNAME(elem), "cancel")) { + if (HAS_ATTR(elem, "sendid")) + details.name += " " + ATTR(elem, "sendid"); } // script --------- - if (iequals(TAGNAME(childElems.item(i)), "script")) { + if (iequals(TAGNAME(elem), "script")) { details.name += " "; - if (HAS_ATTR(childElems.item(i), "src")) - details.name += ATTR(childElems.item(i), "src"); + if (HAS_ATTR(elem, "src")) + details.name += ATTR(elem, "src"); NodeList grandChildElems = childElems.item(i).getChildNodes(); for (int j = 0; j < grandChildElems.getLength(); j++) { if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) { @@ -654,34 +655,34 @@ std::string SCXMLDotWriter::getDetailedLabel(const Element& elem, i } // if --------- - if (iequals(TAGNAME(childElems.item(i)), "if")) { - if (HAS_ATTR(childElems.item(i), "cond")) - details.name += " cond = " + dotEscape(ATTR(childElems.item(i), "cond")); + if (iequals(TAGNAME(elem), "if")) { + if (HAS_ATTR(elem, "cond")) + details.name += " cond = " + dotEscape(ATTR(elem, "cond")); } // elseif --------- - if (iequals(TAGNAME(childElems.item(i)), "elseif")) { - if (HAS_ATTR(childElems.item(i), "cond")) - details.name += " cond = " + dotEscape(ATTR(childElems.item(i), "cond")); + if (iequals(TAGNAME(elem), "elseif")) { + if (HAS_ATTR(elem, "cond")) + details.name += " cond = " + dotEscape(ATTR(elem, "cond")); } // log --------- - if (iequals(TAGNAME(childElems.item(i)), "log")) { + if (iequals(TAGNAME(elem), "log")) { details.name += " "; - if (HAS_ATTR(childElems.item(i), "label")) - details.name += ATTR(childElems.item(i), "label") + " = "; - if (HAS_ATTR(childElems.item(i), "expr")) - details.name += ATTR(childElems.item(i), "expr"); + if (HAS_ATTR(elem, "label")) + details.name += ATTR(elem, "label") + " = "; + if (HAS_ATTR(elem, "expr")) + details.name += ATTR(elem, "expr"); } // foreach --------- - if (iequals(TAGNAME(childElems.item(i)), "foreach")) { - if (HAS_ATTR(childElems.item(i), "item")) - details.name += "
  item = " + ATTR(childElems.item(i), "item"); - if (HAS_ATTR(childElems.item(i), "array")) - details.name += "
  array = " + ATTR(childElems.item(i), "array"); - if (HAS_ATTR(childElems.item(i), "index")) - details.name += "
  index = " + ATTR(childElems.item(i), "index"); + if (iequals(TAGNAME(elem), "foreach")) { + if (HAS_ATTR(elem, "item")) + details.name += "
  item = " + ATTR(elem, "item"); + if (HAS_ATTR(elem, "array")) + details.name += "
  array = " + ATTR(elem, "array"); + if (HAS_ATTR(elem, "index")) + details.name += "
  index = " + ATTR(elem, "index"); } // recurse @@ -814,7 +815,7 @@ std::string SCXMLDotWriter::idForNode(const Node& node) { index++; std::stringstream ssElemId; - ssElemId << TAGNAME(tmpParent) << index << "."; + ssElemId << TAGNAME_CAST(tmpParent) << index << "."; elemId = ssElemId.str() + elemId; } while ((tmpParent = tmpParent.getParentNode())); // elemId = ssElemId.str(); diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 554cd28..92333f1 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -105,7 +105,7 @@ NodeSet InterpreterDraft6::getDocumentInitialTransitions() { Element transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); _nsInfo.setPrefix(transitionElem); - transitionElem.setAttribute("target", ATTR(initialStates[i], "id")); + transitionElem.setAttribute("target", ATTR_CAST(initialStates[i], "id")); initialElem.appendChild(transitionElem); _scxml.appendChild(initialElem); initialTransitions.push_back(transitionElem); @@ -138,13 +138,6 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { setInterpreterState(USCXML_MICROSTEPPED); } - if (!isLegalConfiguration(_configuration)) { - std:: cout << "Illegal configuration: {"; - for (int i = 0; i < _configuration.size(); i++) { - std::cout << ATTR(_configuration[i], "id") << ", " << std::endl; - } - std:: cout << "}" << std::endl; - } assert(isLegalConfiguration(_configuration)); // are there spontaneous transitions? @@ -203,8 +196,9 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); for (unsigned int j = 0; j < invokes.size(); j++) { - if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) { - invoke(invokes[j]); + Element invokeElem = Element(invokes[j]); + if (!HAS_ATTR(invokeElem, "persist") || !DOMUtils::attributeIsTrue(ATTR(invokeElem, "persist"))) { + invoke(invokeElem); } } } @@ -354,8 +348,9 @@ void InterpreterDraft6::stabilize() { for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); for (unsigned int j = 0; j < invokes.size(); j++) { - if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) { - invoke(invokes[j]); + Element invokeElem = Element(invokes[j]); + if (!HAS_ATTR(invokeElem, "persist") || !DOMUtils::attributeIsTrue(ATTR(invokeElem, "persist"))) { + invoke(invokeElem); } } } @@ -641,7 +636,7 @@ void InterpreterDraft6::exitInterpreter() { Arabica::XPath::NodeSet 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(invokeElems[j]); + cancelInvoke(Element(invokeElems[j])); } Element stateElem(statesToExit[i]); if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { @@ -902,8 +897,9 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet& for (unsigned int k = 0; k < statesToEnter.size(); k++) { NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToEnter[k]); for (unsigned int j = 0; j < invokes.size(); j++) { - if (HAS_ATTR(invokes[j], "persist") && DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) { - invoke(invokes[j]); + Element invokeElem = Element(invokes[j]); + if (HAS_ATTR(invokeElem, "persist") && DOMUtils::attributeIsTrue(ATTR(invokeElem, "persist"))) { + invoke(invokeElem); } } } @@ -1063,5 +1059,20 @@ void InterpreterDraft6::addStatesToEnter(const Element& state, } } +void InterpreterDraft6::handleDOMEvent(Arabica::DOM::Events::Event& event) { + InterpreterImpl::handleDOMEvent(event); + + // remove modified states from cache + if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes + return; + Node target = Arabica::DOM::Node(event.getTarget()); + NodeSet transitions = InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "transition", target); + for (int i = 0; i < transitions.size(); i++) { + const Element transElem = Element(transitions[i]); + if (_transWithinParallel.find(transElem) != _transWithinParallel.end()) + _transWithinParallel.erase(transElem); + } +} + } \ No newline at end of file diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h index 062d79a..3414e5e 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.h +++ b/src/uscxml/interpreter/InterpreterDraft6.h @@ -56,6 +56,9 @@ protected: Arabica::DOM::Node findLCPA(const Arabica::XPath::NodeSet& states); std::map, bool> _transWithinParallel; // this is costly to calculate + + virtual void handleDOMEvent(Arabica::DOM::Events::Event& event); + }; } diff --git a/src/uscxml/interpreter/InterpreterRC.cpp b/src/uscxml/interpreter/InterpreterRC.cpp deleted file mode 100644 index 24b9003..0000000 --- a/src/uscxml/interpreter/InterpreterRC.cpp +++ /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 . - * @endcond - */ - -#include "InterpreterRC.h" - -#include "uscxml/Factory.h" -#include "uscxml/concurrency/DelayedEventQueue.h" - -#include -#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 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 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(dataElems[i])); - } - } - } else if(_dataModel) { - // initialize current data elements - NodeSet 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(topDataElems[i])); - } - } - - // executeGlobalScriptElements - NodeSet globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml); - for (unsigned int i = 0; i < globalScriptElems.size(); i++) { - if (_dataModel) { - executeContent(Element(globalScriptElems[i])); - } - } - - NodeSet initialTransitions; - - if (_startConfiguration.size() > 0) { - // we emulate entering a given configuration by creating a pseudo deep history - Element 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 histStates; - for (std::list::const_iterator stateIter = _startConfiguration.begin(); stateIter != _startConfiguration.end(); stateIter++) { - histStates.push_back(getState(*stateIter)); - } - _historyValue[histId] = histStates; - - Element initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element 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 initialStates; - // fetch per draft - initialStates = getInitialStates(); - assert(initialStates.size() > 0); - for (int i = 0; i < initialStates.size(); i++) { - Element initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", ATTR(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 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 invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - invoke(invokes[j]); - } - } - _statesToInvoke = NodeSet(); - - 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(_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 invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _configuration[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - Element invokeElem = (Element)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 finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeElem); - for (int k = 0; k < finalizes.size(); k++) { - Element finalizeElem = Element(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 >::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 statesToExit = _configuration; - statesToExit.forward(false); - statesToExit.sort(); - - for (int i = 0; i < statesToExit.size(); i++) { - Arabica::XPath::NodeSet onExitElems = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", statesToExit[i]); - for (int j = 0; j < onExitElems.size(); j++) { - executeContent(Element(onExitElems[j])); - } - Arabica::XPath::NodeSet invokeElems = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); - for (int j = 0; j < invokeElems.size(); j++) { - cancelInvoke(invokeElems[j]); - } - Element stateElem(statesToExit[i]); - if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { - returnDoneEvent(stateElem); - } - } - _configuration = NodeSet(); -} - -/** -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 InterpreterRC::selectEventlessTransitions() { - Arabica::XPath::NodeSet enabledTransitions; - - NodeSet atomicStates; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(Element(_configuration[i]))) - atomicStates.push_back(_configuration[i]); - } - atomicStates.to_document_order(); - - for (unsigned int i = 0; i < atomicStates.size(); i++) { - const Node& state = atomicStates[i]; - NodeSet withAncestors; - withAncestors.push_back(state); - withAncestors.push_back(getProperAncestors(state, Node())); - for (unsigned int j = 0; j < withAncestors.size(); j++) { - const Node& ancestor = withAncestors[i]; - NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", ancestor); - for (unsigned int k = 0; k < transitions.size(); k++) { - Element 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 InterpreterRC::selectTransitions(const std::string& event) { - Arabica::XPath::NodeSet enabledTransitions; - - NodeSet atomicStates; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(Element(_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& state = atomicStates[i]; -#if 0 - std::cout << " == from " << ATTR(state, "id") << std::endl; -#endif - - NodeSet withAncestors; - withAncestors.push_back(state); - withAncestors.push_back(getProperAncestors(state, Node())); - for (unsigned int j = 0; j < withAncestors.size(); j++) { - const Node& ancestor = withAncestors[j]; - NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", ancestor); - for (unsigned int k = 0; k < transitions.size(); k++) { - if (isEnabledTransition(Element(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& 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 eventNames = tokenizeIdRefs(eventName); - std::list::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 InterpreterRC::removeConflictingTransitions(const Arabica::XPath::NodeSet& enabledTransitions) { - Arabica::XPath::NodeSet filteredTransitions; - - for (unsigned int i = 0; i < enabledTransitions.size(); i++) { - Element t1(enabledTransitions[i]); - bool t1Preempted = false; - Arabica::XPath::NodeSet transitionsToRemove; - - for (unsigned int j = 0; j < filteredTransitions.size(); j++) { - Element 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 > tmp; - for (int i = 0; i < filteredTransitions.size(); i++) { - if (!isMember(filteredTransitions[i], transitionsToRemove)) { - tmp.push_back(filteredTransitions[i]); - } - } - filteredTransitions = NodeSet(); - filteredTransitions.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); - - filteredTransitions.push_back(t1); - } - } - return filteredTransitions; -} - -bool InterpreterRC::hasIntersection(const Arabica::XPath::NodeSet& nodeSet1, const Arabica::XPath::NodeSet& 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& enabledTransitions) { - - USCXML_MONITOR_CALLBACK(beforeMicroStep) - - exitStates(enabledTransitions); - - for (int i = 0; i < enabledTransitions.size(); i++) { - Element 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& enabledTransitions) { - NodeSet statesToExit = computeExitSet(enabledTransitions); - - // remove statesToExit from _statesToInvoke - std::list > tmp; - for (int i = 0; i < _statesToInvoke.size(); i++) { - if (!isMember(_statesToInvoke[i], statesToExit)) { - tmp.push_back(_statesToInvoke[i]); - } - } - _statesToInvoke = NodeSet(); - _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); - - statesToExit.forward(false); - statesToExit.sort(); - - for (int i = 0; i < statesToExit.size(); i++) { - NodeSet histories = filterChildElements(_nsInfo.xmlNSPrefix + "history", statesToExit[i]); - for (int j = 0; j < histories.size(); j++) { - Element historyElem = (Element)histories[j]; - std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow"); - NodeSet historyNodes; - for (int k = 0; k < _configuration.size(); k++) { - if (iequals(historyType, "deep")) { - if (isAtomic(Element(_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(statesToExit[i]), (i + 1 < statesToExit.size())) - - NodeSet onExits = filterChildElements(_nsInfo.xmlNSPrefix + "onExit", statesToExit[i]); - for (int j = 0; j < onExits.size(); j++) { - Element onExitElem = (Element)onExits[j]; - executeContent(onExitElem); - } - - USCXML_MONITOR_CALLBACK3(afterExitingState, Element(statesToExit[i]), (i + 1 < statesToExit.size())) - - NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); - for (int j = 0; j < invokes.size(); j++) { - Element invokeElem = (Element)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(); - _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 InterpreterRC::computeExitSet(const Arabica::XPath::NodeSet& transitions) { - NodeSet statesToExit; - for (unsigned int i = 0; i < transitions.size(); i++) { - Element t(transitions[i]); - if (isTargetless(t)) - continue; - Arabica::DOM::Node domain = getTransitionDomain(t); - if (!domain) - continue; - for (unsigned int j = 0; j < _configuration.size(); j++) { - const Node& 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 InterpreterRC::computeExitSet(const Arabica::DOM::Node& transition) { - Arabica::XPath::NodeSet 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& enabledTransitions) { - NodeSet statesToEnter; - NodeSet statesForDefaultEntry; - // initialize the temporary table for default content in history states - std::map > defaultHistoryContent; - - computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent); - statesToEnter.to_document_order(); - - for (int i = 0; i < statesToEnter.size(); i++) { - Element s = (Element)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 dataModelElems = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", s); - if(dataModelElems.size() > 0 && _dataModel) { - Arabica::XPath::NodeSet 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(dataElems[j])); - } - } - _alreadyEntered.push_back(s); - // stateElem.setAttribute("isFirstEntry", ""); - } - // execute onentry executable content - NodeSet 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 transitions = _xpath.evaluate("" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", s).asNodeSet(); - executeContent(transitions); - } - if (defaultHistoryContent.find(ATTR(s, "id")) != defaultHistoryContent.end()) { - executeContent(Element(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 parent = (Element)s.getParentNode(); - Element grandParent = (Element)parent.getParentNode(); - - internalDoneSend(parent); - - if (isParallel(grandParent)) { - Arabica::XPath::NodeSet 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& transitions, - NodeSet& statesToEnter, - NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent) { - for (int i = 0; i < transitions.size(); i++) { - Element t(transitions[i]); - - NodeSet 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 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 t = (Element)transitions[i]; - Node ancestor = getTransitionDomain(t); - NodeSet targets = getTargetStates(t); - for (int j = 0; j < targets.size(); j++) { - const Node& 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& transition, - NodeSet& statesToEnter, - NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent) { - Arabica::XPath::NodeSet 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& state, - Arabica::XPath::NodeSet& statesToEnter, - Arabica::XPath::NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent) { - if (isHistory(Element(state))) { - std::string stateId = ATTR(state, "id"); - if (_historyValue.find(stateId) != _historyValue.end()) { - const Arabica::XPath::NodeSet& historyValue = _historyValue[stateId]; - for (int i = 0; i < historyValue.size(); i++) { - const Node& s = historyValue[i]; - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); - addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); - } - } else { - NodeSet 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 targets = getTargetStates(Element(transitions[i])); - for (int j = 0; j < targets.size(); j++) { - const Node& 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(state))) { - statesForDefaultEntry.push_back(state); - NodeSet targets = getInitialStates(Element(state)); - for (int i = 0; i < targets.size(); i++) { - const Node& s = targets[i]; - addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); - addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); - } - } else if(isParallel(Element(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 childStates = getChildStates(state); - for (int i = 0; i < childStates.size(); i++) { - const Node& child = childStates[i]; - for (int j = 0; j < statesToEnter.size(); j++) { - const Node& 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& state, - const Arabica::DOM::Node& ancestor, - Arabica::XPath::NodeSet& statesToEnter, - Arabica::XPath::NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent) { - NodeSet ancestors = getProperAncestors(state,ancestor); - for (int i = 0; i < ancestors.size(); i++) { - const Node& anc = ancestors[i]; - statesToEnter.push_back(anc); - if (isParallel(Element(anc))) { - NodeSet childStates = getChildStates(anc); - for (int j = 0; j < childStates.size(); j++) { - const Node& child = childStates[j]; - for (int k = 0; k < statesToEnter.size(); k++) { - const Node& 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& state) { - if (isCompound(Element(state))) { - Arabica::XPath::NodeSet childs = getChildStates(state); - for (int i = 0; i < childs.size(); i++) { - if (isFinal(Element(childs[i])) && isMember(childs[i], _configuration)) - return true; - } - } else if (isParallel(Element(state))) { - Arabica::XPath::NodeSet 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 InterpreterRC::getTransitionDomain(const Arabica::DOM::Element& transition) { - NodeSet tStates = getTargetStates(transition); - Node source = getSourceState(transition); - -#if 0 - std::cout << "getTransitionDomain: " << std::endl << transition << std::endl; -#endif - - if (tStates.size() == 0) { - return Arabica::DOM::Node(); // null - } - std::string transitionType = (HAS_ATTR(transition, "type") ? ATTR(transition, "type") : "external"); - - if (iequals(transitionType, "internal") && isCompound(Element(source))) { - for (int i = 0; i < tStates.size(); i++) { - const Node& s = tStates[i]; - if (!isDescendant(s, source)) - goto BREAK_LOOP; - } - return source; - } -BREAK_LOOP: - ; - Arabica::XPath::NodeSet 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 InterpreterRC::findLCCA(const Arabica::XPath::NodeSet& states) { - Arabica::XPath::NodeSet ancestors = getProperAncestors(states[0], Arabica::DOM::Node()); - // ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec? - Arabica::DOM::Node ancestor; - for (int i = 0; i < ancestors.size(); i++) { - if (!isCompound(Element(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 - 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 InterpreterRC::getProperAncestors(const Arabica::DOM::Node& state1, const Arabica::DOM::Node& state2) { - NodeSet ancestors; - - if (!state1 || !isState(Element(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 element). - */ - Arabica::DOM::Node parent = state1.getParentNode(); - while(parent && isState(Element(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 parent = state1.getParentNode(); - while(parent && isState(Element(parent)) && parent != state2) { - ancestors.push_back(parent); - parent = parent.getParentNode(); - } - return ancestors; -} - -NodeSet InterpreterRC::getTargetStates(const Arabica::DOM::Element& transition) { - NodeSet targetStates; - - std::string targetId = ((Arabica::DOM::Element)transition).getAttribute("target"); - std::list targetIds = InterpreterImpl::tokenizeIdRefs(ATTR(transition, "target")); - if (targetIds.size() > 0) { - for (std::list::const_iterator targetIter = targetIds.begin(); targetIter != targetIds.end(); targetIter++) { - Arabica::DOM::Node 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& state1, const Arabica::DOM::Node& state2) { - return false; -} - -/** -Returns a list containing all , , and children of state1. -*/ -Arabica::XPath::NodeSet InterpreterRC::getChildStates(const Arabica::DOM::Node& state) { - return Arabica::XPath::NodeSet(); -} -#endif - - -} \ No newline at end of file diff --git a/src/uscxml/interpreter/InterpreterRC.cpp.deactivated b/src/uscxml/interpreter/InterpreterRC.cpp.deactivated new file mode 100644 index 0000000..9993227 --- /dev/null +++ b/src/uscxml/interpreter/InterpreterRC.cpp.deactivated @@ -0,0 +1,1292 @@ +/** + * @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 . + * @endcond + */ + +#include "InterpreterRC.h" + +#include "uscxml/Factory.h" +#include "uscxml/concurrency/DelayedEventQueue.h" + +#include +#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 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 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(dataElems[i])); + } + } + } else if(_dataModel) { + // initialize current data elements + NodeSet 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(topDataElems[i])); + } + } + + // executeGlobalScriptElements + NodeSet globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml); + for (unsigned int i = 0; i < globalScriptElems.size(); i++) { + if (_dataModel) { + executeContent(Element(globalScriptElems[i])); + } + } + + NodeSet initialTransitions; + + if (_startConfiguration.size() > 0) { + // we emulate entering a given configuration by creating a pseudo deep history + Element 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 histStates; + for (std::list::const_iterator stateIter = _startConfiguration.begin(); stateIter != _startConfiguration.end(); stateIter++) { + histStates.push_back(getState(*stateIter)); + } + _historyValue[histId] = histStates; + + Element initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); + _nsInfo.setPrefix(initialElem); + + initialElem.setAttribute("generated", "true"); + Element 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 initialStates; + // fetch per draft + initialStates = getInitialStates(); + assert(initialStates.size() > 0); + for (int i = 0; i < initialStates.size(); i++) { + Element initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); + _nsInfo.setPrefix(initialElem); + + initialElem.setAttribute("generated", "true"); + Element 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 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 invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); + for (unsigned int j = 0; j < invokes.size(); j++) { + invoke(invokes[j]); + } + } + _statesToInvoke = NodeSet(); + + 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 invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _configuration[i]); + for (unsigned int j = 0; j < invokes.size(); j++) { + Element invokeElem = (Element)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 finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeElem); + for (int k = 0; k < finalizes.size(); k++) { + Element finalizeElem = Element(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 >::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 statesToExit = _configuration; + statesToExit.forward(false); + statesToExit.sort(); + + for (int i = 0; i < statesToExit.size(); i++) { + Arabica::XPath::NodeSet onExitElems = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", statesToExit[i]); + for (int j = 0; j < onExitElems.size(); j++) { + executeContent(Element(onExitElems[j])); + } + Arabica::XPath::NodeSet invokeElems = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); + for (int j = 0; j < invokeElems.size(); j++) { + cancelInvoke(invokeElems[j]); + } + Element stateElem(statesToExit[i]); + if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { + returnDoneEvent(stateElem); + } + } + _configuration = NodeSet(); +} + +/** +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 InterpreterRC::selectEventlessTransitions() { + Arabica::XPath::NodeSet enabledTransitions; + + NodeSet atomicStates; + for (unsigned int i = 0; i < _configuration.size(); i++) { + if (isAtomic(Element(_configuration[i]))) + atomicStates.push_back(_configuration[i]); + } + atomicStates.to_document_order(); + + for (unsigned int i = 0; i < atomicStates.size(); i++) { + const Node& state = atomicStates[i]; + NodeSet withAncestors; + withAncestors.push_back(state); + withAncestors.push_back(getProperAncestors(state, Node())); + for (unsigned int j = 0; j < withAncestors.size(); j++) { + const Node& ancestor = withAncestors[i]; + NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", ancestor); + for (unsigned int k = 0; k < transitions.size(); k++) { + Element 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 InterpreterRC::selectTransitions(const std::string& event) { + Arabica::XPath::NodeSet enabledTransitions; + + NodeSet atomicStates; + for (unsigned int i = 0; i < _configuration.size(); i++) { + if (isAtomic(Element(_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& state = atomicStates[i]; +#if 0 + std::cout << " == from " << ATTR(state, "id") << std::endl; +#endif + + NodeSet withAncestors; + withAncestors.push_back(state); + withAncestors.push_back(getProperAncestors(state, Node())); + for (unsigned int j = 0; j < withAncestors.size(); j++) { + const Node& ancestor = withAncestors[j]; + NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", ancestor); + for (unsigned int k = 0; k < transitions.size(); k++) { + if (isEnabledTransition(Element(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& 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 eventNames = tokenizeIdRefs(eventName); + std::list::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 InterpreterRC::removeConflictingTransitions(const Arabica::XPath::NodeSet& enabledTransitions) { + Arabica::XPath::NodeSet filteredTransitions; + + for (unsigned int i = 0; i < enabledTransitions.size(); i++) { + Element t1(enabledTransitions[i]); + bool t1Preempted = false; + Arabica::XPath::NodeSet transitionsToRemove; + + for (unsigned int j = 0; j < filteredTransitions.size(); j++) { + Element 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 > tmp; + for (int i = 0; i < filteredTransitions.size(); i++) { + if (!isMember(filteredTransitions[i], transitionsToRemove)) { + tmp.push_back(filteredTransitions[i]); + } + } + filteredTransitions = NodeSet(); + filteredTransitions.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); + + filteredTransitions.push_back(t1); + } + } + return filteredTransitions; +} + +bool InterpreterRC::hasIntersection(const Arabica::XPath::NodeSet& nodeSet1, const Arabica::XPath::NodeSet& 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& enabledTransitions) { + + USCXML_MONITOR_CALLBACK(beforeMicroStep) + + exitStates(enabledTransitions); + + for (int i = 0; i < enabledTransitions.size(); i++) { + Element 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& enabledTransitions) { + NodeSet statesToExit = computeExitSet(enabledTransitions); + + // remove statesToExit from _statesToInvoke + std::list > tmp; + for (int i = 0; i < _statesToInvoke.size(); i++) { + if (!isMember(_statesToInvoke[i], statesToExit)) { + tmp.push_back(_statesToInvoke[i]); + } + } + _statesToInvoke = NodeSet(); + _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); + + statesToExit.forward(false); + statesToExit.sort(); + + for (int i = 0; i < statesToExit.size(); i++) { + NodeSet histories = filterChildElements(_nsInfo.xmlNSPrefix + "history", statesToExit[i]); + for (int j = 0; j < histories.size(); j++) { + Element historyElem = (Element)histories[j]; + std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow"); + NodeSet historyNodes; + for (int k = 0; k < _configuration.size(); k++) { + if (iequals(historyType, "deep")) { + if (isAtomic(Element(_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(statesToExit[i]), (i + 1 < statesToExit.size())) + + NodeSet onExits = filterChildElements(_nsInfo.xmlNSPrefix + "onExit", statesToExit[i]); + for (int j = 0; j < onExits.size(); j++) { + Element onExitElem = (Element)onExits[j]; + executeContent(onExitElem); + } + + USCXML_MONITOR_CALLBACK3(afterExitingState, Element(statesToExit[i]), (i + 1 < statesToExit.size())) + + NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]); + for (int j = 0; j < invokes.size(); j++) { + Element invokeElem = (Element)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(); + _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 InterpreterRC::computeExitSet(const Arabica::XPath::NodeSet& transitions) { + NodeSet statesToExit; + for (unsigned int i = 0; i < transitions.size(); i++) { + Element t(transitions[i]); + if (isTargetless(t)) + continue; + Arabica::DOM::Node domain = getTransitionDomain(t); + if (!domain) + continue; + for (unsigned int j = 0; j < _configuration.size(); j++) { + const Node& 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 InterpreterRC::computeExitSet(const Arabica::DOM::Node& transition) { + Arabica::XPath::NodeSet 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& enabledTransitions) { + NodeSet statesToEnter; + NodeSet statesForDefaultEntry; + // initialize the temporary table for default content in history states + std::map > defaultHistoryContent; + + computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent); + statesToEnter.to_document_order(); + + for (int i = 0; i < statesToEnter.size(); i++) { + Element s = (Element)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 dataModelElems = filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", s); + if(dataModelElems.size() > 0 && _dataModel) { + Arabica::XPath::NodeSet 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(dataElems[j])); + } + } + _alreadyEntered.push_back(s); + // stateElem.setAttribute("isFirstEntry", ""); + } + // execute onentry executable content + NodeSet 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 transitions = _xpath.evaluate("" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", s).asNodeSet(); + executeContent(transitions); + } + if (defaultHistoryContent.find(ATTR(s, "id")) != defaultHistoryContent.end()) { + executeContent(Element(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 parent = (Element)s.getParentNode(); + Element grandParent = (Element)parent.getParentNode(); + + internalDoneSend(parent); + + if (isParallel(grandParent)) { + Arabica::XPath::NodeSet 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& transitions, + NodeSet& statesToEnter, + NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent) { + for (int i = 0; i < transitions.size(); i++) { + Element t(transitions[i]); + + NodeSet 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 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 t = (Element)transitions[i]; + Node ancestor = getTransitionDomain(t); + NodeSet targets = getTargetStates(t); + for (int j = 0; j < targets.size(); j++) { + const Node& 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& transition, + NodeSet& statesToEnter, + NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent) { + Arabica::XPath::NodeSet 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& state, + Arabica::XPath::NodeSet& statesToEnter, + Arabica::XPath::NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent) { + if (isHistory(Element(state))) { + std::string stateId = ATTR(state, "id"); + if (_historyValue.find(stateId) != _historyValue.end()) { + const Arabica::XPath::NodeSet& historyValue = _historyValue[stateId]; + for (int i = 0; i < historyValue.size(); i++) { + const Node& s = historyValue[i]; + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + } else { + NodeSet 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 targets = getTargetStates(Element(transitions[i])); + for (int j = 0; j < targets.size(); j++) { + const Node& 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(state))) { + statesForDefaultEntry.push_back(state); + NodeSet targets = getInitialStates(Element(state)); + for (int i = 0; i < targets.size(); i++) { + const Node& s = targets[i]; + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent); + addAncestorStatesToEnter(s, getParentState(s), statesToEnter, statesForDefaultEntry, defaultHistoryContent); + } + } else if(isParallel(Element(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 childStates = getChildStates(state); + for (int i = 0; i < childStates.size(); i++) { + const Node& child = childStates[i]; + for (int j = 0; j < statesToEnter.size(); j++) { + const Node& 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& state, + const Arabica::DOM::Node& ancestor, + Arabica::XPath::NodeSet& statesToEnter, + Arabica::XPath::NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent) { + NodeSet ancestors = getProperAncestors(state,ancestor); + for (int i = 0; i < ancestors.size(); i++) { + const Node& anc = ancestors[i]; + statesToEnter.push_back(anc); + if (isParallel(Element(anc))) { + NodeSet childStates = getChildStates(anc); + for (int j = 0; j < childStates.size(); j++) { + const Node& child = childStates[j]; + for (int k = 0; k < statesToEnter.size(); k++) { + const Node& 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& state) { + if (isCompound(Element(state))) { + Arabica::XPath::NodeSet childs = getChildStates(state); + for (int i = 0; i < childs.size(); i++) { + if (isFinal(Element(childs[i])) && isMember(childs[i], _configuration)) + return true; + } + } else if (isParallel(Element(state))) { + Arabica::XPath::NodeSet 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 InterpreterRC::getTransitionDomain(const Arabica::DOM::Element& transition) { + NodeSet tStates = getTargetStates(transition); + Node source = getSourceState(transition); + +#if 0 + std::cout << "getTransitionDomain: " << std::endl << transition << std::endl; +#endif + + if (tStates.size() == 0) { + return Arabica::DOM::Node(); // null + } + std::string transitionType = (HAS_ATTR(transition, "type") ? ATTR(transition, "type") : "external"); + + if (iequals(transitionType, "internal") && isCompound(Element(source))) { + for (int i = 0; i < tStates.size(); i++) { + const Node& s = tStates[i]; + if (!isDescendant(s, source)) + goto BREAK_LOOP; + } + return source; + } +BREAK_LOOP: + ; + Arabica::XPath::NodeSet 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 InterpreterRC::findLCCA(const Arabica::XPath::NodeSet& states) { + Arabica::XPath::NodeSet ancestors = getProperAncestors(states[0], Arabica::DOM::Node()); + // ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec? + Arabica::DOM::Node ancestor; + for (int i = 0; i < ancestors.size(); i++) { + if (!isCompound(Element(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 + 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 InterpreterRC::getProperAncestors(const Arabica::DOM::Node& state1, const Arabica::DOM::Node& state2) { + NodeSet ancestors; + + if (!state1 || !isState(Element(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 element). + */ + Arabica::DOM::Node parent = state1.getParentNode(); + while(parent && isState(Element(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 parent = state1.getParentNode(); + while(parent && isState(Element(parent)) && parent != state2) { + ancestors.push_back(parent); + parent = parent.getParentNode(); + } + return ancestors; +} + +NodeSet InterpreterRC::getTargetStates(const Arabica::DOM::Element& transition) { + NodeSet targetStates; + + std::string targetId = ((Arabica::DOM::Element)transition).getAttribute("target"); + std::list targetIds = InterpreterImpl::tokenizeIdRefs(ATTR(transition, "target")); + if (targetIds.size() > 0) { + for (std::list::const_iterator targetIter = targetIds.begin(); targetIter != targetIds.end(); targetIter++) { + Arabica::DOM::Node 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& state1, const Arabica::DOM::Node& state2) { + return false; +} + +/** +Returns a list containing all , , and children of state1. +*/ +Arabica::XPath::NodeSet InterpreterRC::getChildStates(const Arabica::DOM::Node& state) { + return Arabica::XPath::NodeSet(); +} +#endif + + +} \ No newline at end of file diff --git a/src/uscxml/interpreter/InterpreterRC.h b/src/uscxml/interpreter/InterpreterRC.h deleted file mode 100644 index 9afc2e6..0000000 --- a/src/uscxml/interpreter/InterpreterRC.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file - * @author 2012-2013 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 . - * @endcond - */ - -#ifndef INTERPRETERRC_H_WLJEI019 -#define INTERPRETERRC_H_WLJEI019 - -#include "uscxml/Interpreter.h" - -namespace uscxml { - -class InterpreterRC : public InterpreterImpl { - InterpreterState interpret(); - void mainEventLoop(); - void exitInterpreter(); - - void microstep(const Arabica::XPath::NodeSet& enabledTransitions); - - Arabica::XPath::NodeSet selectEventlessTransitions(); - Arabica::XPath::NodeSet selectTransitions(const std::string& event); - bool isEnabledTransition(const Arabica::DOM::Element& transition, const std::string& event); - bool hasIntersection(const Arabica::XPath::NodeSet& nodeSet1, const Arabica::XPath::NodeSet& nodeSet2); - - void enterStates(const Arabica::XPath::NodeSet& enabledTransitions); - void exitStates(const Arabica::XPath::NodeSet& enabledTransitions); - - Arabica::XPath::NodeSet computeExitSet(const Arabica::XPath::NodeSet& transitions); - Arabica::XPath::NodeSet computeExitSet(const Arabica::DOM::Node& transition); - - void computeEntrySet(const Arabica::XPath::NodeSet& transitions, - Arabica::XPath::NodeSet& statesToEnter, - Arabica::XPath::NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent); - void computeEntrySet(const Arabica::DOM::Node& transition, - Arabica::XPath::NodeSet& statesToEnter, - Arabica::XPath::NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent); - - Arabica::XPath::NodeSet removeConflictingTransitions(const Arabica::XPath::NodeSet& enabledTransitions); - Arabica::DOM::Node getTransitionDomain(const Arabica::DOM::Element& transition); - - void addDescendantStatesToEnter(const Arabica::DOM::Node& state, - Arabica::XPath::NodeSet& statesToEnter, - Arabica::XPath::NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent); - - void addAncestorStatesToEnter(const Arabica::DOM::Node& state, - const Arabica::DOM::Node& ancestor, - Arabica::XPath::NodeSet& statesToEnter, - Arabica::XPath::NodeSet& statesForDefaultEntry, - std::map > defaultHistoryContent); - - bool isInFinalState(const Arabica::DOM::Node& state); - Arabica::DOM::Node findLCCA(const Arabica::XPath::NodeSet& states); - - Arabica::XPath::NodeSet getProperAncestors(const Arabica::DOM::Node& s1, - const Arabica::DOM::Node& s2); - - Arabica::XPath::NodeSet getTargetStates(const Arabica::DOM::Element& transition); - -#if 0 - bool isDescendant(const Arabica::DOM::Node& state1, const Arabica::DOM::Node& state2); - Arabica::XPath::NodeSet getChildStates(const Arabica::DOM::Node& state); -#endif - - bool _running; - -}; - -} - -#endif /* end of include guard: INTERPRETERRC_H_WLJEI019 */ diff --git a/src/uscxml/interpreter/InterpreterRC.h.deactivated b/src/uscxml/interpreter/InterpreterRC.h.deactivated new file mode 100644 index 0000000..9afc2e6 --- /dev/null +++ b/src/uscxml/interpreter/InterpreterRC.h.deactivated @@ -0,0 +1,87 @@ +/** + * @file + * @author 2012-2013 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 . + * @endcond + */ + +#ifndef INTERPRETERRC_H_WLJEI019 +#define INTERPRETERRC_H_WLJEI019 + +#include "uscxml/Interpreter.h" + +namespace uscxml { + +class InterpreterRC : public InterpreterImpl { + InterpreterState interpret(); + void mainEventLoop(); + void exitInterpreter(); + + void microstep(const Arabica::XPath::NodeSet& enabledTransitions); + + Arabica::XPath::NodeSet selectEventlessTransitions(); + Arabica::XPath::NodeSet selectTransitions(const std::string& event); + bool isEnabledTransition(const Arabica::DOM::Element& transition, const std::string& event); + bool hasIntersection(const Arabica::XPath::NodeSet& nodeSet1, const Arabica::XPath::NodeSet& nodeSet2); + + void enterStates(const Arabica::XPath::NodeSet& enabledTransitions); + void exitStates(const Arabica::XPath::NodeSet& enabledTransitions); + + Arabica::XPath::NodeSet computeExitSet(const Arabica::XPath::NodeSet& transitions); + Arabica::XPath::NodeSet computeExitSet(const Arabica::DOM::Node& transition); + + void computeEntrySet(const Arabica::XPath::NodeSet& transitions, + Arabica::XPath::NodeSet& statesToEnter, + Arabica::XPath::NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent); + void computeEntrySet(const Arabica::DOM::Node& transition, + Arabica::XPath::NodeSet& statesToEnter, + Arabica::XPath::NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent); + + Arabica::XPath::NodeSet removeConflictingTransitions(const Arabica::XPath::NodeSet& enabledTransitions); + Arabica::DOM::Node getTransitionDomain(const Arabica::DOM::Element& transition); + + void addDescendantStatesToEnter(const Arabica::DOM::Node& state, + Arabica::XPath::NodeSet& statesToEnter, + Arabica::XPath::NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent); + + void addAncestorStatesToEnter(const Arabica::DOM::Node& state, + const Arabica::DOM::Node& ancestor, + Arabica::XPath::NodeSet& statesToEnter, + Arabica::XPath::NodeSet& statesForDefaultEntry, + std::map > defaultHistoryContent); + + bool isInFinalState(const Arabica::DOM::Node& state); + Arabica::DOM::Node findLCCA(const Arabica::XPath::NodeSet& states); + + Arabica::XPath::NodeSet getProperAncestors(const Arabica::DOM::Node& s1, + const Arabica::DOM::Node& s2); + + Arabica::XPath::NodeSet getTargetStates(const Arabica::DOM::Element& transition); + +#if 0 + bool isDescendant(const Arabica::DOM::Node& state1, const Arabica::DOM::Node& state2); + Arabica::XPath::NodeSet getChildStates(const Arabica::DOM::Node& state); +#endif + + bool _running; + +}; + +} + +#endif /* end of include guard: INTERPRETERRC_H_WLJEI019 */ diff --git a/src/uscxml/messages/Data.cpp b/src/uscxml/messages/Data.cpp index 911730a..7afad43 100644 --- a/src/uscxml/messages/Data.cpp +++ b/src/uscxml/messages/Data.cpp @@ -97,7 +97,7 @@ Data::Data(const Arabica::DOM::Node& dom) { std::string key; switch (child.getNodeType()) { case Arabica::DOM::Node_base::ELEMENT_NODE: - key = TAGNAME(child); + key = TAGNAME_CAST(child); break; case Arabica::DOM::Node_base::ATTRIBUTE_NODE: key = ((Arabica::DOM::Attr)child).getName(); diff --git a/src/uscxml/messages/Event.cpp b/src/uscxml/messages/Event.cpp index f8a880f..43c6600 100644 --- a/src/uscxml/messages/Event.cpp +++ b/src/uscxml/messages/Event.cpp @@ -121,8 +121,8 @@ Event Event::fromXML(const std::string& xmlString) { Arabica::DOM::NodeList properties = payloadElem.getElementsByTagName("scxml:property"); if (properties.getLength() > 0) { for (int i = 0; i < properties.getLength(); i++) { - if (HAS_ATTR(properties.item(i), "name")) { - std::string key = ATTR(properties.item(i), "name"); + if (HAS_ATTR_CAST(properties.item(i), "name")) { + std::string key = ATTR_CAST(properties.item(i), "name"); std::string value; Arabica::DOM::NodeList childs = properties.item(i).getChildNodes(); for (int j = 0; j < childs.getLength(); j++) { diff --git a/src/uscxml/plugins/DataModel.h b/src/uscxml/plugins/DataModel.h index 1a4deba..b1eafb9 100644 --- a/src/uscxml/plugins/DataModel.h +++ b/src/uscxml/plugins/DataModel.h @@ -61,10 +61,10 @@ public: virtual std::string evalAsString(const std::string& expr) = 0; - virtual bool evalAsBool(const Arabica::DOM::Node& scriptNode, + virtual bool evalAsBool(const Arabica::DOM::Element& scriptNode, const std::string& expr) = 0; virtual bool evalAsBool(const std::string& expr) { - return evalAsBool(Arabica::DOM::Node(), expr); + return evalAsBool(Arabica::DOM::Element(), expr); } virtual bool isDeclared(const std::string& expr) = 0; @@ -150,7 +150,7 @@ public: virtual bool evalAsBool(const std::string& expr) { return _impl->evalAsBool(expr); } - virtual bool evalAsBool(const Arabica::DOM::Node& scriptNode, + virtual bool evalAsBool(const Arabica::DOM::Element& scriptNode, const std::string& expr) { return _impl->evalAsBool(scriptNode, expr); } diff --git a/src/uscxml/plugins/ExecutableContent.h b/src/uscxml/plugins/ExecutableContent.h index 6f4335b..6916b5f 100644 --- a/src/uscxml/plugins/ExecutableContent.h +++ b/src/uscxml/plugins/ExecutableContent.h @@ -44,8 +44,8 @@ public: virtual std::string getNamespace() { return "http://www.w3.org/2005/07/scxml"; ///< The namespace of the element. } - virtual void enterElement(const Arabica::DOM::Node& node) = 0; ///< Invoked when entering the element as part of evaluating executable content. - virtual void exitElement(const Arabica::DOM::Node& node) = 0; ///< Invoked when exiting the element as part of evaluating executable content. + virtual void enterElement(const Arabica::DOM::Element& node) = 0; ///< Invoked when entering the element as part of evaluating executable content. + virtual void exitElement(const Arabica::DOM::Element& node) = 0; ///< Invoked when exiting the element as part of evaluating executable content. virtual bool processChildren() = 0; ///< Whether or not the interpreter should process this elements children. protected: @@ -86,10 +86,10 @@ public: std::string getNamespace() { return _impl->getNamespace(); } - void enterElement(const Arabica::DOM::Node& node) { + void enterElement(const Arabica::DOM::Element& node) { return _impl->enterElement(node); } - void exitElement(const Arabica::DOM::Node& node) { + void exitElement(const Arabica::DOM::Element& node) { return _impl->exitElement(node); } bool processChildren() { diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index 6d15f72..3a9cb27 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -514,7 +514,7 @@ void JSCDataModel::eval(const Element& scriptElem, evalAsValue(expr); } -bool JSCDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { +bool JSCDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { JSValueRef result = evalAsValue(expr); return JSValueToBoolean(_ctx, result); } diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h index fea2234..6792130 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h @@ -66,7 +66,7 @@ public: const std::string& expr); virtual std::string evalAsString(const std::string& expr); - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr); + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr); virtual bool isDeclared(const std::string& expr); diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp index bf8b538..a36a5f7 100644 --- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp +++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp @@ -435,7 +435,7 @@ void LuaDataModel::init(const std::string& location, const Data& data) { * The predicate must return 'true' if and only if that state is in the current * state configuration. */ -bool LuaDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { +bool LuaDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { // we need the result of the expression on the lua stack -> has to "return"! std::string trimmedExpr = boost::trim_copy(expr); if (!boost::starts_with(trimmedExpr, "return")) { diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h index 86e7e17..69b8d57 100644 --- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h +++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h @@ -83,7 +83,7 @@ public: virtual void eval(const Arabica::DOM::Element& scriptElem, const std::string& expr); virtual std::string evalAsString(const std::string& expr); - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr); + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr); virtual std::string andExpressions(std::list); diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp index d86bdb2..ae75c88 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp @@ -104,7 +104,7 @@ bool NULLDataModel::isDeclared(const std::string& expr) { * The predicate must return 'true' if and only if that state is in the current * state configuration. */ -bool NULLDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { +bool NULLDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { std::string trimmedExpr = expr; boost::trim(trimmedExpr); if (!boost::istarts_with(trimmedExpr, "in")) diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.h b/src/uscxml/plugins/datamodel/null/NULLDataModel.h index 2870388..da0374e 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.h +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.h @@ -77,7 +77,7 @@ public: virtual void eval(const Arabica::DOM::Element& scriptElem, const std::string& expr); virtual std::string evalAsString(const std::string& expr); - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr); + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr); protected: diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index 924e14a..f6131f8 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -676,10 +676,10 @@ void SWIDataModel::eval(const Element& scriptElem, const std::strin } bool SWIDataModel::evalAsBool(const std::string& expr) { - return evalAsBool(Arabica::DOM::Node(), expr); + return evalAsBool(Arabica::DOM::Element(), expr); } -bool SWIDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { +bool SWIDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { SWIEngineLock engineLock; try { PlCompound compound(expr.c_str()); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h index a673a40..1bf7b6a 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -97,7 +97,7 @@ public: virtual Data getStringAsData(const std::string& content); virtual std::string evalAsString(const std::string& expr); - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr); + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr); virtual bool evalAsBool(const std::string& expr); static foreign_t inPredicate(term_t a0, int arity, void* context); diff --git a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp index 6d34677..f83d0c8 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp +++ b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp @@ -141,10 +141,10 @@ void PromelaDataModel::eval(const Element& scriptElem, const std::s } bool PromelaDataModel::evalAsBool(const std::string& expr) { - return evalAsBool(Arabica::DOM::Node(), expr); + return evalAsBool(Arabica::DOM::Element(), expr); } -bool PromelaDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { +bool PromelaDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { PromelaParser parser(expr, PromelaParser::PROMELA_EXPR); // parser.dump(); return evaluateExpr(parser.ast) > 0; diff --git a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.h b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.h index ca6b19d..89078bd 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.h +++ b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.h @@ -78,7 +78,7 @@ public: virtual Data getStringAsData(const std::string& content); virtual std::string evalAsString(const std::string& expr); - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr); + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr); virtual bool evalAsBool(const std::string& expr); virtual std::string andExpressions(std::list expressions); diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index 41e015e..06461aa 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -229,7 +229,7 @@ void XPathDataModel::setEvent(const Event& event) { Node oldEventElem = _datamodel.getFirstChild(); while(oldEventElem) { if (oldEventElem.getNodeType() == Node_base::ELEMENT_NODE) { - if (HAS_ATTR(oldEventElem, "id") && iequals(ATTR(oldEventElem, "id"), "_event")) + if (HAS_ATTR_CAST(oldEventElem, "id") && iequals(ATTR_CAST(oldEventElem, "id"), "_event")) break; } oldEventElem = oldEventElem.getNextSibling(); @@ -393,10 +393,10 @@ bool XPathDataModel::isDeclared(const std::string& expr) { } bool XPathDataModel::evalAsBool(const std::string& expr) { - return evalAsBool(Arabica::DOM::Node(), expr); + return evalAsBool(Arabica::DOM::Element(), expr); } -bool XPathDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string& expr) { +bool XPathDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { // std::cout << std::endl << evalAsString(expr); XPathValue result; try { diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h index 09d63fa..fe454b3 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h @@ -123,7 +123,7 @@ public: virtual std::string evalAsString(const std::string& expr); virtual bool evalAsBool(const std::string& expr); - virtual bool evalAsBool(const Arabica::DOM::Node& node, const std::string& expr); + virtual bool evalAsBool(const Arabica::DOM::Element& node, const std::string& expr); virtual double evalAsNumber(const std::string& expr); protected: diff --git a/src/uscxml/plugins/element/fetch/FetchElement.cpp b/src/uscxml/plugins/element/fetch/FetchElement.cpp index b40f487..9f97ca9 100644 --- a/src/uscxml/plugins/element/fetch/FetchElement.cpp +++ b/src/uscxml/plugins/element/fetch/FetchElement.cpp @@ -80,7 +80,7 @@ void FetchElement::downloadFailed(const URL& url, int errorCode) { } -void FetchElement::enterElement(const Arabica::DOM::Node& node) { +void FetchElement::enterElement(const Arabica::DOM::Element& node) { if (!HAS_ATTR(node, "target") && !HAS_ATTR(node, "targetexpr")) { LOG(ERROR) << "Fetch element requires target or targetexpr"; return; @@ -123,7 +123,7 @@ void FetchElement::enterElement(const Arabica::DOM::Node& node) { } -void FetchElement::exitElement(const Arabica::DOM::Node& node) { +void FetchElement::exitElement(const Arabica::DOM::Element& node) { } diff --git a/src/uscxml/plugins/element/fetch/FetchElement.h b/src/uscxml/plugins/element/fetch/FetchElement.h index 433f3f5..e3e5008 100644 --- a/src/uscxml/plugins/element/fetch/FetchElement.h +++ b/src/uscxml/plugins/element/fetch/FetchElement.h @@ -46,8 +46,8 @@ public: return false; } - void enterElement(const Arabica::DOM::Node& node); - void exitElement(const Arabica::DOM::Node& node); + void enterElement(const Arabica::DOM::Element& node); + void exitElement(const Arabica::DOM::Element& node); void downloadCompleted(const URL& url); void downloadFailed(const URL& url, int errorCode); diff --git a/src/uscxml/plugins/element/file/FileElement.cpp b/src/uscxml/plugins/element/file/FileElement.cpp index 247c3c8..decd5ca 100644 --- a/src/uscxml/plugins/element/file/FileElement.cpp +++ b/src/uscxml/plugins/element/file/FileElement.cpp @@ -48,7 +48,7 @@ boost::shared_ptr FileElement::create(InterpreterImpl* in FileElement::~FileElement() { } -void FileElement::enterElement(const Arabica::DOM::Node& node) { +void FileElement::enterElement(const Arabica::DOM::Element& node) { if (!HAS_ATTR(node, "url") && !HAS_ATTR(node, "urlexpr")) { LOG(ERROR) << "File element requires url or urlexpr"; return; @@ -251,7 +251,7 @@ void FileElement::enterElement(const Arabica::DOM::Node& node) { } -void FileElement::exitElement(const Arabica::DOM::Node& node) { +void FileElement::exitElement(const Arabica::DOM::Element& node) { } diff --git a/src/uscxml/plugins/element/file/FileElement.h b/src/uscxml/plugins/element/file/FileElement.h index e236918..b1b3426 100644 --- a/src/uscxml/plugins/element/file/FileElement.h +++ b/src/uscxml/plugins/element/file/FileElement.h @@ -62,8 +62,8 @@ public: return false; } - void enterElement(const Arabica::DOM::Node& node); - void exitElement(const Arabica::DOM::Node& node); + void enterElement(const Arabica::DOM::Element& node); + void exitElement(const Arabica::DOM::Element& node); protected: diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.cpp b/src/uscxml/plugins/element/postpone/PostponeElement.cpp index 7a18b38..a041a9e 100644 --- a/src/uscxml/plugins/element/postpone/PostponeElement.cpp +++ b/src/uscxml/plugins/element/postpone/PostponeElement.cpp @@ -44,7 +44,7 @@ boost::shared_ptr PostponeElement::create(InterpreterImpl return invoker; } -void PostponeElement::enterElement(const Arabica::DOM::Node& node) { +void PostponeElement::enterElement(const Arabica::DOM::Element& node) { if (!_interpreter->getDataModel()) { LOG(ERROR) << "Postpone element requires a datamodel"; return; @@ -116,7 +116,7 @@ void PostponeElement::enterElement(const Arabica::DOM::Node& node) Resubmitter::postpone(currEvent, until, 0, chained, _interpreter); } -void PostponeElement::exitElement(const Arabica::DOM::Node& node) { +void PostponeElement::exitElement(const Arabica::DOM::Element& node) { } void PostponeElement::Resubmitter::postpone(const Event& event, std::string until, uint64_t timeout, bool chained, InterpreterImpl* interpreter) { diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.h b/src/uscxml/plugins/element/postpone/PostponeElement.h index 56464e2..9840c75 100644 --- a/src/uscxml/plugins/element/postpone/PostponeElement.h +++ b/src/uscxml/plugins/element/postpone/PostponeElement.h @@ -56,8 +56,8 @@ public: return false; } - void enterElement(const Arabica::DOM::Node& node); - void exitElement(const Arabica::DOM::Node& node); + void enterElement(const Arabica::DOM::Element& node); + void exitElement(const Arabica::DOM::Element& node); protected: // once per interpreter diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp index 6445249..a62f934 100644 --- a/src/uscxml/plugins/element/respond/RespondElement.cpp +++ b/src/uscxml/plugins/element/respond/RespondElement.cpp @@ -43,7 +43,7 @@ boost::shared_ptr RespondElement::create(InterpreterImpl* return invoker; } -void RespondElement::enterElement(const Arabica::DOM::Node& node) { +void RespondElement::enterElement(const Arabica::DOM::Element& node) { // try to get the request id if (!HAS_ATTR(node, "to")) { LOG(ERROR) << "Respond element requires to attribute"; @@ -81,10 +81,11 @@ void RespondElement::enterElement(const Arabica::DOM::Node& node) { // extract the content Arabica::XPath::NodeSet contents = InterpreterImpl::filterChildElements(_interpreter->getNameSpaceInfo().getXMLPrefixForNS(getNamespace()) + "content", node); if (contents.size() > 0) { - if (HAS_ATTR(contents[0], "expr")) { // -- content is evaluated string from datamodel ------ + Arabica::DOM::Element contentElem = Arabica::DOM::Element(contents[0]); + if (HAS_ATTR(contentElem, "expr")) { // -- content is evaluated string from datamodel ------ if (_interpreter->getDataModel()) { try { - Data contentData = _interpreter->getDataModel().getStringAsData(ATTR(contents[0], "expr")); + Data contentData = _interpreter->getDataModel().getStringAsData(ATTR(contentElem, "expr")); if (contentData.atom.length() > 0) { httpReply.content = contentData.atom; httpReply.headers["Content-Type"] = "text/plain"; @@ -108,19 +109,19 @@ void RespondElement::enterElement(const Arabica::DOM::Node& node) { LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; return; } - } else if (HAS_ATTR(contents[0], "file") || HAS_ATTR(contents[0], "fileexpr")) { // -- content is from file ------ + } else if (HAS_ATTR(contentElem, "file") || HAS_ATTR(contentElem, "fileexpr")) { // -- content is from file ------ URL file; - if (HAS_ATTR(contents[0], "fileexpr")) { + if (HAS_ATTR(contentElem, "fileexpr")) { if (_interpreter->getDataModel()) { try { - file = "file://" + _interpreter->getDataModel().evalAsString(ATTR(contents[0], "fileexpr")); + file = "file://" + _interpreter->getDataModel().evalAsString(ATTR(contentElem, "fileexpr")); } catch (Event e) { LOG(ERROR) << "Syntax error with fileexpr in content child of Respond element:" << std::endl << e << std::endl; return; } } } else { - file = "file://" + ATTR(contents[0], "fileexpr"); + file = "file://" + ATTR(contentElem, "fileexpr"); } if (file) { httpReply.content = file.getInContent(); @@ -144,13 +145,15 @@ void RespondElement::enterElement(const Arabica::DOM::Node& node) { // process headers Arabica::XPath::NodeSet headers = InterpreterImpl::filterChildElements(_interpreter->getNameSpaceInfo().getXMLPrefixForNS(getNamespace()) + "header", node); for (int i = 0; i < headers.size(); i++) { + Arabica::DOM::Element headerElem = Arabica::DOM::Element(headers[i]); + std::string name; - if (HAS_ATTR(headers[i], "name")) { - name = ATTR(headers[i], "name"); - } else if(HAS_ATTR(headers[i], "nameexpr")) { + if (HAS_ATTR(headerElem, "name")) { + name = ATTR(headerElem, "name"); + } else if(HAS_ATTR(headerElem, "nameexpr")) { if (_interpreter->getDataModel()) { try { - name = _interpreter->getDataModel().evalAsString(ATTR(headers[i], "nameexpr")); + name = _interpreter->getDataModel().evalAsString(ATTR(headerElem, "nameexpr")); } catch (Event e) { LOG(ERROR) << "Syntax error with nameexpr in header child of Respond element:" << std::endl << e << std::endl; return; @@ -165,12 +168,12 @@ void RespondElement::enterElement(const Arabica::DOM::Node& node) { } std::string value; - if (HAS_ATTR(headers[i], "value")) { - value = ATTR(headers[i], "value"); - } else if(HAS_ATTR(headers[i], "valueexpr")) { + if (HAS_ATTR(headerElem, "value")) { + value = ATTR(headerElem, "value"); + } else if(HAS_ATTR(headerElem, "valueexpr")) { if (_interpreter->getDataModel()) { try { - value = _interpreter->getDataModel().evalAsString(ATTR(headers[i], "valueexpr")); + value = _interpreter->getDataModel().evalAsString(ATTR(headerElem, "valueexpr")); } catch (Event e) { LOG(ERROR) << "Syntax error with valueexpr in header child of Respond element:" << std::endl << e << std::endl; return; @@ -192,7 +195,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node& node) { servlet->getRequests().erase(requestId); } -void RespondElement::exitElement(const Arabica::DOM::Node& node) { +void RespondElement::exitElement(const Arabica::DOM::Element& node) { } diff --git a/src/uscxml/plugins/element/respond/RespondElement.h b/src/uscxml/plugins/element/respond/RespondElement.h index 71b7fec..2e8cec7 100644 --- a/src/uscxml/plugins/element/respond/RespondElement.h +++ b/src/uscxml/plugins/element/respond/RespondElement.h @@ -46,8 +46,8 @@ public: return false; } - void enterElement(const Arabica::DOM::Node& node); - void exitElement(const Arabica::DOM::Node& node); + void enterElement(const Arabica::DOM::Element& node); + void exitElement(const Arabica::DOM::Element& node); }; diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp index 9e435d2..dac4f99 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp @@ -66,9 +66,9 @@ bool pluginConnect(pluma::Host& host) { #endif #define OSG_TAG_HANDLE(tagName, procFunc) \ -} else if (iequals(LOCALNAME(childs.item(i)), tagName) && \ +} else if (iequals(LOCALNAME(childElem), tagName) && \ validChildren.find(tagName) != validChildren.end()) { \ - procFunc(childs.item(i));\ + procFunc(childElem);\ OSGInvoker::OSGInvoker() { @@ -167,7 +167,7 @@ void OSGInvoker::handleEvent(Arabica::DOM::Events::Event& event) { } } -void OSGInvoker::processDisplay(const Arabica::DOM::Node& element) { +void OSGInvoker::processDisplay(const Arabica::DOM::Element& element) { // std::cout << element << std::endl; if (_displays.find(element) == _displays.end()) { @@ -188,7 +188,7 @@ void OSGInvoker::processDisplay(const Arabica::DOM::Node& element) } } -void OSGInvoker::processViewport(const Arabica::DOM::Node& element) { +void OSGInvoker::processViewport(const Arabica::DOM::Element& element) { if (_displays.find(element.getParentNode()) == _displays.end()) return; @@ -236,7 +236,7 @@ void OSGInvoker::processViewport(const Arabica::DOM::Node& element) void OSGInvoker::processCamera(const Arabica::DOM::Node& element) {} void OSGInvoker::updateCamera(osg::ref_ptr node, Arabica::DOM::Events::Event& event) {} -void OSGInvoker::processTranslation(const Arabica::DOM::Node& element) { +void OSGInvoker::processTranslation(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr node = _nodes[element.getParentNode()]; @@ -269,7 +269,7 @@ void OSGInvoker::processTranslation(const Arabica::DOM::Node& eleme processChildren(validChilds, element); } -void OSGInvoker::processRotation(const Arabica::DOM::Node& element) { +void OSGInvoker::processRotation(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr node = _nodes[element.getParentNode()]; @@ -296,12 +296,12 @@ void OSGInvoker::updateRotation(osg::ref_ptr node, Arabica::DOM::Even osg::ref_ptr transform = static_cast(node->asTransform()); if (false) { } else if (iequals(event.getType(), "DOMAttrModified")) { - osg::Matrix rotation = rotationFromElement(Arabica::DOM::Node(event.getTarget())); + osg::Matrix rotation = rotationFromElement(Arabica::DOM::Element(Arabica::DOM::Node(event.getTarget()))); transform->setMatrix(rotation); } } -osg::Matrix OSGInvoker::rotationFromElement(const Arabica::DOM::Node& element) { +osg::Matrix OSGInvoker::rotationFromElement(const Arabica::DOM::Element& element) { double pitch = 0, roll = 0, yaw = 0; if (HAS_ATTR(element, "pitch")) { NumAttr pitchAttr = NumAttr(ATTR(element, "pitch")); @@ -342,7 +342,7 @@ osg::Matrix OSGInvoker::rotationFromElement(const Arabica::DOM::Node& element) { +void OSGInvoker::processScale(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr node = _nodes[element.getParentNode()]; @@ -375,7 +375,7 @@ void OSGInvoker::processScale(const Arabica::DOM::Node& element) { processChildren(validChilds, element); } -void OSGInvoker::processNode(const Arabica::DOM::Node& element) { +void OSGInvoker::processNode(const Arabica::DOM::Element& element) { _nodes_t::iterator nodeIter = _nodes.find(element.getParentNode()); assert(nodeIter != _nodes.end()); @@ -407,7 +407,7 @@ void OSGInvoker::processNode(const Arabica::DOM::Node& element) { } } -void OSGInvoker::processSphere(const Arabica::DOM::Node& element) { +void OSGInvoker::processSphere(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr parent = _nodes[element.getParentNode()]; @@ -434,7 +434,7 @@ void OSGInvoker::processSphere(const Arabica::DOM::Node& element) { void OSGInvoker::updateSphere(osg::ref_ptr node, Arabica::DOM::Events::Event& event) { } -void OSGInvoker::processBox(const Arabica::DOM::Node& element) { +void OSGInvoker::processBox(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr parent = _nodes[element.getParentNode()]; @@ -462,7 +462,7 @@ void OSGInvoker::processBox(const Arabica::DOM::Node& element) { } void OSGInvoker::updateBox(osg::ref_ptr node, Arabica::DOM::Events::Event& event) { } -void OSGInvoker::processCapsule(const Arabica::DOM::Node& element) { +void OSGInvoker::processCapsule(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr parent = _nodes[element.getParentNode()]; @@ -487,7 +487,7 @@ void OSGInvoker::processCapsule(const Arabica::DOM::Node& element) void OSGInvoker::updateCapsule(osg::ref_ptr node, Arabica::DOM::Events::Event& event) { } -void OSGInvoker::processCone(const Arabica::DOM::Node& element) { +void OSGInvoker::processCone(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr parent = _nodes[element.getParentNode()]; @@ -514,7 +514,7 @@ void OSGInvoker::processCone(const Arabica::DOM::Node& element) { void OSGInvoker::updateCone(osg::ref_ptr node, Arabica::DOM::Events::Event& event) { } -void OSGInvoker::processCylinder(const Arabica::DOM::Node& element) { +void OSGInvoker::processCylinder(const Arabica::DOM::Element& element) { assert(_nodes.find(element.getParentNode()) != _nodes.end()); osg::ref_ptr parent = _nodes[element.getParentNode()]; @@ -541,7 +541,7 @@ void OSGInvoker::processCylinder(const Arabica::DOM::Node& element) void OSGInvoker::updateCylinder(osg::ref_ptr node, Arabica::DOM::Events::Event& event) { } -osg::Vec4 OSGInvoker::getColor(const Arabica::DOM::Node& element, const std::string& attr, bool& valid) { +osg::Vec4 OSGInvoker::getColor(const Arabica::DOM::Element& element, const std::string& attr, bool& valid) { if (HAS_ATTR(element, attr)) { std::string color = ATTR(element, attr); @@ -576,7 +576,7 @@ osg::Vec4 OSGInvoker::getColor(const Arabica::DOM::Node& element, c return osg::Vec4(); } -osg::ref_ptr OSGInvoker::getMaterial(const Arabica::DOM::Node& element) { +osg::ref_ptr OSGInvoker::getMaterial(const Arabica::DOM::Element& element) { osg::ref_ptr nodeMat; @@ -630,6 +630,7 @@ void OSGInvoker::processChildren(const std::set& validChildren, con for (int i = 0; i < childs.getLength(); ++i) { if (childs.item(i).getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE) continue; + Arabica::DOM::Element childElem = Arabica::DOM::Element(childs.item(i)); if (false) { OSG_TAG_HANDLE("node", processNode); OSG_TAG_HANDLE("translation", processTranslation); @@ -644,12 +645,12 @@ void OSGInvoker::processChildren(const std::set& validChildren, con OSG_TAG_HANDLE("capsule", processCapsule); OSG_TAG_HANDLE("cylinder", processCylinder); } else { - LOG(INFO) << "Unknown XML element " << TAGNAME(childs.item(i)); + LOG(INFO) << "Unknown XML element " << TAGNAME(childElem); } } } -void OSGInvoker::getViewport(const Arabica::DOM::Node& element, +void OSGInvoker::getViewport(const Arabica::DOM::Element& element, unsigned int& x, unsigned int& y, unsigned int& width, @@ -659,7 +660,7 @@ void OSGInvoker::getViewport(const Arabica::DOM::Node& element, } -void OSGInvoker::getViewport(const Arabica::DOM::Node& element, +void OSGInvoker::getViewport(const Arabica::DOM::Element& element, unsigned int& x, unsigned int& y, unsigned int& width, @@ -674,7 +675,7 @@ void OSGInvoker::getViewport(const Arabica::DOM::Node& element, getViewport(element, x, y, width, height, fullWidth, fullHeight); } -void OSGInvoker::getViewport(const Arabica::DOM::Node& element, +void OSGInvoker::getViewport(const Arabica::DOM::Element& element, unsigned int& x, unsigned int& y, unsigned int& width, diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h index af06e23..30be8ca 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h @@ -61,58 +61,58 @@ public: virtual void runOnMainThread(); protected: - void processDisplay(const Arabica::DOM::Node& element); + void processDisplay(const Arabica::DOM::Element& element); void updateDisplay(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processViewport(const Arabica::DOM::Node& element); + void processViewport(const Arabica::DOM::Element& element); void updateViewport(osg::ref_ptr node, Arabica::DOM::Events::Event& event); void processCamera(const Arabica::DOM::Node& element); void updateCamera(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processTranslation(const Arabica::DOM::Node& element); + void processTranslation(const Arabica::DOM::Element& element); void updateTranslation(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processRotation(const Arabica::DOM::Node& element); + void processRotation(const Arabica::DOM::Element& element); void updateRotation(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - static osg::Matrix rotationFromElement(const Arabica::DOM::Node& element); + static osg::Matrix rotationFromElement(const Arabica::DOM::Element& element); - void processScale(const Arabica::DOM::Node& element); + void processScale(const Arabica::DOM::Element& element); void updateScale(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processNode(const Arabica::DOM::Node& element); + void processNode(const Arabica::DOM::Element& element); void updateNode(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processSphere(const Arabica::DOM::Node& element); + void processSphere(const Arabica::DOM::Element& element); void updateSphere(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processBox(const Arabica::DOM::Node& element); + void processBox(const Arabica::DOM::Element& element); void updateBox(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processCapsule(const Arabica::DOM::Node& element); + void processCapsule(const Arabica::DOM::Element& element); void updateCapsule(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processCone(const Arabica::DOM::Node& element); + void processCone(const Arabica::DOM::Element& element); void updateCone(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - void processCylinder(const Arabica::DOM::Node& element); + void processCylinder(const Arabica::DOM::Element& element); void updateCylinder(osg::ref_ptr node, Arabica::DOM::Events::Event& event); - osg::Vec4 getColor(const Arabica::DOM::Node& element, const std::string& attr, bool& valid); - osg::ref_ptr getMaterial(const Arabica::DOM::Node& element); + osg::Vec4 getColor(const Arabica::DOM::Element& element, const std::string& attr, bool& valid); + osg::ref_ptr getMaterial(const Arabica::DOM::Element& element); osg::Vec4 parseVec4(const std::string& coeffs, int& number); void processChildren(const std::set& validChildren, const Arabica::DOM::Node& element); - void getViewport(const Arabica::DOM::Node& element, + void getViewport(const Arabica::DOM::Element& element, unsigned int& x, unsigned int& y, unsigned int& width, unsigned int& height, int& screenId); - void getViewport(const Arabica::DOM::Node& element, + void getViewport(const Arabica::DOM::Element& element, unsigned int& x, unsigned int& y, unsigned int& width, unsigned int& height, CompositeDisplay* display); - void getViewport(const Arabica::DOM::Node& element, + void getViewport(const Arabica::DOM::Element& element, unsigned int& x, unsigned int& y, unsigned int& width, diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp index 5b67f7c..285db72 100644 --- a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp @@ -186,11 +186,12 @@ void XHTMLInvoker::reply(const SendRequest& req, const HTTPServer::Request& long std::stringstream ss; // Arabica::DOM::Node content = req.dom.getDocumentElement(); Arabica::DOM::Node content = req.dom; - if (content && iequals(content.getLocalName(), "content")) { - reply.headers["X-SCXML-Type"] = (HAS_ATTR(content, "type") ? ATTR(content, "type") : "replacechildren"); - reply.headers["X-SCXML-XPath"] = (HAS_ATTR(content, "xpath") ? ATTR(content, "xpath") : "/html/body"); - if (HAS_ATTR(content, "attr")) - reply.headers["X-SCXML-Attr"] = ATTR(content, "attr"); + if (content && content.getNodeType() == Arabica::DOM::Node_base::ELEMENT_NODE && iequals(content.getLocalName(), "content")) { + Arabica::DOM::Element contentElem = Arabica::DOM::Element(content); + reply.headers["X-SCXML-Type"] = (HAS_ATTR(contentElem, "type") ? ATTR(contentElem, "type") : "replacechildren"); + reply.headers["X-SCXML-XPath"] = (HAS_ATTR(contentElem, "xpath") ? ATTR(contentElem, "xpath") : "/html/body"); + if (HAS_ATTR(contentElem, "attr")) + reply.headers["X-SCXML-Attr"] = ATTR(contentElem, "attr"); } // ss << req.getFirstDOMElement(); ss << req.dom; diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp index 820e3bc..83b8195 100644 --- a/src/uscxml/transform/ChartToFSM.cpp +++ b/src/uscxml/transform/ChartToFSM.cpp @@ -216,7 +216,7 @@ InterpreterState FlatteningInterpreter::interpret() { initialElem.setAttribute("generated", "true"); Element transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); _nsInfo.setPrefix(transitionElem); - transitionElem.setAttribute("target", ATTR(initialStates[i], "id")); + transitionElem.setAttribute("target", ATTR_CAST(initialStates[i], "id")); initialElem.appendChild(transitionElem); _scxml.appendChild(initialElem); initialTransitions.push_back(transitionElem); @@ -277,14 +277,14 @@ void FlatteningInterpreter::executeContent(const Arabica::DOM::Elementactions.push_back(action); } -void FlatteningInterpreter::invoke(const Arabica::DOM::Node& element) { +void FlatteningInterpreter::invoke(const Arabica::DOM::Element& element) { GlobalTransition::Action action; action.invoke = element; _currGlobalTransition->actions.push_back(action); _currGlobalTransition->invoke.push_back(element); } -void FlatteningInterpreter::cancelInvoke(const Arabica::DOM::Node& element) { +void FlatteningInterpreter::cancelInvoke(const Arabica::DOM::Element& element) { GlobalTransition::Action action; action.uninvoke = element; _currGlobalTransition->actions.push_back(action); @@ -323,7 +323,7 @@ void FlatteningInterpreter::internalDoneSend(const Arabica::DOM::Element& transitions) { p2 = p2.getParentNode(); // TODO: think about again! while(p2) { if (p1 == p2) { - std::string eventDesc1 = ATTR(t1, "event"); - std::string eventDesc2 = ATTR(t2, "event"); + std::string eventDesc1 = ATTR_CAST(t1, "event"); + std::string eventDesc2 = ATTR_CAST(t2, "event"); if (InterpreterImpl::nameMatch(eventDesc1, eventDesc2)) { return false; } @@ -453,7 +453,7 @@ void FlatteningInterpreter::explode() { for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]); for (unsigned int j = 0; j < invokes.size(); j++) { - invoke(invokes[j]); + invoke(Element(invokes[j])); } } _statesToInvoke = NodeSet(); @@ -595,11 +595,11 @@ void FlatteningInterpreter::explode() { int nrDepth = 0; int prioPerLevel = 0; for (int i = 0; i < transitions.size(); i++) { - int depth = strTo(ATTR(transitions[i], "depth")); + int depth = strTo(ATTR_CAST(transitions[i], "depth")); if (depth != currDepth) continue; nrDepth++; - int order = strTo(ATTR(transitions[i], "order")); + int order = strTo(ATTR_CAST(transitions[i], "order")); if (order < lowestOrder) lowestOrder = order; prioPerLevel += pow(static_cast(maxOrder), maxOrder - order); @@ -673,7 +673,7 @@ NEXT_DEPTH: } void FlatteningInterpreter::createDocument() { - Node _origSCXML = _scxml; + Element _origSCXML = _scxml; _scxml = _flatDoc.createElementNS(_nsInfo.nsURL, "scxml"); _nsInfo.setPrefix(_scxml); @@ -952,10 +952,11 @@ void FlatteningInterpreter::labelTransitions() { Arabica::XPath::NodeSet states = getAllStates(); states.push_back(_scxml); for (int i = 0; i < states.size(); i++) { - std::string stateId = ATTR(states[i], "id"); - NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", states[i]); + Arabica::DOM::Element stateElem = Arabica::DOM::Element(states[i]); + std::string stateId = ATTR(stateElem, "id"); + NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", stateElem); // some transitions are in the inital elements - NodeSet initials = filterChildElements(_nsInfo.xmlNSPrefix + "initial", states[i]); + NodeSet initials = filterChildElements(_nsInfo.xmlNSPrefix + "initial", stateElem); transitions.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "transition", initials)); for (int j = 0; j < transitions.size(); j++) { Element transition = Element(transitions[j]); @@ -1014,12 +1015,12 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet& activeState for (int i = 0; i < activeStates.size(); i++) { if (!InterpreterImpl::isFinal(Element(activeStates[i]))) isFinal = false; - idSS << ATTR(activeStates[i], "id") << "-"; + idSS << ATTR_CAST(activeStates[i], "id") << "-"; } idSS << ";"; idSS << "entered-"; for (int i = 0; i < alreadyEnteredStates.size(); i++) { - idSS << ATTR(alreadyEnteredStates[i], "id") << "-"; + idSS << ATTR_CAST(alreadyEnteredStates[i], "id") << "-"; } idSS << ";"; @@ -1030,7 +1031,7 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet& activeState idSS << "history--"; idSS << histIter->first << "-"; for (int i = 0; i < histStates.size(); i++) { - idSS << ATTR(histStates[i], "id") << "-"; + idSS << ATTR_CAST(histStates[i], "id") << "-"; } } @@ -1053,13 +1054,14 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet& t std::list conditions; std::ostringstream setId; // also build id for subset for (int i = 0; i < transitions.size(); i++) { + Arabica::DOM::Element transElem = Arabica::DOM::Element(transitions[i]); // get a unique string for the transition - we assume it is sorted - assert(HAS_ATTR(transitions[i], "id")); - setId << ATTR(transitions[i], "id") << "-"; + assert(HAS_ATTR(transElem, "id")); + setId << ATTR(transElem, "id") << "-"; // gather conditions while we are iterating anyway - if (HAS_ATTR(transitions[i], "cond")) { - conditions.push_back(ATTR(transitions[i], "cond")); + if (HAS_ATTR(transElem, "cond")) { + conditions.push_back(ATTR(transElem, "cond")); } } transitionId = setId.str(); @@ -1077,10 +1079,11 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet& t bool foundTargetLess = false; for (int i = 0; i < transitions.size(); i++) { - if (HAS_ATTR(transitions[i], "eventexpr")) { + Arabica::DOM::Element transElem = Arabica::DOM::Element(transitions[i]); + if (HAS_ATTR(transElem, "eventexpr")) { ERROR_EXECUTION_THROW("Cannot flatten document with eventexpr attributes"); } - if (HAS_ATTR(transitions[i], "event")) { + if (HAS_ATTR(transElem, "event")) { foundWithEvent = true; if (foundEventLess) break; @@ -1089,7 +1092,7 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet& t if (foundWithEvent) break; } - if (HAS_ATTR(transitions[i], "target")) { + if (HAS_ATTR(transElem, "target")) { foundWithTarget = true; if (foundTargetLess) break; @@ -1151,7 +1154,7 @@ std::list GlobalTransition::getCommonEvents(const NodeSet eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(transitions[i], "event")); + std::list eventNames = InterpreterImpl::tokenizeIdRefs(ATTR_CAST(transitions[i], "event")); for (std::list::iterator eventNameIter = eventNames.begin(); eventNameIter != eventNames.end(); @@ -1170,7 +1173,7 @@ std::list GlobalTransition::getCommonEvents(const NodeSet onEntry; - Arabica::DOM::Node onExit; - Arabica::DOM::Node transition; - Arabica::DOM::Node entered; - Arabica::DOM::Node exited; - Arabica::DOM::Node invoke; - Arabica::DOM::Node uninvoke; + Arabica::DOM::Element onEntry; + Arabica::DOM::Element onExit; + Arabica::DOM::Element transition; + Arabica::DOM::Element entered; + Arabica::DOM::Element exited; + Arabica::DOM::Element invoke; + Arabica::DOM::Element uninvoke; }; GlobalTransition(const Arabica::XPath::NodeSet& transitions, DataModel dataModel); @@ -112,11 +112,11 @@ protected: void executeContent(const Arabica::DOM::Element& content, bool rethrow = false); // invoke and uninvoke - virtual void invoke(const Arabica::DOM::Node& element); - virtual void cancelInvoke(const Arabica::DOM::Node& element); + virtual void invoke(const Arabica::DOM::Element& element); + virtual void cancelInvoke(const Arabica::DOM::Element& element); // override to do nothing - void send(const Arabica::DOM::Node& element) {} + void send(const Arabica::DOM::Element& element) {} void internalDoneSend(const Arabica::DOM::Element& state); // InterpreterMonitor diff --git a/src/uscxml/transform/FSMToCPP.cpp b/src/uscxml/transform/FSMToCPP.cpp index 6bf4535..980c389 100644 --- a/src/uscxml/transform/FSMToCPP.cpp +++ b/src/uscxml/transform/FSMToCPP.cpp @@ -56,14 +56,14 @@ void FSMToCPP::writeStates(std::ostream& stream) { stream << "// state name identifiers" << std::endl; for (int i = 0; i < _globalStates.size(); i++) { stream << "#define " << "s" << i << " " << i; - stream << " // from \"" << ATTR(_globalStates[i], "id") << "\"" << std::endl; + stream << " // from \"" << ATTR_CAST(_globalStates[i], "id") << "\"" << std::endl; } } -Arabica::XPath::NodeSet FSMToCPP::getTransientContent(const Arabica::DOM::Node& state) { +Arabica::XPath::NodeSet FSMToCPP::getTransientContent(const Arabica::DOM::Element& state) { Arabica::XPath::NodeSet content; - Arabica::DOM::Node currState = state; + Arabica::DOM::Element currState = state; for (;;) { if (!HAS_ATTR(currState, "transient") || !DOMUtils::attributeIsTrue(ATTR(currState, "transient"))) break; @@ -71,24 +71,24 @@ Arabica::XPath::NodeSet FSMToCPP::getTransientContent(const Arabica content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "onentry", currState)); content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "onexit", currState)); NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", currState); - currState = _states[ATTR(transitions[0], "target")]; + currState = _states[ATTR_CAST(transitions[0], "target")]; } return content; } -Node FSMToCPP::getUltimateTarget(const Arabica::DOM::Node& transition) { - Arabica::DOM::Node currState = _states[ATTR(transition, "target")]; +Node FSMToCPP::getUltimateTarget(const Arabica::DOM::Element& transition) { + Arabica::DOM::Element currState = _states[ATTR(transition, "target")]; for (;;) { if (!HAS_ATTR(currState, "transient") || !DOMUtils::attributeIsTrue(ATTR(currState, "transient"))) return currState; NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", currState); - currState = _states[ATTR(transitions[0], "target")]; + currState = _states[ATTR_CAST(transitions[0], "target")]; } } -void FSMToCPP::writeInlineComment(std::ostream& stream, const Arabica::DOM::Node& node) { +void FSMToCPP::writeInlineComment(std::ostream& stream, const Arabica::DOM::Element& node) { if (node.getNodeType() != Node_base::COMMENT_NODE) return; @@ -107,7 +107,7 @@ void FSMToCPP::writeInlineComment(std::ostream& stream, const Arabica::DOM::Node } } -void FSMToCPP::writeExecutableContent(std::ostream& stream, const Arabica::DOM::Node& node, int indent) { +void FSMToCPP::writeExecutableContent(std::ostream& stream, const Arabica::DOM::Element& node, int indent) { std::string padding; for (int i = 0; i < indent; i++) { @@ -140,12 +140,12 @@ void FSMToCPP::writeExecutableContent(std::ostream& stream, const Arabica::DOM:: if (HAS_ATTR(node, "transient") && DOMUtils::attributeIsTrue(ATTR(node, "transient"))) { Arabica::XPath::NodeSet execContent = getTransientContent(node); for (int i = 0; i < execContent.size(); i++) { - writeExecutableContent(stream, execContent[i], indent); + writeExecutableContent(stream, Arabica::DOM::Element(execContent[i]), indent); } } else { Arabica::DOM::Node child = node.getFirstChild(); while(child) { - writeExecutableContent(stream, child, indent); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent); child = child.getNextSibling(); } } @@ -173,7 +173,7 @@ void FSMToCPP::writeExecutableContent(std::ostream& stream, const Arabica::DOM:: } else if(TAGNAME(node) == "onentry" || TAGNAME(node) == "onexit") { Arabica::DOM::Node child = node.getFirstChild(); while(child) { - writeExecutableContent(stream, child, indent); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent); child = child.getNextSibling(); } @@ -192,7 +192,7 @@ void FSMToCPP::writeExecutableContent(std::ostream& stream, const Arabica::DOM:: stream << padding << "for (" << ATTR(node, "item") << " in " << ATTR(node, "array") << ") {" << std::endl; Arabica::DOM::Node child = node.getFirstChild(); while(child) { - writeExecutableContent(stream, child, indent + 1); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent + 1); child = child.getNextSibling(); } if (HAS_ATTR(node, "index")) @@ -239,7 +239,7 @@ void FSMToCPP::writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet< bool noNext = condChain.size() == 1; bool nextIsElse = false; if (condChain.size() > 1) { - if (TAGNAME(condChain[1]) == "else") { + if (TAGNAME_CAST(condChain[1]) == "else") { nextIsElse = true; } } @@ -248,20 +248,20 @@ void FSMToCPP::writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet< stream << padding << "if" << std::endl; // we need to nest the elseifs to resolve promela if semantics - stream << padding << ":: (" << ATTR(ifNode, "cond") << ") -> {" << std::endl; + stream << padding << ":: (" << ATTR_CAST(ifNode, "cond") << ") -> {" << std::endl; Arabica::DOM::Node child; - if (TAGNAME(ifNode) == "if") { + if (TAGNAME_CAST(ifNode) == "if") { child = ifNode.getFirstChild(); } else { child = ifNode.getNextSibling(); } while(child) { if (child.getNodeType() == Node_base::ELEMENT_NODE) { - if (TAGNAME(child) == "elseif" || TAGNAME(child) == "else") + if (TAGNAME_CAST(child) == "elseif" || TAGNAME_CAST(child) == "else") break; } - writeExecutableContent(stream, child, indent + 1); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent + 1); child = child.getNextSibling(); } stream << padding << "}" << std::endl; @@ -271,7 +271,7 @@ void FSMToCPP::writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet< child = condChain[1].getNextSibling(); stream << "{" << std::endl; while(child) { - writeExecutableContent(stream, child, indent + 1); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent + 1); child = child.getNextSibling(); } stream << padding << "}" << std::endl; @@ -360,14 +360,14 @@ void FSMToCPP::writeFSM(std::ostream& stream) { transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _startState); assert(transitions.size() == 1); stream << " // transition's executable content" << std::endl; - writeExecutableContent(stream, transitions[0], 1); + writeExecutableContent(stream, Arabica::DOM::Element(transitions[0]), 1); for (int i = 0; i < _globalStates.size(); i++) { if (_globalStates[i] == _startState) continue; NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _globalStates[i]); for (int j = 0; j < transitions.size(); j++) { - writeExecutableContent(stream, transitions[j], 1); + writeExecutableContent(stream, Arabica::DOM::Element(transitions[j]), 1); } } @@ -424,7 +424,7 @@ void FSMToCPP::writeDispatchingBlock(std::ostream& stream, const Arabica::XPath: stream << padding << ":: ((0"; Node currTrans = transChain[0]; - std::string eventDesc = ATTR(currTrans, "event"); + std::string eventDesc = ATTR_CAST(currTrans, "event"); if (boost::ends_with(eventDesc, "*")) eventDesc = eventDesc.substr(0, eventDesc.size() - 1); if (boost::ends_with(eventDesc, ".")) @@ -443,8 +443,8 @@ void FSMToCPP::writeDispatchingBlock(std::ostream& stream, const Arabica::XPath: } stream << ") && "; - stream << (HAS_ATTR(currTrans, "cond") ? ATTR(currTrans, "cond") : "1"); - stream << ") -> goto t" << _transitions[currTrans] << ";" << std::endl; + stream << (HAS_ATTR_CAST(currTrans, "cond") ? ATTR_CAST(currTrans, "cond") : "1"); + stream << ") -> goto t" << _transitions[Arabica::DOM::Element(currTrans)] << ";" << std::endl; ; stream << padding << ":: else {" << std::endl; @@ -473,8 +473,9 @@ void FSMToCPP::initNodes() { // get all states NodeSet states = filterChildElements(_nsInfo.xmlNSPrefix + "state", _scxml); for (int i = 0; i < states.size(); i++) { - _states[ATTR(states[i], "id")] = states[i]; - if (HAS_ATTR(states[i], "transient") && DOMUtils::attributeIsTrue(ATTR(states[i], "transient"))) + Arabica::DOM::Element stateElem = Arabica::DOM::Element(states[i]); + _states[ATTR(stateElem, "id")] = stateElem; + if (HAS_ATTR(stateElem, "transient") && DOMUtils::attributeIsTrue(ATTR(stateElem, "transient"))) continue; _globalStates.push_back(states[i]); } @@ -487,8 +488,8 @@ void FSMToCPP::initNodes() { internalEventNames.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "send", _scxml).asNodeSet()); for (int i = 0; i < internalEventNames.size(); i++) { - if (HAS_ATTR(internalEventNames[i], "event")) { - std::string eventNames = ATTR(internalEventNames[i], "event"); + if (HAS_ATTR_CAST(internalEventNames[i], "event")) { + std::string eventNames = ATTR_CAST(internalEventNames[i], "event"); std::list events = tokenizeIdRefs(eventNames); for (std::list::iterator eventIter = events.begin(); eventIter != events.end(); eventIter++) { @@ -506,7 +507,7 @@ void FSMToCPP::initNodes() { NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); int index = 0; for (int i = 0; i < transitions.size(); i++) { - _transitions[transitions[i]] = index++; + _transitions[Arabica::DOM::Element(transitions[i])] = index++; } } diff --git a/src/uscxml/transform/FSMToCPP.h b/src/uscxml/transform/FSMToCPP.h index 59231b0..18df7c1 100644 --- a/src/uscxml/transform/FSMToCPP.h +++ b/src/uscxml/transform/FSMToCPP.h @@ -47,8 +47,8 @@ protected: void writeEvents(std::ostream& stream); void writeStates(std::ostream& stream); void writeDeclarations(std::ostream& stream); - void writeExecutableContent(std::ostream& stream, const Arabica::DOM::Node& node, int indent = 0); - void writeInlineComment(std::ostream& stream, const Arabica::DOM::Node& node); + void writeExecutableContent(std::ostream& stream, const Arabica::DOM::Element& node, int indent = 0); + void writeInlineComment(std::ostream& stream, const Arabica::DOM::Element& node); void writeFSM(std::ostream& stream); void writeEventDispatching(std::ostream& stream); void writeMain(std::ostream& stream); @@ -56,14 +56,14 @@ protected: void writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet& condChain, int indent = 0); void writeDispatchingBlock(std::ostream& stream, const Arabica::XPath::NodeSet& transChain, int indent = 0); - Arabica::XPath::NodeSet getTransientContent(const Arabica::DOM::Node& state); - Arabica::DOM::Node getUltimateTarget(const Arabica::DOM::Node& transition); + Arabica::XPath::NodeSet getTransientContent(const Arabica::DOM::Element& state); + Arabica::DOM::Node getUltimateTarget(const Arabica::DOM::Element& transition); Trie _eventTrie; Arabica::XPath::NodeSet _globalStates; - Arabica::DOM::Node _startState; - std::map > _states; - std::map, int> _transitions; + Arabica::DOM::Element _startState; + std::map > _states; + std::map, int> _transitions; }; diff --git a/src/uscxml/transform/FSMToPromela.cpp b/src/uscxml/transform/FSMToPromela.cpp index 3607071..238e40f 100644 --- a/src/uscxml/transform/FSMToPromela.cpp +++ b/src/uscxml/transform/FSMToPromela.cpp @@ -199,14 +199,14 @@ void FSMToPromela::writeStates(std::ostream& stream) { stream << "// state name identifiers" << std::endl; for (int i = 0; i < _globalStates.size(); i++) { stream << "#define " << "s" << i << " " << i; - stream << " // from \"" << ATTR(_globalStates[i], "id") << "\"" << std::endl; + stream << " // from \"" << ATTR_CAST(_globalStates[i], "id") << "\"" << std::endl; } } -Arabica::XPath::NodeSet FSMToPromela::getTransientContent(const Arabica::DOM::Node& state) { +Arabica::XPath::NodeSet FSMToPromela::getTransientContent(const Arabica::DOM::Element& state) { Arabica::XPath::NodeSet content; - Arabica::DOM::Node currState = state; + Arabica::DOM::Element currState = state; for (;;) { if (!HAS_ATTR(currState, "transient") || !DOMUtils::attributeIsTrue(ATTR(currState, "transient"))) break; @@ -214,20 +214,20 @@ Arabica::XPath::NodeSet FSMToPromela::getTransientContent(const Ara content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "onentry", currState)); content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "onexit", currState)); NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", currState); - currState = _states[ATTR(transitions[0], "target")]; + currState = _states[ATTR_CAST(transitions[0], "target")]; } return content; } -Node FSMToPromela::getUltimateTarget(const Arabica::DOM::Node& transition) { - Arabica::DOM::Node currState = _states[ATTR(transition, "target")]; +Node FSMToPromela::getUltimateTarget(const Arabica::DOM::Element& transition) { + Arabica::DOM::Element currState = _states[ATTR_CAST(transition, "target")]; for (;;) { if (!HAS_ATTR(currState, "transient") || !DOMUtils::attributeIsTrue(ATTR(currState, "transient"))) return currState; NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", currState); - currState = _states[ATTR(transitions[0], "target")]; + currState = _states[ATTR_CAST(transitions[0], "target")]; } } @@ -250,7 +250,7 @@ void FSMToPromela::writeInlineComment(std::ostream& stream, const Arabica::DOM:: } } -void FSMToPromela::writeExecutableContent(std::ostream& stream, const Arabica::DOM::Node& node, int indent) { +void FSMToPromela::writeExecutableContent(std::ostream& stream, const Arabica::DOM::Element& node, int indent) { std::string padding; for (int i = 0; i < indent; i++) { @@ -283,12 +283,12 @@ void FSMToPromela::writeExecutableContent(std::ostream& stream, const Arabica::D if (HAS_ATTR(node, "transient") && DOMUtils::attributeIsTrue(ATTR(node, "transient"))) { Arabica::XPath::NodeSet execContent = getTransientContent(node); for (int i = 0; i < execContent.size(); i++) { - writeExecutableContent(stream, execContent[i], indent); + writeExecutableContent(stream, Arabica::DOM::Element(execContent[i]), indent); } } else { Arabica::DOM::Node child = node.getFirstChild(); while(child) { - writeExecutableContent(stream, child, indent); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent); child = child.getNextSibling(); } } @@ -326,7 +326,7 @@ void FSMToPromela::writeExecutableContent(std::ostream& stream, const Arabica::D } else if(TAGNAME(node) == "onentry" || TAGNAME(node) == "onexit") { Arabica::DOM::Node child = node.getFirstChild(); while(child) { - writeExecutableContent(stream, child, indent); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent); child = child.getNextSibling(); } @@ -345,7 +345,7 @@ void FSMToPromela::writeExecutableContent(std::ostream& stream, const Arabica::D stream << padding << "for (" << ATTR(node, "item") << " in " << ATTR(node, "array") << ") {" << std::endl; Arabica::DOM::Node child = node.getFirstChild(); while(child) { - writeExecutableContent(stream, child, indent + 1); + writeExecutableContent(stream, Arabica::DOM::Element(child), indent + 1); child = child.getNextSibling(); } if (HAS_ATTR(node, "index")) @@ -483,22 +483,22 @@ void FSMToPromela::writeIfBlock(std::ostream& stream, const Arabica::XPath::Node bool noNext = condChain.size() == 1; bool nextIsElse = false; if (condChain.size() > 1) { - if (TAGNAME(condChain[1]) == "else") { + if (TAGNAME_CAST(condChain[1]) == "else") { nextIsElse = true; } } - Node ifNode = condChain[0]; + Element ifNode = Element(condChain[0]); stream << padding << "if" << std::endl; // we need to nest the elseifs to resolve promela if semantics stream << padding << ":: (" << ATTR(ifNode, "cond") << ") -> {" << std::endl; - Arabica::DOM::Node child; + Arabica::DOM::Element child; if (TAGNAME(ifNode) == "if") { - child = ifNode.getFirstChild(); + child = Arabica::DOM::Element(ifNode.getFirstChild()); } else { - child = ifNode.getNextSibling(); + child = Arabica::DOM::Element(ifNode.getNextSibling()); } while(child) { if (child.getNodeType() == Node_base::ELEMENT_NODE) { @@ -506,17 +506,17 @@ void FSMToPromela::writeIfBlock(std::ostream& stream, const Arabica::XPath::Node break; } writeExecutableContent(stream, child, indent + 1); - child = child.getNextSibling(); + child = Arabica::DOM::Element(child.getNextSibling()); } stream << padding << "}" << std::endl; stream << padding << ":: else -> "; if (nextIsElse) { - child = condChain[1].getNextSibling(); + child = Arabica::DOM::Element(condChain[1].getNextSibling()); stream << "{" << std::endl; while(child) { writeExecutableContent(stream, child, indent + 1); - child = child.getNextSibling(); + child = Arabica::DOM::Element(child.getNextSibling()); } stream << padding << "}" << std::endl; @@ -630,14 +630,14 @@ void FSMToPromela::writeFSM(std::ostream& stream) { transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _startState); assert(transitions.size() == 1); stream << " // transition's executable content" << std::endl; - writeExecutableContent(stream, transitions[0], 1); + writeExecutableContent(stream, Arabica::DOM::Element(transitions[0]), 1); for (int i = 0; i < _globalStates.size(); i++) { if (_globalStates[i] == _startState) continue; NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _globalStates[i]); for (int j = 0; j < transitions.size(); j++) { - writeExecutableContent(stream, transitions[j], 1); + writeExecutableContent(stream, Arabica::DOM::Element(transitions[j]), 1); } } @@ -702,7 +702,7 @@ void FSMToPromela::writeDispatchingBlock(std::ostream& stream, const Arabica::XP stream << padding << "if" << std::endl; stream << padding << ":: ((0"; - Node currTrans = transChain[0]; + Element currTrans = Element(transChain[0]); std::string eventDesc = ATTR(currTrans, "event"); if (boost::ends_with(eventDesc, "*")) eventDesc = eventDesc.substr(0, eventDesc.size() - 1); @@ -754,8 +754,8 @@ void FSMToPromela::initNodes() { // get all states NodeSet states = filterChildElements(_nsInfo.xmlNSPrefix + "state", _scxml); for (int i = 0; i < states.size(); i++) { - _states[ATTR(states[i], "id")] = states[i]; - if (HAS_ATTR(states[i], "transient") && DOMUtils::attributeIsTrue(ATTR(states[i], "transient"))) + _states[ATTR_CAST(states[i], "id")] = Element(states[i]); + if (HAS_ATTR_CAST(states[i], "transient") && DOMUtils::attributeIsTrue(ATTR_CAST(states[i], "transient"))) continue; _globalStates.push_back(states[i]); } @@ -768,8 +768,8 @@ void FSMToPromela::initNodes() { internalEventNames.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "send", _scxml).asNodeSet()); for (int i = 0; i < internalEventNames.size(); i++) { - if (HAS_ATTR(internalEventNames[i], "event")) { - std::string eventNames = ATTR(internalEventNames[i], "event"); + if (HAS_ATTR_CAST(internalEventNames[i], "event")) { + std::string eventNames = ATTR_CAST(internalEventNames[i], "event"); std::list events = tokenizeIdRefs(eventNames); for (std::list::iterator eventIter = events.begin(); eventIter != events.end(); eventIter++) { @@ -793,17 +793,17 @@ void FSMToPromela::initNodes() { PromelaInlines promInls = getInlinePromela(promelaEventSourceComments[i]); PromelaEventSource promES(promInls, promelaEventSourceComments[i].getParentNode()); - if (TAGNAME(promelaEventSourceComments[i].getParentNode()) == "scxml") { + if (TAGNAME_CAST(promelaEventSourceComments[i].getParentNode()) == "scxml") { promES.type = PromelaEventSource::PROMELA_EVENT_SOURCE_GLOBAL; promES.trie = &_eventTrie; promES.name = "global"; _globalEventSource = promES; - } else if (TAGNAME(promelaEventSourceComments[i].getParentNode()) == "invoke") { - if (!HAS_ATTR(promelaEventSourceComments[i].getParentNode(), "invokeid")) { + } else if (TAGNAME_CAST(promelaEventSourceComments[i].getParentNode()) == "invoke") { + if (!HAS_ATTR_CAST(promelaEventSourceComments[i].getParentNode(), "invokeid")) { Element invoker = Element(promelaEventSourceComments[i].getParentNode()); invoker.setAttribute("invokeid", "invoker" + toStr(_invokers.size())); } - std::string invokeId = ATTR(promelaEventSourceComments[i].getParentNode(), "invokeid"); + std::string invokeId = ATTR_CAST(promelaEventSourceComments[i].getParentNode(), "invokeid"); promES.type = PromelaEventSource::PROMELA_EVENT_SOURCE_INVOKER; promES.trie = &_eventTrie; promES.name = invokeId; @@ -815,7 +815,7 @@ void FSMToPromela::initNodes() { NodeSet transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true); int index = 0; for (int i = 0; i < transitions.size(); i++) { - _transitions[transitions[i]] = index++; + _transitions[Element(transitions[i])] = index++; } } diff --git a/src/uscxml/transform/FSMToPromela.h b/src/uscxml/transform/FSMToPromela.h index e507fdc..62381cd 100644 --- a/src/uscxml/transform/FSMToPromela.h +++ b/src/uscxml/transform/FSMToPromela.h @@ -129,7 +129,7 @@ protected: void writeStates(std::ostream& stream); void writeDeclarations(std::ostream& stream); void writeEventSources(std::ostream& stream); - void writeExecutableContent(std::ostream& stream, const Arabica::DOM::Node& node, int indent = 0); + void writeExecutableContent(std::ostream& stream, const Arabica::DOM::Element& node, int indent = 0); void writeInlineComment(std::ostream& stream, const Arabica::DOM::Node& node); void writeFSM(std::ostream& stream); void writeEventDispatching(std::ostream& stream); @@ -138,8 +138,8 @@ protected: void writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet& condChain, int indent = 0); void writeDispatchingBlock(std::ostream& stream, const Arabica::XPath::NodeSet& transChain, int indent = 0); - Arabica::XPath::NodeSet getTransientContent(const Arabica::DOM::Node& state); - Arabica::DOM::Node getUltimateTarget(const Arabica::DOM::Node& transition); + Arabica::XPath::NodeSet getTransientContent(const Arabica::DOM::Element& state); + Arabica::DOM::Node getUltimateTarget(const Arabica::DOM::Element& transition); static PromelaInlines getInlinePromela(const std::string&); static PromelaInlines getInlinePromela(const Arabica::XPath::NodeSet& elements, bool recurse = false); @@ -148,8 +148,8 @@ protected: Trie _eventTrie; Arabica::XPath::NodeSet _globalStates; Arabica::DOM::Node _startState; - std::map > _states; - std::map, int> _transitions; + std::map > _states; + std::map, int> _transitions; std::map _invokers; PromelaEventSource _globalEventSource; diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp index 65b56dd..7eb54a7 100644 --- a/test/src/test-w3c.cpp +++ b/test/src/test-w3c.cpp @@ -135,7 +135,7 @@ class W3CStatusMonitor : public uscxml::InterpreterMonitor { void printNodeSet(const Arabica::XPath::NodeSet& config) { std::string seperator; for (int i = 0; i < config.size(); i++) { - std::cout << seperator << ATTR(config[i], "id"); + std::cout << seperator << ATTR_CAST(config[i], "id"); seperator = ", "; } } @@ -144,13 +144,13 @@ class W3CStatusMonitor : public uscxml::InterpreterMonitor { Arabica::XPath::NodeSet config = interpreter.getConfiguration(); if (config.size() == 1) { if (withFlattening) { - std::cout << ATTR(config[0], "id") << std::endl; - if (boost::starts_with(ATTR(config[0], "id"), "active-pass")) { + std::cout << ATTR_CAST(config[0], "id") << std::endl; + if (boost::starts_with(ATTR_CAST(config[0], "id"), "active-pass")) { std::cout << "TEST SUCCEEDED" << std::endl; exit(EXIT_SUCCESS); } } else { - if (boost::iequals(ATTR(config[0], "id"), "pass")) { + if (boost::iequals(ATTR_CAST(config[0], "id"), "pass")) { std::cout << "TEST SUCCEEDED" << std::endl; exit(EXIT_SUCCESS); } diff --git a/test/uscxml/test-performance-events.scxml b/test/uscxml/test-performance-events.scxml new file mode 100644 index 0000000..0af8272 --- /dev/null +++ b/test/uscxml/test-performance-events.scxml @@ -0,0 +1,28 @@ + + + 100000 + + { + string: 'bar', + integer: 12, + float: 234243.2342 + } + + + + + + + + + + this is space normalized! + + + + + + + + + \ No newline at end of file -- cgit v0.12