summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-05-15 19:55:13 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-05-15 19:55:13 (GMT)
commitf9a620340ddce2a17fd775d1e210268cac13377b (patch)
tree58d8dad794e5a34237c2738fe77c151d0810624f
parent49127140ed2ad91bfcf532b3d2265582cb80b0db (diff)
downloaduscxml-f9a620340ddce2a17fd775d1e210268cac13377b.zip
uscxml-f9a620340ddce2a17fd775d1e210268cac13377b.tar.gz
uscxml-f9a620340ddce2a17fd775d1e210268cac13377b.tar.bz2
Introduced interpreter.step()
-rw-r--r--README.md13
-rw-r--r--contrib/java/.classpath5
-rw-r--r--contrib/java/.project5
-rw-r--r--src/uscxml/Interpreter.cpp184
-rw-r--r--src/uscxml/Interpreter.h19
-rw-r--r--src/uscxml/debug/Debugger.cpp4
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp12
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.cpp484
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.h5
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp4
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp4
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp2
-rw-r--r--src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp4
-rw-r--r--src/uscxml/plugins/element/respond/RespondElement.cpp4
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp5
-rw-r--r--src/uscxml/transform/ChartToFSM.cpp8
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/src/test-arabica-namespaces.cpp6
-rw-r--r--test/src/test-lifecycle.cpp129
-rw-r--r--test/src/test-predicates.cpp38
20 files changed, 643 insertions, 297 deletions
diff --git a/README.md b/README.md
index 90d988b..7499b63 100644
--- a/README.md
+++ b/README.md
@@ -107,6 +107,19 @@ or return immediately. You will have to call this method every now and then if y
Interpreter scxml = Interpreter::fromXML("<scxml><final id="exit"/></scxml>");
scxml.interpret(); // blocking
+When using blocking interpretation, it is assumed that it is running on the main thread and
+it will call <tt>runOnMainThread</tt> between stable configurations.
+
+### Interleaved Interpretation with inline SCXML
+ Interpreter scxml = Interpreter::fromXML("<scxml><final id="exit"/></scxml>");
+ InterpreterState state;
+ do {
+ state = interpreter.step(true); // boolean argument causes blocking or not
+ } while(state > 0)
+
+Using <tt>step</tt>, you can run a single macrostep of the interpreter and interleave
+interpretation with the rest of your code.
+
### Callbacks for an Interpreter
You can register an <tt>InterpreterMonitor</tt> prior to start in order to receive
diff --git a/contrib/java/.classpath b/contrib/java/.classpath
index 7592c3b..0830f8a 100644
--- a/contrib/java/.classpath
+++ b/contrib/java/.classpath
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="java"/>
<classpathentry kind="src" path="uscxml"/>
- <classpathentry kind="src" path="bindings"/>
- <classpathentry kind="src" path="applications"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/umundo"/>
- <classpathentry kind="lib" path="src/js.jar"/>
+ <classpathentry kind="lib" path="/Users/sradomski/Documents/TK/Code/rhino1_7R4/build/rhino1_7R4/js.jar" sourcepath="/Users/sradomski/Documents/TK/Code/rhino1_7R4/src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/contrib/java/.project b/contrib/java/.project
index 260e80f..bed7874 100644
--- a/contrib/java/.project
+++ b/contrib/java/.project
@@ -26,6 +26,11 @@
<location>/Users/sradomski/Documents/TK/Code/uscxml/src/bindings/swig/java</location>
</link>
<link>
+ <name>java</name>
+ <type>2</type>
+ <location>/Users/sradomski/Documents/TK/Code/uscxml/src/bindings/swig/java</location>
+ </link>
+ <link>
<name>uscxml</name>
<type>2</type>
<location>/Users/sradomski/Documents/TK/Code/uscxml/build/cli/src/bindings/swig/java</location>
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 75d44c1..e2ee1da 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -292,9 +292,11 @@ InterpreterImpl::InterpreterImpl() {
_running = false;
_destroyed = false;
_done = true;
+ _stable = false;
_isInitialized = false;
_httpServlet = NULL;
_factory = NULL;
+ _sessionId = UUID::getUUID();
_capabilities = CAN_BASIC_HTTP | CAN_GENERIC_HTTP;
_domEventListener._interpreter = this;
@@ -389,7 +391,7 @@ Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>&
if (parser.parse(source) && parser.getDocument() && parser.getDocument().hasChildNodes()) {
interpreterImpl->setNameSpaceInfo(parser.nameSpace);
interpreterImpl->_document = parser.getDocument();
- interpreterImpl->init();
+// interpreterImpl->init();
interpreter = Interpreter(interpreterImpl);
_instances[interpreterImpl->getSessionId()] = interpreterImpl;
} else {
@@ -473,6 +475,7 @@ InterpreterImpl::~InterpreterImpl() {
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
if (_thread) {
if (_thread->get_id() != tthread::this_thread::get_id()) {
+
// unblock event queue
Event event;
event.name = "unblock.and.die";
@@ -488,8 +491,6 @@ InterpreterImpl::~InterpreterImpl() {
if (_sendQueue)
delete _sendQueue;
-// if (_httpServlet)
-// delete _httpServlet;
}
void InterpreterImpl::start() {
@@ -550,52 +551,116 @@ bool InterpreterImpl::runOnMainThread(int fps, bool blocking) {
}
void InterpreterImpl::init() {
- if (_document) {
- NodeList<std::string> scxmls;
- if (_nsInfo.nsURL.size() == 0) {
- scxmls = _document.getElementsByTagName("scxml");
- } else {
- scxmls = _document.getElementsByTagNameNS(_nsInfo.nsURL, "scxml");
- }
- if (scxmls.getLength() > 0) {
- _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
+ if (!_document) {
+ LOG(ERROR) << "Interpreter has no DOM at all!" << std::endl;
+ _done = true;
+ return;
+ }
+
+ // find scxml element
+ NodeList<std::string> scxmls;
+ if (_nsInfo.nsURL.size() == 0) {
+ scxmls = _document.getElementsByTagName("scxml");
+ } else {
+ scxmls = _document.getElementsByTagNameNS(_nsInfo.nsURL, "scxml");
+ }
+
+ if (scxmls.getLength() > 0) {
+ _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
- // setup xpath and check that it works
- if (_nsInfo.getNSContext() != NULL)
- _xpath.setNamespaceContext(*_nsInfo.getNSContext());
+ // setup xpath and check that it works
+ if (_nsInfo.getNSContext() != NULL)
+ _xpath.setNamespaceContext(*_nsInfo.getNSContext());
- if (_name.length() == 0)
- _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : UUID::getUUID());
+ if (_name.length() == 0)
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : UUID::getUUID());
- normalize(_scxml);
+ // normalize document
+ normalize(_scxml);
- // setup event queue for delayed send
- _sendQueue = new DelayedEventQueue();
- _sendQueue->start();
+ // setup event queue for delayed send
+ _sendQueue = new DelayedEventQueue();
+ _sendQueue->start();
- // register for dom events to manage cached states
- Arabica::DOM::Events::EventTarget<std::string> eventTarget(_scxml);
- eventTarget.addEventListener("DOMNodeInserted", _domEventListener, true);
- eventTarget.addEventListener("DOMNodeRemoved", _domEventListener, true);
- eventTarget.addEventListener("DOMSubtreeModified", _domEventListener, true);
+ // register for dom events to manage cached states
+ Arabica::DOM::Events::EventTarget<std::string> eventTarget(_scxml);
+ eventTarget.addEventListener("DOMNodeInserted", _domEventListener, true);
+ eventTarget.addEventListener("DOMNodeRemoved", _domEventListener, true);
+ eventTarget.addEventListener("DOMSubtreeModified", _domEventListener, true);
- if (_factory == NULL)
- _factory = Factory::getInstance();
+ if (_factory == NULL)
+ _factory = Factory::getInstance();
- } else {
- LOG(ERROR) << "Cannot find SCXML element" << std::endl;
- _done = true;
- return;
- }
} else {
- LOG(ERROR) << "Interpreter has no DOM at all!" << std::endl;
+ LOG(ERROR) << "Cannot find SCXML element" << std::endl;
_done = true;
+ return;
}
-
+
if (_sessionId.length() == 0)
_sessionId = UUID::getUUID();
+
+ setupIOProcessors();
+
+ std::string datamodelName;
+ if (HAS_ATTR(_scxml, "datamodel")) {
+ datamodelName = ATTR(_scxml, "datamodel");
+ } else if (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);
+ }
+
+ _dataModel.assign("_x.args", _cmdLineOptions);
+
+ _running = true;
+#if VERBOSE
+ std::cout << "running " << this << std::endl;
+#endif
+
+ _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
+
+ // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
+
+ if (_binding == EARLY) {
+ // initialize all data elements
+ NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet();
+ for (unsigned int i = 0; i < dataElems.size(); i++) {
+ // do not process data elements of nested documents from invokers
+ if (!getAncestorElement(dataElems[i], _nsInfo.xmlNSPrefix + "invoke"))
+ if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) {
+ initializeData(Element<std::string>(dataElems[i]));
+ }
+ }
+ } else {
+ // initialize current data elements
+ NodeSet<std::string> topDataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", _scxml));
+ for (unsigned int i = 0; i < topDataElems.size(); i++) {
+ if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE)
+ initializeData(Element<std::string>(topDataElems[i]));
+ }
+ }
+
+ // executeGlobalScriptElements
+ NodeSet<std::string> globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml);
+ for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
+ if (_dataModel) {
+ executeContent(globalScriptElems[i]);
+ }
+ }
+
_isInitialized = true;
+ _stable = false;
}
/**
@@ -641,11 +706,13 @@ void InterpreterImpl::initializeData(const Element<std::string>& data) {
void InterpreterImpl::normalize(Arabica::DOM::Element<std::string>& scxml) {
// TODO: Resolve XML includes
- // make sure every state has an id and set isFirstEntry to true (replaced by _alreadyEntered NodeSet)
- Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "state", _scxml).asNodeSet();
+ // make sure every state has an id
+ Arabica::XPath::NodeSet<std::string> states;
+ states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "state", _scxml).asNodeSet());
+ states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "final", _scxml).asNodeSet());
+ states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "history", _scxml).asNodeSet());
for (int i = 0; i < states.size(); i++) {
Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]);
-// stateElem.setAttribute("isFirstEntry", "true");
if (!stateElem.hasAttribute("id")) {
stateElem.setAttribute("id", UUID::getUUID());
}
@@ -658,45 +725,25 @@ void InterpreterImpl::normalize(Arabica::DOM::Element<std::string>& scxml) {
if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) {
invokeElem.setAttribute("id", UUID::getUUID());
}
-// // make sure every finalize element contained has the invoke id as an attribute
-// Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _xpathPrefix + "finalize", invokeElem).asNodeSet();
-// for (int j = 0; j < finalizes.size(); j++) {
-// Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[j]);
-// finalizeElem.setAttribute("invokeid", invokeElem.getAttribute("id"));
-// }
- }
-
- Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "final", _scxml).asNodeSet();
- for (int i = 0; i < finals.size(); i++) {
- Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]);
-// finalElem.setAttribute("isFirstEntry", "true");
- if (!finalElem.hasAttribute("id")) {
- finalElem.setAttribute("id", UUID::getUUID());
- }
- }
-
- Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "history", _scxml).asNodeSet();
- for (int i = 0; i < histories.size(); i++) {
- Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]);
- if (!historyElem.hasAttribute("id")) {
- historyElem.setAttribute("id", UUID::getUUID());
- }
}
if (!scxml.hasAttribute("id")) {
scxml.setAttribute("id", UUID::getUUID());
}
-
}
void InterpreterImpl::receiveInternal(const Event& event) {
-// std::cout << _name << " receiveInternal: " << event.name << std::endl;
+#if VERBOSE
+ std::cout << _name << " receiveInternal: " << event.name << std::endl;
+#endif
_internalQueue.push_back(event);
// _condVar.notify_all();
}
void InterpreterImpl::receive(const Event& event, bool toFront) {
-// std::cout << _name << " receive: " << event.name << std::endl;
+#if VERBOSE
+ std::cout << _name << " receive: " << event.name << std::endl;
+#endif
if (toFront) {
_externalQueue.push_front(event);
} else {
@@ -1562,11 +1609,16 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont
if (_dataModel) {
if (HAS_ATTR(content, "src")) {
URL scriptUrl(ATTR(content, "src"));
- if (!scriptUrl.toAbsolute(_baseURI)) {
+ if (!scriptUrl.isAbsolute() && !_baseURI) {
LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter";
return;
}
+ if (!scriptUrl.toAbsolute(_baseURI)) {
+ LOG(ERROR) << "Failed to convert relative script URI " << ATTR(content, "src") << " to absolute with base URI " << _baseURI.asString();
+ return;
+ }
+
std::stringstream srcContent;
try {
if (_cachedURLs.find(scriptUrl.asString()) != _cachedURLs.end() && false) {
@@ -2434,7 +2486,7 @@ void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event<
if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes
return;
Node<std::string> target = Arabica::DOM::Node<std::string>(event.getTarget());
- NodeSet<std::string> childs = Interpreter::filterChildElements(_interpreter->_nsInfo.xmlNSPrefix + "state", target);
+ NodeSet<std::string> childs = InterpreterImpl::filterChildElements(_interpreter->_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"));
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 6a11c46..93062e6 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -188,6 +188,16 @@ private:
void init(const std::map<std::string, std::string>& nsInfo);
};
+// values larger than 0 indicate that you ought to step again
+enum InterpreterState {
+ FINISHED = 0, // machine reached a final configuration
+ INIT_FAILED = -1, // could not initialize interpreter
+ INTERRUPTED = -2, // machine was interrupted
+ NOTHING_TODO = 4, // when non-blocking returns nothing to do
+ PROCESSED = 8, // an event was processed
+ INITIALIZED = 16 // initial stable configuration was assumed
+};
+
class USCXML_API InterpreterImpl : public boost::enable_shared_from_this<InterpreterImpl> {
public:
@@ -214,7 +224,8 @@ public:
}
/// This one ought to be pure, but SWIG will generate gibberish if it is
- virtual void interpret() {};
+ virtual void interpret() = 0;
+ virtual InterpreterState step(bool blocking = false) = 0;
void addMonitor(InterpreterMonitor* monitor) {
_monitors.insert(monitor);
@@ -535,6 +546,10 @@ public:
_impl->interpret();
};
+ InterpreterState step(bool blocking = false) {
+ return _impl->step(blocking);
+ };
+
void addMonitor(InterpreterMonitor* monitor) {
return _impl->addMonitor(monitor);
}
@@ -684,6 +699,7 @@ public:
return _impl->isLegalConfiguration(config);
}
+#if 0
static bool isState(const Arabica::DOM::Node<std::string>& state) {
return InterpreterImpl::isState(state);
}
@@ -773,6 +789,7 @@ public:
Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2) {
return _impl->getProperAncestors(s1, s2);
}
+#endif
boost::shared_ptr<InterpreterImpl> getImpl() const {
return _impl;
diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp
index d1a8068..b74b2a9 100644
--- a/src/uscxml/debug/Debugger.cpp
+++ b/src/uscxml/debug/Debugger.cpp
@@ -66,8 +66,8 @@ std::list<Breakpoint> getQualifiedInvokeBreakpoints(Interpreter interpreter, con
std::list<Breakpoint> getQualifiedTransBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, Breakpoint breakpointTemplate) {
std::list<Breakpoint> breakpoints;
- Arabica::DOM::Element<std::string> source(interpreter.getSourceState(transition));
- Arabica::XPath::NodeSet<std::string> targets = interpreter.getTargetStates(transition);
+ Arabica::DOM::Element<std::string> source(interpreter.getImpl()->getSourceState(transition));
+ Arabica::XPath::NodeSet<std::string> targets = interpreter.getImpl()->getTargetStates(transition);
for (int j = 0; j < targets.size(); j++) {
Arabica::DOM::Element<std::string> target(targets[j]);
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
index 2058d72..93f09ab 100644
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -110,7 +110,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele
return;
_knownIds.insert(elemId);
- bool subgraph = Interpreter::isCompound(elem) || Interpreter::isParallel(elem);
+ bool subgraph = InterpreterImpl::isCompound(elem) || InterpreterImpl::isParallel(elem);
if (subgraph) {
_indentation++;
os << getPrefix() << "subgraph \"cluster_" << elemId << "\" {" << std::endl;
@@ -122,11 +122,11 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele
os << "label=<<b>State</b><br />" << nameForNode(elem) << ">,";
// is the state initial?
- if (_interpreter.isInitial(elem))
+ if (_interpreter.getImpl()->isInitial(elem))
os << "style=filled, fillcolor=lightgrey, ";
// is this state final?
- if (_interpreter.isFinal(elem))
+ if (_interpreter.getImpl()->isFinal(elem))
os << "shape=doublecircle,";
// is the current state in the basic configuration?
@@ -176,7 +176,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele
os << "]" << std::endl;
}
}
- if (Interpreter::isState(childElems.item(i))) {
+ if (InterpreterImpl::isState(childElems.item(i))) {
writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
}
if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && iequals(TAGNAME(childElems.item(i)), "initial")) {
@@ -200,7 +200,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele
void SCXMLDotWriter::writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
std::string elemId = idForNode(elem);
- Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getTargetStates(elem);
+ Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(elem);
bool active = (elem == _transition);
@@ -256,7 +256,7 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE)
continue;
- if (Interpreter::isState(childElems.item(i)) ||
+ if (InterpreterImpl::isState(childElems.item(i)) ||
iequals(TAGNAME(childElems.item(i)), "transition") ||
iequals(TAGNAME(childElems.item(i)), "initial") ||
false)
diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp
index f80ad24..8be2634 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.cpp
+++ b/src/uscxml/interpreter/InterpreterDraft6.cpp
@@ -31,152 +31,321 @@ using namespace Arabica::XPath;
using namespace Arabica::DOM;
// see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation
+
void InterpreterDraft6::interpret() {
- try {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- if (!_isInitialized)
- init();
+ InterpreterState state;
+ while(true) {
+ state = step(true);
+
+ switch (state) {
+ case uscxml::INIT_FAILED:
+ case uscxml::FINISHED:
+ case uscxml::INTERRUPTED:
+ // return as we finished
+ return;
+ case uscxml::NOTHING_TODO:
+ // die as this can never happen with a blocking call
+ assert(false);
+ case uscxml::INITIALIZED:
+ case uscxml::PROCESSED:
+
+ // process invokers on main thread
+ if(_thread == NULL) {
+ runOnMainThread(200);
+ }
- if (!_scxml) {
- return;
+ // process next step
+ break;
}
- // dump();
-
- // just make sure we have a session id
- assert(_sessionId.length() > 0);
+ }
+}
- setupIOProcessors();
+// setup / fetch the documents initial transitions
+NodeSet<std::string> InterpreterDraft6::getDocumentInitialTransitions() {
+ NodeSet<std::string> initialTransitions;
+
+ if (_userDefinedStartConfiguration.size() > 0) {
+ // we emulate entering a given configuration by creating a pseudo deep history
+ Element<std::string> initHistory = _document.createElementNS(_nsInfo.nsURL, "history");
+ _nsInfo.setPrefix(initHistory);
+
+ initHistory.setAttribute("id", UUID::getUUID());
+ initHistory.setAttribute("type", "deep");
+ _scxml.insertBefore(initHistory, _scxml.getFirstChild());
+
+ std::string histId = ATTR(initHistory, "id");
+ NodeSet<std::string> histStates;
+ for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) {
+ histStates.push_back(getState(_userDefinedStartConfiguration[i]));
+ }
+ _historyValue[histId] = histStates;
+
+ Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial");
+ _nsInfo.setPrefix(initialElem);
+
+ initialElem.setAttribute("generated", "true");
+ Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition");
+ _nsInfo.setPrefix(transitionElem);
+
+ transitionElem.setAttribute("target", histId);
+ initialElem.appendChild(transitionElem);
+ _scxml.appendChild(initialElem);
+ initialTransitions.push_back(transitionElem);
+
+ } else {
+ // try to get initial transition from initial element
+ initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet();
+ if (initialTransitions.size() == 0) {
+ Arabica::XPath::NodeSet<std::string> initialStates;
+ // fetch per draft
+ initialStates = getInitialStates();
+ assert(initialStates.size() > 0);
+ for (int i = 0; i < initialStates.size(); i++) {
+ Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial");
+ _nsInfo.setPrefix(initialElem);
+
+ initialElem.setAttribute("generated", "true");
+ Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition");
+ _nsInfo.setPrefix(transitionElem);
+
+ transitionElem.setAttribute("target", ATTR(initialStates[i], "id"));
+ initialElem.appendChild(transitionElem);
+ _scxml.appendChild(initialElem);
+ initialTransitions.push_back(transitionElem);
+ }
+ }
+ }
+ return initialTransitions;
+}
+
+// a macrostep
+InterpreterState InterpreterDraft6::step(bool blocking) {
+ try {
- 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;
+ monIter_t monIter;
+ NodeSet<std::string> enabledTransitions;
+
+ // setup document and interpreter
+ if (!_isInitialized)
+ init();
+
+ // if we failed return false
+ if (!_isInitialized)
+ return INIT_FAILED;
+
+ // run initial transitions
+ if (!_stable) {
+ stabilize();
+ // we might only need a single step
+ if (!_running)
+ goto EXIT_INTERPRETER;
+ return INITIALIZED;
+ }
+
+ if (!_running)
+ return FINISHED;
+
+ // read an external event and react
+ if (blocking) {
+ // wait until an event becomes available
+ while(_externalQueue.isEmpty()) {
+ _condVar.wait(_mutex);
}
} else {
- _dataModel = _factory->createDataModel("null", this);
- }
- if(datamodelName.length() > 0 && !_dataModel) {
- LOG(ERROR) << "No datamodel for " << datamodelName << " registered";
+ // return immediately if external queue is empty
+ if (_externalQueue.isEmpty())
+ return NOTHING_TODO;
}
+ _currEvent = _externalQueue.pop();
- if (_dataModel) {
- _dataModel.assign("_x.args", _cmdLineOptions);
+ #if VERBOSE
+ std::cout << "Received externalEvent event " << _currEvent.name << std::endl;
+ if (_running && _currEvent.name == "unblock.and.die") {
+ std::cout << "Still running " << this << std::endl;
+ } else {
+ std::cout << "Aborting " << this << std::endl;
}
+ #endif
+ _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external
- _running = true;
-#if VERBOSE
- std::cout << "running " << this << std::endl;
-#endif
-
- _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
-
- // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
-
- if (_dataModel && _binding == EARLY) {
- // initialize all data elements
- NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet();
- for (unsigned int i = 0; i < dataElems.size(); i++) {
- // do not process data elements of nested documents from invokers
- if (!getAncestorElement(dataElems[i], _nsInfo.xmlNSPrefix + "invoke"))
- if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) {
- initializeData(Element<std::string>(dataElems[i]));
- }
- }
- } else if(_dataModel) {
- // initialize current data elements
- NodeSet<std::string> topDataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", _scxml));
- for (unsigned int i = 0; i < topDataElems.size(); i++) {
- if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE)
- initializeData(Element<std::string>(topDataElems[i]));
+ // when we were blocking on destructor invocation
+ if (!_running) {
+ goto EXIT_INTERPRETER;
+ return INTERRUPTED;
+ }
+ // --- MONITOR: beforeProcessingEvent ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
}
+ USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
+ }
+
+ if (iequals(_currEvent.name, "cancel.invoke." + _sessionId))
+ return INTERRUPTED;
+
+ try {
+ _dataModel.setEvent(_currEvent);
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent;
}
- // executeGlobalScriptElements
- NodeSet<std::string> globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml);
- for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
- if (_dataModel) {
- executeContent(globalScriptElems[i]);
+ for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
+ invokeIter != _invokers.end();
+ invokeIter++) {
+ if (iequals(invokeIter->first, _currEvent.invokeid)) {
+ Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeIter->second.getElement());
+ for (int k = 0; k < finalizes.size(); k++) {
+ Element<std::string> finalizeElem = Element<std::string>(finalizes[k]);
+ executeContent(finalizeElem);
+ }
+ }
+ if (HAS_ATTR(invokeIter->second.getElement(), "autoforward") && DOMUtils::attributeIsTrue(ATTR(invokeIter->second.getElement(), "autoforward"))) {
+ 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"))
+ invokeIter->second.send(_currEvent);
+ } catch(...) {
+ LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first;
+ }
}
}
- NodeSet<std::string> initialTransitions;
-
- if (_userDefinedStartConfiguration.size() > 0) {
- // we emulate entering a given configuration by creating a pseudo deep history
- Element<std::string> initHistory = _document.createElementNS(_nsInfo.nsURL, "history");
- _nsInfo.setPrefix(initHistory);
-
- initHistory.setAttribute("id", UUID::getUUID());
- initHistory.setAttribute("type", "deep");
- _scxml.insertBefore(initHistory, _scxml.getFirstChild());
+
+ // run internal processing until we reach a stable configuration again
+ enabledTransitions = selectTransitions(_currEvent.name);
+ if (!enabledTransitions.empty()) {
+ // test 403b
+ enabledTransitions.to_document_order();
+ microstep(enabledTransitions);
+ }
- std::string histId = ATTR(initHistory, "id");
- NodeSet<std::string> histStates;
- for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) {
- histStates.push_back(getState(_userDefinedStartConfiguration[i]));
+ stabilize();
+ return PROCESSED;
+
+ EXIT_INTERPRETER:
+ if (!_running) {
+ // --- MONITOR: beforeCompletion ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeCompletion(shared_from_this());
+ }
+ USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
}
- _historyValue[histId] = histStates;
-
- Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial");
- _nsInfo.setPrefix(initialElem);
-
- initialElem.setAttribute("generated", "true");
- Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition");
- _nsInfo.setPrefix(transitionElem);
-
- transitionElem.setAttribute("target", histId);
- initialElem.appendChild(transitionElem);
- _scxml.appendChild(initialElem);
- initialTransitions.push_back(transitionElem);
-
- } else {
- // try to get initial transition from initial element
- initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet();
- if (initialTransitions.size() == 0) {
- Arabica::XPath::NodeSet<std::string> initialStates;
- // fetch per draft
- initialStates = getInitialStates();
- assert(initialStates.size() > 0);
- for (int i = 0; i < initialStates.size(); i++) {
- Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial");
- _nsInfo.setPrefix(initialElem);
-
- initialElem.setAttribute("generated", "true");
- Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition");
- _nsInfo.setPrefix(transitionElem);
-
- transitionElem.setAttribute("target", ATTR(initialStates[i], "id"));
- initialElem.appendChild(transitionElem);
- _scxml.appendChild(initialElem);
- initialTransitions.push_back(transitionElem);
+
+ exitInterpreter();
+ if (_sendQueue) {
+ std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
+ while(sendIter != _sendIds.end()) {
+ _sendQueue->cancelEvent(sendIter->first);
+ sendIter++;
+ }
+ }
+
+ // --- MONITOR: afterCompletion ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterCompletion(shared_from_this());
}
+ USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
}
+ return FINISHED;
}
+
+ assert(hasLegalConfiguration());
+ _mutex.unlock();
- assert(initialTransitions.size() > 0);
+ // remove datamodel
+ if(_dataModel)
+ _dataModel = DataModel();
- enterStates(initialTransitions);
- // _mutex.unlock();
-
- // assert(hasLegalConfiguration());
- mainEventLoop();
+ return PROCESSED;
+
} catch (boost::bad_weak_ptr e) {
LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
+ return INTERRUPTED;
}
+
// set datamodel to null from this thread
if(_dataModel)
_dataModel = DataModel();
}
+// process transitions until we are in a stable configuration again
+void InterpreterDraft6::stabilize() {
+
+ monIter_t monIter;
+ NodeSet<std::string> enabledTransitions;
+ _stable = false;
+
+ if (_configuration.size() == 0) {
+ // goto initial configuration
+ NodeSet<std::string> initialTransitions = getDocumentInitialTransitions();
+ assert(initialTransitions.size() > 0);
+ enterStates(initialTransitions);
+ }
+
+ do { // process microsteps for enabled transitions until there are no more left
+
+ enabledTransitions = selectEventlessTransitions();
+
+ if (enabledTransitions.size() == 0) {
+ if (_internalQueue.size() == 0) {
+ _stable = true;
+ } else {
+ _currEvent = _internalQueue.front();
+ _internalQueue.pop_front();
+#if VERBOSE
+ std::cout << "Received internal event " << _currEvent.name << std::endl;
+#endif
+
+ // --- MONITOR: beforeProcessingEvent ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
+ }
+ USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
+ }
+
+ if (_dataModel)
+ _dataModel.setEvent(_currEvent);
+ enabledTransitions = selectTransitions(_currEvent.name);
+ }
+ }
+
+ if (!enabledTransitions.empty()) {
+ // test 403b
+ enabledTransitions.to_document_order();
+ microstep(enabledTransitions);
+ }
+ } while(!_internalQueue.empty() || !_stable);
+
+ monIter = _monitors.begin();
+
+ // --- MONITOR: onStableConfiguration ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->onStableConfiguration(shared_from_this());
+ }
+ USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
+ }
+
+ // when we reach a stable configuration, invoke
+ for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
+ NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) {
+ invoke(invokes[j]);
+ }
+ }
+ }
+ _statesToInvoke = NodeSet<std::string>();
+
+}
+#if 0
void InterpreterDraft6::mainEventLoop() {
monIter_t monIter;
@@ -234,24 +403,15 @@ void InterpreterDraft6::mainEventLoop() {
}
}
}
-
_statesToInvoke = NodeSet<std::string>();
+
if (!_internalQueue.empty())
continue;
// assume that we have a legal configuration as soon as the internal queue is empty
assert(hasLegalConfiguration());
-#if 0
- std::cout << "Configuration: ";
- for (int i = 0; i < _configuration.size(); i++) {
- std::cout << ATTR(_configuration[i], "id") << ", ";
- }
- std::cout << std::endl;
-#endif
-
monIter = _monitors.begin();
-// if (!_sendQueue || _sendQueue->isEmpty()) {
// --- MONITOR: onStableConfiguration ------------------------------
for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
@@ -261,9 +421,8 @@ void InterpreterDraft6::mainEventLoop() {
USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
}
-// }
-
_mutex.unlock();
+
// whenever we have a stable configuration, run the mainThread hooks with 200fps
while(_externalQueue.isEmpty() && _thread == NULL) {
runOnMainThread(200);
@@ -304,46 +463,6 @@ void InterpreterDraft6::mainEventLoop() {
LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent;
}
}
-#if 0
- 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++) {
- Element<std::string> invokeElem = (Element<std::string>)invokes[j];
- std::string invokeId;
- if (HAS_ATTR(invokeElem, "id")) {
- invokeId = ATTR(invokeElem, "id");
- } else {
- if (HAS_ATTR(invokeElem, "idlocation") && _dataModel) {
- try {
- invokeId = _dataModel.evalAsString(ATTR(invokeElem, "idlocation"));
- } catch(Event e) {
- LOG(ERROR) << "Syntax error while assigning idlocation from invoke:" << std::endl << e << std::endl;
- }
- }
- }
- std::string autoForward = invokeElem.getAttribute("autoforward");
- if (iequals(invokeId, _currEvent.invokeid)) {
-
- Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_xmlNSPrefix + "finalize", invokeElem);
- for (int k = 0; k < finalizes.size(); k++) {
- Element<std::string> finalizeElem = Element<std::string>(finalizes[k]);
- executeContent(finalizeElem);
- }
-
- }
- if (iequals(autoForward, "true")) {
- try {
- // do not autoforward to invokers that send to #_parent from the SCXML IO Processor!
- // Yes do so, see test229!
- // if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"))
- _invokers[invokeId].send(_currEvent);
- } catch(...) {
- LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId;
- }
- }
- }
- }
-#else
for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
invokeIter != _invokers.end();
invokeIter++) {
@@ -365,7 +484,6 @@ void InterpreterDraft6::mainEventLoop() {
}
}
}
-#endif
enabledTransitions = selectTransitions(_currEvent.name);
if (!enabledTransitions.empty()) {
// test 403b
@@ -401,7 +519,8 @@ EXIT_INTERPRETER:
}
}
-
+#endif
+
Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectTransitions(const std::string& event) {
Arabica::XPath::NodeSet<std::string> enabledTransitions;
@@ -627,7 +746,7 @@ NEXT_ANCESTOR:
}
void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
-#if 0
+#if VERBOSE
std::cout << "Transitions: ";
for (int i = 0; i < enabledTransitions.size(); i++) {
std::cout << ((Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl;
@@ -685,6 +804,9 @@ void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& en
}
void InterpreterDraft6::exitInterpreter() {
+#if VERBOSE
+ std::cout << "Exiting interpreter " << _name << std::endl;
+#endif
NodeSet<std::string> statesToExit = _configuration;
statesToExit.forward(false);
statesToExit.sort();
@@ -712,7 +834,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
monIter_t monIter;
#if VERBOSE
- std::cout << "Enabled exit transitions: " << std::endl;
+ std::cout << _name << ": Enabled exit transitions: " << std::endl;
for (int i = 0; i < enabledTransitions.size(); i++) {
std::cout << enabledTransitions[i] << std::endl;
}
@@ -741,7 +863,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
tmpStates.push_back(source);
tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
#if VERBOSE
- std::cout << "tmpStates: ";
+ std::cout << _name << ": tmpStates: ";
for (int i = 0; i < tmpStates.size(); i++) {
std::cout << ATTR(tmpStates[i], "id") << ", ";
}
@@ -750,7 +872,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
ancestor = findLCCA(tmpStates);
}
#if VERBOSE
- std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl;;
+ std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl;;
#endif
for (int j = 0; j < _configuration.size(); j++) {
if (isDescendant(_configuration[j], ancestor))
@@ -772,7 +894,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
statesToExit.sort();
#if VERBOSE
- std::cout << "States to exit: ";
+ std::cout << _name << ": States to exit: ";
for (int i = 0; i < statesToExit.size(); i++) {
std::cout << LOCALNAME(statesToExit[i]) << ":" << ATTR(statesToExit[i], "id") << ", ";
}
@@ -795,8 +917,8 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
}
}
_historyValue[historyElem.getAttribute("id")] = historyNodes;
-#if 0
- std::cout << "History node " << ATTR(historyElem, "id") << " contains: ";
+#if VERBOSE
+ std::cout << _name << ": History node " << ATTR(historyElem, "id") << " contains: ";
for (int i = 0; i < historyNodes.size(); i++) {
std::cout << ATTR(historyNodes[i], "id") << ", ";
}
@@ -857,9 +979,9 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
monIter_t monIter;
#if VERBOSE
- std::cout << "Enabled enter transitions: " << std::endl;
+ std::cout << _name << ": Enabled enter transitions: " << std::endl;
for (int i = 0; i < enabledTransitions.size(); i++) {
- std::cout << enabledTransitions[i] << std::endl;
+ std::cout << "\t" << enabledTransitions[i] << std::endl;
}
std::cout << std::endl;
#endif
@@ -871,7 +993,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
NodeSet<std::string> tStates = getTargetStates(transition);
#if VERBOSE
- std::cout << "Target States: ";
+ std::cout << _name << ": Target States: ";
for (int i = 0; i < tStates.size(); i++) {
std::cout << ATTR(tStates[i], "id") << ", ";
}
@@ -881,7 +1003,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
Node<std::string> ancestor;
Node<std::string> source = getSourceState(transition);
#if VERBOSE
- std::cout << "Source States: " << ATTR(source, "id") << std::endl;
+ std::cout << _name << ": Source States: " << ATTR(source, "id") << std::endl;
#endif
assert(source);
@@ -905,7 +1027,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
}
#if VERBOSE
- std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl;
+ std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl;
#endif
for (int j = 0; j < tStates.size(); j++) {
@@ -913,7 +1035,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
}
#if VERBOSE
- std::cout << "States to enter: ";
+ std::cout << _name << ": States to enter: ";
for (int i = 0; i < statesToEnter.size(); i++) {
std::cout << LOCALNAME(statesToEnter[i]) << ":" << ATTR(statesToEnter[i], "id") << ", ";
}
@@ -924,7 +1046,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor);
#if VERBOSE
- std::cout << "Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": ";
+ std::cout << _name << ": Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": ";
for (int i = 0; i < ancestors.size(); i++) {
std::cout << ATTR(ancestors[i], "id") << ", ";
}
@@ -955,7 +1077,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
statesToEnter.to_document_order();
#if VERBOSE
- std::cout << "States to enter: ";
+ std::cout << _name << ": States to enter: ";
for (int i = 0; i < statesToEnter.size(); i++) {
std::cout << ATTR(statesToEnter[i], "id") << ", ";
}
diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h
index 7550124..a958b47 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.h
+++ b/src/uscxml/interpreter/InterpreterDraft6.h
@@ -27,7 +27,8 @@ namespace uscxml {
class InterpreterDraft6 : public InterpreterImpl {
protected:
void interpret();
- void mainEventLoop();
+ InterpreterState step(bool blocking);
+ void stabilize();
void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
@@ -44,6 +45,8 @@ protected:
bool isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2);
bool isEnabledTransition(const Arabica::DOM::Node<std::string>& transition, const std::string& event);
+ Arabica::XPath::NodeSet<std::string> getDocumentInitialTransitions();
+
bool isCrossingBounds(const Arabica::DOM::Node<std::string>& transition);
bool isWithinParallel(const Arabica::DOM::Node<std::string>& transition);
Arabica::DOM::Node<std::string> findLCPA(const Arabica::XPath::NodeSet<std::string>& states);
diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
index 3130d42..a064394 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
@@ -230,7 +230,7 @@ void JSCDataModel::setEvent(const Event& event) {
handleException(exception);
} else {
JSStringRef propName = JSStringCreateWithUTF8CString("data");
- JSStringRef contentStr = JSStringCreateWithUTF8CString(Interpreter::spaceNormalize(event.content).c_str());
+ JSStringRef contentStr = JSStringCreateWithUTF8CString(InterpreterImpl::spaceNormalize(event.content).c_str());
JSObjectSetProperty(_ctx, eventObj, propName, JSValueMakeString(_ctx, contentStr), 0, &exception);
JSStringRelease(propName);
JSStringRelease(contentStr);
@@ -566,7 +566,7 @@ void JSCDataModel::assign(const Element<std::string>& assignElem,
try {
evalAsValue(key + " = " + content);
} catch (...) {
- evalAsValue(key + " = " + "\"" + Interpreter::spaceNormalize(content) + "\"");
+ evalAsValue(key + " = " + "\"" + InterpreterImpl::spaceNormalize(content) + "\"");
}
} else {
JSObjectSetProperty(_ctx, JSContextGetGlobalObject(_ctx), JSStringCreateWithUTF8CString(key.c_str()), JSValueMakeUndefined(_ctx), 0, &exception);
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index bddea83..ec9557e 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -236,7 +236,7 @@ void V8DataModel::setEvent(const Event& event) {
if (json) {
eventObj->Set(v8::String::New("data"), getDataAsValue(json));
} else {
- eventObj->Set(v8::String::New("data"), v8::String::New(Interpreter::spaceNormalize(event.content).c_str()));
+ eventObj->Set(v8::String::New("data"), v8::String::New(InterpreterImpl::spaceNormalize(event.content).c_str()));
}
} else {
// _event.data is KVP
@@ -603,7 +603,7 @@ void V8DataModel::assign(const Element<std::string>& assignElem,
try {
evalAsValue(key + " = " + content);
} catch (...) {
- evalAsValue(key + " = " + "\"" + Interpreter::spaceNormalize(content) + "\"");
+ evalAsValue(key + " = " + "\"" + InterpreterImpl::spaceNormalize(content) + "\"");
}
} else {
global->Set(v8::String::New(key.c_str()), v8::Undefined());
diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
index 0ad6030..4cbe8f5 100644
--- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
@@ -275,7 +275,7 @@ void SWIDataModel::setEvent(const Event& event) {
dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), assert(event(data(DATA)))";
PlCall(dataInitStr.str().c_str());
} else if (event.content.size() > 0) {
- PlCall("assert", PlCompound("event", PlCompound("data", PlString(Interpreter::spaceNormalize(event.content).c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("data", PlString(InterpreterImpl::spaceNormalize(event.content).c_str()))));
} else if (event.data) {
assertFromData(event.data, "event(data(", 2);
}
diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp
index bf32bf9..4d9854b 100644
--- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp
@@ -195,7 +195,7 @@ void XPathDataModel::setEvent(const Event& event) {
}
if (event.content.size() > 0) {
- Text<std::string> textNode = _doc.createTextNode(Interpreter::spaceNormalize(event.content).c_str());
+ Text<std::string> textNode = _doc.createTextNode(InterpreterImpl::spaceNormalize(event.content).c_str());
eventDataElem.appendChild(textNode);
}
if (event.dom) {
@@ -501,7 +501,7 @@ void XPathDataModel::assign(const Element<std::string>& assignElem,
}
assign(key, nodeSet, assignElem);
} else if (content.length() > 0) {
- Text<std::string> textNode = _doc.createTextNode(Interpreter::spaceNormalize(content));
+ Text<std::string> textNode = _doc.createTextNode(InterpreterImpl::spaceNormalize(content));
nodeSet.push_back(textNode);
assign(key, nodeSet, assignElem);
} else if (HAS_ATTR(assignElem, "expr")) {
diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp
index f415b19..4fe0d2e 100644
--- a/src/uscxml/plugins/element/respond/RespondElement.cpp
+++ b/src/uscxml/plugins/element/respond/RespondElement.cpp
@@ -78,7 +78,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
httpReply.status = strTo<int>(statusStr);;
// extract the content
- Arabica::XPath::NodeSet<std::string> contents = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node);
+ Arabica::XPath::NodeSet<std::string> contents = InterpreterImpl::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node);
if (contents.size() > 0) {
if (HAS_ATTR(contents[0], "expr")) { // -- content is evaluated string from datamodel ------
if (_interpreter->getDataModel()) {
@@ -141,7 +141,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
}
// process headers
- Arabica::XPath::NodeSet<std::string> headers = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "header", node);
+ Arabica::XPath::NodeSet<std::string> headers = InterpreterImpl::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "header", node);
for (int i = 0; i < headers.size(); i++) {
std::string name;
if (HAS_ATTR(headers[i], "name")) {
diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
index d89d8ac..f232e52 100644
--- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
@@ -43,7 +43,8 @@ USCXMLInvoker::~USCXMLInvoker() {
_cancelled = true;
Event event;
event.name = "unblock.and.die";
- _invokedInterpreter.receive(event);
+ if (_invokedInterpreter)
+ _invokedInterpreter.receive(event);
};
boost::shared_ptr<InvokerImpl> USCXMLInvoker::create(InterpreterImpl* interpreter) {
@@ -84,6 +85,7 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) {
if (_invokedInterpreter) {
DataModel dataModel(_invokedInterpreter.getImpl()->getDataModel());
_invokedInterpreter.getImpl()->setParentQueue(&_parentQueue);
+
// transfer namespace prefixes
_invokedInterpreter.setNameSpaceInfo(_parentInterpreter->getNameSpaceInfo());
_invokedInterpreter.getImpl()->_sessionId = req.invokeid;
@@ -92,7 +94,6 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) {
_invokedInterpreter.getImpl()->setInvokeRequest(req);
_invokedInterpreter.start();
-// tthread::this_thread::sleep_for(tthread::chrono::seconds(1));
} else {
/// test 530
_parentInterpreter->receive(Event("done.invoke." + _invokeId, Event::PLATFORM));
diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp
index 8b1725c..7f38397 100644
--- a/src/uscxml/transform/ChartToFSM.cpp
+++ b/src/uscxml/transform/ChartToFSM.cpp
@@ -902,7 +902,7 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeState
std::ostringstream idSS;
idSS << "active-";
for (int i = 0; i < activeStates.size(); i++) {
- if (!Interpreter::isFinal(activeStates[i]))
+ if (!InterpreterImpl::isFinal(activeStates[i]))
isFinal = false;
idSS << ATTR(activeStates[i], "id") << "-";
}
@@ -1043,7 +1043,7 @@ std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::stri
for (int i = 0; i < transitions.size(); i++) {
// for every transition
- std::list<std::string> eventNames = Interpreter::tokenizeIdRefs(ATTR(transitions[i], "event"));
+ std::list<std::string> eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(transitions[i], "event"));
for (std::list<std::string>::iterator eventNameIter = eventNames.begin();
eventNameIter != eventNames.end();
@@ -1062,7 +1062,7 @@ std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::stri
// check if token would activate all other transitions
if (i == j)
continue;
- if (!Interpreter::nameMatch(ATTR(transitions[j], "event"), eventName)) {
+ if (!InterpreterImpl::nameMatch(ATTR(transitions[j], "event"), eventName)) {
isMatching = false;
break;
}
@@ -1080,7 +1080,7 @@ std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::stri
for (std::list<std::string>::iterator innerEventNameIter = prefixes.begin();
innerEventNameIter != prefixes.end();
innerEventNameIter++) {
- if (!iequals(*outerEventNameIter, *innerEventNameIter) && Interpreter::nameMatch(*outerEventNameIter, *innerEventNameIter)) {
+ if (!iequals(*outerEventNameIter, *innerEventNameIter) && InterpreterImpl::nameMatch(*outerEventNameIter, *innerEventNameIter)) {
goto IS_PREFIX;
}
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 18dfc03..49169fc 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -62,6 +62,11 @@ target_link_libraries(test-arabica-namespaces uscxml)
add_test(test-arabica-namespaces ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-arabica-namespaces ${CMAKE_SOURCE_DIR}/test)
set_target_properties(test-arabica-namespaces PROPERTIES FOLDER "Tests")
+add_executable(test-lifecycle src/test-lifecycle.cpp)
+target_link_libraries(test-lifecycle uscxml)
+add_test(test-lifecycle ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-arabica-namespaces)
+set_target_properties(test-lifecycle PROPERTIES FOLDER "Tests")
+
if (NOT WIN32)
add_executable(test-arabica-events src/test-arabica-events.cpp)
target_link_libraries(test-arabica-events uscxml)
diff --git a/test/src/test-arabica-namespaces.cpp b/test/src/test-arabica-namespaces.cpp
index ae529c9..aa7a5b4 100644
--- a/test/src/test-arabica-namespaces.cpp
+++ b/test/src/test-arabica-namespaces.cpp
@@ -97,7 +97,7 @@ static void validateRootFoo(std::pair<Document<std::string>, NameSpaceInfo>& par
assert(TAGNAME(root) == nsInfo.xmlNSPrefix + "root");
assert(LOCALNAME(root) == "root");
- NodeSet<std::string> foosFiltered = Interpreter::filterChildElements(nsInfo.xmlNSPrefix + "foo", root);
+ NodeSet<std::string> foosFiltered = InterpreterImpl::filterChildElements(nsInfo.xmlNSPrefix + "foo", root);
assert(foosFiltered.size() == 3);
NodeSet<std::string> foosXPath = _xpath.evaluate("//" + nsInfo.xpathPrefix + "foo", root).asNodeSet();
assert(foosXPath.size() == 3);
@@ -119,7 +119,7 @@ static void validateRootFooBar(std::pair<Document<std::string>, NameSpaceInfo>&
Node<std::string> root = document.getDocumentElement();
_xpath.setNamespaceContext(*nsInfo.getNSContext());
- NodeSet<std::string> barsFiltered = Interpreter::filterChildElements(nsInfo.xmlNSPrefix + "bar", root);
+ NodeSet<std::string> barsFiltered = InterpreterImpl::filterChildElements(nsInfo.xmlNSPrefix + "bar", root);
assert(barsFiltered.size() == 3);
NodeSet<std::string> barsXPath = _xpath.evaluate("//" + nsInfo.xpathPrefix + "bar", root).asNodeSet();
assert(barsXPath.size() == 3);
@@ -144,7 +144,7 @@ static void validateRootFooBarBaz(std::pair<Document<std::string>, NameSpaceInfo
assert(TAGNAME(root) == nsInfo.xmlNSPrefix + "root");
assert(LOCALNAME(root) == "root");
- NodeSet<std::string> bazsFiltered = Interpreter::filterChildElements(nsInfo.xmlNSPrefix + "baz", root);
+ NodeSet<std::string> bazsFiltered = InterpreterImpl::filterChildElements(nsInfo.xmlNSPrefix + "baz", root);
assert(bazsFiltered.size() == 3);
NodeSet<std::string> bazsXPath = _xpath.evaluate("//" + nsInfo.xpathPrefix + "baz", root).asNodeSet();
assert(bazsXPath.size() == 3);
diff --git a/test/src/test-lifecycle.cpp b/test/src/test-lifecycle.cpp
new file mode 100644
index 0000000..682e796
--- /dev/null
+++ b/test/src/test-lifecycle.cpp
@@ -0,0 +1,129 @@
+#include "uscxml/config.h"
+#include "uscxml/Interpreter.h"
+#include <glog/logging.h>
+
+#include "uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h"
+#include <boost/algorithm/string.hpp>
+
+#ifdef HAS_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAS_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#ifdef HAS_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifdef _WIN32
+#include "XGetopt.h"
+#endif
+
+int startedAt;
+int lastTransitionAt;
+
+#ifdef HAS_EXECINFO_H
+void printBacktrace(void** array, int size) {
+ char** messages = backtrace_symbols(array, size);
+ for (int i = 0; i < size && messages != NULL; ++i) {
+ std::cerr << "\t" << messages[i] << std::endl;
+ }
+ std::cerr << std::endl;
+ free(messages);
+}
+
+#ifdef HAS_DLFCN_H
+// see https://gist.github.com/nkuln/2020860
+typedef void (*cxa_throw_type)(void *, void *, void (*) (void *));
+cxa_throw_type orig_cxa_throw = 0;
+
+void load_orig_throw_code() {
+ orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");
+}
+
+extern "C"
+void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) {
+ std::cerr << __FUNCTION__ << " will throw exception from " << std::endl;
+ if (orig_cxa_throw == 0)
+ load_orig_throw_code();
+
+ void *array[50];
+ size_t size = backtrace(array, 50);
+ printBacktrace(array, size);
+ orig_cxa_throw(thrown_exception, pvtinfo, dest);
+}
+#endif
+#endif
+
+
+// see http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c
+void customTerminate() {
+ static bool tried_throw = false;
+ try {
+ // try once to re-throw currently active exception
+ if (!tried_throw) {
+ throw;
+ tried_throw = true;
+ } else {
+ tried_throw = false;
+ };
+ } catch (const std::exception &e) {
+ std::cerr << __FUNCTION__ << " caught unhandled exception. what(): "
+ << e.what() << std::endl;
+ } catch (const uscxml::Event &e) {
+ std::cerr << __FUNCTION__ << " caught unhandled exception. Event: "
+ << e << std::endl;
+ } catch (...) {
+ std::cerr << __FUNCTION__ << " caught unknown/unhandled exception."
+ << std::endl;
+ }
+
+#ifdef HAS_EXECINFO_H
+ void * array[50];
+ int size = backtrace(array, 50);
+
+ printBacktrace(array, size);
+#endif
+ abort();
+}
+int main(int argc, char** argv) {
+ using namespace uscxml;
+
+ std::set_terminate(customTerminate);
+
+#if defined(HAS_SIGNAL_H) && !defined(WIN32)
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ google::InitGoogleLogging(argv[0]);
+ google::LogToStderr();
+
+ Interpreter interpreter = Interpreter::fromURI("/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/ecma/test530.scxml");
+ InterpreterState state;
+ do {
+ state = interpreter.step(true);
+ switch (state) {
+ case uscxml::FINISHED:
+ std::cout << "FINISHED" << std::endl;
+ break;
+ case uscxml::INIT_FAILED:
+ std::cout << "INIT_FAILED" << std::endl;
+ break;
+ case uscxml::NOTHING_TODO:
+ std::cout << "NOTHING_TODO" << std::endl;
+ break;
+ case uscxml::INTERRUPTED:
+ std::cout << "INTERRUPTED" << std::endl;
+ break;
+ case uscxml::PROCESSED:
+ std::cout << "PROCESSED" << std::endl;
+ break;
+ default:
+ break;
+ }
+ } while(state != FINISHED);
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/test/src/test-predicates.cpp b/test/src/test-predicates.cpp
index ed155b4..00be408 100644
--- a/test/src/test-predicates.cpp
+++ b/test/src/test-predicates.cpp
@@ -16,24 +16,24 @@ int main(int argc, char** argv) {
assert(interpreter);
Node<std::string> atomicState = interpreter.getState("atomic");
- assert(Interpreter::isAtomic(atomicState));
- assert(!Interpreter::isParallel(atomicState));
- assert(!Interpreter::isCompound(atomicState));
+ assert(InterpreterImpl::isAtomic(atomicState));
+ assert(!InterpreterImpl::isParallel(atomicState));
+ assert(!InterpreterImpl::isCompound(atomicState));
Node<std::string> compoundState = interpreter.getState("compound");
- assert(!Interpreter::isAtomic(compoundState));
- assert(!Interpreter::isParallel(compoundState));
- assert(Interpreter::isCompound(compoundState));
+ assert(!InterpreterImpl::isAtomic(compoundState));
+ assert(!InterpreterImpl::isParallel(compoundState));
+ assert(InterpreterImpl::isCompound(compoundState));
Node<std::string> parallelState = interpreter.getState("parallel");
- assert(!Interpreter::isAtomic(parallelState));
- assert(Interpreter::isParallel(parallelState));
- assert(!Interpreter::isCompound(parallelState)); // parallel states are not compound!
+ assert(!InterpreterImpl::isAtomic(parallelState));
+ assert(InterpreterImpl::isParallel(parallelState));
+ assert(!InterpreterImpl::isCompound(parallelState)); // parallel states are not compound!
- NodeSet<std::string> initialState = interpreter.getInitialStates();
+ NodeSet<std::string> initialState = interpreter.getImpl()->getInitialStates();
assert(initialState[0] == atomicState);
- NodeSet<std::string> childs = interpreter.getChildStates(compoundState);
+ NodeSet<std::string> childs = interpreter.getImpl()->getChildStates(compoundState);
Node<std::string> compoundChild1 = interpreter.getState("compoundChild1");
Node<std::string> compoundChild2 = interpreter.getState("compoundChild2");
assert(childs.size() > 0);
@@ -41,39 +41,39 @@ int main(int argc, char** argv) {
assert(Interpreter::isMember(compoundChild2, childs));
assert(!Interpreter::isMember(compoundState, childs));
- assert(Interpreter::isDescendant(compoundChild1, compoundState));
+ assert(InterpreterImpl::isDescendant(compoundChild1, compoundState));
{
std::string idrefs("id1");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 1);
assert(tokenizedIdrefs.front().compare("id1") == 0);
}
{
std::string idrefs(" id1");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 1);
assert(tokenizedIdrefs.front().compare("id1") == 0);
}
{
std::string idrefs(" id1 ");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 1);
assert(tokenizedIdrefs.front().compare("id1") == 0);
}
{
std::string idrefs(" \tid1\n ");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 1);
assert(tokenizedIdrefs.front().compare("id1") == 0);
}
{
std::string idrefs("id1 id2 id3");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 3);
assert(tokenizedIdrefs.front().compare("id1") == 0);
tokenizedIdrefs.pop_front();
@@ -84,7 +84,7 @@ int main(int argc, char** argv) {
{
std::string idrefs("\t id1 \nid2\n\n id3\t");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 3);
assert(tokenizedIdrefs.front().compare("id1") == 0);
tokenizedIdrefs.pop_front();
@@ -95,7 +95,7 @@ int main(int argc, char** argv) {
{
std::string idrefs("id1 \nid2 \tid3");
- std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs);
+ std::list<std::string> tokenizedIdrefs = InterpreterImpl::tokenizeIdRefs(idrefs);
assert(tokenizedIdrefs.size() == 3);
assert(tokenizedIdrefs.front().compare("id1") == 0);
tokenizedIdrefs.pop_front();