summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-07-15 10:17:15 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-07-15 10:17:15 (GMT)
commit61439d49e15045bbe9c3cf55b62fc15909dd48e2 (patch)
tree6bfacf394b186226e0ba5308d8fcd735203e52a4
parentdbd110e2b7eb08c65218a5f9d09ef12fdc62c04a (diff)
downloaduscxml-61439d49e15045bbe9c3cf55b62fc15909dd48e2.zip
uscxml-61439d49e15045bbe9c3cf55b62fc15909dd48e2.tar.gz
uscxml-61439d49e15045bbe9c3cf55b62fc15909dd48e2.tar.bz2
Improved support for dot output
-rw-r--r--CMakeLists.txt17
-rw-r--r--CTestConfig.cmake2
-rw-r--r--apps/uscxml-browser.cpp8
-rw-r--r--apps/uscxml-dot.cpp107
-rw-r--r--src/bindings/swig/uscxml_ignores.i1
-rw-r--r--src/uscxml/Interpreter.cpp30
-rw-r--r--src/uscxml/Interpreter.h5
-rw-r--r--src/uscxml/URL.cpp6
-rw-r--r--src/uscxml/URL.h5
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp472
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.h48
-rw-r--r--src/uscxml/messages/Data.h2
-rw-r--r--src/uscxml/messages/Event.h22
-rw-r--r--src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp333
-rw-r--r--src/uscxml/plugins/datamodel/lua/LuaDataModel.h1
-rw-r--r--src/uscxml/plugins/datamodel/null/NULLDataModel.cpp3
-rw-r--r--src/uscxml/plugins/datamodel/null/NULLDataModel.h1
-rw-r--r--test/CMakeLists.txt6
-rw-r--r--test/src/test-cmdline-parsing.cpp24
-rw-r--r--test/src/test-predicates.cpp6
-rw-r--r--test/w3c/lua/test152.scxml2
21 files changed, 896 insertions, 205 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f016f98..cfe179c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -164,7 +164,7 @@ else ()
endif()
endif()
-SET(USCXML_LIBRARY_HOST_URL_PREFIX "http://uscxml.tk.informatik.tu-darmstadt.de/prebuilt" CACHE STRING "The root path of an URL where to look for prebuilt libraries.")
+SET(USCXML_LIBRARY_HOST_URL_PREFIX "http://uscxml.mintwerk.de/prebuilt" CACHE STRING "The root path of an URL where to look for prebuilt libraries.")
if (CMAKE_CROSSCOMPILING)
if (IOS)
@@ -306,6 +306,7 @@ else()
OPTION(BUILD_TESTS "Build USCXML tests" ON)
OPTION(BUILD_TESTS_W3C_ECMA "Create W3C ECMAScript tests" ON)
OPTION(BUILD_TESTS_W3C_XPATH "Create W3C XPath tests" ON)
+ OPTION(BUILD_TESTS_W3C_LUA "Create W3C Lua tests" ON)
OPTION(BUILD_TESTS_FSM_ECMA "Create FSM converted W3C ECMAScript tests" OFF)
OPTION(BUILD_TESTS_FSM_XPATH "Create FSM converted W3C XPath tests" OFF)
endif()
@@ -1041,6 +1042,20 @@ if (NOT CMAKE_CROSSCOMPILING)
set_target_properties(uscxml-transform PROPERTIES FOLDER "Apps")
install_executable(TARGETS uscxml-transform COMPONENT tools)
+ if (WIN32)
+ add_executable(uscxml-dot apps/uscxml-dot.cpp ${PROJECT_SOURCE_DIR}/contrib/src/getopt/getopt.c)
+ else()
+ add_executable(uscxml-dot apps/uscxml-dot.cpp)
+ endif()
+ target_link_libraries(uscxml-dot uscxml)
+ if (NOT CMAKE_CROSSCOMPILING)
+ if (ENABLE_COTIRE)
+ set_target_properties(uscxml-dot PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
+ endif()
+ endif()
+ set_target_properties(uscxml-dot PROPERTIES FOLDER "Apps")
+ install_executable(TARGETS uscxml-dot COMPONENT tools)
+
if (PROTOBUF_FOUND AND OFF)
file(GLOB W3C-MMI-COMMON ${PROJECT_SOURCE_DIR}/apps/w3c-mmi/*.cpp ${PROJECT_SOURCE_DIR}/apps/w3c-mmi/*.h)
diff --git a/CTestConfig.cmake b/CTestConfig.cmake
index 7345182..89043b5 100644
--- a/CTestConfig.cmake
+++ b/CTestConfig.cmake
@@ -9,6 +9,6 @@ set(CTEST_PROJECT_NAME "uscxml")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_DROP_METHOD "http")
-set(CTEST_DROP_SITE "umundo.tk.informatik.tu-darmstadt.de")
+set(CTEST_DROP_SITE "umundo.mintwerk.de")
set(CTEST_DROP_LOCATION "/cdash/submit.php?project=uscxml")
set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/apps/uscxml-browser.cpp b/apps/uscxml-browser.cpp
index 50b3202..e431fdf 100644
--- a/apps/uscxml-browser.cpp
+++ b/apps/uscxml-browser.cpp
@@ -167,11 +167,10 @@ int main(int argc, char** argv) {
// instantiate and configure interpreters
std::list<Interpreter> interpreters;
- std::map<std::string, InterpreterOptions*>::iterator confIter = options.interpreters.begin();
- while(confIter != options.interpreters.end()) {
+ for(int i = 0; i < options.interpreters.size(); i++) {
- InterpreterOptions* currOptions = confIter->second;
- std::string documentURL = confIter->first;
+ InterpreterOptions* currOptions = options.interpreters[0].second;
+ std::string documentURL = options.interpreters[0].first;
LOG(INFO) << "Processing " << documentURL;
Interpreter interpreter = Interpreter::fromURI(documentURL);
@@ -192,7 +191,6 @@ int main(int argc, char** argv) {
} else {
LOG(ERROR) << "Cannot create interpreter from " << documentURL;
}
- confIter++;
}
// start interpreters
diff --git a/apps/uscxml-dot.cpp b/apps/uscxml-dot.cpp
new file mode 100644
index 0000000..3324e54
--- /dev/null
+++ b/apps/uscxml-dot.cpp
@@ -0,0 +1,107 @@
+#include "uscxml/config.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/DOMUtils.h"
+#include "uscxml/debug/SCXMLDotWriter.h"
+#include <glog/logging.h>
+
+#include "uscxml/Factory.h"
+#include <boost/algorithm/string.hpp>
+
+using namespace uscxml;
+
+void printUsageAndExit(const char* progName) {
+ // remove path from program name
+ std::string progStr(progName);
+ if (progStr.find_last_of(PATH_SEPERATOR) != std::string::npos) {
+ progStr = progStr.substr(progStr.find_last_of(PATH_SEPERATOR) + 1, progStr.length() - (progStr.find_last_of(PATH_SEPERATOR) + 1));
+ }
+
+ printf("%s version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n", progStr.c_str());
+ printf("Usage\n");
+ printf("\t%s", progStr.c_str());
+ printf(" [-dN_0] URL");
+ printf(" [[-dN_1] state_id1] .. [[-dN_M] state_idM]");
+ printf("\n");
+ printf("Options\n");
+ printf("\tURL : URL of SCXML document\n");
+ printf("\t-d : depth below anchor node (INF per default)\n");
+ printf("\tstate_id : anchor node state id (topmost scxml element per default)\n");
+ printf("\n");
+ exit(1);
+}
+
+int currOpt = 1;
+
+int consumeDepthOption(int argc, char** argv) {
+ std::string test = argv[currOpt];
+ if (boost::starts_with(test, "-")) {
+ int value = 0;
+ if (test.size() > 2) {
+ // no space before value
+ value = strTo<int>(test.substr(2, test.size() - 2));
+ } else {
+ // space before value
+ if (argc > currOpt) {
+ std::string tmp = argv[++currOpt];
+ value = strTo<int>(tmp);
+ } else {
+ printUsageAndExit(argv[0]);
+ }
+ }
+ currOpt++;
+ return value;
+ }
+
+ return -1;
+}
+
+int main(int argc, char** argv) {
+
+ // setup logging
+ google::LogToStderr();
+ google::InitGoogleLogging(argv[0]);
+
+ std::list<SCXMLDotWriter::StateAnchor> stateAnchors;
+
+ if (argc < 2)
+ printUsageAndExit(argv[0]);
+
+ try {
+ // see if there is an initial depth given for root
+ int depth = consumeDepthOption(argc, argv);
+ if (depth >= 0) {
+ SCXMLDotWriter::StateAnchor anchor;
+ anchor.depth = depth;
+ stateAnchors.push_back(anchor);
+ }
+
+ // current option has to be the interpreter's name
+ URL inputFile(argv[currOpt++]);
+ Interpreter interpreter = Interpreter::fromURI(inputFile);
+
+ for (; currOpt < argc; currOpt++) {
+ SCXMLDotWriter::StateAnchor anchor;
+ depth = consumeDepthOption(argc, argv);
+
+ if (depth >= 0) {
+ anchor.depth = depth;
+ }
+
+ if (argc > currOpt) {
+ std::string expr(argv[currOpt++]);
+ anchor.element = interpreter.getImpl()->getState(expr);
+ } else {
+ printUsageAndExit(argv[0]);
+ }
+
+ stateAnchors.push_back(anchor);
+ }
+
+ SCXMLDotWriter::toDot("machine.dot", interpreter, stateAnchors);
+
+ } catch(Event e) {
+ std::cerr << e << std::cout;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/bindings/swig/uscxml_ignores.i b/src/bindings/swig/uscxml_ignores.i
index 9a0dbe4..24a6ffa 100644
--- a/src/bindings/swig/uscxml_ignores.i
+++ b/src/bindings/swig/uscxml_ignores.i
@@ -38,6 +38,7 @@
%ignore uscxml::Interpreter::Interpreter(const boost::shared_ptr<InterpreterImpl>);
%ignore uscxml::Interpreter::Interpreter(const Interpreter&);
%ignore uscxml::Interpreter::getDelayQueue();
+%ignore uscxml::Interpreter::fromURI(const URI&);
%ignore uscxml::Interpreter::fromDOM;
%ignore uscxml::Interpreter::fromClone;
%ignore uscxml::Interpreter::start();
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index d010a8a..8a9ba63 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -210,8 +210,9 @@ InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
goto DONE_PARSING_CMD;
std::string url = argv[optind];
- options.interpreters[url] = new InterpreterOptions();
- currOptions = options.interpreters[url];
+
+ options.interpreters.push_back(std::make_pair(url, new InterpreterOptions()));
+ currOptions = options.interpreters.back().second;
argc -= optind;
argv += optind;
@@ -369,9 +370,9 @@ Interpreter Interpreter::fromDOM(const Arabica::DOM::Document<std::string>& dom,
tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex);
boost::shared_ptr<INTERPRETER_IMPL> interpreterImpl = boost::shared_ptr<INTERPRETER_IMPL>(new INTERPRETER_IMPL);
Interpreter interpreter(interpreterImpl);
- interpreterImpl->_document = dom;
interpreterImpl->setNameSpaceInfo(nameSpaceInfo);
interpreterImpl->_document = dom;
+ interpreterImpl->setupDOM();
// interpreterImpl->init();
_instances[interpreterImpl->getSessionId()] = interpreterImpl;
@@ -389,7 +390,12 @@ Interpreter Interpreter::fromXML(const std::string& xml) {
}
Interpreter Interpreter::fromURI(const std::string& uri) {
- URL absUrl(uri);
+ URL url(uri);
+ return fromURI(url);
+}
+
+Interpreter Interpreter::fromURI(const URL& uri) {
+ URL absUrl = uri;
if (!absUrl.isAbsolute()) {
if (!absUrl.toAbsoluteCwd()) {
ERROR_COMMUNICATION_THROW("URL is not absolute or does not have file schema");
@@ -450,6 +456,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->setupDOM();
} else {
if (parser.errorsReported()) {
ERROR_PLATFORM_THROW(parser.errors())
@@ -483,7 +490,7 @@ void InterpreterImpl::copyTo(InterpreterImpl* other) {
if (parser.parse(inputSource) && parser.getDocument() && parser.getDocument().hasChildNodes()) {
other->setNameSpaceInfo(parser.nameSpace);
other->_document = parser.getDocument();
- other->init();
+ other->setupDOM();
} else {
if (parser.errorsReported()) {
LOG(ERROR) << parser.errors();
@@ -505,7 +512,7 @@ void InterpreterImpl::copyTo(InterpreterImpl* other) {
other->_document = clonedDocument;
other->setNameSpaceInfo(_nsInfo);
- other->init();
+ other->setupDOM();
#endif
}
}
@@ -688,7 +695,7 @@ void InterpreterImpl::reset() {
setInterpreterState(USCXML_INSTANTIATED);
}
-void InterpreterImpl::setupAndNormalizeDOM() {
+void InterpreterImpl::setupDOM() {
if (_domIsSetup)
return;
@@ -748,6 +755,7 @@ void InterpreterImpl::setupAndNormalizeDOM() {
eventTarget.addEventListener("DOMNodeRemoved", _domEventListener, true);
eventTarget.addEventListener("DOMSubtreeModified", _domEventListener, true);
+ _domIsSetup = true;
}
void InterpreterImpl::init() {
@@ -756,7 +764,7 @@ void InterpreterImpl::init() {
_factory = Factory::getInstance();
// setup and normalize DOM
- setupAndNormalizeDOM();
+ setupDOM();
// get our name or generate as UUID
if (_name.length() == 0)
@@ -2326,7 +2334,11 @@ bool InterpreterImpl::isInitial(const Arabica::DOM::Element<std::string>& state)
if (!isState(state))
return false;
- Arabica::DOM::Element<std::string> parent = (Element<std::string>)state.getParentNode();
+ Arabica::DOM::Node<std::string> parentNode = state.getParentNode();
+ if (parentNode.getNodeType() != Node_base::ELEMENT_NODE)
+ return false;
+
+ Arabica::DOM::Element<std::string> parent = (Element<std::string>)parentNode;
if (!isState(parent))
return true; // scxml element
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 1bdae5c..4659b13 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -132,7 +132,7 @@ public:
std::string certificate;
std::string privateKey;
std::string publicKey;
- std::map<std::string, InterpreterOptions*> interpreters;
+ std::vector<std::pair<std::string, InterpreterOptions*> > interpreters;
std::map<std::string, std::string> additionalParameters;
std::string error;
@@ -423,7 +423,7 @@ protected:
InterpreterImpl();
void init();
- void setupAndNormalizeDOM();
+ void setupDOM();
virtual void setupIOProcessors();
void initializeData(const Arabica::DOM::Element<std::string>& data);
@@ -529,6 +529,7 @@ public:
const NameSpaceInfo& nameSpaceInfo);
static Interpreter fromXML(const std::string& xml);
static Interpreter fromURI(const std::string& uri);
+ static Interpreter fromURI(const URL& uri);
static Interpreter fromClone(const Interpreter& other);
Interpreter() : _impl() {} // the empty, invalid interpreter
diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp
index 08135fd..624f6c1 100644
--- a/src/uscxml/URL.cpp
+++ b/src/uscxml/URL.cpp
@@ -350,6 +350,12 @@ const std::string URLImpl::getInContent(bool forceReload) {
return _rawInContent.str();
}
+const std::string URLImpl::file() const {
+ if (_pathComponents.size() > 0 && !boost::ends_with(path(), "/")) {
+ return _pathComponents[_pathComponents.size() - 1];
+ }
+}
+
const void URLImpl::download(bool blocking) {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h
index 01f3e1b..00c2b30 100644
--- a/src/uscxml/URL.h
+++ b/src/uscxml/URL.h
@@ -80,6 +80,7 @@ public:
const std::string path() const {
return _uri.path();
}
+ const std::string file() const;
const std::vector<std::string> pathComponents() const {
return _pathComponents;
}
@@ -259,6 +260,10 @@ public:
const std::vector<std::string> pathComponents() const {
return _impl->pathComponents();
}
+ const std::string file() const {
+ return _impl->file();
+ }
+
const std::string asString() const {
if (_impl)
return _impl->asString();
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
index d5471de..4061f41 100644
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -32,9 +32,30 @@ SCXMLDotWriter::SCXMLDotWriter() {
_indentation = 0;
}
-SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
+SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter,
+ const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
+ const Arabica::DOM::Element<std::string>& transition) {
_interpreter = interpreter;
+ _xmlNSPrefix = _interpreter.getNameSpaceInfo().xmlNSPrefix;
_transition = transition;
+ _anchors = stateAnchors;
+
+ if (_anchors.size() == 0) {
+ NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
+
+ StateAnchor anchor;
+ anchor.element = (Arabica::DOM::Element<std::string>)scxmlElems.item(0);
+ _anchors.push_back(anchor);
+ }
+
+ for (std::list<StateAnchor>::iterator anchIter = _anchors.begin(); anchIter != _anchors.end(); anchIter++) {
+ if (!anchIter->element) {
+ NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
+ anchIter->element = (Arabica::DOM::Element<std::string>)scxmlElems.item(0);
+ }
+ assembleGraph(anchIter->element, anchIter->depth);
+ }
+
_iteration = 0;
_indentation = 0;
}
@@ -61,7 +82,9 @@ void SCXMLDotWriter::beforeMicroStep(Interpreter interpreter) {
// toDot(fileSS.str(), interpreter);
}
-void SCXMLDotWriter::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
+void SCXMLDotWriter::beforeTakingTransition(Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& transition,
+ bool moreComing) {
std::ostringstream fileSS;
fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
toDot(fileSS.str(), interpreter, transition);
@@ -74,162 +97,350 @@ std::string SCXMLDotWriter::getPrefix() {
return prefix;
}
-void SCXMLDotWriter::toDot(const std::string& filename, Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
- std::ofstream outfile(filename.c_str());
- NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
- SCXMLDotWriter writer(interpreter, transition);
- if (scxmlElems.getLength() > 0) {
- writer._indentation++;
- outfile << "digraph {" << std::endl;
- outfile << "rankdir=TB; fontsize=10;" << std::endl;
- writer.writeSCXMLElement(outfile, (Arabica::DOM::Element<std::string>)scxmlElems.item(0));
- writer._indentation--;
- outfile << "}" << std::endl;
+void SCXMLDotWriter::writeTo(std::ostream& os) {
+ os << "digraph {" << std::endl;
+ os << " rankdir=TB;" << std::endl;
+ os << " fontsize=10;" << std::endl;
+ // outfile << " splines=ortho;" << std::endl;
+ // outfile << " splines=false;" << std::endl;
+ // outfile << " nodesep=1.0;" << std::endl;
+
+ _indentation++;
+ for (std::list<SCXMLDotWriter::StateAnchor>::iterator anchIter = _anchors.begin();
+ anchIter != _anchors.end(); anchIter++) {
+ writeStateElement(os, _graph[idForNode(anchIter->element)]);
}
+ _indentation--;
+
+
+ os << "}" << std::endl;
}
-void SCXMLDotWriter::writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
- writeStateElement(os, elem);
+void SCXMLDotWriter::toDot(const std::string& filename,
+ Interpreter interpreter,
+ const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
+ const Arabica::DOM::Element<std::string>& transition) {
-// std::string elemId = idForNode(elem);
-// os << getPrefix() << "subgraph \"cluster" << elemId.substr(1, elemId.length() - 1) << " {" << std::endl;
-// _indentation++;
-// os << getPrefix() << "label=\"" << nameForNode(elem) << "\"" << std::endl;
-// writeStateElement(os, (Arabica::DOM::Element<std::string>)_interpreter->getInitialState());
-// os << getPrefix() << "} " << std::endl;
+ std::ofstream outfile(filename.c_str());
+ SCXMLDotWriter writer(interpreter, stateAnchors, transition);
+ writer.writeTo(outfile);
}
-void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
+void SCXMLDotWriter::assembleGraph(const Arabica::DOM::Element<std::string>& state, uint32_t depth) {
+ std::string nodeId = idForNode(state);
- std::string elemId = idForNode(elem);
- NodeList<std::string > childElems = elem.getChildNodes();
+ // been here
+ if (_graph.find(nodeId) != _graph.end())
+ return;
+
+ if (depth == 0) {
+ _graph[nodeId].isBorder = true;
+ }
+
+ if (ATTR(state, "id") == "WiFiOff") {
+ assert(true);
+ }
+
+ _graph[nodeId].node = state;
+
+ if (depth == 0)
+ return;
+
+ Arabica::XPath::NodeSet<std::string> childElems = InterpreterImpl::filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, state);
+ for (int i = 0; i < childElems.size(); i++) {
+ Arabica::DOM::Element<std::string> childElem(childElems[i]);
+
+ if (iequals(TAGNAME(childElem), "history")) {
+ _histories[ATTR(childElem, "id")] = ATTR(state, "id") + ":" + ATTR(childElem, "id");
+ }
+
+ if (iequals(TAGNAME(childElem), "transition")) {
+ Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(childElem);
+ for (int j = 0; j < targetStates.size(); j++) {
+ std::string remoteNodeId = idForNode(targetStates[j]);
+ _graph[nodeId].targets.insert(std::make_pair(remoteNodeId, childElem));
+
+ // recurse along the transition targets
+ assembleGraph((Arabica::DOM::Element<std::string>)targetStates[j], depth - 1);
+ }
+ if (targetStates.size() == 0)
+ _graph[nodeId].targets.insert(std::make_pair(nodeId, childElem));
+
+ std::list<std::string> eventNames;
+ if (HAS_ATTR(childElem, "event"))
+ eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(childElem, "event"));
+ if (eventNames.size() == 0)
+ _graph[nodeId].events.insert(std::make_pair("", childElem));
+ for (std::list<std::string>::iterator evIter = eventNames.begin(); evIter != eventNames.end(); evIter++) {
+ _graph[nodeId].events.insert(std::make_pair(*evIter, childElem));
+ }
+ }
- if (_knownIds.find(elemId) != _knownIds.end())
+ if (InterpreterImpl::isState(Element<std::string>(childElem))) {
+ // add to initial states if it is initial
+ if (_interpreter.getImpl()->isInitial(Element<std::string>(childElem))) {
+ _graph[nodeId].initialchilds.insert(idForNode(childElem));
+ } else if (_interpreter.getImpl()->isParallel(Element<std::string>(state))) {
+ _graph[nodeId].initialchilds.insert(idForNode(childElem));
+ }
+ // in any case, it is a child state
+ _graph[nodeId].childs.insert(idForNode(childElem));
+
+ // recurse
+ assembleGraph(childElem, depth - 1);
+ }
+
+
+ }
+}
+
+void SCXMLDotWriter::writeStateElement(std::ostream& os, const DotState& state) {
+ const Arabica::DOM::Element<std::string>& stateElem = state.node;
+ std::string stateId = idForNode(stateElem);
+
+ if (_knownIds.find(stateId) != _knownIds.end())
return;
- _knownIds.insert(elemId);
+ _knownIds.insert(stateId);
- bool subgraph = InterpreterImpl::isCompound(elem) || InterpreterImpl::isParallel(elem);
+ bool subgraph = InterpreterImpl::isCompound(stateElem) || InterpreterImpl::isParallel(stateElem);
if (subgraph) {
_indentation++;
- os << getPrefix() << "subgraph \"cluster_" << elemId << "\" {" << std::endl;
- os << getPrefix() << "label=\"" << nameForNode(elem) << "\\l\"" << std::endl;
- }
+ os << std::endl;
+ os << getPrefix() << "subgraph \"cluster_" << stateId << "\" {" << std::endl;
+ _indentation++;
+ os << getPrefix() << "fontsize=14" << std::endl;
+ os << getPrefix() << "label=<<b>";
+ if (InterpreterImpl::isCompound(stateElem)) {
+ os << "Compound: ";
+ } else {
+ os << "Parallel: ";
+ }
+ os << nameForNode(stateElem) << "</b>>" << std::endl;
+// os << getPrefix() << "rank=\"same\"" << std::endl;
+ os << getPrefix() << "labeljust=l" << std::endl;
+// os << getPrefix() << "ranksep=\"equally\"" << std::endl;
- os << getPrefix() << "\"" << elemId << "\"[";
- os << "fontsize=10,";
- os << "label=<<b>State</b><br />" << nameForNode(elem) << ">,";
+ }
- // is the state initial?
- if (_interpreter.getImpl()->isInitial(elem))
- os << "style=filled, fillcolor=lightgrey, ";
+ os << std::endl;
+ os << getPrefix() << "\"" << stateId << "\" [" << std::endl;
+ _indentation++;
- // is this state final?
- if (_interpreter.getImpl()->isFinal(elem))
- os << "shape=doublecircle,";
+ os << getPrefix() << "fontsize=10," << std::endl;
+ os << getPrefix() << "shape=plaintext," << std::endl;
// is the current state in the basic configuration?
- if (InterpreterImpl::isMember(elem, _interpreter.getBasicConfiguration()))
- os << "color=red, penwidth=3,";
-
- // is the current state a target state?
-#if 0
- for (int i = 0; i < _transitions.size(); i++) {
- if (InterpreterImpl::isMember(elem, _interpreter.getTargetStates(_transitions[i]))) {
- os << "color=red, penwidth=3,";
- break;
- }
- }
-#endif
+ if (InterpreterImpl::isMember(stateElem, _interpreter.getBasicConfiguration()))
+ os << getPrefix() << "color=red, penwidth=3," << std::endl;
- os << "];" << std::endl;
+ // is the current state in the basic configuration?
+ if (state.isBorder)
+ os << getPrefix() << "color=blue," << std::endl;
- std::string details = getDetailedLabel(elem);
-// std::cout << details << std::endl;
+ // is this state final?
+ if (_interpreter.getImpl()->isFinal(stateElem)) {
+ os << getPrefix() << "shape=doublecircle," << std::endl;
+ os << getPrefix() << "color=black," << std::endl;
+ os << getPrefix() << "penwidth=2," << std::endl;
+ os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl;
+ _indentation--;
+ os << getPrefix() << "];" << std::endl;
+ return;
+ }
- if (details.size() > 0) {
- os << getPrefix() << "\"" << elemId << "Exec\"[";
- os << "fontsize=8,";
- os << "shape=box,";
- os << "color=grey,";
- os << "label=<" << details << ">";
- os << "]" << std::endl;
- os << getPrefix() << "\"" << elemId << "\" -> \"" << elemId << "Exec\" [arrowhead=none, color=grey]" << std::endl;
+ // is the state initial?
+ bool isInitial = _interpreter.getImpl()->isInitial(stateElem);
+// if (isInitial)
+// os << getPrefix() << "style=filled, fillcolor=lightgrey, " << std::endl;
+
+ DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
+ std::list<std::string> outPorts; // count unique keys
+#if PER_EVENT_TRANS
+ // count unique event names
+ for(DotState::mmap_s_e_t::const_iterator it = state.events.begin(), end = state.events.end();
+ it != end;
+ it = state.events.upper_bound(it->first)) {
+ outPorts.push_back(it->first);
+ }
+#else
+ // count unique adjecent nodes
+ for(DotState::mmap_s_e_t::const_iterator it = state.targets.begin(), end = state.targets.end();
+ it != end;
+ it = state.targets.upper_bound(it->first)) {
+ outPorts.push_back(it->first);
}
+#endif
-// NodeList<std::string > childElems = elem.getChildNodes();
-// for (int i = 0; i < childElems.getLength(); i++) {
-// if (Interpreter::isState(childElems.item(i))) {
-// writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
-// }
-// }
+ os << getPrefix() << "label = < " << std::endl;
- for (int i = 0; i < childElems.getLength(); i++) {
- if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && iequals(TAGNAME(childElems.item(i)), "transition")) {
- writeTransitionElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
- bool active = (childElems.item(i) == _transition);
- os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(childElems.item(i)) << "\" [arrowhead=none" << std::endl;
- if (active) {
- os << ", penwidth=3, color=red]" << std::endl;
- } else {
- os << "]" << std::endl;
- }
+ /*
+ <table cellborder="1" border="0" cellspacing="0" cellpadding="2" style="rounded">
+ <tr><td port="name" rowspan="4"><b>step</b></td></tr>
+ <tr><td port="foo.error.port" align="right">foo.error.port</td></tr>
+ <tr><td port="bar" align="right">bar</td></tr>
+ <tr><td port="baz" align="right">baz</td></tr>
+ </table>
+ */
+
+ std::string details = getDetailedLabel(stateElem);
+
+ os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\" >" << std::endl;
+ os << " <tr><td port=\"__name\" rowspan=\"" << outPorts.size() + 1 << "\"><b>" << nameForNode(stateElem) << "</b></td></tr>" << std::endl;
+ for(std::list<std::string>::iterator nameIter = outPorts.begin(); nameIter != outPorts.end(); nameIter++) {
+#ifdef PER_EVENT_TRANS
+ os << " <tr><td port=\"" << portEscape(*nameIter) << "\" align=\"right\">" << *nameIter << "</td></tr>" << std::endl;
+#else
+ // gather all events that activate the transition
+ std::string portName = *nameIter;
+
+// std::cout << ATTR(stateElem, "id") << std::endl;
+
+ if (ATTR(stateElem, "id") == "ConfirmQuit") {
+ assert(true);
}
- if (InterpreterImpl::isState(Element<std::string>(childElems.item(i)))) {
- writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
+
+ std::multimap<std::string, std::string> eventConds; // event to condition
+ std::pair <DotState::mmap_s_e_t::const_iterator, DotState::mmap_s_e_t::const_iterator> targetKeyRange = state.targets.equal_range(portName);
+ for (destIterB = targetKeyRange.first; destIterB != targetKeyRange.second; ++destIterB) {
+ const Arabica::DOM::Element<std::string>& transElem = destIterB->second;
+ std::list<std::string> eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(transElem, "event"));
+ for (std::list<std::string>::iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) {
+ eventConds.insert(std::make_pair(*eventIter, ATTR(transElem, "cond")));
+ }
+ if (eventNames.size() == 0) {
+ // spontaneous transition
+ eventConds.insert(std::make_pair("&#8709;", ATTR(transElem, "cond")));
+ }
}
- if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && iequals(TAGNAME(childElems.item(i)), "initial")) {
- NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
- for (int j = 0; j < grandChildElems.getLength(); j++) {
- if (grandChildElems.item(j).getNodeType() == Node_base::ELEMENT_NODE && iequals(TAGNAME(grandChildElems.item(j)), "transition")) {
- writeTransitionElement(os, (Arabica::DOM::Element<std::string>)grandChildElems.item(j));
- os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(grandChildElems.item(j)) << "\"" << std::endl;
- }
+
+ typedef std::multimap<std::string, std::string>::iterator condIter_t;
+ std::stringstream outPortSS;
+ outPortSS << "<b>" << portName << "</b><br align=\"right\" />";
+
+ std::string opener = "{";
+ std::string closer;
+ std::string seperator;
+ condIter_t iterA, iterB;
+ for(iterA = eventConds.begin(); iterA != eventConds.end(); iterA = iterB) {
+ std::string eventName = iterA->first;
+ bool hasCondition = false;
+
+ std::pair <condIter_t, condIter_t> condRange = eventConds.equal_range(eventName);
+ for (iterB = condRange.first; iterB != condRange.second; ++iterB) {
+ hasCondition = true;
}
+
+ outPortSS << opener << seperator << eventName << (hasCondition ? "" : "");
+ seperator = ", ";
+ opener = "";
+ closer = "}";
}
+ outPortSS << closer;
+
+ os << " <tr><td port=\"" << portEscape(portName) << "\" align=\"right\">" << outPortSS.str() << "</td></tr>" << std::endl;
+
+#endif
}
- if (subgraph) {
- _indentation--;
- os << getPrefix() << "} " << std::endl;
+ if (details.size() > 0) {
+ os << " <tr><td colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\">" << std::endl;
+ os << details << std::endl;
+ os << " </td></tr>" << std::endl;
}
-}
+ Arabica::XPath::NodeSet<std::string> histories = InterpreterImpl::filterChildElements(_xmlNSPrefix + "history", stateElem);
+ for (int i = 0; i < histories.size(); i++) {
+ os << " <tr><td port=\"" << ATTR(histories[i], "id") << "\" colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR(histories[i], "id") << "</td></tr>" << std::endl;
+
+ }
-void SCXMLDotWriter::writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
- std::string elemId = idForNode(elem);
+ os << "</table>" << std::endl << getPrefix() << ">" << std::endl;
- Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(elem);
+ _indentation--;
+ os << getPrefix() << "];" << std::endl;
- bool active = (elem == _transition);
+ // always display childs up to the desired depth
+ for (std::set<std::string>::iterator childIter = state.childs.begin(); childIter != state.childs.end(); childIter++) {
+ if (_graph.find(*childIter) != _graph.end())
+ writeStateElement(os, _graph[*childIter]);
+ }
- std::string label;
- os << getPrefix() << "\"" << elemId << "\"[";
- if (active) {
- os << "color=red, penwidth=3, ";
+ if (subgraph) {
+ _indentation--;
+ os << getPrefix() << "} " << std::endl;
+ _indentation--;
}
- os << "fontsize=10,";
- os << "shape=box,";
- os << "label=<<b>Transition</b><br align=\"left\" />";
- if (HAS_ATTR(elem, "event"))
- os << "event: " << ATTR(elem, "event");
- if (HAS_ATTR(elem, "cond"))
- os << "cond: " << dotEscape(ATTR(elem, "cond"));
- if (!HAS_ATTR(elem, "cond") && !HAS_ATTR(elem, "event"))
- os << "unconditional";
- os << ">";
- os << "]" << std::endl;
-
- for (int i = 0; i < targetStates.size(); i++) {
- os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(targetStates[i]) << "\"";
- if (active) {
- os << " [penwidth=3, color=red]" << std::endl;
+
+#if 1
+ std::string initialEdgeStyle = "style=\"dashed\", color=\"black\"";
+ std::string transitionEdgeStyle = "color=black";
+
+ for (std::set<std::string>::iterator initIter = state.initialchilds.begin(); initIter != state.initialchilds.end(); initIter++) {
+ std::string destId = *initIter;
+ if (_histories.find(destId) != _histories.end()) {
+ os << getPrefix() << stateId << ":__name -> " << _histories[destId] << " [" << initialEdgeStyle << "]" << std::endl;
+ } else if(InterpreterImpl::isFinal(_graph[destId].node)) {
+ os << getPrefix() << stateId << ":__name -> " << destId << ":__name:nw [" << initialEdgeStyle << "]" << std::endl;
} else {
- os << std::endl;
+ os << getPrefix() << stateId << ":__name -> " << destId << ":__name:nw [" << initialEdgeStyle << "]" << std::endl;
+ }
+ }
+
+#if PER_EVENT_TRANS
+ // iterate all events and make connections
+ DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
+ for(destIterF = state.events.begin(); destIterF != state.events.end(); destIterF = destIterB) {
+ std::string eventName = destIterF->first;
+
+ // all these react to the same event
+ std::pair <DotState::mmap_s_e_t::const_iterator,DotState::mmap_s_e_t::const_iterator> keyRange = state.events.equal_range(eventName);
+ for (destIterB = keyRange.first; destIterB != keyRange.second; ++destIterB) {
+ const Arabica::DOM::Element<std::string>& transElem = destIterB->second;
+ Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(transElem);
+ for (int i = 0; i < targetStates.size(); i++) {
+ std::string destId = idForNode(targetStates[i]);
+ if (_histories.find(destId) != _histories.end()) {
+ os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << _histories[destId] << " [" << transitionEdgeStyle << "]" << std::endl;
+ } else if(InterpreterImpl::isFinal(_graph[destId].node)) {
+ os << getPrefix() << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << " [" << transitionEdgeStyle << "]" << std::endl;
+ } else {
+ os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << ":__name [" << transitionEdgeStyle << "]" << std::endl;
+ }
+ }
+ }
+ }
+#else
+ // iterate all *targets* and make connections
+ for(destIterF = state.targets.begin(); destIterF != state.targets.end(); destIterF = destIterB) {
+ std::string eventName = destIterF->first;
+
+ // all these react to the same event
+ std::pair <DotState::mmap_s_e_t::const_iterator,DotState::mmap_s_e_t::const_iterator> keyRange = state.targets.equal_range(eventName);
+ std::set<Arabica::DOM::Element<std::string> > targetSet;
+ for (destIterB = keyRange.first; destIterB != keyRange.second; ++destIterB) {
+ const Arabica::DOM::Element<std::string>& transElem = destIterB->second;
+ Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(transElem);
+ for (int i = 0; i < targetStates.size(); i++) {
+ targetSet.insert(Arabica::DOM::Element<std::string>(targetStates[i]));
+ }
+ }
+ for (std::set<Arabica::DOM::Element<std::string> >::iterator stateIter = targetSet.begin(); stateIter != targetSet.end(); stateIter++) {
+ std::string destId = idForNode(*stateIter);
+ if (_histories.find(destId) != _histories.end()) {
+ os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << _histories[destId] << " [" << transitionEdgeStyle << "]" << std::endl;
+ } else if(InterpreterImpl::isFinal(_graph[destId].node)) {
+ os << getPrefix() << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << " [" << transitionEdgeStyle << "]" << std::endl;
+ } else {
+ os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << ":__name [" << transitionEdgeStyle << "]" << std::endl;
+ }
+ writeStateElement(os, _graph[destId]);
}
- writeStateElement(os, (Arabica::DOM::Element<std::string>)targetStates[i]);
}
+#endif
+
+#endif
}
@@ -265,6 +476,10 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
struct ElemDetails details;
details.name = "<b>" + TAGNAME(childElems.item(i)) + ":</b>";
+ if (iequals(TAGNAME(childElems.item(i)), "history")) {
+ continue;
+ }
+
// provide details for special elements here
// param ---------
@@ -311,6 +526,8 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
// send ---------
if (iequals(TAGNAME(childElems.item(i)), "send")) {
+ if (HAS_ATTR(childElems.item(i), "id"))
+ details.name += "<br />id = " + ATTR(childElems.item(i), "id");
if (HAS_ATTR(childElems.item(i), "type"))
details.name += "<br />type = " + ATTR(childElems.item(i), "type");
if (HAS_ATTR(childElems.item(i), "typeexpr"))
@@ -329,6 +546,12 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
details.name += "<br />delay = " + ATTR(childElems.item(i), "delayexpr");
}
+ // cancel ---------
+ if (iequals(TAGNAME(childElems.item(i)), "cancel")) {
+ if (HAS_ATTR(childElems.item(i), "sendid"))
+ details.name += " " + ATTR(childElems.item(i), "sendid");
+ }
+
// script ---------
if (iequals(TAGNAME(childElems.item(i)), "script")) {
details.name += " ";
@@ -381,7 +604,7 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
std::stringstream ssContent;
if (content.size() > 0) {
- ssContent << "<table cellspacing=\"2\" cellpadding=\"0\" border=\"0\">";
+ ssContent << "<table cellspacing=\"2\" cellpadding=\"0\" border=\"0\" bgcolor=\"#" << colorForIndent(indentation + 1) << "\">";
std::list<struct ElemDetails>::iterator contentIter = content.begin();
while(contentIter != content.end()) {
@@ -404,6 +627,13 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
return ssContent.str();
}
+std::string SCXMLDotWriter::portEscape(const std::string& text) {
+ std::string escaped(text);
+ boost::replace_all(escaped, ".", "-");
+
+ return escaped;
+}
+
std::string SCXMLDotWriter::dotEscape(const std::string& text) {
std::string escaped(text);
boost::replace_all(escaped, " ", "&nbsp;");
@@ -429,10 +659,12 @@ std::string SCXMLDotWriter::nameForNode(const Arabica::DOM::Node<std::string>& n
std::string elemName;
if (node.getNodeType() == Node_base::ELEMENT_NODE) {
Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
+ if (InterpreterImpl::isParallel(elem))
+ elemName += "<i>Parallel</i><br />";
if (elem.hasAttribute("name")) {
- elemName = elem.getAttribute("name");
+ elemName += elem.getAttribute("name");
} else if (elem.hasAttribute("id")) {
- elemName = elem.getAttribute("id");
+ elemName += elem.getAttribute("id");
}
}
if (elemName.size() == 0)
diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h
index 4e2d7a8..30d5fcf 100644
--- a/src/uscxml/debug/SCXMLDotWriter.h
+++ b/src/uscxml/debug/SCXMLDotWriter.h
@@ -26,6 +26,9 @@
#include <fstream>
#include <set>
+#undef max
+#include <limits>
+
namespace uscxml {
class Interpreter;
@@ -54,24 +57,53 @@ class Interpreter;
class USCXML_API SCXMLDotWriter : public InterpreterMonitor {
public:
+ struct StateAnchor {
+ StateAnchor() : depth(std::numeric_limits<int32_t>::max()) {}
+ Arabica::DOM::Element<std::string> element;
+ uint32_t depth;
+ };
+
struct ElemDetails {
std::string name;
std::string details;
std::string content;
};
+ struct DotState {
+ DotState() : isBorder(false) {}
+ Arabica::DOM::Element<std::string> node;
+ std::multimap<std::string, Arabica::DOM::Element<std::string> > targets; // key is remote node, transition is element
+ std::multimap<std::string, Arabica::DOM::Element<std::string> > events; // key is event name, value is transitions that react
+
+ bool isBorder;
+ std::set<std::string> childs;
+ std::set<std::string> initialchilds;
+ typedef std::multimap<std::string, Arabica::DOM::Element<std::string> > mmap_s_e_t;
+ };
+
SCXMLDotWriter();
~SCXMLDotWriter();
virtual void onStableConfiguration(Interpreter interpreter);
virtual void afterCompletion(Interpreter interpreter);
- virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition);
+ virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing);
virtual void beforeMicroStep(Interpreter interpreter);
static void toDot(const std::string& filename,
Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& transition = Arabica::DOM::Element<std::string>()) {
+ std::list<SCXMLDotWriter::StateAnchor> emptyAnchors = std::list<SCXMLDotWriter::StateAnchor>();
+ toDot(filename, interpreter, emptyAnchors, transition);
+ }
+
+
+ static void toDot(const std::string& filename,
+ Interpreter interpreter,
+ const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
const Arabica::DOM::Element<std::string>& transition = Arabica::DOM::Element<std::string>());
+ void writeTo(std::ostream& os);
+
std::string getDetailedLabel(const Arabica::DOM::Element<std::string>& elem, int indentation = 0);
std::string colorForIndent(int indent);
@@ -80,23 +112,31 @@ public:
std::string getPrefix();
static std::string dotEscape(const std::string& text);
+ static std::string portEscape(const std::string& text);
protected:
SCXMLDotWriter(Interpreter interpreter,
+ const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
const Arabica::DOM::Element<std::string>& transition);
- void writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
- void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
- void writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
+ void assembleGraph(const Arabica::DOM::Element<std::string>& start, uint32_t depth = std::numeric_limits<int32_t>::max());
+ void writeStateElement(std::ostream& os, const DotState& elem);
+ void writeUnknownNode(std::ostream& os, const std::string& targetId);
int _iteration;
std::set<std::string> _knownIds;
+ std::set<std::string> _unknownNodes;
int _indentation;
+ std::map<std::string, DotState> _graph;
+
// these are only set in ephemeral instances per monitor call
Arabica::DOM::Element<std::string> _transition;
Interpreter _interpreter;
+ std::string _xmlNSPrefix;
+ std::list<StateAnchor> _anchors;
+ std::map<std::string, std::string> _histories;
};
}
diff --git a/src/uscxml/messages/Data.h b/src/uscxml/messages/Data.h
index 11b46fb..584bf09 100644
--- a/src/uscxml/messages/Data.h
+++ b/src/uscxml/messages/Data.h
@@ -212,7 +212,7 @@ public:
this->array = array;
}
- std::string getAtom() {
+ std::string getAtom() const {
return atom;
}
void setAtom(const std::string& atom) {
diff --git a/src/uscxml/messages/Event.h b/src/uscxml/messages/Event.h
index 6697bb9..1aa66a1 100644
--- a/src/uscxml/messages/Event.h
+++ b/src/uscxml/messages/Event.h
@@ -99,35 +99,35 @@ public:
return !(*this == other);
}
- std::string getName() {
+ std::string getName() const {
return name;
}
void setName(const std::string& name) {
this->name = name;
}
- Type getEventType() {
+ Type getEventType() const {
return eventType;
}
void setEventType(const Type type) {
this->eventType = type;
}
- std::string getOrigin() {
+ std::string getOrigin() const {
return origin;
}
void setOrigin(const std::string& origin) {
this->origin = origin;
}
- std::string getOriginType() {
+ std::string getOriginType() const {
return origintype;
}
void setOriginType(const std::string& originType) {
this->origintype = originType;
}
- Arabica::DOM::Node<std::string> getDOM() {
+ Arabica::DOM::Node<std::string> getDOM() const {
return dom;
}
void setDOM(const Arabica::DOM::Node<std::string>& dom) {
@@ -140,42 +140,42 @@ public:
// static Arabica::DOM::Node<std::string> getFirstDOMElement(const Arabica::DOM::Document<std::string> dom);
// static Arabica::DOM::Document<std::string> getStrippedDOM(const Arabica::DOM::Document<std::string> dom);
- std::string getRaw() {
+ std::string getRaw() const {
return raw;
}
void setRaw(const std::string& raw) {
this->raw = raw;
}
- std::string getContent() {
+ std::string getContent() const {
return content;
}
void setContent(const std::string& content) {
this->content = content;
}
- std::string getXML() {
+ std::string getXML() const {
return xml;
}
void setXML(const std::string& xml) {
this->xml = xml;
}
- std::string getSendId() {
+ std::string getSendId() const {
return sendid;
}
void setSendId(const std::string& sendId) {
this->sendid = sendId;
}
- std::string getInvokeId() {
+ std::string getInvokeId() const {
return invokeid;
}
void setInvokeId(const std::string& invokeId) {
this->invokeid = invokeId;
}
- Data getData() {
+ Data getData() const {
return data;
}
void setData(const Data& data) {
diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
index 6fb0369..84833fb 100644
--- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
@@ -21,7 +21,10 @@
#include "uscxml/Common.h"
#include "LuaDataModel.h"
+
#include "LuaBridge.h"
+//#include "RefCountedPtr.h"
+
#include "uscxml/DOMUtils.h"
#include "uscxml/Message.h"
@@ -45,17 +48,6 @@ LuaDataModel::LuaDataModel() {
_luaState = NULL;
}
-static int luaEventData(lua_State * l);
-static int luaEventOrigin(lua_State * l);
-static int luaEventOriginType(lua_State * l);
-static int luaEventRaw(lua_State * l);
-static int luaEventXML(lua_State * l);
-static int luaEventName(lua_State * l);
-static int luaEventContent(lua_State * l);
-static int luaEventSendId(lua_State * l);
-static int luaEventInvokeId(lua_State * l);
-static int luaEventDestructor(lua_State * l);
-
static int luaInFunction(lua_State * l) {
luabridge::LuaRef ref = luabridge::getGlobal(l, "__interpreter");
InterpreterImpl* interpreter = ref.cast<InterpreterImpl*>();
@@ -81,9 +73,23 @@ boost::shared_ptr<DataModelImpl> LuaDataModel::create(InterpreterImpl* interpret
dm->_luaState = luaL_newstate();
luaL_openlibs(dm->_luaState);
- luabridge::getGlobalNamespace(dm->_luaState).beginClass<InterpreterImpl>("__interpreter").endClass();
+ luabridge::getGlobalNamespace(dm->_luaState).beginClass<InterpreterImpl>("Interpreter").endClass();
luabridge::getGlobalNamespace(dm->_luaState).addCFunction("In", luaInFunction);
+// luabridge::getGlobalNamespace(dm->_luaState)
+// .beginClass <uscxml::Event> ("Event")
+// .addProperty("name", &uscxml::Event::getName)
+// .addProperty("raw", &uscxml::Event::getRaw)
+// .addProperty("data", &uscxml::Event::getData)
+// .addProperty("xml", &uscxml::Event::getXML)
+// .addProperty("eventType", &uscxml::Event::getEventType)
+// .addProperty("origin", &uscxml::Event::getOrigin)
+// .addProperty("originType", &uscxml::Event::getOriginType)
+// .addProperty("content", &uscxml::Event::getContent)
+// .addProperty("invokeId", &uscxml::Event::getInvokeId)
+// .addProperty("sendId", &uscxml::Event::getSendId)
+// .endClass ();
+
luabridge::setGlobal(dm->_luaState, dm->_interpreter, "__interpreter");
return dm;
@@ -103,13 +109,161 @@ void LuaDataModel::popContext() {
void LuaDataModel::initialize() {
}
+static Data getLuaAsData(const luabridge::LuaRef& lua) {
+ Data data;
+ if (lua.isFunction()) {
+ // TODO: this might lead to a stack-overflow
+ luabridge::LuaRef luaEvald = lua();
+ return getLuaAsData(luaEvald);
+ } else if(lua.isLightUserdata() || lua.isUserdata()) {
+ // not sure what to do
+ } else if(lua.isThread()) {
+ // not sure what to do
+ } else if(lua.isNil()) {
+ data.atom = "undefined";
+ data.type = Data::INTERPRETED;
+ } else if(lua.isString()) {
+ data.atom = lua.tostring();
+ data.type = Data::VERBATIM;
+ } else if(lua.isNumber()) {
+ data.atom = lua.tostring();
+ data.type = Data::INTERPRETED;
+ } else if(lua.isTable()) {
+ for (luabridge::Iterator iter (lua); !iter.isNil (); ++iter) {
+ luabridge::LuaRef luaKey = iter.key();
+ luabridge::LuaRef luaVal = *iter;
+ data.compound[luaKey.tostring()] = getLuaAsData(luaVal);
+ }
+ }
+ return data;
+}
+
+static luabridge::LuaRef getDataAsLua(lua_State* _luaState, const Data& data) {
+ luabridge::LuaRef luaData (_luaState);
+
+ if (data.node) {
+ ERROR_EXECUTION_THROW("No DOM support in Lua datamodel");
+ }
+ if (data.compound.size() > 0) {
+ luaData = luabridge::newTable(_luaState);
+ std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ luaData[compoundIter->first] = getDataAsLua(_luaState, compoundIter->second);
+ compoundIter++;
+ }
+ return luaData;
+ }
+ if (data.array.size() > 0) {
+ luaData = luabridge::newTable(_luaState);
+ std::list<Data>::const_iterator arrayIter = data.array.begin();
+ uint32_t index = 0;
+ while(arrayIter != data.array.end()) {
+ luaData[index++] = getDataAsLua(_luaState, *arrayIter);
+ arrayIter++;
+ }
+ return luaData;
+ }
+ if (data.atom.size() > 0) {
+ switch (data.type) {
+ case Data::VERBATIM: {
+ luaData = "\"" + data.atom + "\"";
+ break;
+ }
+ case Data::INTERPRETED: {
+ luaData = data.atom; // not sure
+ }
+ }
+ return luaData;
+ }
+ return luaData;
+}
+
void LuaDataModel::setEvent(const Event& event) {
+ luabridge::LuaRef luaEvent(_luaState);
+ luaEvent = luabridge::newTable(_luaState);
+
+ luaEvent["name"] = event.name;
+ luaEvent["raw"] = event.raw;
+ luaEvent["xml"] = event.xml;
+ luaEvent["origin"] = event.origin;
+ luaEvent["origintype"] = event.origintype;
+ luaEvent["content"] = event.content;
+ luaEvent["invokeId"] = event.invokeid;
+ luaEvent["sendId"] = event.sendid;
+
+ switch (event.eventType) {
+ case Event::INTERNAL:
+ luaEvent["type"] = "internal";
+ break;
+ case Event::EXTERNAL:
+ luaEvent["type"] = "external";
+ break;
+ case Event::PLATFORM:
+ luaEvent["type"] = "platform";
+ break;
+
+ default:
+ break;
+ }
+
+ if (event.dom) {
+ ERROR_EXECUTION_THROW("No DOM support in Lua datamodel");
+ } else if (event.content.length() > 0) {
+ // _event.data is a string or JSON
+ Data json = Data::fromJSON(event.content);
+ if (!json.empty()) {
+ luaEvent["data"] = getDataAsLua(_luaState, json);
+ } else {
+ luaEvent["data"] = InterpreterImpl::spaceNormalize(event.content);
+ }
+ } else {
+ // _event.data is KVP
+ Event eventCopy(event);
+
+ if (!eventCopy.params.empty()) {
+ Event::params_t::iterator paramIter = eventCopy.params.begin();
+ while(paramIter != eventCopy.params.end()) {
+ eventCopy.data.compound[paramIter->first] = paramIter->second;
+ paramIter++;
+ }
+ }
+ if (!eventCopy.namelist.empty()) {
+ Event::namelist_t::iterator nameListIter = eventCopy.namelist.begin();
+ while(nameListIter != eventCopy.namelist.end()) {
+ eventCopy.data.compound[nameListIter->first] = nameListIter->second;
+ nameListIter++;
+ }
+ }
+
+ if (!eventCopy.data.empty()) {
+ luabridge::LuaRef luaData = getDataAsLua(_luaState, eventCopy.data);
+ assert(luaEvent.isTable());
+ assert(luaData.isTable());
+ luaEvent["data"] = luaData;
+ }
+ }
+
+ luabridge::setGlobal(_luaState, luaEvent, "_event");
}
Data LuaDataModel::getStringAsData(const std::string& content) {
Data data = Data::fromJSON(content);
if (data.empty()) {
- data = Data(content, Data::VERBATIM);
+ std::string trimmedExpr = boost::trim_copy(content);
+ if (!boost::starts_with(trimmedExpr, "return")) {
+ trimmedExpr = "return(" + trimmedExpr + ");";
+ }
+
+ int preStack = lua_gettop(_luaState);
+ eval(Arabica::DOM::Element<std::string>(), trimmedExpr);
+ int postStack = lua_gettop(_luaState);
+ int retVals = postStack - preStack;
+ if (retVals == 1) {
+ data = getLuaAsData(luabridge::LuaRef::fromStack(_luaState, -1));
+ }
+ postStack = lua_gettop(_luaState);
+ lua_pop(_luaState, postStack - preStack);
+
}
return data;
}
@@ -123,6 +277,29 @@ bool LuaDataModel::isLocation(const std::string& expr) {
}
uint32_t LuaDataModel::getLength(const std::string& expr) {
+ // we need the result of the expression on the lua stack -> has to "return"!
+ std::string trimmedExpr = boost::trim_copy(expr);
+
+// luabridge::LuaRef val = luabridge::getGlobal(_luaState, expr.c_str());
+// std::cout << val.tostring() << std::endl;
+
+ if (!boost::starts_with(trimmedExpr, "return")) {
+ trimmedExpr = "return(#" + trimmedExpr + ")";
+ }
+
+ int preStack = lua_gettop(_luaState);
+ eval(Arabica::DOM::Element<std::string>(), trimmedExpr);
+ int postStack = lua_gettop(_luaState);
+ int retVals = postStack - preStack;
+
+ if (retVals == 1 && lua_isnumber(_luaState, -1)) {
+ int result = lua_tointeger(_luaState, -1);
+ lua_pop(_luaState, 1);
+ return result;
+ }
+
+ lua_pop(_luaState, retVals);
+ ERROR_EXECUTION_THROW("'" + expr + "' does not evaluate to an array.");
return 0;
}
@@ -130,35 +307,113 @@ void LuaDataModel::setForeach(const std::string& item,
const std::string& array,
const std::string& index,
uint32_t iteration) {
+ iteration++; // test153: arrays start at 1
+
+ const luabridge::LuaRef& arrRef = luabridge::getGlobal(_luaState, array.c_str());
+ if (arrRef.isTable()) {
+ int preStack = lua_gettop(_luaState);
+
+ // trigger syntax error for invalid items
+ eval(Arabica::DOM::Element<std::string>(), "return(" + item + ");");
+ int postStack = lua_gettop(_luaState);
+ lua_pop(_luaState, postStack - preStack);
+
+ const luabridge::LuaRef& val = arrRef[iteration];
+ luabridge::setGlobal(_luaState, val, item.c_str());
+
+// luabridge::LuaRef retVal = luabridge::getGlobal(_luaState, item.c_str());
+// std::cout << retVal.tostring() << std::endl;
+
+ if (index.length() > 0) {
+ // assign iteration element to index
+ luabridge::setGlobal(_luaState, iteration, index.c_str());
+ }
+ }
}
void LuaDataModel::eval(const Arabica::DOM::Element<std::string>& scriptElem,
const std::string& expr) {
-
+ int error = luaL_loadstring(_luaState, expr.c_str()) || lua_pcall(_luaState, 0, LUA_MULTRET, 0);
+ if (error) {
+ std::string errMsg = lua_tostring(_luaState, -1);
+ lua_pop(_luaState, 1); /* pop error message from the stack */
+ ERROR_EXECUTION_THROW(errMsg);
+ }
}
bool LuaDataModel::isDeclared(const std::string& expr) {
+ // see: http://lua-users.org/wiki/DetectingUndefinedVariables
return true;
}
void LuaDataModel::assign(const Arabica::DOM::Element<std::string>& assignElem,
const Arabica::DOM::Node<std::string>& node,
const std::string& content) {
+ std::string key;
+ if (HAS_ATTR(assignElem, "id")) {
+ key = ATTR(assignElem, "id");
+ } else if (HAS_ATTR(assignElem, "location")) {
+ key = ATTR(assignElem, "location");
+ }
+ if (key.length() == 0) {
+ ERROR_EXECUTION_THROW("Assign element has neither id nor location");
+ }
+
+ // flags on attribute are ignored?
+ if (key.compare("_sessionid") == 0) // test 322
+ ERROR_EXECUTION_THROW("Cannot assign to _sessionId");
+ if (key.compare("_name") == 0)
+ ERROR_EXECUTION_THROW("Cannot assign to _name");
+ if (key.compare("_ioprocessors") == 0) // test 326
+ ERROR_EXECUTION_THROW("Cannot assign to _ioprocessors");
+ if (key.compare("_invokers") == 0)
+ ERROR_EXECUTION_THROW("Cannot assign to _invokers");
+ if (key.compare("_event") == 0)
+ ERROR_EXECUTION_THROW("Cannot assign to _event");
+
+// lua_pushnil(_luaState);
+// lua_setglobal(_luaState, key.c_str());
+
+// luabridge::setGlobal(_luaState, luabridge::Nil(), key.c_str());
+// luabridge::LuaRef val = luabridge::getGlobal(_luaState, key.c_str());
+// std::cout << val.tostring() << std::endl;
+
+ int preStack = lua_gettop(_luaState);
+
+ if (HAS_ATTR(assignElem, "expr")) {
+ eval(Arabica::DOM::Element<std::string>(), key + " = " + ATTR(assignElem, "expr") + ";");
+ } else if (node) {
+ ERROR_EXECUTION_THROW("Cannot assign xml nodes in lua datamodel");
+ } else if (content.size() > 0) {
+ try {
+ eval(Arabica::DOM::Element<std::string>(), key + " = " + content + ";");
+ } catch (...) {
+ eval(Arabica::DOM::Element<std::string>(), key + " = " + "\"" + InterpreterImpl::spaceNormalize(content) + "\";");
+ }
+ } else {
+ eval(Arabica::DOM::Element<std::string>(), key + " = " + "nil;");
+ }
+
+// val = luabridge::getGlobal(_luaState, key.c_str());
+// std::cout << val.tostring() << std::endl;
+
+ int postStack = lua_gettop(_luaState);
+ int retVals = postStack - preStack;
}
void LuaDataModel::assign(const std::string& location, const Data& data) {
-
+ std::cout << "assign" << std::endl;
}
void LuaDataModel::init(const Arabica::DOM::Element<std::string>& dataElem,
const Arabica::DOM::Node<std::string>& node,
const std::string& content) {
-
+ assign(dataElem, node, content);
}
void LuaDataModel::init(const std::string& location, const Data& data) {
-
+ std::cout << "init" << std::endl;
}
/**
@@ -171,29 +426,43 @@ bool LuaDataModel::evalAsBool(const Arabica::DOM::Node<std::string>& node, const
// we need the result of the expression on the lua stack -> has to "return"!
std::string trimmedExpr = boost::trim_copy(expr);
if (!boost::starts_with(trimmedExpr, "return")) {
- trimmedExpr = "return(" + trimmedExpr + ")";
+ trimmedExpr = "return(" + trimmedExpr + ");";
}
- int error = luaL_loadstring(_luaState, trimmedExpr.c_str()) || lua_pcall(_luaState, 0, LUA_MULTRET, 0);
- if (error) {
- std::string errMsg = lua_tostring(_luaState, -1);
- lua_pop(_luaState, 1); /* pop error message from the stack */
- ERROR_EXECUTION_THROW(errMsg);
+
+ int preStack = lua_gettop(_luaState);
+ eval(Arabica::DOM::Element<std::string>(), trimmedExpr);
+ int postStack = lua_gettop(_luaState);
+ int retVals = postStack - preStack;
+
+ if (retVals == 1 && lua_isboolean(_luaState, -1)) {
+ bool result = lua_toboolean(_luaState, -1);
+ lua_pop(_luaState, 1);
+ return result;
}
- int stackSize = lua_gettop(_luaState);
- if (stackSize != 1)
- return false;
- if (lua_isboolean(_luaState, -1))
- return lua_toboolean(_luaState, -1);
+ lua_pop(_luaState, retVals);
return false;
}
std::string LuaDataModel::evalAsString(const std::string& expr) {
- return expr;
-}
+ std::string trimmedExpr = boost::trim_copy(expr);
+ if (!boost::starts_with(trimmedExpr, "return")) {
+ trimmedExpr = "return(" + trimmedExpr + ")";
+ }
-double LuaDataModel::evalAsNumber(const std::string& expr) {
- return 0;
+ int preStack = lua_gettop(_luaState);
+ eval(Arabica::DOM::Element<std::string>(), trimmedExpr);
+ int postStack = lua_gettop(_luaState);
+ int retVals = postStack - preStack;
+
+ if (retVals == 1 && lua_isstring(_luaState, -1)) {
+ std::string result = lua_tostring(_luaState, -1);
+ lua_pop(_luaState, 1);
+ return result;
+ }
+ lua_pop(_luaState, retVals);
+ return "";
}
+
} \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
index 9677307..c5d9e4b 100644
--- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
+++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
@@ -84,7 +84,6 @@ public:
const std::string& expr);
virtual std::string evalAsString(const std::string& expr);
virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& node, const std::string& expr);
- virtual double evalAsNumber(const std::string& expr);
protected:
diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp
index 073657a..d86bdb2 100644
--- a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp
@@ -150,8 +150,5 @@ std::string NULLDataModel::evalAsString(const std::string& expr) {
return expr;
}
-double NULLDataModel::evalAsNumber(const std::string& expr) {
- return 0;
-}
} \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.h b/src/uscxml/plugins/datamodel/null/NULLDataModel.h
index f9609c4..2870388 100644
--- a/src/uscxml/plugins/datamodel/null/NULLDataModel.h
+++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.h
@@ -78,7 +78,6 @@ public:
const std::string& expr);
virtual std::string evalAsString(const std::string& expr);
virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& node, const std::string& expr);
- virtual double evalAsNumber(const std::string& expr);
protected:
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 7a610a6..10c1213 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -188,6 +188,12 @@ foreach( W3C_TEST ${W3C_TESTS} )
add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
endif()
+
+ if (BUILD_DM_LUA AND LUA_FOUND AND BUILD_TESTS_W3C_LUA AND TEST_NAME MATCHES "^lua\\/.*")
+ add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+# set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ endif()
endif()
endforeach()
diff --git a/test/src/test-cmdline-parsing.cpp b/test/src/test-cmdline-parsing.cpp
index 341f24e..6fa0c57 100644
--- a/test/src/test-cmdline-parsing.cpp
+++ b/test/src/test-cmdline-parsing.cpp
@@ -47,7 +47,7 @@ int main(int argc, char** argv) {
assert(options);
assert(options.verbose);
assert(options.interpreters.size() == 1);
- assert(options.interpreters.find("/foo/bar.scxml") != options.interpreters.end());
+ assert(options.interpreters.front().first == "/foo/bar.scxml");
}
if (true) {
@@ -66,12 +66,13 @@ int main(int argc, char** argv) {
assert(options);
assert(options.httpPort == 80);
assert(options.interpreters.size() == 3);
- assert(options.interpreters.find("/foo/bar1.scxml") != options.interpreters.end());
- assert(options.interpreters.find("/foo/bar2.scxml") != options.interpreters.end());
- assert(options.interpreters.find("/foo/bar3.scxml") != options.interpreters.end());
- assert(!options.interpreters["/foo/bar1.scxml"]->withHTTP);
- assert(options.interpreters["/foo/bar2.scxml"]->withHTTP);
- assert(!options.interpreters["/foo/bar3.scxml"]->withHTTP);
+ assert(options.interpreters[0].first == "/foo/bar1.scxml");
+ assert(options.interpreters[1].first == "/foo/bar2.scxml");
+ assert(options.interpreters[2].first == "/foo/bar3.scxml");
+
+ assert(!options.interpreters[0].second->withHTTP);
+ assert(options.interpreters[1].second->withHTTP);
+ assert(!options.interpreters[2].second->withHTTP);
}
if (true) {
@@ -88,9 +89,12 @@ int main(int argc, char** argv) {
assert(options);
assert(options.httpPort == 80);
assert(options.interpreters.size() == 1);
- assert(options.interpreters.find("/foo/bar1.scxml") != options.interpreters.end());
- assert(options.interpreters["/foo/bar1.scxml"]->additionalParameters.find("vrml-path") != options.interpreters["/foo/bar1.scxml"]->additionalParameters.end());
- assert(options.interpreters["/foo/bar1.scxml"]->additionalParameters.find("tmp-path") != options.interpreters["/foo/bar1.scxml"]->additionalParameters.end());
+ assert(options.interpreters[0].first == "/foo/bar1.scxml");
+
+ assert(options.interpreters[0].second->additionalParameters.find("vrml-path")
+ != options.interpreters[0].second->additionalParameters.end());
+ assert(options.interpreters[0].second->additionalParameters.find("tmp-path")
+ != options.interpreters[0].second->additionalParameters.end());
}
return EXIT_SUCCESS;
diff --git a/test/src/test-predicates.cpp b/test/src/test-predicates.cpp
index fb4551e..02e0faf 100644
--- a/test/src/test-predicates.cpp
+++ b/test/src/test-predicates.cpp
@@ -24,17 +24,17 @@ int main(int argc, char** argv) {
assert(interpreter);
interpreter.getImpl()->init();
- Node<std::string> atomicState = interpreter.getImpl()->getState("atomic");
+ Element<std::string> atomicState = interpreter.getImpl()->getState("atomic");
assert(InterpreterImpl::isAtomic(atomicState));
assert(!InterpreterImpl::isParallel(atomicState));
assert(!InterpreterImpl::isCompound(atomicState));
- Node<std::string> compoundState = interpreter.getImpl()->getState("compound");
+ Element<std::string> compoundState = interpreter.getImpl()->getState("compound");
assert(!InterpreterImpl::isAtomic(compoundState));
assert(!InterpreterImpl::isParallel(compoundState));
assert(InterpreterImpl::isCompound(compoundState));
- Node<std::string> parallelState = interpreter.getImpl()->getState("parallel");
+ Element<std::string> parallelState = interpreter.getImpl()->getState("parallel");
assert(!InterpreterImpl::isAtomic(parallelState));
assert(InterpreterImpl::isParallel(parallelState));
assert(!InterpreterImpl::isCompound(parallelState)); // parallel states are not compound!
diff --git a/test/w3c/lua/test152.scxml b/test/w3c/lua/test152.scxml
index 1147c4b..71ff703 100644
--- a/test/w3c/lua/test152.scxml
+++ b/test/w3c/lua/test152.scxml
@@ -23,7 +23,7 @@ not being executed. -->
<state id="s1">
<onentry>
<!-- illegal item, legal array -->
- <foreach array="testvar5" index="testvar3" item="_no">
+ <foreach array="testvar5" index="testvar3" item="!_no">
<assign location="testvar1" expr="testvar1+1"/>
</foreach>
<raise event="bar"/>