diff options
-rw-r--r-- | src/uscxml/Interpreter.cpp | 235 | ||||
-rw-r--r-- | src/uscxml/Interpreter.h | 5 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.cpp | 206 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.h | 1 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 5 | ||||
-rw-r--r-- | test/samples/w3c/tests/test552.txt | 1 | ||||
-rw-r--r-- | test/samples/w3c/tests/test557.txt | 4 | ||||
-rw-r--r-- | test/samples/w3c/tests/test558.txt | 3 |
8 files changed, 261 insertions, 199 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index e252d54..85c2e04 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -31,7 +31,7 @@ catch (Event e) {\ } else {\ e.name = "error.execution";\ e.type = Event::PLATFORM;\ - _internalQueue.push_back(e);\ + receiveInternal(e);\ }\ } @@ -296,6 +296,114 @@ void Interpreter::init() { _isInitialized = true; } +/** + * Called with a single data element from the topmost datamodel element. + */ +void Interpreter::initializeData(const Node<std::string>& data) { + if (!_dataModel) { + LOG(ERROR) << "Cannot initialize data when no datamodel is given!"; + return; + } + + if (!HAS_ATTR(data, "id")) { + LOG(ERROR) << "Data element has no id!"; + return; + } + + /// test 240 - initialize from invoke request + if (_invokeReq.params.find(ATTR(data, "id")) != _invokeReq.params.end()) { + try { + _dataModel.assign(ATTR(data, "id"), _invokeReq.params.find(ATTR(data, "id"))->second); + } catch (Event e) { + LOG(ERROR) << "Syntax error when initializing data from parameters:" << std::endl << e << std::endl; + receiveInternal(e); + } + return; + } + if (_invokeReq.namelist.find(ATTR(data, "id")) != _invokeReq.namelist.end()) { + try { + _dataModel.assign(ATTR(data, "id"), _invokeReq.namelist.find(ATTR(data, "id"))->second); + } catch (Event e) { + LOG(ERROR) << "Syntax error when initializing data from namelist:" << std::endl << e << std::endl; + receiveInternal(e); + } + return; + } + + try { + std::string contentToProcess; + if (HAS_ATTR(data, "expr")) { + // expression given directly + std::string value = ATTR(data, "expr"); + _dataModel.assign(ATTR(data, "id"), value); + } else if (HAS_ATTR(data, "src")) { + // fetch us some string and proess below + URL srcURL(ATTR(data, "src")); + if (!srcURL.isAbsolute()) + toAbsoluteURI(srcURL); + + std::stringstream ss; + if (_cachedURLs.find(srcURL.asString()) != _cachedURLs.end()) { + ss << _cachedURLs[srcURL.asString()]; + } else { + ss << srcURL; + _cachedURLs[srcURL.asString()] = srcURL; + } + contentToProcess = ss.str(); + } else if (data.hasChildNodes()) { + bool presentAsDom = false; + Node<std::string> contentChild = data.getFirstChild(); + while(contentChild) { + if (contentChild.getNodeType() == Node_base::TEXT_NODE) { + break; + } + if (contentChild.getNodeType() == Node_base::ELEMENT_NODE) { + presentAsDom = true; + break; + } + contentChild = contentChild.getNextSibling(); + } + + if (contentChild && presentAsDom) { + LOG(ERROR) << "Passing DOM in data is TODO."; + } else if (contentChild) { + // get first child and process below + contentToProcess = contentChild.getNodeValue(); + } else { + LOG(ERROR) << "content element has no text or element children."; + } + } + if (contentToProcess.length() > 0) { + /// try to interpret as JSON + try { + _dataModel.assign(ATTR(data, "id"), contentToProcess); + } catch(Event e) { + /// create space normalized string if that failed + /// test 558 + std::istringstream iss(contentToProcess); + std::stringstream spaceNormalized; + std::string seperator; + do { + std::string token; + iss >> token; + if (token.length() > 0) { + spaceNormalized << seperator << token; + seperator = " "; + } + } while (iss); + _dataModel.assign(ATTR(data, "id"), Data(spaceNormalized.str(), Data::VERBATIM)); + } + } else { + _dataModel.assign(ATTR(data, "id"), "undefined"); + } + + } catch (Event e) { + LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; + /// test 487 + receiveInternal(e); + } +} + void Interpreter::normalize(Arabica::DOM::Element<std::string>& scxml) { // make sure every state has an id and set isFirstEntry to true Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _xpathPrefix + "state", _scxml).asNodeSet(); @@ -354,6 +462,11 @@ void Interpreter::normalize(Arabica::DOM::Element<std::string>& scxml) { std::cout << _scxml <<std::endl; #endif } + +void Interpreter::receiveInternal(const Event& event) { + std::cout << "receiveInternal: " << event.name << std::endl; + _internalQueue.push_back(event); +} void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) { @@ -377,61 +490,66 @@ void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) } event.name = "done.state." + ATTR(stateElem.getParentNode(), "id"); // parent?! - _internalQueue.push_back(event); + receiveInternal(event); } void Interpreter::processContentElement(const Arabica::DOM::Node<std::string>& content, Arabica::DOM::Document<std::string>& dom, std::string& text) { - if (HAS_ATTR(content, "expr")) { - if (_dataModel) { - /// this is out of spec - std::string contentValue = _dataModel.evalAsString(ATTR(content, "expr")); - text = contentValue; - // sendReq.data.atom = contentValue; - // sendReq.data.type = Data::VERBATIM; - } else { - LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; - } - } else if (content.hasChildNodes()) { - bool presentAsDOM = false; - NodeList<std::string> contentChilds = content.getChildNodes(); - for (int i = 0; i < contentChilds.getLength(); i++) { - if (contentChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) { - presentAsDOM = true; - break; + try { + if (HAS_ATTR(content, "expr")) { + if (_dataModel) { + /// this is out of spec + std::string contentValue = _dataModel.evalAsString(ATTR(content, "expr")); + text = contentValue; + // sendReq.data.atom = contentValue; + // sendReq.data.type = Data::VERBATIM; + } else { + LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; } - } - if (presentAsDOM) { - // use the whole dom - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - dom = domFactory.createDocument(content.getNamespaceURI(), "", 0); - Node<std::string> newNode = dom.importNode(content, true); - dom.appendChild(newNode); - } else { - Node<std::string> textChild = content.getFirstChild(); - while(textChild && textChild.getNodeType() != Node_base::TEXT_NODE) { - textChild = textChild.getNextSibling(); + } else if (content.hasChildNodes()) { + bool presentAsDOM = false; + NodeList<std::string> contentChilds = content.getChildNodes(); + for (int i = 0; i < contentChilds.getLength(); i++) { + if (contentChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) { + presentAsDOM = true; + break; + } } - if (textChild && textChild.getNodeType() == Node_base::TEXT_NODE) { - /// create space normalized string - std::istringstream iss(content.getFirstChild().getNodeValue()); - std::stringstream content; - std::string seperator; - do { - std::string token; - iss >> token; - if (token.length() > 0) { - content << seperator << token; - seperator = " "; - } - } while (iss); - text = content.str(); + if (presentAsDOM) { + // use the whole dom + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + dom = domFactory.createDocument(content.getNamespaceURI(), "", 0); + Node<std::string> newNode = dom.importNode(content, true); + dom.appendChild(newNode); } else { - LOG(ERROR) << "content element has neither text nor element children."; + Node<std::string> textChild = content.getFirstChild(); + while(textChild && textChild.getNodeType() != Node_base::TEXT_NODE) { + textChild = textChild.getNextSibling(); + } + if (textChild && textChild.getNodeType() == Node_base::TEXT_NODE) { + /// create space normalized string + std::istringstream iss(content.getFirstChild().getNodeValue()); + std::stringstream content; + std::string seperator; + do { + std::string token; + iss >> token; + if (token.length() > 0) { + content << seperator << token; + seperator = " "; + } + } while (iss); + text = content.str(); + } else { + LOG(ERROR) << "content element has neither text nor element children."; + } } + } else { + LOG(ERROR) << "content element does not specify any content."; } - } else { - LOG(ERROR) << "content element does not specify any content."; + } catch (Event e) { + e.name = "error.execution"; + receiveInternal(e); } } @@ -463,7 +581,7 @@ void Interpreter::processParamChilds(const Arabica::DOM::Node<std::string>& elem params.erase(paramIter++); } e.name = "error.execution"; - _internalQueue.push_back(e); + receiveInternal(e); } } @@ -634,7 +752,7 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl; } } else if (boost::iequals(sendReq.target, "#_internal")) { - INSTANCE->_internalQueue.push_back(sendReq); + INSTANCE->receiveInternal(sendReq); } else if (sendReq.target.find_first_of("#_") == 0) { // send to invoker std::string invokeId = sendReq.target.substr(2, sendReq.target.length() - 2); @@ -647,6 +765,8 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { } } else { LOG(ERROR) << "Can not send to invoked component '" << invokeId << "', no such invokeId" << std::endl; + Event e("error.communication", Event::PLATFORM); + INSTANCE->receiveInternal(e); } } else if (sendReq.target.length() == 0 && (sendReq.type.length() == 0 || @@ -672,7 +792,7 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { exceptionEvent.name = "error.execution"; exceptionEvent.type = Event::PLATFORM; exceptionEvent.sendid = sendReq.sendid; - INSTANCE->_internalQueue.push_back(exceptionEvent); + INSTANCE->receiveInternal(exceptionEvent); } } assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end()); @@ -688,8 +808,6 @@ void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) { invokeReq.type = _dataModel.evalAsString(ATTR(element, "typeexpr")); } else if (HAS_ATTR(element, "type")) { invokeReq.type = ATTR(element, "type"); - } else { - LOG(ERROR) << "invoke element is missing expr or typeexpr or no datamodel is specified"; } // src @@ -756,6 +874,10 @@ void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) { return; } + // test 422 + if (invokeReq.type.size() == 0) + invokeReq.type = "http://www.w3.org/TR/scxml/"; + Invoker invoker(Factory::createInvoker(invokeReq.type, this)); if (invoker) { tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); @@ -812,13 +934,14 @@ void Interpreter::cancelInvoke(const Arabica::DOM::Node<std::string>& element) { } else { LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no soch invokation"; } + //receiveInternal(Event("done.invoke." + invokeId, Event::PLATFORM)); } // see: http://www.w3.org/TR/scxml/#EventDescriptors bool Interpreter::nameMatch(const std::string& transitionEvent, const std::string& event) { - assert(transitionEvent.size() > 0); - assert(event.size() > 0); + if(transitionEvent.length() == 0 || event.length() == 0) + return false; // naive case of single descriptor and exact match if (boost::equals(transitionEvent, event)) @@ -870,7 +993,7 @@ bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& condi } catch (Event e) { LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl; e.name = "error.execution"; - _internalQueue.push_back(e); + receiveInternal(e); return false; } } @@ -911,7 +1034,7 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "raise")) { // --- RAISE -------------------------- if (HAS_ATTR(content, "event")) { - _internalQueue.push_back(Event(ATTR(content, "event"))); + receiveInternal(Event(ATTR(content, "event"))); } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "if")) { // --- IF / ELSEIF / ELSE -------------- diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 0352f2b..c2e24fa 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -156,6 +156,7 @@ public: return ""; } + void inline receiveInternal(const Event& event); void receive(const Event& event, bool toFront = false) { if (toFront) { _externalQueue.push_front(event); @@ -163,9 +164,6 @@ public: _externalQueue.push(event); } } - void receiveInternal(const Event& event) { - _internalQueue.push_back(event); - } Event getCurrentEvent() { return _currEvent; @@ -243,6 +241,7 @@ protected: void init(); void normalize(Arabica::DOM::Element<std::string>& scxml); + void initializeData(const Arabica::DOM::Node<std::string>& data); void setupIOProcessors(); bool _stable; diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index d8e8296..453e64f 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -84,9 +84,9 @@ void InterpreterDraft6::interpret() { assert(initialStates.size() > 0); for (int i = 0; i < initialStates.size(); i++) { - Arabica::DOM::Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial"); + Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial"); initialElem.setAttribute("generated", "true"); - Arabica::DOM::Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition"); + Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition"); transitionElem.setAttribute("target", ATTR(initialStates[i], "id")); initialElem.appendChild(transitionElem); _scxml.appendChild(initialElem); @@ -114,74 +114,6 @@ void InterpreterDraft6::interpret() { } -/** - * Called with a single data element from the topmost datamodel element. - */ -void InterpreterDraft6::initializeData(const Arabica::DOM::Node<std::string>& data) { - if (!_dataModel) { - LOG(ERROR) << "Cannot initialize data when no datamodel is given!"; - return; - } - - if (!HAS_ATTR(data, "id")) { - LOG(ERROR) << "Data element has no id!"; - return; - } - - /// test 240 - if (_invokeReq.params.find(ATTR(data, "id")) != _invokeReq.params.end()) { - try { - _dataModel.assign(ATTR(data, "id"), _invokeReq.params.find(ATTR(data, "id"))->second); - } catch (Event e) { - LOG(ERROR) << "Syntax error when initializing data from parameters:" << std::endl << e << std::endl; - } - return; - } - if (_invokeReq.namelist.find(ATTR(data, "id")) != _invokeReq.namelist.end()) { - try { - _dataModel.assign(ATTR(data, "id"), _invokeReq.namelist.find(ATTR(data, "id"))->second); - } catch (Event e) { - LOG(ERROR) << "Syntax error when initializing data from namelist:" << std::endl << e << std::endl; - } - return; - } - - try { - if (HAS_ATTR(data, "expr")) { - std::string value = ATTR(data, "expr"); - _dataModel.assign(ATTR(data, "id"), value); - } else if (HAS_ATTR(data, "src")) { - URL srcURL(ATTR(data, "src")); - if (!srcURL.isAbsolute()) - toAbsoluteURI(srcURL); - - std::stringstream ss; - if (_cachedURLs.find(srcURL.asString()) != _cachedURLs.end()) { - ss << _cachedURLs[srcURL.asString()]; - } else { - ss << srcURL; - _cachedURLs[srcURL.asString()] = srcURL; - } - _dataModel.assign(ATTR(data, "id"), ss.str()); - - } else if (data.hasChildNodes()) { - // search for the text node with the actual script - NodeList<std::string> dataChilds = data.getChildNodes(); - for (int i = 0; i < dataChilds.getLength(); i++) { - if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) { - Data value = Data(dataChilds.item(i).getNodeValue()); - _dataModel.assign(ATTR(data, "id"), value); - break; - } - } - } else { - _dataModel.assign(ATTR(data, "id"), "undefined"); - } - - } catch (Event e) { - LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; - } -} void InterpreterDraft6::mainEventLoop() { std::set<InterpreterMonitor*>::iterator monIter; @@ -298,7 +230,7 @@ void InterpreterDraft6::mainEventLoop() { for (unsigned int i = 0; i < _configuration.size(); i++) { NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", _configuration[i]); for (unsigned int j = 0; j < invokes.size(); j++) { - Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j]; + Element<std::string> invokeElem = (Element<std::string>)invokes[j]; std::string invokeId; if (HAS_ATTR(invokeElem, "id")) { invokeId = ATTR(invokeElem, "id"); @@ -316,7 +248,7 @@ void InterpreterDraft6::mainEventLoop() { Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_xmlNSPrefix + "finalize", invokeElem); for (int k = 0; k < finalizes.size(); k++) { - Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]); + Element<std::string> finalizeElem = Element<std::string>(finalizes[k]); executeContent(finalizeElem); } @@ -425,7 +357,7 @@ Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectTransitions(const return enabledTransitions; } -bool InterpreterDraft6::isEnabledTransition(const Arabica::DOM::Node<std::string>& transition, const std::string& event) { +bool InterpreterDraft6::isEnabledTransition(const Node<std::string>& transition, const std::string& event) { std::string eventName; if (HAS_ATTR(transition, "event")) { eventName = ATTR(transition, "event"); @@ -440,10 +372,16 @@ bool InterpreterDraft6::isEnabledTransition(const Arabica::DOM::Node<std::string return false; } - if (eventName.length() > 0 && - nameMatch(eventName, event) && - hasConditionMatch(transition)) { - return true; + std::vector<std::string> eventNames = tokenizeIdRefs(eventName); + + if (eventNames.size() > 0 && hasConditionMatch(transition)) { + std::vector<std::string>::iterator eventIter = eventNames.begin(); + while(eventIter != eventNames.end()) { + if(nameMatch(*eventIter, event)) { + return true; + } + eventIter++; + } } return false; } @@ -502,12 +440,12 @@ Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectEventlessTransitio Arabica::XPath::NodeSet<std::string> InterpreterDraft6::filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { Arabica::XPath::NodeSet<std::string> filteredTransitions; for (unsigned int i = 0; i < enabledTransitions.size(); i++) { - Arabica::DOM::Node<std::string> t = enabledTransitions[i]; + Node<std::string> t = enabledTransitions[i]; if (!isTargetless(t)) { for (unsigned int j = 0; j < filteredTransitions.size(); j++) { if (j == i) continue; - Arabica::DOM::Node<std::string> t2 = filteredTransitions[j]; + Node<std::string> t2 = filteredTransitions[j]; if (isPreemptingTransition(t2, t)) { #if 0 std::cout << "#####" << std::endl << "Transition " << std::endl @@ -531,7 +469,7 @@ LOOP: /** * Is t1 preempting t2? */ -bool InterpreterDraft6::isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2) { +bool InterpreterDraft6::isPreemptingTransition(const Node<std::string>& t1, const Node<std::string>& t2) { assert(t1); assert(t2); @@ -551,13 +489,13 @@ bool InterpreterDraft6::isPreemptingTransition(const Arabica::DOM::Node<std::str return false; } -bool InterpreterDraft6::isCrossingBounds(const Arabica::DOM::Node<std::string>& transition) { +bool InterpreterDraft6::isCrossingBounds(const Node<std::string>& transition) { if (!isTargetless(transition) && !isWithinParallel(transition)) return true; return false; } -bool InterpreterDraft6::isWithinParallel(const Arabica::DOM::Node<std::string>& transition) { +bool InterpreterDraft6::isWithinParallel(const Node<std::string>& transition) { if (isTargetless(transition)) return false; @@ -570,13 +508,13 @@ bool InterpreterDraft6::isWithinParallel(const Arabica::DOM::Node<std::string>& NodeSet<std::string> targets = getTargetStates(transition); targets.push_back(source); - Arabica::DOM::Node<std::string> lcpa = findLCPA(targets); + Node<std::string> lcpa = findLCPA(targets); return lcpa; } -Arabica::DOM::Node<std::string> InterpreterDraft6::findLCPA(const Arabica::XPath::NodeSet<std::string>& states) { - Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>()); - Arabica::DOM::Node<std::string> ancestor; +Node<std::string> InterpreterDraft6::findLCPA(const Arabica::XPath::NodeSet<std::string>& states) { + Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Node<std::string>()); + Node<std::string> ancestor; for (int i = 0; i < ancestors.size(); i++) { if (!isParallel(ancestors[i])) continue; @@ -596,10 +534,10 @@ void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& en #if 0 std::cout << "Transitions: "; for (int i = 0; i < enabledTransitions.size(); i++) { - std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl; + std::cout << ((Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl; NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]); for (int j = 0; j < targetSet.size(); j++) { - std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl; + std::cout << " " << ((Element<std::string>)targetSet[j]).getAttribute("id") << std::endl; } } std::cout << std::endl; @@ -612,8 +550,8 @@ void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& en void InterpreterDraft6::exitInterpreter() { NodeSet<std::string> statesToExit = _configuration; - statesToExit.to_document_order(); - statesToExit.reverse(); + statesToExit.forward(false); + statesToExit.sort(); for (int i = 0; i < statesToExit.size(); i++) { Arabica::XPath::NodeSet<std::string> onExitElems = filterChildElements(_xmlNSPrefix + "onexit", statesToExit[i]); @@ -645,13 +583,12 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e #endif for (int i = 0; i < enabledTransitions.size(); i++) { - Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]); - if (!isTargetless(transition)) { - std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); - NodeSet<std::string> tStates = getTargetStates(transition); - Arabica::DOM::Node<std::string> ancestor; - Arabica::DOM::Node<std::string> source = getSourceState(transition); - + Element<std::string> t = ((Element<std::string>)enabledTransitions[i]); + if (!isTargetless(t)) { + Node<std::string> ancestor; + Node<std::string> source = getSourceState(t); + NodeSet<std::string> tStates = getTargetStates(t); + bool isInternal = (HAS_ATTR(t, "type") && boost::iequals(ATTR(t, "type"), "internal")); // external is default bool allDescendants = true; for (int j = 0; j < tStates.size(); j++) { if (!isDescendant(tStates[j], source)) { @@ -659,15 +596,12 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e break; } } - if (boost::iequals(transitionType, "internal") && - isCompound(source) && - allDescendants) { + if (isInternal && allDescendants && isCompound(source)) { ancestor = source; } else { NodeSet<std::string> tmpStates; tmpStates.push_back(source); tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end()); - #if VERBOSE std::cout << "tmpStates: "; for (int i = 0; i < tmpStates.size(); i++) { @@ -677,29 +611,17 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e #endif ancestor = findLCCA(tmpStates); } - #if VERBOSE std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl;; #endif - for (int j = 0; j < _configuration.size(); j++) { if (isDescendant(_configuration[j], ancestor)) statesToExit.push_back(_configuration[j]); - } + } } } - -#if VERBOSE - std::cout << "States to exit: "; - for (int i = 0; i < statesToExit.size(); i++) { - std::cout << LOCALNAME(statesToExit[i]) << ":" << ATTR(statesToExit[i], "id") << ", "; - } - std::cout << std::endl; - -#endif - // remove statesToExit from _statesToInvoke - std::list<Arabica::DOM::Node<std::string> > tmp; + std::list<Node<std::string> > tmp; for (int i = 0; i < _statesToInvoke.size(); i++) { if (!isMember(_statesToInvoke[i], statesToExit)) { tmp.push_back(_statesToInvoke[i]); @@ -708,9 +630,17 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e _statesToInvoke = NodeSet<std::string>(); _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); - statesToExit.to_document_order(); - statesToExit.reverse(); + statesToExit.forward(false); + statesToExit.sort(); +#if VERBOSE + std::cout << "States to exit: "; + for (int i = 0; i < statesToExit.size(); i++) { + std::cout << LOCALNAME(statesToExit[i]) << ":" << ATTR(statesToExit[i], "id") << ", "; + } + std::cout << std::endl; +#endif + monIter = _monitors.begin(); while(monIter != _monitors.end()) { try { @@ -726,7 +656,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e for (int i = 0; i < statesToExit.size(); i++) { NodeSet<std::string> histories = filterChildElements(_xmlNSPrefix + "history", statesToExit[i]); for (int j = 0; j < histories.size(); j++) { - Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)histories[j]; + Element<std::string> historyElem = (Element<std::string>)histories[j]; std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow"); NodeSet<std::string> historyNodes; for (int k = 0; k < _configuration.size(); k++) { @@ -745,7 +675,6 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e std::cout << ATTR(historyNodes[i], "id") << ", "; } std::cout << std::endl; - #endif } @@ -754,25 +683,24 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e for (int i = 0; i < statesToExit.size(); i++) { NodeSet<std::string> onExits = filterChildElements(_xmlNSPrefix + "onExit", statesToExit[i]); for (int j = 0; j < onExits.size(); j++) { - Arabica::DOM::Element<std::string> onExitElem = (Arabica::DOM::Element<std::string>)onExits[j]; + Element<std::string> onExitElem = (Element<std::string>)onExits[j]; executeContent(onExitElem); } NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", statesToExit[i]); for (int j = 0; j < invokes.size(); j++) { - Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j]; + Element<std::string> invokeElem = (Element<std::string>)invokes[j]; cancelInvoke(invokeElem); } - } - - // remove statesToExit from _configuration - tmp.clear(); - for (int i = 0; i < _configuration.size(); i++) { - if (!isMember(_configuration[i], statesToExit)) { - tmp.push_back(_configuration[i]); + // remove statesToExit[i] from _configuration - test409 + tmp.clear(); + for (int j = 0; j < _configuration.size(); j++) { + if (_configuration[j] != statesToExit[i]) { + tmp.push_back(_configuration[j]); + } } + _configuration = NodeSet<std::string>(); + _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); } - _configuration = NodeSet<std::string>(); - _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); monIter = _monitors.begin(); while(monIter != _monitors.end()) { @@ -802,7 +730,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& #endif for (int i = 0; i < enabledTransitions.size(); i++) { - Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]); + Element<std::string> transition = ((Element<std::string>)enabledTransitions[i]); if (!isTargetless(transition)) { std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); NodeSet<std::string> tStates = getTargetStates(transition); @@ -815,8 +743,8 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& std::cout << std::endl; #endif - Arabica::DOM::Node<std::string> ancestor; - Arabica::DOM::Node<std::string> source = getSourceState(transition); + Node<std::string> ancestor; + Node<std::string> source = getSourceState(transition); #if VERBOSE std::cout << "Source States: " << ATTR(source, "id") << std::endl; #endif @@ -904,7 +832,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& } for (int i = 0; i < statesToEnter.size(); i++) { - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i]; + Element<std::string> stateElem = (Element<std::string>)statesToEnter[i]; _configuration.push_back(stateElem); _statesToInvoke.push_back(stateElem); if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) { @@ -931,10 +859,10 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& if (isFinal(stateElem)) { internalDoneSend(stateElem); - Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); + Element<std::string> parent = (Element<std::string>)stateElem.getParentNode(); if (isParallel(parent.getParentNode())) { - Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode(); + Element<std::string> grandParent = (Element<std::string>)parent.getParentNode(); Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent); bool inFinalState = true; @@ -951,7 +879,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& } } for (int i = 0; i < _configuration.size(); i++) { - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i]; + Element<std::string> stateElem = (Element<std::string>)_configuration[i]; if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { _running = false; _done = true; @@ -972,10 +900,10 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& } -void InterpreterDraft6::addStatesToEnter(const Arabica::DOM::Node<std::string>& state, +void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state, Arabica::XPath::NodeSet<std::string>& statesToEnter, Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) { - std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id"); + std::string stateId = ((Element<std::string>)state).getAttribute("id"); #if VERBOSE std::cout << "Adding state to enter: " << stateId << std::endl; diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h index c0af7dc..9ecfd3b 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.h +++ b/src/uscxml/interpreter/InterpreterDraft6.h @@ -10,7 +10,6 @@ protected: void interpret(); void mainEventLoop(); - void initializeData(const Arabica::DOM::Node<std::string>& data); void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); void addStatesToEnter(const Arabica::DOM::Node<std::string>& state, diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 7ad528d..bbd2538 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -48,6 +48,8 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { _invokedInterpreter = Interpreter::fromURI(req.src); } else if (req.dom) { _invokedInterpreter = Interpreter::fromDOM(req.dom); + } else if (req.content.size() > 0) { + LOG(ERROR) << "Instantiating nested SCXML interpreter by content not supported yet"; } else { LOG(ERROR) << "Cannot invoke nested SCXML interpreter, neither src attribute nor DOM is given"; } @@ -73,6 +75,9 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { _invokedInterpreter->setInvokeRequest(req); _invokedInterpreter->start(); + } else { + /// test 530 + _parentInterpreter->receive(Event("done.invoke." + _invokeId, Event::PLATFORM)); } } diff --git a/test/samples/w3c/tests/test552.txt b/test/samples/w3c/tests/test552.txt new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/test/samples/w3c/tests/test552.txt @@ -0,0 +1 @@ +2 diff --git a/test/samples/w3c/tests/test557.txt b/test/samples/w3c/tests/test557.txt new file mode 100644 index 0000000..a8e51da --- /dev/null +++ b/test/samples/w3c/tests/test557.txt @@ -0,0 +1,4 @@ +<books xmlns=""> + <book title="title1"/> + <book title="title2"/> + </books>
\ No newline at end of file diff --git a/test/samples/w3c/tests/test558.txt b/test/samples/w3c/tests/test558.txt new file mode 100644 index 0000000..bb2bcc7 --- /dev/null +++ b/test/samples/w3c/tests/test558.txt @@ -0,0 +1,3 @@ + +this is +a string
\ No newline at end of file |