summaryrefslogtreecommitdiffstats
path: root/src/uscxml/debug
diff options
context:
space:
mode:
authorStefan Radomski <github@mintwerk.de>2016-05-12 13:12:33 (GMT)
committerStefan Radomski <github@mintwerk.de>2016-05-12 13:12:33 (GMT)
commitb62e7979600feee23dc7cdb61042a8fc7673122b (patch)
treef7351372f37979dd2d048e0b68a16a4cd3b2aadb /src/uscxml/debug
parent1b11b310be61e51b3ac5ebb83f7c8a33aef3d6e8 (diff)
downloaduscxml-b62e7979600feee23dc7cdb61042a8fc7673122b.zip
uscxml-b62e7979600feee23dc7cdb61042a8fc7673122b.tar.gz
uscxml-b62e7979600feee23dc7cdb61042a8fc7673122b.tar.bz2
Major Refactoring v2.0
Diffstat (limited to 'src/uscxml/debug')
-rw-r--r--src/uscxml/debug/Breakpoint.cpp266
-rw-r--r--src/uscxml/debug/Breakpoint.h95
-rw-r--r--src/uscxml/debug/Complexity.cpp206
-rw-r--r--src/uscxml/debug/Complexity.h78
-rw-r--r--src/uscxml/debug/DebugSession.cpp378
-rw-r--r--src/uscxml/debug/DebugSession.h99
-rw-r--r--src/uscxml/debug/Debugger.cpp256
-rw-r--r--src/uscxml/debug/Debugger.h105
-rw-r--r--src/uscxml/debug/DebuggerServlet.cpp262
-rw-r--r--src/uscxml/debug/DebuggerServlet.h106
-rw-r--r--src/uscxml/debug/InterpreterIssue.cpp601
-rw-r--r--src/uscxml/debug/InterpreterIssue.h8
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp888
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.h201
14 files changed, 353 insertions, 3196 deletions
diff --git a/src/uscxml/debug/Breakpoint.cpp b/src/uscxml/debug/Breakpoint.cpp
deleted file mode 100644
index d7eb2af..0000000
--- a/src/uscxml/debug/Breakpoint.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#include "uscxml/debug/Breakpoint.h"
-#include "uscxml/Interpreter.h"
-#include "uscxml/dom/DOMUtils.h"
-
-namespace uscxml {
-
-Breakpoint::Breakpoint(const Data& data) {
- enabled = true;
- subject = UNDEF_SUBJECT;
- when = UNDEF_WHEN;
- action = UNDEF_ACTION;
-
- if (data.hasKey("when")) {
- if (false) {
- } else if (data.at("when").atom == "before") {
- when = BEFORE;
- } else if (data.at("when").atom == "after") {
- when = AFTER;
- } else if (data.at("when").atom == "on") {
- when = ON;
- }
- }
-
- if (data.hasKey("action")) {
- if (false) {
- } else if (data.at("action").atom == "enter") {
- action = ENTER;
- } else if (data.at("action").atom == "exit") {
- action = EXIT;
- } else if (data.at("action").atom == "invoke") {
- action = INVOKE;
- } else if (data.at("action").atom == "cancel") {
- action = UNINVOKE;
- }
- }
-
- if (data.hasKey("subject")) {
- if (false) {
- } else if (data.at("subject").atom == "state") {
- subject = STATE;
- } else if (data.at("subject").atom == "transition") {
- subject = TRANSITION;
- } else if (data.at("subject").atom == "stable") {
- subject = STABLE;
- } else if (data.at("subject").atom == "microstep") {
- subject = MICROSTEP;
- } else if (data.at("subject").atom == "event") {
- subject = EVENT;
- } else if (data.at("subject").atom == "invoker") {
- subject = INVOKER;
- } else if (data.at("subject").atom == "executable") {
- subject = EXECUTABLE;
- }
- }
-
- if (data.hasKey("condition"))
- condition = data.at("condition").atom;
-
- if (data.hasKey("invokeId"))
- invokeId = data.at("invokeId").atom;
-
- if (data.hasKey("invokeType"))
- invokeType = data.at("invokeType").atom;
-
- if (data.hasKey("eventName"))
- eventName = data.at("eventName").atom;
-
- if (data.hasKey("executableName"))
- executableName = data.at("executableName").atom;
-
- if (data.hasKey("executableXPath"))
- executableXPath = data.at("executableXPath").atom;
-
- if (data.hasKey("stateId"))
- stateId = data.at("stateId").atom;
-
- if (data.hasKey("transSourceId"))
- transSourceId = data.at("transSourceId").atom;
-
- if (data.hasKey("transTargetId"))
- transTargetId = data.at("transTargetId").atom;
-
-}
-
-Data Breakpoint::toData() const {
- Data data;
-
- switch (subject) {
- case STATE:
- data.compound["subject"] = Data("state", Data::VERBATIM);
- break;
- case TRANSITION:
- data.compound["subject"] = Data("transition", Data::VERBATIM);
- break;
- case STABLE:
- data.compound["subject"] = Data("stable", Data::VERBATIM);
- break;
- case MICROSTEP:
- data.compound["subject"] = Data("microstep", Data::VERBATIM);
- break;
- case EVENT:
- data.compound["subject"] = Data("event", Data::VERBATIM);
- break;
- case INVOKER:
- data.compound["subject"] = Data("invoker", Data::VERBATIM);
- break;
- case EXECUTABLE:
- data.compound["subject"] = Data("executable", Data::VERBATIM);
- break;
- default:
- break;
- }
-
- switch (when) {
- case AFTER:
- data.compound["when"] = Data("after", Data::VERBATIM);
- break;
- case BEFORE:
- data.compound["when"] = Data("before", Data::VERBATIM);
- break;
- case ON:
- data.compound["when"] = Data("on", Data::VERBATIM);
- break;
- default:
- break;
- }
-
- switch (action) {
- case ENTER:
- data.compound["action"] = Data("enter", Data::VERBATIM);
- break;
- case EXIT:
- data.compound["action"] = Data("exit", Data::VERBATIM);
- break;
- case INVOKE:
- data.compound["action"] = Data("invoke", Data::VERBATIM);
- break;
- case UNINVOKE:
- data.compound["action"] = Data("cancel", Data::VERBATIM);
- break;
- default:
- break;
- }
-
- if (invokeId.length() > 0)
- data.compound["invokeId"] = Data(invokeId, Data::VERBATIM);
-
- if (invokeType.length() > 0)
- data.compound["invokeType"] = Data(invokeType, Data::VERBATIM);
-
- if (eventName.length() > 0)
- data.compound["eventName"] = Data(eventName, Data::VERBATIM);
-
- if (executableName.length() > 0)
- data.compound["executableName"] = Data(executableName, Data::VERBATIM);
-
- if (executableXPath.length() > 0) {
- data.compound["executableXPath"] = Data(executableXPath, Data::VERBATIM);
- }
-
- if (element)
- data.compound["xpath"] = Data(DOMUtils::xPathForNode(element, "*"), Data::VERBATIM);
-
- if (stateId.length() > 0)
- data.compound["stateId"] = Data(stateId, Data::VERBATIM);
-
- if (transSourceId.length() > 0)
- data.compound["transSourceId"] = Data(transSourceId, Data::VERBATIM);
-
- if (transTargetId.length() > 0)
- data.compound["transTargetId"] = Data(transTargetId, Data::VERBATIM);
-
- if (condition.length() > 0)
- data.compound["condition"] = Data(condition, Data::VERBATIM);
-
- return data;
-}
-
-bool Breakpoint::matches(Interpreter interpreter, const Breakpoint& other) const {
- // would we match the given breakpoint?
-
- if (subject != UNDEF_SUBJECT &&
- other.subject != subject)
- return false; // subject does not match
-
- if (when != UNDEF_WHEN &&
- other.when != when)
- return false; // time does not match
-
- if (action != UNDEF_ACTION &&
- other.action != action)
- return false; // action does not match
-
- // when we have a qualifier it has to match
- if(invokeId.length() > 0 && invokeId != other.invokeId) {
- return false;
- }
-
- if(invokeType.length() > 0 && invokeType != other.invokeType) {
- return false;
- }
-
- if(stateId.length() > 0 && stateId != other.stateId) {
- return false;
- }
-
- if(eventName.length() > 0 && !nameMatch(eventName, other.eventName)) {
- return false;
- }
-
- if(executableName.length() > 0 && executableName != other.executableName) {
- return false;
- }
-
- if(executableXPath.length()) {
- Arabica::XPath::NodeSet<std::string> nodes;
- try {
- nodes = interpreter.getNodeSetForXPath(executableXPath);
- } catch (...) {
- return false;
- }
- return InterpreterImpl::isMember(other.element, nodes);
- }
-
- if(transSourceId.length() > 0 && transSourceId != other.transSourceId) {
- return false;
- }
-
- if(transTargetId.length() > 0 && transTargetId != other.transTargetId) {
- return false;
- }
-
- if (condition.length() > 0) {
- try {
- DataModel dm = interpreter.getDataModel();
- if (!dm || !dm.evalAsBool(condition)) {
- return false;
- }
- } catch (...) {
- return false;
- }
- }
-
- return true;
-}
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/Breakpoint.h b/src/uscxml/debug/Breakpoint.h
deleted file mode 100644
index d7df03d..0000000
--- a/src/uscxml/debug/Breakpoint.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#ifndef BREAKPOINT_H_VR7K7T1X
-#define BREAKPOINT_H_VR7K7T1X
-
-#include <string> // for string
-#include "uscxml/Common.h" // for USCXML_API
-#include "uscxml/Interpreter.h"
-#include "DOM/Element.hpp" // for Element
-#include "uscxml/messages/Data.h" // for Data
-
-namespace uscxml {
-
-class USCXML_API Breakpoint {
-public:
-
- enum When {
- UNDEF_WHEN, AFTER, BEFORE, ON
- };
-
- enum Subject {
- UNDEF_SUBJECT, STATE, TRANSITION, STABLE, MICROSTEP, EVENT, INVOKER, EXECUTABLE
- };
-
- enum Action {
- UNDEF_ACTION, ENTER, EXIT, INVOKE, UNINVOKE
- };
-
- Breakpoint() {
- subject = UNDEF_SUBJECT;
- when = UNDEF_WHEN;
- action = UNDEF_ACTION;
- }
- Breakpoint(const Data& data);
-
- // would we match the given breakpoint as well?
- bool matches(Interpreter interpreter, const Breakpoint& other) const;
-
- Data toData() const;
-
- bool operator<(const Breakpoint& other) const {
- return (toData() < other.toData());
- }
-
- operator bool() {
- return (subject != UNDEF_SUBJECT ||
- when != UNDEF_WHEN ||
- action != UNDEF_ACTION);
- }
-
- mutable bool enabled;
-
- When when;
- Subject subject;
- Action action;
-
- Arabica::DOM::Element<std::string> element;
-
- std::string invokeId;
- std::string invokeType;
-
- std::string eventName;
-
- std::string executableName;
- std::string executableXPath;
-
- std::string stateId;
- std::string transSourceId;
- std::string transTargetId;
-
- std::string condition;
-};
-
-}
-
-
-
-#endif /* end of include guard: BREAKPOINT_H_VR7K7T1X */
diff --git a/src/uscxml/debug/Complexity.cpp b/src/uscxml/debug/Complexity.cpp
deleted file mode 100644
index 232260c..0000000
--- a/src/uscxml/debug/Complexity.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
-* @file
-* @author 2012-2015 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
-* @copyright Simplified BSD
-*
-* @cond
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the FreeBSD license as published by the FreeBSD
-* project.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*
-* You should have received a copy of the FreeBSD license along with this
-* program. If not, see <http://www.opensource.org/licenses/bsd-license>.
-* @endcond
-*/
-
-#include "Complexity.h"
-#include "uscxml/dom/DOMUtils.h"
-
-#include <boost/algorithm/string.hpp>
-
-namespace uscxml {
-
-using namespace Arabica::DOM;
-using namespace Arabica::XPath;
-
-std::list<std::set<Element<std::string> > > Complexity::getAllConfigurations(const Arabica::DOM::Element<std::string>& root) {
-
- std::list<std::set<Element<std::string> > > allConfigurations;
- std::string nsPrefix = (root.getPrefix().size() > 0 ? root.getPrefix() + ":" : "");
- std::string localName = root.getLocalName();
- bool isAtomic = true;
-
- NodeList<std::string> children = root.getChildNodes();
- for (size_t i = 0; i < children.getLength(); i++) {
- if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- Element<std::string> childElem(children.item(i));
- if (childElem.getTagName() == nsPrefix + "state" ||
- childElem.getTagName() == nsPrefix + "parallel" ||
- childElem.getTagName() == nsPrefix + "final") {
- // nested child state
- std::list<std::set<Element<std::string> > > nestedConfigurations = getAllConfigurations(childElem);
- isAtomic = false;
- if (localName == "parallel" && allConfigurations.size() > 0) {
- // for every nested configuration, every new nested is valid
- std::list<std::set<Element<std::string> > > combinedConfigurations;
- for (std::list<std::set<Element<std::string> > >::iterator existIter = allConfigurations.begin(); existIter != allConfigurations.end(); existIter++) {
- std::set<Element<std::string> > existingConfig = *existIter;
-
- for (std::list<std::set<Element<std::string> > >::iterator newIter = nestedConfigurations.begin(); newIter != nestedConfigurations.end(); newIter++) {
-
- std::set<Element<std::string> > newConfig = *newIter;
- std::set<Element<std::string> > combinedSet;
- combinedSet.insert(existingConfig.begin(), existingConfig.end());
- combinedSet.insert(newConfig.begin(), newConfig.end());
-
- combinedConfigurations.push_back(combinedSet);
- }
- }
- allConfigurations = combinedConfigurations;
- } else {
- // just add nested configurations and this
- for (std::list<std::set<Element<std::string> > >::iterator newIter = nestedConfigurations.begin(); newIter != nestedConfigurations.end(); newIter++) {
- std::set<Element<std::string> > newConfig = *newIter;
- if (localName != "scxml")
- newConfig.insert(root);
- allConfigurations.push_back(newConfig);
- }
- }
- }
- }
-
- if (isAtomic) {
- std::set<Element<std::string> > soleConfig;
- soleConfig.insert(root);
- allConfigurations.push_back(soleConfig);
- }
- return allConfigurations;
-}
-
-std::map<size_t, size_t> Complexity::getTransitionHistogramm(const Arabica::DOM::Element<std::string>& root) {
- std::map<size_t, size_t> histogram;
- std::string nameSpace;
-
- std::list<std::set<Element<std::string> > > allConfig = Complexity::getAllConfigurations(root);
-
- // for every legal configuration, count the transitions
- for (std::list<std::set<Element<std::string> > >::iterator confIter = allConfig.begin(); confIter != allConfig.end(); confIter++) {
- NodeSet<std::string> configNodeSet;
- std::set<Element<std::string> > config = *confIter;
- for (std::set<Element<std::string> >::iterator elemIter = config.begin(); elemIter != config.end(); elemIter++) {
- configNodeSet.push_back(*elemIter);
- if (nameSpace.size() == 0 && elemIter->getPrefix().size() > 0)
- nameSpace = elemIter->getPrefix() + ":";
- }
- NodeSet<std::string> transitions = DOMUtils::filterChildElements(nameSpace + "transition", configNodeSet);
- histogram[transitions.size()]++;
- }
-
- return histogram;
-}
-
-
-uint64_t Complexity::stateMachineComplexity(InterpreterImpl* interpreter, Variant variant) {
- Arabica::DOM::Element<std::string> root = interpreter->getDocument().getDocumentElement();
-
- Arabica::XPath::NodeSet<std::string> reachable;
-
- if (variant & IGNORE_UNREACHABLE) {
- reachable = interpreter->getReachableStates();
- }
-
- Complexity complexity = calculateStateMachineComplexity(root, reachable);
- uint64_t value = complexity.value;
-
- if (!(variant & IGNORE_HISTORY)) {
- for (std::list<uint64_t>::const_iterator histIter = complexity.history.begin(); histIter != complexity.history.end(); histIter++) {
- value *= *histIter;
- }
- }
-
- if (!(variant & IGNORE_NESTED_DATA)) {
- bool ignoreNestedData = false;
- if (root.getLocalName() == "scxml" && (!HAS_ATTR_CAST(root, "binding") || boost::to_lower_copy(ATTR_CAST(root, "binding")) == "early")) {
- ignoreNestedData = true;
- }
-
- if (!ignoreNestedData) {
- uint64_t power = complexity.nestedData;
- while(power--) {
- value *= 2;
- }
- }
- }
-
- return value;
-}
-
-Complexity Complexity::calculateStateMachineComplexity(const Arabica::DOM::Element<std::string>& root, const Arabica::XPath::NodeSet<std::string>& reachable) {
- Complexity complexity;
-
- bool hasFlatHistory = false;
- bool hasDeepHistory = false;
- bool hasNestedData = false;
-
- Arabica::DOM::NodeList<std::string> childElems = root.getChildNodes();
- for (size_t i = 0; i < childElems.getLength(); i++) {
- if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- Element<std::string> childElem = Element<std::string>(childElems.item(i));
- if (InterpreterImpl::isHistory(childElem)) {
- if (HAS_ATTR(childElem, "type") && ATTR(childElem, "type") == "deep") {
- hasDeepHistory = true;
- } else {
- hasFlatHistory = true;
- }
- }
- if (!hasNestedData && childElem.getLocalName() == "datamodel") {
- Arabica::DOM::NodeList<std::string> dataElemChilds = childElem.getChildNodes();
- for (size_t j = 0; j < dataElemChilds.getLength(); j++) {
- if (dataElemChilds.item(j).getLocalName() == "data")
- hasNestedData = true;
- }
- }
- }
-
- if (hasNestedData)
- complexity.nestedData++;
-
- if (reachable.size() > 0 && !InterpreterImpl::isMember(root, reachable)) {
- return 0;
- } else if (InterpreterImpl::isCompound(root) || TAGNAME(root) == "scxml") {
- // compounds can be in any of the child state -> add
- NodeSet<std::string> childs = InterpreterImpl::getChildStates(root);
- for (size_t i = 0; i < childs.size(); i++) {
- complexity += calculateStateMachineComplexity(Element<std::string>(childs[i]), reachable);
- }
- if (hasFlatHistory) {
- complexity.history.push_back(childs.size());
- }
- if (hasDeepHistory) {
- complexity.history.push_back(complexity.value);
- }
- } else if (InterpreterImpl::isParallel(root)) {
- // parallels are in all states -> multiply
- NodeSet<std::string> childs = InterpreterImpl::getChildStates(root);
- complexity.value = 1;
- for (size_t i = 0; i < childs.size(); i++) {
- complexity *= calculateStateMachineComplexity(Element<std::string>(childs[i]), reachable);
- }
- if (hasDeepHistory) {
- complexity.history.push_back(complexity.value);
- }
-
- } else if (InterpreterImpl::isAtomic(root)) {
- return 1;
- }
-
- return complexity;
-}
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/Complexity.h b/src/uscxml/debug/Complexity.h
deleted file mode 100644
index de05692..0000000
--- a/src/uscxml/debug/Complexity.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * @file
- * @author 2012-2015 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#ifndef COMPLEXITY_H_F972C065
-#define COMPLEXITY_H_F972C065
-
-#include "uscxml/Common.h" // for USCXML_API
-#include "uscxml/Interpreter.h"
-
-namespace uscxml {
-
-class USCXML_API Complexity {
-public:
-
- enum Variant {
- IGNORE_NOTHING = 0x0000,
- IGNORE_HISTORY = 0x0001,
- IGNORE_NESTED_DATA = 0x0002,
- IGNORE_UNREACHABLE = 0x0004,
- };
-
- Complexity() : value(0), nestedData(0) {}
- Complexity(uint64_t value) : value(value), nestedData(0) {}
-
- Complexity& operator+=(const Complexity& rhs) {
- value += rhs.value;
- nestedData += rhs.nestedData;
- history.insert(history.end(), rhs.history.begin(), rhs.history.end());
- return *this;
- }
-
- Complexity& operator*=(const Complexity& rhs) {
- value *= rhs.value;
- nestedData += rhs.nestedData;
- history.insert(history.end(), rhs.history.begin(), rhs.history.end());
- return *this;
- }
-
- static uint64_t stateMachineComplexity(const Interpreter& interpreter, Complexity::Variant variant = IGNORE_NOTHING) {
- return stateMachineComplexity(interpreter.getImpl().get());
- }
- static uint64_t stateMachineComplexity(InterpreterImpl* interpreter, Complexity::Variant variant = IGNORE_NOTHING);
-
- static std::list<std::set<Arabica::DOM::Element<std::string> > > getAllConfigurations(const Arabica::DOM::Element<std::string>& root);
- static std::map<size_t, size_t> getTransitionHistogramm(const Arabica::DOM::Element<std::string>& root);
-
-protected:
- static Complexity calculateStateMachineComplexity(const Arabica::DOM::Element<std::string>& root, const Arabica::XPath::NodeSet<std::string>& reachable);
-
- uint64_t value;
- uint64_t nestedData;
- std::list<uint64_t> history;
-};
-
-inline Complexity::Variant operator | ( Complexity::Variant lhs, Complexity::Variant rhs ) {
- // Cast to int first otherwise we'll just end up recursing
- return static_cast< Complexity::Variant >( static_cast< int >( lhs ) | static_cast< int >( rhs ) );
-}
-
-}
-
-#endif /* end of include guard: COMPLEXITY_H_F972C065 */
diff --git a/src/uscxml/debug/DebugSession.cpp b/src/uscxml/debug/DebugSession.cpp
deleted file mode 100644
index 6e81563..0000000
--- a/src/uscxml/debug/DebugSession.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#include "uscxml/debug/DebugSession.h"
-#include "uscxml/debug/Debugger.h"
-
-namespace uscxml {
-
-void DebugSession::checkBreakpoints(const std::list<Breakpoint> qualifiedBreakpoints) {
- std::list<Breakpoint>::const_iterator qualifiedBreakpointIter = qualifiedBreakpoints.begin();
-
- if (!_breakpointsEnabled)
- return;
-
- while(qualifiedBreakpointIter != qualifiedBreakpoints.end()) {
- const Breakpoint& qualifiedBreakpoint = *qualifiedBreakpointIter++;
-
- // check if one of the user-supplied breakpoints match
- bool userBreakpointMatched = false;
- Data replyData;
-
- if (_skipTo) {
- if (_skipTo.matches(_interpreter, qualifiedBreakpoint)) {
- replyData.compound["breakpoint"] = _skipTo.toData();
- replyData.compound["qualified"] = qualifiedBreakpoint.toData();
- breakExecution(replyData);
- _skipTo = Breakpoint();
- }
- continue;
- }
-
- std::set<Breakpoint>::const_iterator breakpointIter = _breakPoints.begin();
- while(breakpointIter != _breakPoints.end()) {
- const Breakpoint& breakpoint = *breakpointIter++;
- if (!breakpoint.enabled)
- continue;
- if (breakpoint.matches(_interpreter, qualifiedBreakpoint)) {
- // do we have a condition?
-
- replyData.compound["breakpoint"] = breakpoint.toData();
- replyData.compound["qualified"] = qualifiedBreakpoint.toData();
-
- userBreakpointMatched = true;
- breakExecution(replyData);
- }
- }
- if (_isStepping && !userBreakpointMatched) {
- replyData.compound["qualified"] = qualifiedBreakpoint.toData();
- breakExecution(replyData);
-
- }
- }
-}
-
-void DebugSession::breakExecution(Data replyData) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- Arabica::XPath::NodeSet<std::string> basicConf = _interpreter.getBasicConfiguration();
- for (size_t i = 0; i < basicConf.size(); i++) {
- Arabica::DOM::Element<std::string> element = Arabica::DOM::Element<std::string>(basicConf[i]);
- if (element.hasAttribute("id")) {
- replyData.compound["basicStates"].array.push_back(Data(element.getAttribute("id"), Data::VERBATIM));
- }
- }
-
- Arabica::XPath::NodeSet<std::string> activeConf = _interpreter.getConfiguration();
- for (size_t i = 0; i < activeConf.size(); i++) {
- Arabica::DOM::Element<std::string> element = Arabica::DOM::Element<std::string>(activeConf[i]);
- if (element.hasAttribute("id")) {
- replyData.compound["activeStates"].array.push_back(Data(element.getAttribute("id"), Data::VERBATIM));
- }
- }
-
- replyData.compound["replyType"] = Data("breakpoint", Data::VERBATIM);
- _debugger->pushData(shared_from_this(), replyData);
- _resumeCond.wait(_mutex);
-}
-
-Data DebugSession::debugPrepare(const Data& data) {
- Data replyData;
-
- if (!data.hasKey("xml") && !data.hasKey("url")) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No XML or URL given", Data::VERBATIM);
- return replyData;
- }
-
- debugStop(data);
-
- _isAttached = false;
-
- if (data.hasKey("xml")) {
- _interpreter = Interpreter::fromXML(data.at("xml").atom, "");
- } else if (data.hasKey("url")) {
- _interpreter = Interpreter::fromURL(data.at("url").atom);
- } else {
- _interpreter = Interpreter();
- }
-
- if (_interpreter) {
- // register ourself as a monitor
- _interpreter.addMonitor(_debugger);
- _debugger->attachSession(_interpreter, shared_from_this());
- if (data.hasKey("url")) {
- // this allows to resolve relative external reources
- _interpreter.setSourceURL(data.at("url").atom);
- }
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
-
- return replyData;
-}
-
-Data DebugSession::debugAttach(const Data& data) {
- Data replyData;
- _isAttached = true;
-
- if (!data.hasKey("attach")) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No id to attach to given", Data::VERBATIM);
- return replyData;
- }
-
- std::string interpreterId = data.at("attach").atom;
- bool interpreterFound = false;
-
- // find interpreter for sessionid
- std::map<std::string, boost::weak_ptr<InterpreterImpl> > instances = Interpreter::getInstances();
- for (std::map<std::string, boost::weak_ptr<InterpreterImpl> >::iterator instIter = instances.begin();
- instIter != instances.end();
- instIter++) {
-
- boost::shared_ptr<InterpreterImpl> instance = instIter->second.lock();
- if (instance && instance->getSessionId() == interpreterId) {
- _interpreter = instance;
- _debugger->attachSession(_interpreter, shared_from_this());
- interpreterFound = true;
- break;
- }
- }
-
- if (!interpreterFound) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No interpreter with given id found", Data::VERBATIM);
- } else {
- replyData.compound["xml"].node = _interpreter.getDocument();
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- }
-
- return replyData;
-}
-
-Data DebugSession::debugDetach(const Data& data) {
- Data replyData;
- _isAttached = false;
-
- _debugger->detachSession(_interpreter);
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- return replyData;
-}
-
-Data DebugSession::debugStart(const Data& data) {
- Data replyData;
-
- if (_isAttached) {
- replyData.compound["reason"] = Data("Already started when attached", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- } else if (!_interpreter) {
- replyData.compound["reason"] = Data("No interpreter attached or loaded", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- } else {
- _interpreter.start();
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- }
-
- return replyData;
-}
-
-Data DebugSession::debugStop(const Data& data) {
- Data replyData;
-
- if (_interpreter) {
- // detach from old intepreter
- _debugger->detachSession(_interpreter);
- }
-
- if (_interpreter && !_isAttached)
- _interpreter.stop();
- // unblock
- _resumeCond.notify_all();
-
- _skipTo = Breakpoint();
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- // calls destructor
- _interpreter = Interpreter();
-
- return replyData;
-}
-
-Data DebugSession::debugStep(const Data& data) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- stepping(true);
- _resumeCond.notify_one();
-
- Data replyData;
- if (_interpreter) {
- // register ourself as a monitor
- if (!_interpreter.isRunning())
- _interpreter.start();
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
- return replyData;
-}
-
-Data DebugSession::debugResume(const Data& data) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- stepping(false);
-
- Data replyData;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- _resumeCond.notify_one();
- return replyData;
-}
-
-
-Data DebugSession::debugPause(const Data& data) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- _skipTo = Breakpoint();
- stepping(true);
-
- Data replyData;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- return replyData;
-}
-
-Data DebugSession::skipToBreakPoint(const Data& data) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- _skipTo = Breakpoint(data);
-
- Data replyData;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- _resumeCond.notify_one();
- return replyData;
-}
-
-Data DebugSession::addBreakPoint(const Data& data) {
- Breakpoint breakpoint(data);
-
- Data replyData;
- if (_breakPoints.find(breakpoint) == _breakPoints.end()) {
- _breakPoints.insert(breakpoint);
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- } else {
- replyData.compound["reason"] = Data("Breakpoint already exists", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
- return replyData;
-}
-
-Data DebugSession::removeBreakPoint(const Data& data) {
- Breakpoint breakpoint(data);
-
- Data replyData;
- if (_breakPoints.find(breakpoint) != _breakPoints.end()) {
- _breakPoints.erase(breakpoint);
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["reason"] = Data("No such breakpoint", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
- return replyData;
-}
-
-Data DebugSession::enableBreakPoint(const Data& data) {
- Breakpoint breakpoint(data);
-
- Data replyData;
- if (_breakPoints.find(breakpoint) != _breakPoints.end()) {
- _breakPoints.find(breakpoint)->enabled = true;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["reason"] = Data("No such breakpoint", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
-
- return replyData;
-}
-Data DebugSession::disableBreakPoint(const Data& data) {
- Breakpoint breakpoint(data);
-
- Data replyData;
- if (_breakPoints.find(breakpoint) != _breakPoints.end()) {
- _breakPoints.find(breakpoint)->enabled = false;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- } else {
- replyData.compound["reason"] = Data("No such breakpoint", Data::VERBATIM);
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- }
-
- return replyData;
-}
-Data DebugSession::enableAllBreakPoints() {
- Data replyData;
-
- _breakpointsEnabled = true;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- return replyData;
-}
-Data DebugSession::disableAllBreakPoints() {
- Data replyData;
-
- _breakpointsEnabled = false;
- replyData.compound["status"] = Data("success", Data::VERBATIM);
-
- return replyData;
-}
-
-Data DebugSession::debugEval(const Data& data) {
- Data replyData;
-
- if (!data.hasKey("expression")) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No expression given", Data::VERBATIM);
- return replyData;
- }
-
- std::string expr = data.at("expression").atom;
-
- if (!_interpreter) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No interpreter running", Data::VERBATIM);
- } else if (!_interpreter.getDataModel()) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No datamodel available", Data::VERBATIM);
- } else {
- try {
- replyData.compound["eval"] = _interpreter.getDataModel().getStringAsData(expr);
- } catch (Event e) {
- replyData.compound["eval"] = e.data;
- replyData.compound["eval"].compound["error"] = Data(e.name, Data::VERBATIM);
- }
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- }
- return replyData;
-}
-
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/DebugSession.h b/src/uscxml/debug/DebugSession.h
deleted file mode 100644
index 1fb4f4d..0000000
--- a/src/uscxml/debug/DebugSession.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#ifndef DEBUGSESSION_H_M8YHEGV6
-#define DEBUGSESSION_H_M8YHEGV6
-
-#include "uscxml/debug/Breakpoint.h"
-#include "uscxml/Interpreter.h"
-#include <time.h>
-
-namespace uscxml {
-
-class Debugger;
-
-class USCXML_API DebugSession : public boost::enable_shared_from_this<DebugSession> {
-public:
- DebugSession() {
- _isStepping = false;
- _isAttached = false;
- _breakpointsEnabled = true;
- _markedForDeletion = false;
- _debugger = NULL;
- }
-
- void stepping(bool enable) {
- _isStepping = enable;
- }
-
- void checkBreakpoints(const std::list<Breakpoint> qualifiedBreakpoints);
-
- Data debugPrepare(const Data& data);
- Data debugAttach(const Data& data);
- Data debugDetach(const Data& data);
- Data debugStart(const Data& data);
- Data debugStop(const Data& data);
- Data debugStep(const Data& data);
- Data debugResume(const Data& data);
- Data debugPause(const Data& data);
- Data skipToBreakPoint(const Data& data);
- Data addBreakPoint(const Data& data);
- Data removeBreakPoint(const Data& data);
- Data enableBreakPoint(const Data& data);
- Data disableBreakPoint(const Data& data);
- Data enableAllBreakPoints();
- Data disableAllBreakPoints();
- Data debugEval(const Data& data);
-
- void setDebugger(Debugger* debugger) {
- _debugger = debugger;
- }
-
- Interpreter getInterpreter() {
- return _interpreter;
- }
-
- void markForDeletion(bool mark) {
- _markedForDeletion = mark;
- }
-
-protected:
- void breakExecution(Data replyData);
-
- bool _isStepping;
- bool _isAttached;
- bool _breakpointsEnabled;
-
- tthread::condition_variable _resumeCond;
- tthread::recursive_mutex _runMutex;
- tthread::recursive_mutex _mutex;
-
- bool _markedForDeletion;
- Debugger* _debugger;
- Interpreter _interpreter;
- std::set<Breakpoint> _breakPoints;
- Breakpoint _skipTo;
-
-};
-
-
-}
-
-
-#endif /* end of include guard: DEBUGSESSION_H_M8YHEGV6 */
diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp
deleted file mode 100644
index f8b13fe..0000000
--- a/src/uscxml/debug/Debugger.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
-* @file
-* @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
-* @copyright Simplified BSD
-*
-* @cond
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the FreeBSD license as published by the FreeBSD
-* project.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*
-* You should have received a copy of the FreeBSD license along with this
-* program. If not, see <http://www.opensource.org/licenses/bsd-license>.
-* @endcond
-*/
-
-#include "uscxml/debug/Debugger.h"
-#include "uscxml/dom/DOMUtils.h"
-#include "uscxml/debug/DebugSession.h"
-
-namespace uscxml {
-
-void Debugger::afterCompletion(Interpreter interpreter) {
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- Data msg;
- msg.compound["replyType"] = Data("finished", Data::VERBATIM);
- pushData(session, msg);
-}
-
-std::list<Breakpoint> getQualifiedStateBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, Breakpoint breakpointTemplate) {
- std::list<Breakpoint> breakpoints;
-
- Breakpoint bp = breakpointTemplate; // copy base as template
- bp.stateId = ATTR(state, "id");
- bp.element = state;
- bp.subject = Breakpoint::STATE;
- breakpoints.push_back(bp);
-
- return breakpoints;
-}
-
-std::list<Breakpoint> getQualifiedInvokeBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string invokeId, Breakpoint breakpointTemplate) {
- std::list<Breakpoint> breakpoints;
-
- Breakpoint bp = breakpointTemplate; // copy base as template
- bp.subject = Breakpoint::INVOKER;
- bp.element = invokeElem;
- bp.invokeId = invokeId;
-
- if (HAS_ATTR(invokeElem, "type")) {
- bp.invokeType = ATTR(invokeElem, "type");
- } else if (HAS_ATTR(invokeElem, "typeexpr")) {
- bp.invokeType = interpreter.getDataModel().evalAsString(ATTR(invokeElem, "typeexpr"));
- }
-
- breakpoints.push_back(bp);
-
- return breakpoints;
-}
-
-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.getImpl()->getSourceState(transition));
- Arabica::XPath::NodeSet<std::string> targets = interpreter.getImpl()->getTargetStates(transition);
-
- for (size_t j = 0; j < targets.size(); j++) {
- Arabica::DOM::Element<std::string> target(targets[j]);
-
- Breakpoint bp = breakpointTemplate; // copy base as template
- bp.element = transition;
- bp.transSourceId = ATTR(source, "id");
- bp.transTargetId = ATTR(target, "id");
- bp.subject = Breakpoint::TRANSITION;
-
- breakpoints.push_back(bp);
- }
-
- return breakpoints;
-}
-
-void Debugger::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) {
- handleTransition(interpreter, transition, Breakpoint::BEFORE);
-}
-void Debugger::afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) {
- handleTransition(interpreter, transition, Breakpoint::AFTER);
-}
-void Debugger::beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& content) {
- handleExecutable(interpreter, Arabica::DOM::Element<std::string>(content), Breakpoint::BEFORE);
-}
-void Debugger::afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& content) {
- handleExecutable(interpreter, Arabica::DOM::Element<std::string>(content), Breakpoint::AFTER);
-}
-void Debugger::beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
- handleState(interpreter, state, Breakpoint::BEFORE, Breakpoint::EXIT);
-}
-void Debugger::afterExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
- handleState(interpreter, state, Breakpoint::AFTER, Breakpoint::EXIT);
-}
-void Debugger::beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
- handleState(interpreter, state, Breakpoint::BEFORE, Breakpoint::ENTER);
-}
-void Debugger::afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing) {
- handleState(interpreter, state, Breakpoint::AFTER, Breakpoint::ENTER);
-}
-void Debugger::beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
- handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::BEFORE, Breakpoint::UNINVOKE);
-}
-void Debugger::afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
- handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::AFTER, Breakpoint::UNINVOKE);
-}
-void Debugger::beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
- handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::BEFORE, Breakpoint::INVOKE);
-}
-void Debugger::afterInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
- handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::AFTER, Breakpoint::INVOKE);
-}
-void Debugger::onStableConfiguration(Interpreter interpreter) {
- handleStable(interpreter, Breakpoint::ON);
-}
-void Debugger::beforeMicroStep(Interpreter interpreter) {
- handleMicrostep(interpreter, Breakpoint::BEFORE);
-}
-void Debugger::afterMicroStep(Interpreter interpreter) {
- handleMicrostep(interpreter, Breakpoint::AFTER);
-}
-void Debugger::beforeProcessingEvent(Interpreter interpreter, const Event& event) {
- handleEvent(interpreter, event, Breakpoint::BEFORE);
-}
-
-void Debugger::handleExecutable(Interpreter interpreter,
- const Arabica::DOM::Element<std::string>& execContentElem,
- Breakpoint::When when) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- std::list<Breakpoint> breakpoints;
-
- Breakpoint breakpoint;
- breakpoint.when = when;
- breakpoint.element = execContentElem;
- breakpoint.executableName = execContentElem.getLocalName();
- breakpoint.subject = Breakpoint::EXECUTABLE;
- breakpoints.push_back(breakpoint);
-
- session->checkBreakpoints(breakpoints);
-
-}
-
-void Debugger::handleEvent(Interpreter interpreter, const Event& event, Breakpoint::When when) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- std::list<Breakpoint> breakpoints;
-
- Breakpoint breakpoint;
- breakpoint.when = when;
- breakpoint.eventName = event.name;
- breakpoint.subject = Breakpoint::EVENT;
- breakpoints.push_back(breakpoint);
-
- session->checkBreakpoints(breakpoints);
-
-}
-
-void Debugger::handleStable(Interpreter interpreter, Breakpoint::When when) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- std::list<Breakpoint> breakpoints;
-
- Breakpoint breakpoint;
- breakpoint.when = when;
- breakpoint.subject = Breakpoint::STABLE;
- breakpoints.push_back(breakpoint);
-
- session->checkBreakpoints(breakpoints);
-}
-
-void Debugger::handleMicrostep(Interpreter interpreter, Breakpoint::When when) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- std::list<Breakpoint> breakpoints;
-
- Breakpoint breakpoint;
- breakpoint.when = when;
- breakpoint.subject = Breakpoint::MICROSTEP;
- breakpoints.push_back(breakpoint);
-
- session->checkBreakpoints(breakpoints);
-}
-
-void Debugger::handleTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, Breakpoint::When when) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- Breakpoint breakpointTemplate;
- breakpointTemplate.when = when;
- std::list<Breakpoint> qualifiedBreakpoints = getQualifiedTransBreakpoints(interpreter, transition, breakpointTemplate);
- session->checkBreakpoints(qualifiedBreakpoints);
-}
-
-void Debugger::handleState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, Breakpoint::When when, Breakpoint::Action action) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- Breakpoint breakpointTemplate;
- breakpointTemplate.when = when;
- breakpointTemplate.action = action;
- std::list<Breakpoint> qualifiedBreakpoints = getQualifiedStateBreakpoints(interpreter, state, breakpointTemplate);
- session->checkBreakpoints(qualifiedBreakpoints);
-
-}
-
-void Debugger::handleInvoke(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeId, Breakpoint::When when, Breakpoint::Action action) {
- if (!interpreter.isRunning())
- return;
- boost::shared_ptr<DebugSession> session = getSession(interpreter);
- if (!session)
- return;
-
- Breakpoint breakpointTemplate;
- breakpointTemplate.when = when;
- breakpointTemplate.action = action;
- std::list<Breakpoint> qualifiedBreakpoints = getQualifiedInvokeBreakpoints(interpreter, invokeElem, invokeId, breakpointTemplate);
- session->checkBreakpoints(qualifiedBreakpoints);
-
-}
-
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/Debugger.h b/src/uscxml/debug/Debugger.h
deleted file mode 100644
index 03846e5..0000000
--- a/src/uscxml/debug/Debugger.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#ifndef DEBUGGERMONITOR_H_Z050WPFH
-#define DEBUGGERMONITOR_H_Z050WPFH
-
-#include "uscxml/messages/Data.h" // for Data
-#include "uscxml/messages/Event.h" // for Event
-#include "uscxml/Interpreter.h"
-#include "uscxml/debug/Breakpoint.h"
-
-namespace uscxml {
-
-class DebugSession;
-
-class USCXML_API Debugger : public InterpreterMonitor {
-public:
- Debugger() {
- }
- virtual ~Debugger() {}
-
- virtual void attachSession(Interpreter interpreter, boost::shared_ptr<DebugSession> session) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_sessionMutex);
- _sessionForInterpreter[interpreter] = session;
- }
-
- virtual void detachSession(Interpreter interpreter) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_sessionMutex);
- _sessionForInterpreter.erase(interpreter);
- }
-
- virtual boost::shared_ptr<DebugSession> getSession(Interpreter interpreter) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_sessionMutex);
- if (_sessionForInterpreter.find(interpreter) != _sessionForInterpreter.end())
- return _sessionForInterpreter[interpreter];
- return boost::shared_ptr<DebugSession>();
- }
-
- virtual void pushData(boost::shared_ptr<DebugSession> session, Data pushData) = 0;
-
- // InterpreterMonitor
- virtual void beforeProcessingEvent(Interpreter interpreter, const Event& event);
- virtual void beforeMicroStep(Interpreter interpreter);
- virtual void beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing);
- virtual void afterExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing);
- virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element);
- virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element);
- virtual void beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
- virtual void afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
- virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing);
- virtual void afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing);
- virtual void beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing);
- virtual void afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing);
- virtual void beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
- virtual void afterInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
- virtual void afterMicroStep(Interpreter interpreter);
- virtual void onStableConfiguration(Interpreter interpreter);
- virtual void beforeCompletion(Interpreter interpreter) {}
- virtual void afterCompletion(Interpreter interpreter);
-
-protected:
-
- void handleTransition(Interpreter interpreter,
- const Arabica::DOM::Element<std::string>& transition,
- Breakpoint::When when);
- void handleState(Interpreter interpreter,
- const Arabica::DOM::Element<std::string>& state,
- Breakpoint::When when,
- Breakpoint::Action action);
- void handleInvoke(Interpreter interpreter,
- const Arabica::DOM::Element<std::string>& invokeElem,
- const std::string& invokeId,
- Breakpoint::When when,
- Breakpoint::Action action);
- void handleExecutable(Interpreter interpreter,
- const Arabica::DOM::Element<std::string>& execContentElem,
- Breakpoint::When when);
- void handleStable(Interpreter interpreter, Breakpoint::When when);
- void handleMicrostep(Interpreter interpreter, Breakpoint::When when);
- void handleEvent(Interpreter interpreter, const Event& event, Breakpoint::When when);
-
- tthread::recursive_mutex _sessionMutex;
- std::map<Interpreter, boost::shared_ptr<DebugSession> > _sessionForInterpreter;
-};
-
-}
-
-
-#endif /* end of include guard: DEBUGGERMONITOR_H_Z050WPFH */
diff --git a/src/uscxml/debug/DebuggerServlet.cpp b/src/uscxml/debug/DebuggerServlet.cpp
deleted file mode 100644
index 64426ff..0000000
--- a/src/uscxml/debug/DebuggerServlet.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#include "uscxml/debug/DebuggerServlet.h"
-#include "uscxml/debug/DebugSession.h"
-#include "uscxml/UUID.h"
-#include <boost/algorithm/string.hpp>
-
-namespace uscxml {
-
-void DebuggerServlet::pushData(boost::shared_ptr<DebugSession> session, Data pushData) {
- std::cout << "trying to push " << pushData.at("replyType").atom << std::endl;
-
- if (!session) {
- if (_sendQueues.size() > 0) // logging is not aware of its interpreter
- _sendQueues.begin()->second.push(pushData);
- } else {
- _sendQueues[session].push(pushData);
- }
-
- serverPushData(session);
-}
-
-void DebuggerServlet::serverPushData(boost::shared_ptr<DebugSession> session) {
- if (_sendQueues[session].isEmpty())
- return;
-
- if (!_clientConns[session])
- return;
-
- Data reply = _sendQueues[session].pop();
- std::cout << "pushing " << reply.at("replyType").atom << std::endl;
- returnData(_clientConns[session], reply);
- _clientConns[session] = HTTPServer::Request();
-}
-
-void DebuggerServlet::returnData(const HTTPServer::Request& request, Data replyData) {
- HTTPServer::Reply reply(request);
-
- if (!replyData.hasKey("status")) {
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- }
-
- std::cout << "<- " << replyData << std::endl;
-
- reply.content = Data::toJSON(replyData);
- reply.headers["Access-Control-Allow-Origin"] = "*";
- reply.headers["Content-Type"] = "application/json";
- HTTPServer::reply(reply);
-}
-
-bool DebuggerServlet::isCORS(const HTTPServer::Request& request) {
- return (request.data.at("type").atom == "options" &&
- request.data.at("header").hasKey("Origin") &&
- request.data.at("header").hasKey("Access-Control-Request-Method"));
-}
-
-void DebuggerServlet::handleCORS(const HTTPServer::Request& request) {
- HTTPServer::Reply corsReply(request);
- if (request.data.at("header").hasKey("Origin")) {
- corsReply.headers["Access-Control-Allow-Origin"] = request.data.at("header").at("Origin").atom;
- } else {
- corsReply.headers["Access-Control-Allow-Origin"] = "*";
- }
- if (request.data.at("header").hasKey("Access-Control-Request-Method"))
- corsReply.headers["Access-Control-Allow-Methods"] = request.data.at("header").at("Access-Control-Request-Method").atom;
- if (request.data.at("header").hasKey("Access-Control-Request-Headers"))
- corsReply.headers["Access-Control-Allow-Headers"] = request.data.at("header").at("Access-Control-Request-Headers").atom;
-
- // std::cout << "CORS!" << std::endl << request << std::endl;
- HTTPServer::reply(corsReply);
-}
-
-bool DebuggerServlet::httpRecvRequest(const HTTPServer::Request& request) {
- if (!request.data.hasKey("path"))
- return false; // returnError(request);
-
- if (isCORS(request)) {
- handleCORS(request);
- return true;
- }
-
- std::cout << request.data["path"] << ": " << request.data["content"] << std::endl;
-
- Data replyData;
- // process request that don't need a session
- if (false) {
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/connect")) {
- processConnect(request);
- return true;
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/sessions")) {
- processListSessions(request);
- return true;
- }
-
- // get session or return error
- if (false) {
- } else if (!request.data.at("content").hasKey("session")) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
- } else if (_sessionForId.find(request.data.at("content").at("session").atom) == _sessionForId.end()) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
- }
- if (!replyData.empty()) {
- returnData(request, replyData);
- return true;
- }
-
- boost::shared_ptr<DebugSession> session = _sessionForId[request.data.at("content").at("session").atom];
-
- if (false) {
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/poll")) {
- // save long-standing client poll
- _clientConns[session] = request;
- serverPushData(session);
-
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/disconnect")) {
- processDisconnect(request);
-
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/enable/all")) {
- replyData = session->enableAllBreakPoints();
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/disable/all")) {
- replyData = session->disableAllBreakPoints();
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/skipto")) {
- replyData = session->skipToBreakPoint(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/add")) {
- replyData = session->addBreakPoint(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/remove")) {
- replyData = session->removeBreakPoint(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/enable")) {
- replyData = session->enableBreakPoint(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/disable")) {
- replyData = session->disableBreakPoint(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/stop")) {
- replyData = session->debugStop(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/prepare")) {
- replyData = session->debugPrepare(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/attach")) {
- replyData = session->debugAttach(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/start")) {
- replyData = session->debugStart(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/step")) {
- replyData = session->debugStep(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/pause")) {
- replyData = session->debugPause(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/resume")) {
- replyData = session->debugResume(request.data["content"]);
- } else if (boost::starts_with(request.data.at("path").atom, "/debug/eval")) {
- replyData = session->debugEval(request.data["content"]);
- }
-
- if (!replyData.empty()) {
- returnData(request, replyData);
- return true;
- }
-
- return true;
-}
-
-// someone connected, create a new session
-void DebuggerServlet::processConnect(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- std::string sessionId = UUID::getUUID();
-
- _sessionForId[sessionId] = boost::shared_ptr<DebugSession>(new DebugSession());
- _sessionForId[sessionId]->setDebugger(this);
-
- Data replyData;
- replyData.compound["session"] = Data(sessionId, Data::VERBATIM);
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- returnData(request, replyData);
-}
-
-void DebuggerServlet::processDisconnect(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- Data replyData;
-
- if (!request.data.at("content").hasKey("session")) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
- returnData(request, replyData);
- }
-
- std::string sessionId = request.data.at("content").at("session").atom;
-
- if (_sessionForId.find(sessionId) == _sessionForId.end()) {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
- replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
- } else {
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- detachSession(_sessionForId[sessionId]->getInterpreter());
- _sessionForId[sessionId]->debugStop(request.data["content"]);
- _clientConns.erase(_sessionForId[sessionId]);
- _sendQueues.erase(_sessionForId[sessionId]);
- _sessionForId.erase(sessionId);
- }
-
- returnData(request, replyData);
-}
-
-void DebuggerServlet::processListSessions(const HTTPServer::Request& request) {
- Data replyData;
-
- std::map<std::string, boost::weak_ptr<InterpreterImpl> > instances = Interpreter::getInstances();
- for (std::map<std::string, boost::weak_ptr<InterpreterImpl> >::iterator instIter = instances.begin();
- instIter != instances.end();
- instIter++) {
-
- boost::shared_ptr<InterpreterImpl> instance = instIter->second.lock();
- if (instance) {
- Data sessionData;
- sessionData.compound["name"] = Data(instance->getName(), Data::VERBATIM);
- sessionData.compound["id"] = Data(instance->getSessionId(), Data::VERBATIM);
- sessionData.compound["source"] = Data(instance->getSourceURL(), Data::VERBATIM);
- sessionData.compound["xml"].node = instance->getDocument();
-
- replyData.compound["sessions"].array.push_back(sessionData);
- }
- }
-
- replyData.compound["status"] = Data("success", Data::VERBATIM);
- returnData(request, replyData);
-}
-
-void DebuggerServlet::send(google::LogSeverity severity, const char* full_filename,
- const char* base_filename, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len) {
-
- // _sendQueue is thread-safe, not sure about ToString though
-
- LogMessage msg(severity,
- full_filename,
- base_filename,
- line,
- tm_time,
- std::string(message, message_len),
- ToString(severity, base_filename, line, tm_time, message, message_len));
- msg.compound["replyType"] = Data("log", Data::VERBATIM);
- pushData(boost::shared_ptr<DebugSession>(), msg);
-}
-
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/DebuggerServlet.h b/src/uscxml/debug/DebuggerServlet.h
deleted file mode 100644
index 8abe741..0000000
--- a/src/uscxml/debug/DebuggerServlet.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * @file
- * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#ifndef DEBUGGERSERVLET_H_ATUMDA3G
-#define DEBUGGERSERVLET_H_ATUMDA3G
-
-#include "uscxml/Common.h"
-#include <glog/logging.h>
-
-#include "uscxml/server/HTTPServer.h"
-
-#include "uscxml/debug/Debugger.h"
-#include "uscxml/concurrency/tinythread.h"
-
-namespace uscxml {
-
-class USCXML_API DebuggerServlet : public Debugger, public HTTPServlet, public google::LogSink {
-public:
- class LogMessage : public Data {
- public:
- LogMessage(google::LogSeverity severity, const char* full_filename,
- const char* base_filename, int line,
- const struct ::tm* tm_time,
- std::string message, std::string formatted) {
-
- compound["severity"] = severity;
- compound["fullFilename"] = Data(full_filename, Data::VERBATIM);
- compound["baseFilename"] = Data(base_filename, Data::VERBATIM);
- compound["line"] = line;
- compound["message"] = Data(message, Data::VERBATIM);
- compound["time"] = Data(mktime((struct ::tm*)tm_time), Data::INTERPRETED);
- compound["formatted"] = Data(formatted, Data::VERBATIM);
- }
- };
-
- virtual ~DebuggerServlet() {}
-
- // from Debugger
- virtual void addBreakpoint(const Breakpoint& breakpoint) {};
-
- bool isCORS(const HTTPServer::Request& request);
- void handleCORS(const HTTPServer::Request& request);
-
- bool httpRecvRequest(const HTTPServer::Request& request);
- void setURL(const std::string& url) {
- _url = url;
- }
-
- void pushData(boost::shared_ptr<DebugSession> session, Data pushData);
- void returnData(const HTTPServer::Request& request, Data replyData);
-
- void processDisconnect(const HTTPServer::Request& request);
- void processConnect(const HTTPServer::Request& request);
- void processListSessions(const HTTPServer::Request& request);
-
-// void processDebugPrepare(const HTTPServer::Request& request);
-// void processDebugAttach(const HTTPServer::Request& request);
-// void processDebugStart(const HTTPServer::Request& request);
-// void processDebugStop(const HTTPServer::Request& request);
-
-// void processDebugEval(const HTTPServer::Request& request);
-// void processDebugStart(const HTTPServer::Request& request);
-// void processDebugStop(const HTTPServer::Request& request);
-// void processDebugStep(const HTTPServer::Request& request);
-// void processDebugResume(const HTTPServer::Request& request);
-// void processDebugPause(const HTTPServer::Request& request);
-// void processAddBreakPoint(const HTTPServer::Request& request);
-// void processRemoveBreakPoint(const HTTPServer::Request& request);
-// void processPoll(const HTTPServer::Request& request);
-
- // Logsink
- virtual void send(google::LogSeverity severity, const char* full_filename,
- const char* base_filename, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len);
-
-protected:
- void serverPushData(boost::shared_ptr<DebugSession>);
-
- std::string _url;
- std::map<boost::shared_ptr<DebugSession>, HTTPServer::Request> _clientConns;
- std::map<boost::shared_ptr<DebugSession>, concurrency::BlockingQueue<Data> > _sendQueues;
- std::map<std::string, boost::shared_ptr<DebugSession> > _sessionForId;
-
- tthread::recursive_mutex _mutex;
-};
-
-}
-
-#endif /* end of include guard: DEBUGGERSERVLET_H_ATUMDA3G */
diff --git a/src/uscxml/debug/InterpreterIssue.cpp b/src/uscxml/debug/InterpreterIssue.cpp
index 1bb14f6..ce61af6 100644
--- a/src/uscxml/debug/InterpreterIssue.cpp
+++ b/src/uscxml/debug/InterpreterIssue.cpp
@@ -20,67 +20,128 @@
#include <string>
#include "InterpreterIssue.h"
-#include "uscxml/dom/DOMUtils.h"
-#include "uscxml/debug/Complexity.h"
+#include "uscxml/util/DOM.h"
+#include "uscxml/util/String.h"
+#include "uscxml/util/Predicates.h"
+//#include "uscxml/debug/Complexity.h"
#include "uscxml/Interpreter.h"
-#include "uscxml/Factory.h"
+#include "uscxml/plugins/Factory.h"
-#include <XPath/XPath.hpp>
-#include <DOM/Document.hpp>
+#include <xercesc/dom/DOMDocument.hpp>
namespace uscxml {
-using namespace Arabica::XPath;
-using namespace Arabica::DOM;
+using namespace xercesc;
-InterpreterIssue::InterpreterIssue(const std::string& msg, Arabica::DOM::Node<std::string> node, IssueSeverity severity, const std::string& specRef) : message(msg), node(node), severity(severity), specRef(specRef) {
+InterpreterIssue::InterpreterIssue(const std::string& msg, DOMNode* node, IssueSeverity severity, const std::string& specRef) : message(msg), node(node), severity(severity), specRef(specRef) {
if (node)
xPath = DOMUtils::xPathForNode(node);
}
// find all elements in the SCXML namespace in one traversal
-void assembleNodeSets(const std::string nsPrefix, const Node<std::string>& node, std::map<std::string, NodeSet<std::string> >& sets) {
- NodeList<std::string> childs = node.getChildNodes();
- for (unsigned int i = 0; i < childs.getLength(); i++) {
- if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+void assembleNodeSets(const std::string nsPrefix, DOMNode* node, std::map<std::string, std::list<DOMElement*> >& sets) {
+ DOMNodeList* childs = node->getChildNodes();
+ for (unsigned int i = 0; i < childs->getLength(); i++) {
+ if (childs->item(i)->getNodeType() != DOMNode::ELEMENT_NODE)
continue;
// std::cout << TAGNAME(childs.item(i)) << std::endl;
- if (TAGNAME_CAST(childs.item(i)).find(nsPrefix) == 0) {
+ if (TAGNAME_CAST(childs->item(i)).find(nsPrefix) == 0) {
// correct namespace, insert via localname
- sets[LOCALNAME_CAST(childs.item(i))].push_back(childs.item(i));
+ sets[LOCALNAME_CAST(childs->item(i))].push_back(static_cast<DOMElement*>(childs->item(i)));
}
- assembleNodeSets(nsPrefix, childs.item(i), sets);
+ assembleNodeSets(nsPrefix, childs->item(i), sets);
}
}
+std::list<std::set<const DOMElement* > > getAllConfigurations(const DOMElement* root) {
+ std::list<std::set<const DOMElement* > > allConfigurations;
+ std::string nsPrefix = X(root->getPrefix());
+ std::string localName = X(root->getLocalName());
+ bool isAtomic = true;
+
+ std::cout << *root;
+
+ DOMNodeList* children = root->getChildNodes();
+ for (size_t i = 0; i < children->getLength(); i++) {
+ if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE)
+ continue;
+ DOMElement* childElem = static_cast<DOMElement*>(children->item(i));
+ std::cout << *childElem;
+
+ if (XMLString::compareIString(childElem->getTagName(), X(nsPrefix + "state")) == 0 ||
+ XMLString::compareIString(childElem->getTagName(), X(nsPrefix + "parallel")) == 0 ||
+ XMLString::compareIString(childElem->getTagName(), X(nsPrefix + "final")) == 0) {
+ // nested child state
+ std::list<std::set<const DOMElement*> > nestedConfigurations = getAllConfigurations(childElem);
+ isAtomic = false;
+ if (localName == "parallel" && allConfigurations.size() > 0) {
+ // for every nested configuration, every new nested is valid
+ std::list<std::set<const DOMElement*> > combinedConfigurations;
+ for (auto existIter = allConfigurations.begin(); existIter != allConfigurations.end(); existIter++) {
+ std::set<const DOMElement*> existingConfig = *existIter;
+
+ for (auto newIter = nestedConfigurations.begin(); newIter != nestedConfigurations.end(); newIter++) {
+
+ std::set<const DOMElement*> newConfig = *newIter;
+ std::set<const DOMElement*> combinedSet;
+ combinedSet.insert(existingConfig.begin(), existingConfig.end());
+ combinedSet.insert(newConfig.begin(), newConfig.end());
+
+ combinedConfigurations.push_back(combinedSet);
+ }
+ }
+ allConfigurations = combinedConfigurations;
+ } else {
+ // just add nested configurations and this
+ for (auto newIter = nestedConfigurations.begin(); newIter != nestedConfigurations.end(); newIter++) {
+ std::set<const DOMElement*> newConfig = *newIter;
+ if (localName != "scxml")
+ newConfig.insert(root);
+ allConfigurations.push_back(newConfig);
+ }
+ }
+ }
+ }
+
+ if (isAtomic) {
+ std::set<const DOMElement*> soleConfig;
+ soleConfig.insert(root);
+ allConfigurations.push_back(soleConfig);
+ }
+ return allConfigurations;
+
+}
/**
* Can the given states ever appear in an active configuration?
*/
-bool hasLegalCompletion(const NodeSet<std::string>& states) {
+bool hasLegalCompletion(const std::list<DOMElement*>& states) {
if (states.size() < 2)
return true;
// iterate every pair
- for (unsigned int outer = 0; outer < states.size() - 1; outer++) {
- Element<std::string> s1(states[outer]);
- for (unsigned int inner = outer + 1; inner < states.size(); inner++) {
- Element<std::string> s2(states[inner]);
- Node<std::string> parent;
+ for (auto outer = states.begin(); outer != states.end(); outer++) {
+ DOMElement* s1 = *outer;
+ for (auto inner = outer; inner != states.end(); inner++) {
+ if (inner == outer)
+ continue;
+
+ DOMElement* s2 = *inner;
+ DOMNode* parent;
// ok to be directly ancestorally related
- if (InterpreterImpl::isDescendant(s1, s2) || InterpreterImpl::isDescendant(s2, s1))
+ if (DOMUtils::isDescendant(s1, s2) || DOMUtils::isDescendant(s2, s1))
goto NEXT_PAIR;
// find least common ancestor
- parent = s1.getParentNode();
- while(parent && parent.getNodeType() == Node_base::ELEMENT_NODE) {
- if (InterpreterImpl::isDescendant(s2, parent)) {
- if (InterpreterImpl::isParallel(Element<std::string>(parent)))
+ parent = s1->getParentNode();
+ while(parent && parent->getNodeType() == DOMNode::ELEMENT_NODE) {
+ if (DOMUtils::isDescendant(s2, parent)) {
+ if (isParallel(static_cast<DOMElement*>(parent)))
goto NEXT_PAIR;
}
- parent = parent.getParentNode();
+ parent = parent->getParentNode();
}
return false;
@@ -100,91 +161,90 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
std::list<InterpreterIssue> issues;
if (!interpreter->_scxml) {
- InterpreterIssue issue("No SCXML element to be found", Node<std::string>(), InterpreterIssue::USCXML_ISSUE_FATAL);
+ InterpreterIssue issue("No SCXML element to be found", NULL, InterpreterIssue::USCXML_ISSUE_FATAL);
issues.push_back(issue);
return issues;
}
- std::map<std::string, Arabica::DOM::Element<std::string> > seenStates;
+ std::map<std::string, DOMElement* > seenStates;
// get some aliases
- Element<std::string>& _scxml = interpreter->_scxml;
- NameSpaceInfo& _nsInfo = interpreter->_nsInfo;
+ DOMElement* _scxml = interpreter->_scxml;
Factory* _factory = interpreter->_factory;
DataModel& _dataModel = interpreter->_dataModel;
+ std::string xmlNSPrefix = interpreter->_xmlPrefix;
+ std::map<std::string, std::list<DOMElement*> > nodeSets;
+ assembleNodeSets(xmlNSPrefix, _scxml, nodeSets);
- std::map<std::string, NodeSet<std::string> > nodeSets;
- assembleNodeSets(_nsInfo.xmlNSPrefix, _scxml, nodeSets);
-
- NodeSet<std::string> scxmls = nodeSets["scxml"];
+ std::list<DOMElement*> scxmls = nodeSets["scxml"];
scxmls.push_back(_scxml);
- NodeSet<std::string> reachable = interpreter->getReachableStates();
-
- NodeSet<std::string>& states = nodeSets["state"];
- NodeSet<std::string>& parallels = nodeSets["parallel"];
- NodeSet<std::string>& transitions = nodeSets["transition"];
- NodeSet<std::string>& initials = nodeSets["initial"];
- NodeSet<std::string>& finals = nodeSets["final"];
- NodeSet<std::string>& onEntries = nodeSets["onentry"];
- NodeSet<std::string>& onExits = nodeSets["onexit"];
- NodeSet<std::string>& histories = nodeSets["history"];
-
- NodeSet<std::string>& raises = nodeSets["raise"];
- NodeSet<std::string>& ifs = nodeSets["if"];
- NodeSet<std::string>& elseIfs = nodeSets["elseif"];
- NodeSet<std::string>& elses = nodeSets["else"];
- NodeSet<std::string>& foreachs = nodeSets["foreach"];
- NodeSet<std::string>& logs = nodeSets["log"];
-
- NodeSet<std::string>& dataModels = nodeSets["datamodel"];
- NodeSet<std::string>& datas = nodeSets["data"];
- NodeSet<std::string>& assigns = nodeSets["assign"];
- NodeSet<std::string>& doneDatas = nodeSets["donedata"];
- NodeSet<std::string>& contents = nodeSets["content"];
- NodeSet<std::string>& params = nodeSets["param"];
- NodeSet<std::string>& scripts = nodeSets["script"];
-
- NodeSet<std::string>& sends = nodeSets["send"];
- NodeSet<std::string>& cancels = nodeSets["cancel"];
- NodeSet<std::string>& invokes = nodeSets["invoke"];
- NodeSet<std::string>& finalizes = nodeSets["finalize"];
-
- NodeSet<std::string> allStates;
- allStates.push_back(states);
- allStates.push_back(parallels);
- allStates.push_back(histories);
- allStates.push_back(finals);
-
- NodeSet<std::string> allExecContents;
- allExecContents.push_back(raises);
- allExecContents.push_back(ifs);
- allExecContents.push_back(elseIfs);
- allExecContents.push_back(elses);
- allExecContents.push_back(foreachs);
- allExecContents.push_back(logs);
- allExecContents.push_back(sends);
- allExecContents.push_back(assigns);
- allExecContents.push_back(scripts);
- allExecContents.push_back(cancels);
-
- NodeSet<std::string> allElements;
- allElements.push_back(scxmls);
- allElements.push_back(allStates);
- allElements.push_back(allExecContents);
- allElements.push_back(transitions);
- allElements.push_back(initials);
- allElements.push_back(onEntries);
- allElements.push_back(onExits);
- allElements.push_back(dataModels);
- allElements.push_back(datas);
- allElements.push_back(doneDatas);
- allElements.push_back(contents);
- allElements.push_back(params);
- allElements.push_back(invokes);
- allElements.push_back(finalizes);
+ std::list<xercesc::DOMElement*> reachable = getReachableStates(_scxml);
+
+ std::list<DOMElement*>& states = nodeSets["state"];
+ std::list<DOMElement*>& parallels = nodeSets["parallel"];
+ std::list<DOMElement*>& transitions = nodeSets["transition"];
+ std::list<DOMElement*>& initials = nodeSets["initial"];
+ std::list<DOMElement*>& finals = nodeSets["final"];
+ std::list<DOMElement*>& onEntries = nodeSets["onentry"];
+ std::list<DOMElement*>& onExits = nodeSets["onexit"];
+ std::list<DOMElement*>& histories = nodeSets["history"];
+
+ std::list<DOMElement*>& raises = nodeSets["raise"];
+ std::list<DOMElement*>& ifs = nodeSets["if"];
+ std::list<DOMElement*>& elseIfs = nodeSets["elseif"];
+ std::list<DOMElement*>& elses = nodeSets["else"];
+ std::list<DOMElement*>& foreachs = nodeSets["foreach"];
+ std::list<DOMElement*>& logs = nodeSets["log"];
+
+ std::list<DOMElement*>& dataModels = nodeSets["datamodel"];
+ std::list<DOMElement*>& datas = nodeSets["data"];
+ std::list<DOMElement*>& assigns = nodeSets["assign"];
+ std::list<DOMElement*>& doneDatas = nodeSets["donedata"];
+ std::list<DOMElement*>& contents = nodeSets["content"];
+ std::list<DOMElement*>& params = nodeSets["param"];
+ std::list<DOMElement*>& scripts = nodeSets["script"];
+
+ std::list<DOMElement*>& sends = nodeSets["send"];
+ std::list<DOMElement*>& cancels = nodeSets["cancel"];
+ std::list<DOMElement*>& invokes = nodeSets["invoke"];
+ std::list<DOMElement*>& finalizes = nodeSets["finalize"];
+
+ std::list<DOMElement*> allStates;
+ allStates.insert(allStates.end(), states.begin(), states.end());
+ allStates.insert(allStates.end(), parallels.begin(), parallels.end());
+ allStates.insert(allStates.end(), histories.begin(), histories.end());
+ allStates.insert(allStates.end(), finals.begin(), finals.end());
+
+ std::list<DOMElement*> allExecContents;
+ allExecContents.insert(allExecContents.end(), raises.begin(), raises.end());
+ allExecContents.insert(allExecContents.end(), ifs.begin(), ifs.end());
+ allExecContents.insert(allExecContents.end(), elseIfs.begin(), elseIfs.end());
+ allExecContents.insert(allExecContents.end(), elses.begin(), elses.end());
+ allExecContents.insert(allExecContents.end(), foreachs.begin(), foreachs.end());
+ allExecContents.insert(allExecContents.end(), logs.begin(), logs.end());
+ allExecContents.insert(allExecContents.end(), sends.begin(), sends.end());
+ allExecContents.insert(allExecContents.end(), assigns.begin(), assigns.end());
+ allExecContents.insert(allExecContents.end(), scripts.begin(), scripts.end());
+ allExecContents.insert(allExecContents.end(), cancels.begin(), cancels.end());
+
+ std::list<DOMElement*> allElements;
+ allElements.insert(allElements.end(), scxmls.begin(), scxmls.end());
+ allElements.insert(allElements.end(), allStates.begin(), allStates.end());
+ allElements.insert(allElements.end(), allExecContents.begin(), allExecContents.end());
+ allElements.insert(allElements.end(), transitions.begin(), transitions.end());
+ allElements.insert(allElements.end(), initials.begin(), initials.end());
+ allElements.insert(allElements.end(), onEntries.begin(), onEntries.end());
+ allElements.insert(allElements.end(), onExits.begin(), onExits.end());
+ allElements.insert(allElements.end(), dataModels.begin(), dataModels.end());
+ allElements.insert(allElements.end(), datas.begin(), datas.end());
+ allElements.insert(allElements.end(), doneDatas.begin(), doneDatas.end());
+ allElements.insert(allElements.end(), contents.begin(), contents.end());
+ allElements.insert(allElements.end(), params.begin(), params.end());
+ allElements.insert(allElements.end(), invokes.begin(), invokes.end());
+ allElements.insert(allElements.end(), finalizes.begin(), finalizes.end());
std::set<std::string> execContentSet;
@@ -278,10 +338,10 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
}
- for (size_t i = 0; i < allStates.size(); i++) {
- Element<std::string> state = Element<std::string>(allStates[i]);
+ for (auto stateIter = allStates.begin(); stateIter != allStates.end(); stateIter++) {
+ DOMElement* state = static_cast<DOMElement*>(*stateIter);
- if (InterpreterImpl::isMember(state, finals) && !HAS_ATTR(state, "id")) // id is not required for finals
+ if (DOMUtils::isMember(state, finals) && !HAS_ATTR(state, "id")) // id is not required for finals
continue;
// check for existance of id attribute - this not actually required!
@@ -299,13 +359,13 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
// check for valid transition with history states
if (LOCALNAME(state) == "history") {
- NodeSet<std::string> transitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", state, false);
+ std::list<DOMElement*> transitions = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "transition", state, false);
if (transitions.size() > 1) {
issues.push_back(InterpreterIssue("History pseudo-state with id '" + stateId + "' has multiple transitions", state, InterpreterIssue::USCXML_ISSUE_FATAL));
} else if (transitions.size() == 0) {
issues.push_back(InterpreterIssue("History pseudo-state with id '" + stateId + "' has no default transition", state, InterpreterIssue::USCXML_ISSUE_FATAL));
} else {
- Element<std::string> transition = Element<std::string>(transitions[0]);
+ DOMElement* transition = static_cast<DOMElement*>(transitions.front());
if (HAS_ATTR(transition, "cond")) {
issues.push_back(InterpreterIssue("Transition in history pseudo-state '" + stateId + "' must not have a condition", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
}
@@ -315,16 +375,16 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
if (!HAS_ATTR(transition, "target")) {
issues.push_back(InterpreterIssue("Transition in history pseudo-state '" + stateId + "' has no target", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
} else {
- NodeSet<std::string> targetStates = interpreter->getTargetStates(transition);
- for (size_t j = 0; j < targetStates.size(); j++) {
- Element<std::string> target = Element<std::string>(targetStates[j]);
+ std::list<DOMElement*> targetStates = getTargetStates(transition, _scxml);
+ for (auto tIter = targetStates.begin(); tIter != targetStates.end(); tIter++) {
+ DOMElement* target = *tIter;
if (HAS_ATTR(state, "type") && ATTR(state, "type") == "deep") {
- if (!InterpreterImpl::isDescendant(target, state.getParentNode())) {
- issues.push_back(InterpreterIssue("Transition in deep history pseudo-state '" + stateId + "' has invalid target state '" + ATTR(target, "id") + "'", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
+ if (!DOMUtils::isDescendant(target, state->getParentNode())) {
+ issues.push_back(InterpreterIssue("Transition in deep history pseudo-state '" + stateId + "' has illegal target state '" + ATTR(target, "id") + "'", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
}
} else {
- if (target.getParentNode() != state.getParentNode()) {
- issues.push_back(InterpreterIssue("Transition in shallow history pseudo-state '" + stateId + "' has invalid target state '" + ATTR(target, "id") + "'", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
+ if (target->getParentNode() != state->getParentNode()) {
+ issues.push_back(InterpreterIssue("Transition in shallow history pseudo-state '" + stateId + "' has illegal target state '" + ATTR(target, "id") + "'", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
}
}
}
@@ -333,7 +393,7 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
}
// check whether state is reachable
- if (!InterpreterImpl::isMember(state, reachable) && !InterpreterImpl::isInEmbeddedDocument(state)) {
+ if (!DOMUtils::isMember(state, reachable) && !isInEmbeddedDocument(state)) {
issues.push_back(InterpreterIssue("State with id '" + stateId + "' is unreachable", state, InterpreterIssue::USCXML_ISSUE_FATAL));
}
@@ -345,8 +405,8 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
seenStates[ATTR(state, "id")] = state;
}
- for (size_t i = 0; i < transitions.size(); i++) {
- Element<std::string> transition = Element<std::string>(transitions[i]);
+ for (auto tIter = transitions.begin(); tIter != transitions.end(); tIter++) {
+ DOMElement* transition = *tIter;
// check for valid target
if (HAS_ATTR(transition, "target")) {
@@ -365,16 +425,14 @@ std::list<InterpreterIssue> InterpreterIssue::forInterpreter(InterpreterImpl* in
}
// check for redundancy of transition
- for (size_t i = 0; i < allStates.size(); i++) {
- Element<std::string> state = Element<std::string>(allStates[i]);
- NodeSet<std::string> transitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", state, false);
-
- transitions.to_document_order();
+ for (auto stateIter = allStates.begin(); stateIter != allStates.end(); stateIter++) {
+ DOMElement* state = *stateIter;
+ std::list<DOMElement*> transitions = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "transition", state, false);
- for (size_t j = 1; j < transitions.size(); j++) {
- Element<std::string> transition = Element<std::string>(transitions[j]);
- for (size_t k = 0; k < j; k++) {
- Element<std::string> earlierTransition = Element<std::string>(transitions[k]);
+ for (auto tIter = transitions.begin(); tIter != transitions.end(); tIter++) {
+ DOMElement* transition = *tIter;
+ for (auto t2Iter = transitions.begin(); t2Iter != tIter; t2Iter++) {
+ DOMElement* earlierTransition = *t2Iter;
// will the earlier transition always be enabled when the later is?
if (!HAS_ATTR(earlierTransition, "cond")) {
@@ -410,16 +468,18 @@ NEXT_TRANSITION:
// check for useless history elements
{
- for (size_t i = 0; i < histories.size(); i++) {
- Element<std::string> history = Element<std::string>(histories[i]);
- if (!history.getParentNode() || history.getParentNode().getNodeType() != Node_base::ELEMENT_NODE)
+ for (auto histIter = histories.begin(); histIter != histories.end(); histIter++) {
+ DOMElement* history = *histIter;
+
+ if (!history->getParentNode() || history->getParentNode()->getNodeType() != DOMNode::ELEMENT_NODE)
continue; // syntax check will have catched this
- Element<std::string> parent(history.getParentNode());
- if (InterpreterImpl::isAtomic(parent)) {
+
+ DOMElement* parent = static_cast<DOMElement*>(history->getParentNode());
+ if (isAtomic(parent)) {
issues.push_back(InterpreterIssue("Useless history '" + ATTR(history, "id") + "' in atomic state", history, InterpreterIssue::USCXML_ISSUE_INFO));
continue;
}
- std::list<std::set<Arabica::DOM::Element<std::string> > > configs = Complexity::getAllConfigurations(parent);
+ std::list<std::set<const DOMElement* > > configs = getAllConfigurations(parent);
if (configs.size() <= 1) {
issues.push_back(InterpreterIssue("Useless history '" + ATTR(history, "id") + "' in state with single legal configuration", history, InterpreterIssue::USCXML_ISSUE_INFO));
continue;
@@ -429,19 +489,24 @@ NEXT_TRANSITION:
// check for valid initial attribute
{
- NodeSet<std::string> withInitialAttr;
- withInitialAttr.push_back(allStates);
+ std::list<DOMElement*> withInitialAttr;
+ withInitialAttr.insert(withInitialAttr.end(), allStates.begin(), allStates.end());
withInitialAttr.push_back(_scxml);
- for (size_t i = 0; i < withInitialAttr.size(); i++) {
- Element<std::string> state = Element<std::string>(withInitialAttr[i]);
+ for (auto stateIter = withInitialAttr.begin(); stateIter != withInitialAttr.end(); stateIter++) {
+ DOMElement* state = *stateIter;
if (HAS_ATTR(state, "initial")) {
- NodeSet<std::string> childs;
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "state", state, true));
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "parallel", state, true));
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "final", state, true));
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "history", state, true));
+ std::list<DOMElement*> childs;
+ std::list<DOMElement*> tmp;
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "state", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "parallel", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "final", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "history", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
std::list<std::string> intials = tokenize(ATTR(state, "initial"));
for (std::list<std::string>::iterator initIter = intials.begin(); initIter != intials.end(); initIter++) {
@@ -450,7 +515,7 @@ NEXT_TRANSITION:
continue;
}
// value of the 'initial' attribute [..] must be descendants of the containing <state> or <parallel> element
- if (!InterpreterImpl::isMember(seenStates[*initIter], childs)) {
+ if (!DOMUtils::isMember(seenStates[*initIter], childs)) {
issues.push_back(InterpreterIssue("Initial attribute references non-child state '" + *initIter + "'", state, InterpreterIssue::USCXML_ISSUE_FATAL));
}
}
@@ -460,37 +525,37 @@ NEXT_TRANSITION:
// check for legal configuration of target sets
{
- std::map<Element<std::string>, std::string > targetIdSets;
- for (size_t i = 0; i < transitions.size(); i++) {
- Element<std::string> transition = Element<std::string>(transitions[i]);
+ std::map<DOMElement*, std::string > targetIdSets;
+ for (auto iter = transitions.begin(); iter != transitions.end(); iter++) {
+ DOMElement* transition = *iter;
if (HAS_ATTR(transition, "target")) {
targetIdSets[transition] = ATTR(transition, "target");
}
}
- for (size_t i = 0; i < initials.size(); i++) {
- Element<std::string> initial = Element<std::string>(initials[i]);
+ for (auto iter = initials.begin(); iter != initials.end(); iter++) {
+ DOMElement* initial = *iter;
if (HAS_ATTR(initial, "target")) {
targetIdSets[initial] = ATTR(initial, "target");
}
}
- for (size_t i = 0; i < allStates.size(); i++) {
- Element<std::string> state = Element<std::string>(allStates[i]);
+ for (auto iter = allStates.begin(); iter != allStates.end(); iter++) {
+ DOMElement* state = *iter;
if (HAS_ATTR(state, "initial")) {
targetIdSets[state] = ATTR(state, "initial");
}
}
- for (std::map<Element<std::string>, std::string >::iterator setIter = targetIdSets.begin();
+ for (auto setIter = targetIdSets.begin();
setIter != targetIdSets.end();
setIter++) {
- NodeSet<std::string> targets;
+ std::list<DOMElement*> targets;
std::list<std::string> targetIds = tokenize(setIter->second);
- for (std::list<std::string>::iterator tgtIter = targetIds.begin(); tgtIter != targetIds.end(); tgtIter++) {
+ for (auto tgtIter = targetIds.begin(); tgtIter != targetIds.end(); tgtIter++) {
if (seenStates.find(*tgtIter) == seenStates.end())
goto NEXT_SET;
targets.push_back(seenStates[*tgtIter]);
@@ -505,21 +570,21 @@ NEXT_SET:
// check for valid initial transition
{
- NodeSet<std::string> initTrans;
-// initTrans.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", histories, true));
+ std::list<DOMElement*> initTrans;
+
+ for (auto iter = initials.begin(); iter != initials.end(); iter++) {
+ DOMElement* initial = *iter;
- for (size_t i = 0; i < initials.size(); i++) {
- Element<std::string> initial = Element<std::string>(initials[i]);
- NodeSet<std::string> initTransitions = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "transition", initial, true);
+ std::list<DOMElement*> initTransitions = DOMUtils::filterChildElements(XML_PREFIX(initial).str() + "transition", initial, true);
if (initTransitions.size() != 1) {
issues.push_back(InterpreterIssue("Initial element must define exactly one transition", initial, InterpreterIssue::USCXML_ISSUE_FATAL));
}
- initTrans.push_back(initTransitions);
+ initTrans.insert(initTrans.end(), initTransitions.begin(), initTransitions.end());
}
- for (size_t i = 0; i < initTrans.size(); i++) {
- Element<std::string> transition = Element<std::string>(initTrans[i]);
+ for (auto iter = initTrans.begin(); iter != initTrans.end(); iter++) {
+ DOMElement* transition = *iter;
/* In a conformant SCXML document, this transition must not contain 'cond' or 'event' attributes, and must specify a non-null 'target'
* whose value is a valid state specification consisting solely of descendants of the containing state
@@ -532,22 +597,29 @@ NEXT_SET:
issues.push_back(InterpreterIssue("Initial transition cannot be eventful", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
}
- if (!transition.getParentNode() || !transition.getParentNode().getParentNode() || transition.getParentNode().getParentNode().getNodeType() != Node_base::ELEMENT_NODE)
+ if (!transition->getParentNode() ||
+ !transition->getParentNode()->getParentNode() ||
+ transition->getParentNode()->getParentNode()->getNodeType() != DOMNode::ELEMENT_NODE)
continue; // syntax will catch this one
- Element<std::string> state(transition.getParentNode().getParentNode());
- if (!InterpreterImpl::isState(state))
+ DOMElement* state = static_cast<DOMElement*>(transition->getParentNode()->getParentNode());
+ if (!isState(state))
continue; // syntax will catch this one
- NodeSet<std::string> childs;
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "state", state, true));
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "parallel", state, true));
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "final", state, true));
- childs.push_back(DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "history", state, true));
+ std::list<DOMElement*> childs;
+ std::list<DOMElement*> tmp;
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "state", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "parallel", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "final", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
+ tmp = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "history", state, true);
+ childs.insert(childs.end(), tmp.begin(), tmp.end());
std::list<std::string> intials = tokenize(ATTR(transition, "target"));
for (std::list<std::string>::iterator initIter = intials.begin(); initIter != intials.end(); initIter++) {
// the 'target' of a <transition> inside an <initial> or <history> element: all the states must be descendants of the containing <state> or <parallel> element
- if (!InterpreterImpl::isMember(seenStates[*initIter], childs)) {
+ if (!DOMUtils::isMember(seenStates[*initIter], childs)) {
issues.push_back(InterpreterIssue("Target of initial transition references non-child state '" + *initIter + "'", transition, InterpreterIssue::USCXML_ISSUE_FATAL));
}
}
@@ -557,8 +629,8 @@ NEXT_SET:
// check that all invokers exists
{
- for (size_t i = 0; i < invokes.size(); i++) {
- Element<std::string> invoke = Element<std::string>(invokes[i]);
+ for (auto iter = invokes.begin(); iter != invokes.end(); iter++) {
+ DOMElement* invoke = *iter;
if (HAS_ATTR(invoke, "type") && !_factory->hasInvoker(ATTR(invoke, "type"))) {
// unknown at factory - adhoc extension?
if (HAS_ATTR(invoke, "id") && interpreter->_invokers.find(ATTR(invoke, "id")) != interpreter->_invokers.end())
@@ -580,10 +652,10 @@ NEXT_SET:
// check that all io processors exists
{
- for (size_t i = 0; i < sends.size(); i++) {
- Element<std::string> send = Element<std::string>(sends[i]);
+ for (auto iter = sends.begin(); iter != sends.end(); iter++) {
+ DOMElement* send = *iter;
if (HAS_ATTR(send, "type") && !_factory->hasIOProcessor(ATTR(send, "type"))) {
- if (interpreter->_ioProcessors.find(ATTR(send, "type")) != interpreter->_ioProcessors.end())
+ if (interpreter->_ioProcs.find(ATTR(send, "type")) != interpreter->_ioProcs.end())
continue; // not an issue, available ad-hoc
issues.push_back(InterpreterIssue("Send to unknown IO Processor '" + ATTR(send, "type") + "'", send, InterpreterIssue::USCXML_ISSUE_FATAL));
@@ -594,23 +666,24 @@ NEXT_SET:
// check that all custom executable content is known
{
- NodeSet<std::string> allExecContentContainers;
- allExecContentContainers.push_back(onEntries);
- allExecContentContainers.push_back(onExits);
- allExecContentContainers.push_back(transitions);
- allExecContentContainers.push_back(finalizes);
-
- for (size_t i = 0; i < allExecContentContainers.size(); i++) {
- Element<std::string> block = Element<std::string>(allExecContentContainers[i]);
- NodeSet<std::string> execContents = DOMUtils::filterChildType(Node_base::ELEMENT_NODE, block);
- for (size_t j = 0; j < execContents.size(); j++) {
- Element<std::string> execContent = Element<std::string>(execContents[j]);
+ std::list<DOMElement*> allExecContentContainers;
+ allExecContentContainers.insert(allExecContentContainers.end(), onEntries.begin(), onEntries.end());
+ allExecContentContainers.insert(allExecContentContainers.end(), onExits.begin(), onExits.end());
+ allExecContentContainers.insert(allExecContentContainers.end(), transitions.begin(), transitions.end());
+ allExecContentContainers.insert(allExecContentContainers.end(), finalizes.begin(), finalizes.end());
+
+ for (auto bIter = allExecContentContainers.begin(); bIter != allExecContentContainers.end(); bIter++) {
+ DOMElement* block = *bIter;
+ std::list<DOMNode*> execContents = DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, block);
+ for (auto ecIter = execContents.begin(); ecIter != execContents.end(); ecIter++) {
+ DOMElement* execContent = static_cast<DOMElement*>(*ecIter);
// SCXML specific executable content, always available
- if (InterpreterImpl::isMember(execContent, allExecContents)) {
+ if (DOMUtils::isMember(execContent, allExecContents)) {
continue;
}
- if (!_factory->hasExecutableContent(execContent.getLocalName(), execContent.getNamespaceURI())) {
- issues.push_back(InterpreterIssue("Executable content element '" + execContent.getLocalName() + "' in namespace '" + execContent.getNamespaceURI() + "' unknown", execContent, InterpreterIssue::USCXML_ISSUE_FATAL));
+
+ if (!_factory->hasExecutableContent(X(execContent->getLocalName()), X(execContent->getNamespaceURI()))) {
+ issues.push_back(InterpreterIssue("Executable content element '" + (std::string)X(execContent->getLocalName()) + "' in namespace '" + (std::string)X(execContent->getNamespaceURI()) + "' unknown", execContent, InterpreterIssue::USCXML_ISSUE_FATAL));
continue;
}
}
@@ -619,8 +692,8 @@ NEXT_SET:
// check that all SCXML elements have valid parents and required attributes
{
- for (size_t i = 0; i < allElements.size(); i++) {
- Element<std::string> element = Element<std::string>(allElements[i]);
+ for (auto iter = allElements.begin(); iter != allElements.end(); iter++) {
+ DOMElement* element = *iter;
std::string localName = LOCALNAME(element);
if (reqAttr.find(localName) != reqAttr.end()) {
@@ -638,12 +711,12 @@ NEXT_SET:
if (localName == "scxml") // can be anywhere: <assign>, <content>, <other:embed>
continue;
- if (!element.getParentNode() || element.getParentNode().getNodeType() != Node_base::ELEMENT_NODE) {
+ if (!element->getParentNode() || element->getParentNode()->getNodeType() != DOMNode::ELEMENT_NODE) {
issues.push_back(InterpreterIssue("Parent of " + localName + " is no element", element, InterpreterIssue::USCXML_ISSUE_WARNING));
continue;
}
- Element<std::string> parent = Element<std::string>(element.getParentNode());
+ DOMElement* parent = static_cast<DOMElement*>(element->getParentNode());
std::string parentName = LOCALNAME(parent);
if (validParents[localName].find(parentName) == validParents[localName].end()) {
@@ -655,55 +728,55 @@ NEXT_SET:
// check attribute constraints
{
- for (size_t i = 0; i < initials.size(); i++) {
- Element<std::string> initial = Element<std::string>(initials[i]);
- if (initial.getParentNode() && initial.getParentNode().getNodeType() == Node_base::ELEMENT_NODE) {
- Element<std::string> state(initial.getParentNode());
+ for (auto iter = initials.begin(); iter != initials.end(); iter++) {
+ DOMElement* initial = *iter;
+ if (initial->getParentNode() && initial->getParentNode()->getNodeType() == DOMNode::ELEMENT_NODE) {
+ DOMElement* state = static_cast<DOMElement*>(initial->getParentNode());
if (HAS_ATTR(state, "initial")) {
issues.push_back(InterpreterIssue("State with initial attribute cannot have <initial> child ", state, InterpreterIssue::USCXML_ISSUE_WARNING));
}
- if (InterpreterImpl::isAtomic(state)) {
+ if (isAtomic(state)) {
issues.push_back(InterpreterIssue("Atomic state cannot have <initial> child ", state, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
}
- for (size_t i = 0; i < allStates.size(); i++) {
- Element<std::string> state = Element<std::string>(allStates[i]);
- if (InterpreterImpl::isAtomic(state) && HAS_ATTR(state, "initial")) {
+ for (auto iter = allStates.begin(); iter != allStates.end(); iter++) {
+ DOMElement* state = *iter;
+ if (isAtomic(state) && HAS_ATTR(state, "initial")) {
issues.push_back(InterpreterIssue("Atomic state cannot have initial attribute ", state, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < assigns.size(); i++) {
- Element<std::string> assign = Element<std::string>(assigns[i]);
- if (HAS_ATTR(assign, "expr") && assign.getChildNodes().getLength() > 0) {
+ for (auto iter = assigns.begin(); iter != assigns.end(); iter++) {
+ DOMElement* assign = *iter;
+ if (HAS_ATTR(assign, "expr") && assign->getChildNodes()->getLength() > 0) {
issues.push_back(InterpreterIssue("Assign element cannot have expr attribute and children", assign, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < contents.size(); i++) {
- Element<std::string> content = Element<std::string>(contents[i]);
- if (HAS_ATTR(content, "expr") && content.getChildNodes().getLength() > 0) {
+ for (auto iter = contents.begin(); iter != contents.end(); iter++) {
+ DOMElement* content = *iter;
+ if (HAS_ATTR(content, "expr") && content->getChildNodes()->getLength() > 0) {
issues.push_back(InterpreterIssue("Content element cannot have expr attribute and children", content, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < params.size(); i++) {
- Element<std::string> param = Element<std::string>(params[i]);
+ for (auto iter = params.begin(); iter != params.end(); iter++) {
+ DOMElement* param = *iter;
if (HAS_ATTR(param, "expr") && HAS_ATTR(param, "location")) {
issues.push_back(InterpreterIssue("Param element cannot have both expr and location attribute", param, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < scripts.size(); i++) {
- Element<std::string> script = Element<std::string>(scripts[i]);
- if (HAS_ATTR(script, "src") && script.getChildNodes().getLength() > 0) {
+ for (auto iter = scripts.begin(); iter != scripts.end(); iter++) {
+ DOMElement* script = *iter;
+ if (HAS_ATTR(script, "src") && script->getChildNodes()->getLength() > 0) {
issues.push_back(InterpreterIssue("Script element cannot have src attribute and children", script, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < sends.size(); i++) {
- Element<std::string> send = Element<std::string>(sends[i]);
+ for (auto iter = sends.begin(); iter != sends.end(); iter++) {
+ DOMElement* send = *iter;
if (HAS_ATTR(send, "event") && HAS_ATTR(send, "eventexpr")) {
issues.push_back(InterpreterIssue("Send element cannot have both event and eventexpr attribute", send, InterpreterIssue::USCXML_ISSUE_WARNING));
}
@@ -723,8 +796,8 @@ NEXT_SET:
issues.push_back(InterpreterIssue("Send element cannot have delay with target _internal", send, InterpreterIssue::USCXML_ISSUE_WARNING));
}
- NodeSet<std::string> contentChilds = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "content", send, false);
- NodeSet<std::string> paramChilds = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "param", send, false);
+ std::list<DOMElement*> contentChilds = DOMUtils::filterChildElements(XML_PREFIX(send).str() + "content", send, false);
+ std::list<DOMElement*> paramChilds = DOMUtils::filterChildElements(XML_PREFIX(send).str() + "param", send, false);
if (HAS_ATTR(send, "namelist") && contentChilds.size() > 0) {
issues.push_back(InterpreterIssue("Send element cannot have namelist attribute and content child", send, InterpreterIssue::USCXML_ISSUE_WARNING));
@@ -735,15 +808,15 @@ NEXT_SET:
}
}
- for (size_t i = 0; i < cancels.size(); i++) {
- Element<std::string> cancel = Element<std::string>(cancels[i]);
+ for (auto iter = cancels.begin(); iter != cancels.end(); iter++) {
+ DOMElement* cancel = *iter;
if (HAS_ATTR(cancel, "sendid") && HAS_ATTR(cancel, "sendidexpr")) {
issues.push_back(InterpreterIssue("Cancel element cannot have both sendid and eventexpr sendidexpr", cancel, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < invokes.size(); i++) {
- Element<std::string> invoke = Element<std::string>(invokes[i]);
+ for (auto iter = invokes.begin(); iter != invokes.end(); iter++) {
+ DOMElement* invoke = *iter;
if (HAS_ATTR(invoke, "type") && HAS_ATTR(invoke, "typeexpr")) {
issues.push_back(InterpreterIssue("Invoke element cannot have both type and typeexpr attribute", invoke, InterpreterIssue::USCXML_ISSUE_WARNING));
}
@@ -753,18 +826,18 @@ NEXT_SET:
if (HAS_ATTR(invoke, "id") && HAS_ATTR(invoke, "idlocation")) {
issues.push_back(InterpreterIssue("Invoke element cannot have both id and idlocation attribute", invoke, InterpreterIssue::USCXML_ISSUE_WARNING));
}
- if (HAS_ATTR(invoke, "namelist") && DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "param", invoke, false).size() > 0) {
+ if (HAS_ATTR(invoke, "namelist") && DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "param", invoke, false).size() > 0) {
issues.push_back(InterpreterIssue("Invoke element cannot have namelist attribute and param child", invoke, InterpreterIssue::USCXML_ISSUE_WARNING));
}
- if (HAS_ATTR(invoke, "src") && DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "content", invoke, false).size() > 0) {
+ if (HAS_ATTR(invoke, "src") && DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "content", invoke, false).size() > 0) {
issues.push_back(InterpreterIssue("Invoke element cannot have src attribute and content child", invoke, InterpreterIssue::USCXML_ISSUE_WARNING));
}
}
- for (size_t i = 0; i < doneDatas.size(); i++) {
- Element<std::string> donedata = Element<std::string>(doneDatas[i]);
- if (DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata, false).size() > 0 &&
- DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "param", donedata, false).size() > 0) {
+ for (auto iter = doneDatas.begin(); iter != doneDatas.end(); iter++) {
+ DOMElement* donedata = *iter;
+ if (DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "content", donedata, false).size() > 0 &&
+ DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "param", donedata, false).size() > 0) {
issues.push_back(InterpreterIssue("Donedata element cannot have param child and content child", donedata, InterpreterIssue::USCXML_ISSUE_WARNING));
}
@@ -798,15 +871,15 @@ NEXT_SET:
// test all scripts for valid syntax
{
- for (size_t i = 0; i < scripts.size(); i++) {
- Element<std::string> script = Element<std::string>(scripts[i]);
+ for (auto iter = scripts.begin(); iter != scripts.end(); iter++) {
+ DOMElement* script = *iter;
- if (script.hasChildNodes()) {
+ if (script->hasChildNodes()) {
// search for the text node with the actual script
std::string scriptContent;
- for (Node<std::string> child = script.getFirstChild(); child; child = child.getNextSibling()) {
- if (child.getNodeType() == Node_base::TEXT_NODE || child.getNodeType() == Node_base::CDATA_SECTION_NODE)
- scriptContent += child.getNodeValue();
+ for (DOMNode* child = script->getFirstChild(); child; child = child->getNextSibling()) {
+ if (child->getNodeType() == DOMNode::TEXT_NODE || child->getNodeType() == DOMNode::CDATA_SECTION_NODE)
+ scriptContent += (std::string)X(child->getNodeValue());
}
if (!_dataModel.isValidSyntax(scriptContent)) {
@@ -818,13 +891,13 @@ NEXT_SET:
// test the various attributes with datamodel expressions for valid syntax
{
- NodeSet<std::string> withCondAttrs;
- withCondAttrs.push_back(transitions);
- withCondAttrs.push_back(ifs);
- withCondAttrs.push_back(elseIfs);
+ std::list<DOMElement*> withCondAttrs;
+ withCondAttrs.insert(withCondAttrs.end(), transitions.begin(), transitions.end());
+ withCondAttrs.insert(withCondAttrs.end(), ifs.begin(), ifs.end());
+ withCondAttrs.insert(withCondAttrs.end(), elseIfs.begin(), elseIfs.end());
- for (size_t i = 0; i < withCondAttrs.size(); i++) {
- Element<std::string> condAttr = Element<std::string>(withCondAttrs[i]);
+ for (auto iter = withCondAttrs.begin(); iter != withCondAttrs.end(); iter++) {
+ DOMElement* condAttr = *iter;
if (HAS_ATTR(condAttr, "cond")) {
if (!_dataModel.isValidSyntax(ATTR(condAttr, "cond"))) {
issues.push_back(InterpreterIssue("Syntax error in cond attribute", condAttr, InterpreterIssue::USCXML_ISSUE_WARNING));
@@ -835,17 +908,17 @@ NEXT_SET:
}
{
- NodeSet<std::string> withExprAttrs;
- withExprAttrs.push_back(logs);
- withExprAttrs.push_back(datas);
- withExprAttrs.push_back(assigns);
- withExprAttrs.push_back(contents);
- withExprAttrs.push_back(params);
-
- for (size_t i = 0; i < withExprAttrs.size(); i++) {
- Element<std::string> withExprAttr = Element<std::string>(withExprAttrs[i]);
+ std::list<DOMElement*> withExprAttrs;
+ withExprAttrs.insert(withExprAttrs.end(), logs.begin(), logs.end());
+ withExprAttrs.insert(withExprAttrs.end(), datas.begin(), datas.end());
+ withExprAttrs.insert(withExprAttrs.end(), assigns.begin(), assigns.end());
+ withExprAttrs.insert(withExprAttrs.end(), contents.begin(), contents.end());
+ withExprAttrs.insert(withExprAttrs.end(), params.begin(), params.end());
+
+ for (auto iter = withExprAttrs.begin(); iter != withExprAttrs.end(); iter++) {
+ DOMElement* withExprAttr = *iter;
if (HAS_ATTR(withExprAttr, "expr")) {
- if (InterpreterImpl::isMember(withExprAttr, datas) || InterpreterImpl::isMember(withExprAttr, assigns)) {
+ if (DOMUtils::isMember(withExprAttr, datas) || DOMUtils::isMember(withExprAttr, assigns)) {
if (!_dataModel.isValidSyntax("foo = " + ATTR(withExprAttr, "expr"))) { // TODO: this is ECMAScripty!
issues.push_back(InterpreterIssue("Syntax error in expr attribute", withExprAttr, InterpreterIssue::USCXML_ISSUE_WARNING));
continue;
@@ -861,8 +934,8 @@ NEXT_SET:
}
{
- for (size_t i = 0; i < foreachs.size(); i++) {
- Element<std::string> foreach = Element<std::string>(foreachs[i]);
+ for (auto iter = foreachs.begin(); iter != foreachs.end(); iter++) {
+ DOMElement* foreach = *iter;
if (HAS_ATTR(foreach, "array")) {
if (!_dataModel.isValidSyntax(ATTR(foreach, "array"))) {
issues.push_back(InterpreterIssue("Syntax error in array attribute", foreach, InterpreterIssue::USCXML_ISSUE_WARNING));
@@ -882,8 +955,8 @@ NEXT_SET:
}
{
- for (size_t i = 0; i < sends.size(); i++) {
- Element<std::string> send = Element<std::string>(sends[i]);
+ for (auto iter = sends.begin(); iter != sends.end(); iter++) {
+ DOMElement* send = *iter;
if (HAS_ATTR(send, "eventexpr")) {
if (!_dataModel.isValidSyntax(ATTR(send, "eventexpr"))) {
issues.push_back(InterpreterIssue("Syntax error in eventexpr attribute", send, InterpreterIssue::USCXML_ISSUE_WARNING));
@@ -914,8 +987,8 @@ NEXT_SET:
}
{
- for (size_t i = 0; i < invokes.size(); i++) {
- Element<std::string> invoke = Element<std::string>(invokes[i]);
+ for (auto iter = invokes.begin(); iter != invokes.end(); iter++) {
+ DOMElement* invoke = *iter;
if (HAS_ATTR(invoke, "typeexpr")) {
if (!_dataModel.isValidSyntax(ATTR(invoke, "typeexpr"))) {
issues.push_back(InterpreterIssue("Syntax error in typeexpr attribute", invoke, InterpreterIssue::USCXML_ISSUE_WARNING));
@@ -938,8 +1011,8 @@ NEXT_SET:
}
{
- for (size_t i = 0; i < cancels.size(); i++) {
- Element<std::string> cancel = Element<std::string>(cancels[i]);
+ for (auto iter = cancels.begin(); iter != cancels.end(); iter++) {
+ DOMElement* cancel = *iter;
if (HAS_ATTR(cancel, "sendidexpr")) {
if (!_dataModel.isValidSyntax(ATTR(cancel, "sendidexpr"))) {
issues.push_back(InterpreterIssue("Syntax error in sendidexpr attribute", cancel, InterpreterIssue::USCXML_ISSUE_WARNING));
@@ -955,5 +1028,29 @@ NEXT_SET:
return issues;
}
+std::ostream& operator<< (std::ostream& os, const InterpreterIssue& issue) {
+ switch (issue.severity) {
+ case InterpreterIssue::USCXML_ISSUE_FATAL:
+ os << "Issue (FATAL) ";
+ break;
+ case InterpreterIssue::USCXML_ISSUE_WARNING:
+ os << "Issue (WARNING) ";
+ break;
+ case InterpreterIssue::USCXML_ISSUE_INFO:
+ os << "Issue (INFO) ";
+ break;
+ default:
+ break;
+ }
+
+ if (issue.xPath.size() > 0) {
+ os << "at " << issue.xPath << ": ";
+ } else {
+ os << ": ";
+ }
+ os << issue.message;
+ return os;
+}
+
} \ No newline at end of file
diff --git a/src/uscxml/debug/InterpreterIssue.h b/src/uscxml/debug/InterpreterIssue.h
index 61b3b6a..f72a7a4 100644
--- a/src/uscxml/debug/InterpreterIssue.h
+++ b/src/uscxml/debug/InterpreterIssue.h
@@ -23,7 +23,7 @@
#include "uscxml/Common.h"
#include <list>
#include <iostream>
-#include <DOM/Node.hpp>
+#include <xercesc/dom/DOMNode.hpp>
namespace uscxml {
@@ -37,17 +37,17 @@ public:
USCXML_ISSUE_INFO
};
- InterpreterIssue(const std::string& msg, Arabica::DOM::Node<std::string> node, IssueSeverity severity, const std::string& specRef = "");
+ InterpreterIssue(const std::string& msg, xercesc::DOMNode* node, IssueSeverity severity, const std::string& specRef = "");
std::string xPath;
std::string message;
- Arabica::DOM::Node<std::string> node;
+ xercesc::DOMNode* node;
IssueSeverity severity;
std::string specRef;
private:
static std::list<InterpreterIssue> forInterpreter(InterpreterImpl* interpreter);
- friend class InterpreterImpl;
+ friend class Interpreter;
};
USCXML_API std::ostream& operator<< (std::ostream& os, const InterpreterIssue& issue);
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
deleted file mode 100644
index 56de37a..0000000
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-/**
- * @file
- * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#include "uscxml/Common.h"
-#include "uscxml/UUID.h"
-#include "SCXMLDotWriter.h"
-#include "../transform/FlatStateIdentifier.h"
-#include "uscxml/dom/DOMUtils.h"
-#include <boost/algorithm/string.hpp> // replace_all
-#include <iomanip>
-
-namespace uscxml {
-
-using namespace Arabica::DOM;
-using namespace Arabica::XPath;
-
-SCXMLDotWriter::SCXMLDotWriter() {
- _iteration = 0;
- _indentation = 0;
-}
-
-SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter,
- const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
- const Element<std::string>& transition) {
- _interpreter = interpreter;
- _xmlNSPrefix = _interpreter.getNameSpaceInfo().xmlNSPrefix;
- _transition = transition;
- _anchors = stateAnchors;
-
- NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
- _scxml = (Element<std::string>)scxmlElems.item(0);
- _isFlat = HAS_ATTR(_scxml, "flat") && stringIsTrue(ATTR(_scxml, "flat"));
-
- if (_anchors.size() == 0) {
- StateAnchor anchor;
- anchor.element = _scxml;
- _anchors.push_back(anchor);
- }
-
- for (std::list<StateAnchor>::iterator anchIter = _anchors.begin(); anchIter != _anchors.end(); anchIter++) {
- if (!anchIter->element)
- anchIter->element = _scxml;
- if (anchIter->childDepth >= 0 && anchIter->transDepth == -1)
- anchIter->transDepth = anchIter->childDepth;
-
- _portType = anchIter->type;
- assembleGraph(anchIter->element, anchIter->childDepth, anchIter->transDepth + 1);
- }
-
- _iteration = 0;
- _indentation = 0;
-}
-
-SCXMLDotWriter::~SCXMLDotWriter() {
-
-}
-
-void SCXMLDotWriter::onStableConfiguration(Interpreter interpreter) {
- std::ostringstream fileSS;
- fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
- toDot(fileSS.str(), interpreter);
-}
-
-void SCXMLDotWriter::afterCompletion(Interpreter interpreter) {
- std::ostringstream fileSS;
- fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
- toDot(fileSS.str(), interpreter);
-}
-
-void SCXMLDotWriter::beforeMicroStep(Interpreter interpreter) {
-// std::ostringstream fileSS;
-// fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
-// toDot(fileSS.str(), interpreter);
-}
-
-void SCXMLDotWriter::beforeTakingTransition(Interpreter interpreter,
- const 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);
-}
-
-std::string SCXMLDotWriter::getPrefix() {
- std::string prefix = "";
- for (size_t i = 0; i < _indentation; i++)
- prefix += " ";
- return prefix;
-}
-
-void SCXMLDotWriter::writeTo(std::ostream& os) {
- os << "digraph {" << std::endl;
- os << " rankdir=LR;" << std::endl;
- os << " fontsize=10;" << std::endl;
- // outfile << " splines=ortho;" << std::endl;
- // outfile << " splines=false;" << std::endl;
- // outfile << " nodesep=1.0;" << std::endl;
-
- _indentation++;
- writeStateElement(os, _scxml);
-
- // write edges at end of file
- for(std::set<DotEdge>::iterator edgeIter = _edges.begin(); edgeIter != _edges.end(); edgeIter++) {
- if (edgeIter->from == edgeIter->to)
- continue;
- if (_histories.find(edgeIter->to) != _histories.end()) {
- if (_histories.find(edgeIter->to)->second.from == _histories.find(edgeIter->to)->second.to)
- continue;
- }
-
- os << getPrefix() << "\"" << portEscape(edgeIter->from) << "\"";
- if (edgeIter->fromPort.size() > 0) {
- os << std::string(":\"") + portEscape(edgeIter->fromPort) + "\":e";
- } else {
- os << ":__name";
- }
- os << " -> ";
-
- if (_histories.find(edgeIter->to) != _histories.end()) {
- os << getPrefix() << "\"" << portEscape(_histories.find(edgeIter->to)->second.to) << "\"";
- if (_histories.find(edgeIter->to)->second.toPort.size() > 0) {
- os << std::string(":\"") + portEscape(_histories.find(edgeIter->to)->second.toPort) + "\"";
- } else {
- os << ":__name";
- }
-
- } else {
- os << getPrefix() << "\"" << portEscape(edgeIter->to) << "\"";
- if (edgeIter->toPort.size() > 0) {
- os << std::string(":\"") + portEscape(edgeIter->toPort) + "\"";
- } else {
- os << ":__name";
- }
- }
-
- if (edgeIter->type == EDGE_INITAL) {
- os << ":nw [style=\"dashed\", color=\"black\"]";
- } else {
- os << " [color=\"black\"]";
- }
- os << std::endl;
-
- }
-
- _indentation--;
-
- os << "}" << std::endl;
-
-}
-
-void SCXMLDotWriter::toDot(const std::string& filename,
- Interpreter interpreter,
- const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
- const Element<std::string>& transition) {
-
- std::ofstream outfile(filename.c_str());
- SCXMLDotWriter writer(interpreter, stateAnchors, transition);
- writer.writeTo(outfile);
-
-}
-
-/**
- * Walk the subset of the graph that is reachable and remember the nodes
- */
-void SCXMLDotWriter::assembleGraph(const Element<std::string>& state, int32_t childDepth, int32_t transDepth) {
- std::string nodeId = idForNode(state);
-
- // this node is neither included per child, nor per transition
- if (childDepth <= 0 && transDepth <= 0) {
- return;
- }
-
- // been here
- if (_graph.find(nodeId) != _graph.end())
- return;
-
- _graph[nodeId].node = state;
- _graph[nodeId].portType = _portType;
-
-
- if (childDepth == 0 && transDepth == 0) {
- _graph[nodeId].isBorder = true;
- }
-
-
- NodeSet<std::string> childElems = DOMUtils::filterChildType(Node_base::ELEMENT_NODE, state);
- for (size_t i = 0; i < childElems.size(); i++) {
- Element<std::string> childElem(childElems[i]);
-
- // remember histories we passed
- if (iequals(TAGNAME(childElem), "history")) {
- _histories[ATTR(childElem, "id")].to = ATTR(state, "id");
- _histories[ATTR(childElem, "id")].toPort = ATTR(childElem, "id");
- }
-
- // follow transitions
- if (iequals(TAGNAME(childElem), "transition")) {
- _graph[nodeId].transitions.push_back(childElem);
- NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(childElem);
- for (size_t 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, no weight from child depth
- assembleGraph((Element<std::string>)targetStates[j], 0, transDepth - 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 = tokenize(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));
- }
- }
-
- // follow childs
- if (InterpreterImpl::isState(Element<std::string>(childElem))) {
- if (_interpreter.getImpl()->isInitial(Element<std::string>(childElem))) {
- // add to initial states if it is initial
- _graph[nodeId].initialchilds.insert(idForNode(childElem));
- } else if (_interpreter.getImpl()->isParallel(Element<std::string>(state))) {
- // add to initial states if we are parallel
- _graph[nodeId].initialchilds.insert(idForNode(childElem));
- }
- // in any case, it is a child state
- _graph[nodeId].childs.insert(idForNode(childElem));
-
- // recurse (do we really need to?)
- assembleGraph(childElem, childDepth - 1, transDepth);
- }
-
- }
-}
-
-
-/**
- * Walk the complete graph and draw reachable subset
- */
-void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::string>& stateElem) {
- std::string stateId = idForNode(stateElem);
-
- if (_knownIds.find(stateId) != _knownIds.end())
- return;
- _knownIds.insert(stateId);
-
- std::list<Node<std::string> > invisParents;
- bool isVisible = (_graph.find(stateId) != _graph.end());
-
- bool subgraph = InterpreterImpl::isCompound(stateElem) || InterpreterImpl::isParallel(stateElem);
- bool fatherIsParallel = (stateElem.getParentNode() &&
- stateElem.getParentNode().getNodeType() == Node_base::ELEMENT_NODE &&
- InterpreterImpl::isParallel(Element<std::string>(stateElem.getParentNode())));
-
- if (subgraph) {
- _indentation++;
- os << std::endl;
- os << getPrefix() << "subgraph \"cluster_" << portEscape(stateId) << "\" {" << std::endl;
- _indentation++;
- os << getPrefix() << "fontsize=14" << std::endl;
- os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl;
- // os << getPrefix() << "rank=\"same\"" << std::endl;
- os << getPrefix() << "labeljust=l" << std::endl;
-
- os << getPrefix() << (fatherIsParallel ? "style=dashed" : "style=solid") << std::endl;
-
- // os << getPrefix() << "ranksep=\"equally\"" << std::endl;
-
- }
-
- if (isVisible) {
- // this state is visible!
- const DotState& dotState = _graph.find(stateId)->second;
-
- // is this a subgraph?
-
- os << std::endl;
- os << getPrefix() << "\"" << portEscape(stateId) << "\" [" << std::endl;
- _indentation++;
-
- os << getPrefix() << "fontsize=10," << std::endl;
- os << getPrefix() << "shape=plaintext," << std::endl;
- os << getPrefix() << (fatherIsParallel ? "style=dashed," : "style=solid,") << std::endl;
-
- // is the current state in the basic configuration?
- if (InterpreterImpl::isMember(stateElem, _interpreter.getBasicConfiguration()))
- os << getPrefix() << "color=red, penwidth=3," << std::endl;
-
- // is the current state in the basic configuration?
- if (dotState.isBorder)
- os << getPrefix() << "color=blue," << 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=< <table cellborder=\"0\" border=\"0\"><tr><td balign=\"left\">" << nameForNode(stateElem) << "</td></tr></table>>" << std::endl;
- _indentation--;
- os << getPrefix() << "];" << std::endl;
-
- return;
- }
-
- // 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
-
- int nrOutPorts = 0;
-
- switch (dotState.portType) {
- case PORT_TARGET: // outports are per target
- for(DotState::mmap_s_e_t::const_iterator it = dotState.targets.begin(), end = dotState.targets.end();
- it != end;
- it = dotState.targets.upper_bound(it->first)) {
- nrOutPorts++;
- }
- break;
- case PORT_EVENT: // outports are per event
- for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end();
- it != end;
- it = dotState.events.upper_bound(it->first)) {
- nrOutPorts++;
- }
- break;
- case PORT_TRANSITION:
- nrOutPorts = dotState.transitions.size();
-// for (size_t i = 0; i < dotState.transitions.size(); i++) {
-// outPorts.push_back(idForNode(dotState.transitions[i]));
-// }
- break;
- }
-
- os << getPrefix() << "label = < " << 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);
- std::string stateLabel = nameForNode(stateElem);
- int stateLines = 0;
-
- std::string::size_type start = 0;
- while ((start = stateLabel.find("<br", start)) != std::string::npos) {
- ++stateLines;
- start += 3;
- }
-
- os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "valign=\"top\" align=\"left\" cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\" >" << std::endl;
- os << " <tr><td port=\"__name\" balign=\"left\" valign=\"top\" align=\"left\" rowspan=\"" << nrOutPorts + 1 << "\">" << stateLabel << "</td></tr>" << std::endl;
-
- switch (dotState.portType) {
- case PORT_TARGET: // outports are per target
- writePerTargetPorts(os, dotState, stateLines);
- break;
- case PORT_EVENT: // outports are per event
- writePerEventPorts(os, dotState, stateLines);
- break;
- case PORT_TRANSITION:
- writePerTransitionPorts(os, dotState, stateLines);
- break;
- }
-
-
- // write details of the state
- if (details.size() > 0) {
- os << " <tr><td balign=\"left\" colspan=\"" << (nrOutPorts == 0 ? 1 : 2) << "\">" << std::endl;
- os << details << std::endl;
- os << " </td></tr>" << std::endl;
- }
-
- // write history states
- NodeSet<std::string> histories = DOMUtils::filterChildElements(_xmlNSPrefix + "history", stateElem);
- for (size_t i = 0; i < histories.size(); i++) {
- os << " <tr><td port=\"" << portEscape(ATTR_CAST(histories[i], "id")) << "\" balign=\"left\" colspan=\"" << (nrOutPorts == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR_CAST(histories[i], "id") << "</td></tr>" << std::endl;
-
- }
-
- os << "</table>" << std::endl << getPrefix() << ">" << std::endl;
-
- _indentation--;
- os << getPrefix() << "];" << std::endl;
-
- for (std::set<std::string>::iterator initIter = dotState.initialchilds.begin(); initIter != dotState.initialchilds.end(); initIter++) {
- std::string destId = *initIter;
- DotEdge edge(stateId, destId);
- edge.type = EDGE_INITAL;
- if (_graph.find(destId) != _graph.end())
- _edges.insert(edge);
- }
-
- }
-
- // recurse into children and search others to draw
- NodeSet<std::string> childElems = DOMUtils::filterChildType(Node_base::ELEMENT_NODE, stateElem);
- for (size_t i = 0; i < childElems.size(); i++) {
- Element<std::string> childElem(childElems[i]);
- if (InterpreterImpl::isState(Element<std::string>(childElem))) {
- writeStateElement(os, childElem);
- }
- }
-
- if (subgraph) {
- _indentation--;
- os << getPrefix() << "} #" << stateId << std::endl;
- _indentation--;
- }
-}
-
-void SCXMLDotWriter::writePerTransitionPorts(std::ostream& os, const DotState& dotState, int stateLines) {
- // TODO: Not implemented
-}
-
-void SCXMLDotWriter::writePerEventPorts(std::ostream& os, const DotState& dotState, int stateLines) {
- // std::multimap<std::string, Arabica::DOM::Element<std::string> > events; // key is event name, value is transitions that react
-
- std::string stateId = idForNode(dotState.node);
- DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
-
- for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end();
- it != end;
- it = dotState.events.upper_bound(it->first)) {
- os << " <tr><td port=\"" << portEscape(it->first) << "\" align=\"right\">" << it->first << "</td></tr>" << std::endl;
- }
-
-}
-
-std::string SCXMLDotWriter::htmlLabelForId(const std::string& stateId, int minRows) {
- FlatStateIdentifier flatId(stateId);
-
- std::list<std::string>::const_iterator listIter;
- std::stringstream labelSS;
- std::string seperator;
-
- labelSS << "<b>active: </b>";
- labelSS << "{";
- for (listIter = flatId.getActive().begin(); listIter != flatId.getActive().end(); listIter++) {
- labelSS << seperator << *listIter;
- seperator = ", ";
- }
- labelSS << "}";
-
- if (flatId.getVisited().size() > 0) {
- minRows--;
-
- labelSS << "<br /><b>init: </b>";
-
- labelSS << "{";
- seperator = "";
- for (listIter = flatId.getVisited().begin(); listIter != flatId.getVisited().end(); listIter++) {
- labelSS << seperator << *listIter;
- seperator = ", ";
- }
- labelSS << "}";
- }
-
- if (flatId.getHistory().size() > 0) {
- minRows--;
-
- seperator = "";
- std::string histSeperator = "<br /> ";
-
- labelSS << "<br /><b>history: </b>";
-
- std::map<std::string, std::list<std::string> >::const_iterator histIter;
- for (histIter = flatId.getHistory().begin(); histIter != flatId.getHistory().end(); histIter++) {
- labelSS << histSeperator << histIter->first << ": {";
-
- for (listIter = histIter->second.begin(); listIter != histIter->second.end(); listIter++) {
- labelSS << seperator << *listIter;
- seperator = ", ";
- }
- labelSS << "}";
- seperator = "";
- }
- }
- return labelSS.str();
-}
-
-
-void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const DotState& dotState, int stateLines) {
- // std::multimap<std::string, Arabica::DOM::Element<std::string> > targets; // key is remote node, transition is element
-
- int nrOutports = 0;
- std::string stateId = idForNode(dotState.node);
-
- typedef DotState::mmap_s_e_t iter_t;
-
- // we need to count outports first for vertical padding
- for(iter_t::const_iterator targetIter = dotState.targets.begin(), end = dotState.targets.end();
- targetIter != end;
- targetIter = dotState.targets.upper_bound(targetIter->first)) {
- nrOutports++;
- }
-
- for(iter_t::const_iterator targetIter = dotState.targets.begin(), end = dotState.targets.end();
- targetIter != end;
- targetIter = dotState.targets.upper_bound(targetIter->first)) {
-
- // gather all events that activate the transition
- std::string targetId = targetIter->first;
-
- std::set<std::string> eventNames;
-
- DotEdge edge(stateId, targetId);
- edge.fromPort = targetId;
-
- std::pair <iter_t::const_iterator, iter_t::const_iterator> targetKeyRange = dotState.targets.equal_range(targetId);
- for (iter_t::const_iterator transIter = targetKeyRange.first; transIter != targetKeyRange.second; ++transIter) {
- const Element<std::string>& transElem = transIter->second;
-
- std::list<std::string> events = tokenize(ATTR(transElem, "event"));
- eventNames.insert(events.begin(), events.end());
-
- if (events.size() == 0) {
- // spontaneous transition
- eventNames.insert("&#35;");
- edge.type = EDGE_SPONTANEOUS;
- }
- }
-
- if (_graph.find(targetId) != _graph.end())
- _edges.insert(edge);
-
- std::stringstream outPortSS;
- outPortSS << (_isFlat ? htmlLabelForId(targetId) : "<b>" + targetId + "</b>" );
-
- if (_isFlat) {
- outPortSS << "<br /><b>events: </b>{";
- } else {
- outPortSS << "<br />{";
- }
-
- std::string seperator;
- for (std::set<std::string>::const_iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) {
- outPortSS << seperator << *eventIter << std::endl;
- seperator = ", ";
- }
- outPortSS << "}";
-
- if (nrOutports == 1) {
- int missing = stateLines - nrOutports;
- while (_isFlat && missing-- >= 1) {
- outPortSS << "<br /> ";
- }
- }
-
- os << " <tr><td port=\"" << portEscape(targetId) << "\" balign=\"left\" align=\"left\">" << outPortSS.str() << "</td></tr>" << std::endl;
-
- }
-}
-
-std::string SCXMLDotWriter::getDetailedLabel(const Element<std::string>& elem, int indentation) {
-
- /*
- <table>
- <tr>
- <td colspan="2">onEntry</td>
- </tr>
- <tr>
- <td>Details</td>
- <td bgcolor="#eee">
- Nested Content
- </td>
- </tr>
- </table>
- */
-
- std::list<struct ElemDetails> content;
-
- NodeList<std::string > childElems = elem.getChildNodes();
- for (size_t i = 0; i < childElems.getLength(); i++) {
- if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- Element<std::string> elem = Element<std::string>(childElems.item(i));
-
- if (InterpreterImpl::isState(elem) ||
- iequals(TAGNAME(elem), "transition") ||
- iequals(TAGNAME(elem), "initial") ||
- false)
- continue;
-
- struct ElemDetails details;
- details.name = "<b>" + TAGNAME(elem) + ":</b>";
-
- if (iequals(TAGNAME(elem), "history")) {
- continue;
- }
-
- // provide details for special elements here
-
- // param ---------
- if (iequals(TAGNAME(elem), "param")) {
- if (HAS_ATTR(elem, "name"))
- details.name += " " + ATTR(elem, "name") + " = ";
- if (HAS_ATTR(elem, "expr"))
- details.name += ATTR(elem, "expr");
- if (HAS_ATTR(elem, "location"))
- details.name += ATTR(elem, "location");
- }
-
- // data ---------
- if (iequals(TAGNAME(elem), "data")) {
- if (HAS_ATTR(elem, "id"))
- details.name += " " + ATTR(elem, "id");
- if (HAS_ATTR(elem, "src"))
- details.name += ATTR(elem, "src");
- if (HAS_ATTR(elem, "expr"))
- details.name += " = " + ATTR(elem, "expr");
- NodeList<std::string > grandChildElems = elem.getChildNodes();
- for (size_t j = 0; j < grandChildElems.getLength(); j++) {
- if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) {
- details.name += dotEscape(grandChildElems.item(j).getNodeValue());
- }
- }
- }
-
- // invoke ---------
- if (iequals(TAGNAME(elem), "invoke")) {
- if (HAS_ATTR(elem, "type"))
- details.name += "<br />type = " + ATTR(elem, "type");
- if (HAS_ATTR(elem, "typeexpr"))
- details.name += "<br />type = " + ATTR(elem, "typeexpr");
- if (HAS_ATTR(elem, "src"))
- details.name += "<br />src = " + ATTR(elem, "src");
- if (HAS_ATTR(elem, "srcexpr"))
- details.name += "<br />src = " + ATTR(elem, "srcexpr");
- if (HAS_ATTR(elem, "id"))
- details.name += "<br />id = " + ATTR(elem, "id");
- if (HAS_ATTR(elem, "idlocation"))
- details.name += "<br />id = " + ATTR(elem, "idlocation");
- }
-
- // send ---------
- if (iequals(TAGNAME(elem), "raise")) {
- if (HAS_ATTR(elem, "event "))
- details.name += "<br />event = " + ATTR(elem, "event");
- }
-
- // send ---------
- if (iequals(TAGNAME(elem), "send")) {
- if (HAS_ATTR(elem, "id"))
- details.name += "<br />id = " + ATTR(elem, "id");
- if (HAS_ATTR(elem, "type"))
- details.name += "<br />type = " + ATTR(elem, "type");
- if (HAS_ATTR(elem, "typeexpr"))
- details.name += "<br />type = " + ATTR(elem, "typeexpr");
- if (HAS_ATTR(elem, "event"))
- details.name += "<br />event = " + ATTR(elem, "event");
- if (HAS_ATTR(elem, "eventexpr"))
- details.name += "<br />event = " + ATTR(elem, "eventexpr");
- if (HAS_ATTR(elem, "target"))
- details.name += "<br />target = " + ATTR(elem, "target");
- if (HAS_ATTR(elem, "targetexpr"))
- details.name += "<br />target = " + ATTR(elem, "targetexpr");
- if (HAS_ATTR(elem, "delay"))
- details.name += "<br />delay = " + ATTR(elem, "delay");
- if (HAS_ATTR(elem, "delayexpr"))
- details.name += "<br />delay = " + ATTR(elem, "delayexpr");
- }
-
- // cancel ---------
- if (iequals(TAGNAME(elem), "cancel")) {
- if (HAS_ATTR(elem, "sendid"))
- details.name += " " + ATTR(elem, "sendid");
- }
-
- // script ---------
- if (iequals(TAGNAME(elem), "script")) {
- details.name += " ";
- if (HAS_ATTR(elem, "src"))
- details.name += ATTR(elem, "src");
- NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
- for (size_t j = 0; j < grandChildElems.getLength(); j++) {
- if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) {
- details.name += dotEscape(grandChildElems.item(j).getNodeValue());
- }
- }
- }
-
- // if ---------
- if (iequals(TAGNAME(elem), "if")) {
- if (HAS_ATTR(elem, "cond"))
- details.name += " cond = " + dotEscape(ATTR(elem, "cond"));
- }
-
- // elseif ---------
- if (iequals(TAGNAME(elem), "elseif")) {
- if (HAS_ATTR(elem, "cond"))
- details.name += " cond = " + dotEscape(ATTR(elem, "cond"));
- }
-
- // log ---------
- if (iequals(TAGNAME(elem), "log")) {
- details.name += " ";
- if (HAS_ATTR(elem, "label"))
- details.name += ATTR(elem, "label") + " = ";
- if (HAS_ATTR(elem, "expr"))
- details.name += ATTR(elem, "expr");
- }
-
- // foreach ---------
- if (iequals(TAGNAME(elem), "foreach")) {
- if (HAS_ATTR(elem, "item"))
- details.name += "<br />&nbsp;&nbsp;item = " + ATTR(elem, "item");
- if (HAS_ATTR(elem, "array"))
- details.name += "<br />&nbsp;&nbsp;array = " + ATTR(elem, "array");
- if (HAS_ATTR(elem, "index"))
- details.name += "<br />&nbsp;&nbsp;index = " + ATTR(elem, "index");
- }
-
- // recurse
- details.content = getDetailedLabel((Element<std::string>)childElems.item(i), indentation + 1);
- content.push_back(details);
- }
-
- std::stringstream ssContent;
-
- if (content.size() > 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()) {
- ssContent << "<tr>";
-// ssContent << "<td align=\"left\" colspan=\"2\">" << contentIter->name << "</td>";
- ssContent << "<td balign=\"left\" align=\"left\">" << contentIter->name << "</td>";
- ssContent << "</tr>";
-
- if (contentIter->content.size() > 0) {
- ssContent << "<tr>";
-// ssContent << "<td>" << contentIter->details << "</td>";
- ssContent << "<td bgcolor=\"#" << colorForIndent(indentation + 1) << "\">" << contentIter->content << "</td>";
- ssContent << "</tr>";
- }
- contentIter++;
-
- }
- ssContent << "</table>";
- }
- return ssContent.str();
-}
-
-std::string SCXMLDotWriter::portEscape(const std::string& text) {
- std::string escaped(text);
- boost::replace_all(escaped, ".", "-");
- boost::replace_all(escaped, "{", "-");
- boost::replace_all(escaped, "}", "-");
- boost::replace_all(escaped, ":", "-");
- return escaped;
-}
-
-std::string SCXMLDotWriter::dotEscape(const std::string& text) {
- std::string escaped(text);
- boost::replace_all(escaped, " ", "&nbsp;");
- boost::replace_all(escaped, "\t", "&nbsp;&nbsp;&nbsp;");
- boost::replace_all(escaped, "<", "&lt;");
- boost::replace_all(escaped, ">", "&gt;");
- boost::replace_all(escaped, "\"", "&quot;");
- boost::replace_all(escaped, "\n", "<br />");
-
- return escaped;
-}
-
-std::string SCXMLDotWriter::colorForIndent(int indent) {
- int color = 255 - (16 * indent);
- std::stringstream ss;
- ss << std::hex << color;
- ss << std::hex << color;
- ss << std::hex << color;
- return ss.str();
-}
-
-std::string SCXMLDotWriter::nameForNode(const Node<std::string>& node) {
- std::string elemName;
- if (node.getNodeType() == Node_base::ELEMENT_NODE) {
- Element<std::string> elem = (Element<std::string>)node;
-
- if (InterpreterImpl::isFinal(elem) && _isFlat) {
- // ignore visited and history with final elements
- FlatStateIdentifier flatId(elem.getAttribute("id"));
- return "<b>" + flatId.getActive().front() + "</b>";
- }
-
- if (elem.hasAttribute("id") && _isFlat) {
- elemName = htmlLabelForId(elem.getAttribute("id"));
- if (elemName.size() > 0)
- return elemName;
- } else if (elem.getTagName() == "scxml") {
- if (elem.hasAttribute("name") && !UUID::isUUID(elem.getAttribute("name"))) {
- elemName += elem.getAttribute("name");
- } else if (elem.hasAttribute("id") && !UUID::isUUID(elem.getAttribute("id"))) {
- elemName += elem.getAttribute("id");
- }
- } else if (InterpreterImpl::isCompound(elem)) {
- elemName = "<i>Compound: </i>" + elem.getAttribute("id");
- } else if (InterpreterImpl::isParallel(elem)) {
- elemName = "<i>Parallel: </i>" + elem.getAttribute("id");
- } else if (elem.hasAttribute("id")) {
- elemName += elem.getAttribute("id");
- }
- }
-
- if (elemName.size() == 0)
- elemName = boost::lexical_cast<std::string>(node.getLocalName());
-
- return "<b>" + elemName + "</b>";
-
-}
-
-std::string SCXMLDotWriter::idForNode(const Node<std::string>& node) {
- std::string elemId;
-
- // try to get the id as the name or id attribute
- if (node.getNodeType() == Node_base::ELEMENT_NODE) {
- Element<std::string> elem = (Element<std::string>)node;
-
-// if (InterpreterImpl::isFinal(elem) && _isFlat) {
-// // ignore visited and history with final elements
-// FlatStateIdentifier flatId(elem.getAttribute("id"));
-//
-// std::stringstream activeSS;
-// activeSS << "active-";
-// for (std::list<std::string>::const_iterator activeIter = flatId.getActive().begin(); activeIter != flatId.getActive().end(); activeIter++) {
-// activeSS << *activeIter << "-";
-// }
-// return activeSS.str();
-// }
-
- if (elem.hasAttribute("name")) {
- elemId = elem.getAttribute("name");
- } else if (elem.hasAttribute("id")) {
- elemId = elem.getAttribute("id");
- }
- }
-
- // no luck, create id from position in tree
- if (elemId.size() == 0) {
- Node<std::string> tmpParent = node;
- Node<std::string> tmpIndex;
- do {
- if (tmpParent.getNodeType() != Node_base::ELEMENT_NODE)
- continue;
-
- tmpIndex = tmpParent;
- int index = 0;
-
- while((tmpIndex = tmpIndex.getPreviousSibling()))
- index++;
-
- std::stringstream ssElemId;
- ssElemId << TAGNAME_CAST(tmpParent) << index << ".";
- elemId = ssElemId.str() + elemId;
- } while ((tmpParent = tmpParent.getParentNode()));
-// elemId = ssElemId.str();
- }
- return elemId;
-}
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h
deleted file mode 100644
index f6c8b3d..0000000
--- a/src/uscxml/debug/SCXMLDotWriter.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * @file
- * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
- * @copyright Simplified BSD
- *
- * @cond
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the FreeBSD license as published by the FreeBSD
- * project.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the FreeBSD license along with this
- * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
- * @endcond
- */
-
-#ifndef SCXMLDOTWRITER_H_AOP0OHXX
-#define SCXMLDOTWRITER_H_AOP0OHXX
-
-#include "uscxml/Interpreter.h"
-#include <DOM/Document.hpp>
-#include <XPath/XPath.hpp>
-#include <fstream>
-#include <set>
-
-#undef max
-#include <limits>
-
-namespace uscxml {
-
-class Interpreter;
-
-
-
-/**
- * This writer, added as a monitor will output .dot files.
- *
- * # create a set of pdfs form the dot files
- * $ dot -Tpdf -O *.dot
- * or
- * $ find . -name "*.dot" -exec dot -Tpdf -O {} \;
- *
- * # create a movie from the pdfs
- * $ dot -Tgif -O *.dot
- * or
- * $ find . -name "*.dot" -exec dot -Tgif -O {} \;
- *
- * $ ffmpeg -r 3 -i <NAME>.%06d.dot.gif -r 25 movie.mpg
- * $ convert -delay 20 *.gif animated.gif
- *
- * # unflatten can be used to create more compact graphs
- * find . -name "*.dot" -exec unflatten -f -l2 -o {}.flat.dot {} \;
- */
-class USCXML_API SCXMLDotWriter : public InterpreterMonitor {
-public:
-
- enum PortType {
- PORT_TARGET,
- PORT_EVENT,
- PORT_TRANSITION
- };
-
- struct StateAnchor {
- StateAnchor() : childDepth(std::numeric_limits<int32_t>::max()), transDepth(std::numeric_limits<int32_t>::max()), type(PORT_TARGET) {}
- Arabica::DOM::Element<std::string> element;
- int32_t childDepth;
- int32_t transDepth;
-
- PortType type;
-
- operator bool() const {
- return childDepth != -1 || transDepth != -1 || element;
- }
- };
-
- struct ElemDetails {
- std::string name;
- std::string details;
- std::string content;
- };
-
- struct DotState {
- DotState() : isBorder(false), portType(PORT_TARGET) {}
- Arabica::DOM::Element<std::string> node;
- Arabica::XPath::NodeSet<std::string> transitions;
- 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;
- PortType portType;
-
- std::set<std::string> childs;
- std::set<std::string> initialchilds;
-
- typedef std::multimap<std::string, Arabica::DOM::Element<std::string> > mmap_s_e_t;
- };
-
- enum EdgeType {
- EDGE_INITAL,
- EDGE_TRANSIION,
- EDGE_SPONTANEOUS
- };
-
- struct DotEdge {
- DotEdge() : type(EDGE_TRANSIION) {}
- DotEdge(const std::string& from, const std::string& to) : type(EDGE_TRANSIION), from(from), to(to) {
- }
-
- bool operator< (const DotEdge& other) const {
- return from + fromPort + to + toPort > other.from + other.fromPort + other.to + other.toPort;
- }
-
- EdgeType type;
- std::string from;
- std::string fromCompass;
- std::string fromPort;
- std::string to;
- std::string toPort;
- std::string toCompass;
- };
-
- SCXMLDotWriter();
- ~SCXMLDotWriter();
-
- virtual void onStableConfiguration(Interpreter interpreter);
- virtual void afterCompletion(Interpreter interpreter);
- virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing);
- virtual void beforeMicroStep(Interpreter interpreter);
-
- static std::string htmlLabelForId(const std::string& stateId, int minRows = 0);
-
- 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);
-
- std::string idForNode(const Arabica::DOM::Node<std::string>& node);
- std::string nameForNode(const Arabica::DOM::Node<std::string>& node);
- 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 assembleGraph(const Arabica::DOM::Element<std::string>& start,
- int32_t childDepth = std::numeric_limits<int32_t>::max(),
- int32_t transDepth = std::numeric_limits<int32_t>::max());
- void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& state);
-
- void writePerTransitionPorts(std::ostream& os, const DotState& dotState, int stateLines = 0);
- void writePerEventPorts(std::ostream& os, const DotState& dotState, int stateLines = 0);
- void writePerTargetPorts(std::ostream& os, const DotState& dotState, int stateLines = 0);
-
- 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;
- std::set<DotEdge> _edges;
-
- // these are only set in ephemeral instances per monitor call
- Arabica::DOM::Element<std::string> _transition;
- Arabica::DOM::Element<std::string> _scxml;
- Interpreter _interpreter;
- bool _isFlat;
-
- std::string _xmlNSPrefix;
- std::list<StateAnchor> _anchors;
- std::map<std::string, DotEdge> _histories;
-
- PortType _portType;
-
-};
-
-}
-
-#endif /* end of include guard: SCXMLDOTWRITER_H_AOP0OHXX */