summaryrefslogtreecommitdiffstats
path: root/src/uscxml/debug
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-08-21 15:16:52 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-08-21 15:16:52 (GMT)
commitbd45c688b3d3aad5d62b85457ce943eaadf989ae (patch)
tree831d54da85c85f3e998be70241f8ffc3fed7f924 /src/uscxml/debug
parenta52fb3364968e31a1a15c85ac45b68d9f531687b (diff)
downloaduscxml-bd45c688b3d3aad5d62b85457ce943eaadf989ae.zip
uscxml-bd45c688b3d3aad5d62b85457ce943eaadf989ae.tar.gz
uscxml-bd45c688b3d3aad5d62b85457ce943eaadf989ae.tar.bz2
Added WebStorage object to document
Some refinements to DotWriter
Diffstat (limited to 'src/uscxml/debug')
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp464
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp.old359
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.h57
3 files changed, 513 insertions, 367 deletions
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
new file mode 100644
index 0000000..d6a9a49
--- /dev/null
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -0,0 +1,464 @@
+#include "uscxml/Common.h"
+#include "SCXMLDotWriter.h"
+#include <boost/algorithm/string.hpp> // replace_all
+#include <iomanip>
+
+namespace uscxml {
+
+using namespace Arabica::DOM;
+
+SCXMLDotWriter::SCXMLDotWriter() {
+ _iteration = 0;
+ _indentation = 0;
+}
+
+SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {
+ _interpreter = interpreter;
+ _transitions = transitions;
+ _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::beforeTakingTransitions(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {
+ std::ostringstream fileSS;
+ fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
+ toDot(fileSS.str(), interpreter, transitions);
+}
+
+std::string SCXMLDotWriter::getPrefix() {
+ std::string prefix = "";
+ for (int i = 0; i < _indentation; i++)
+ prefix += " ";
+ return prefix;
+}
+
+void SCXMLDotWriter::toDot(const std::string& filename, Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {
+ std::ofstream outfile(filename.c_str());
+ NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
+ SCXMLDotWriter writer(interpreter, transitions);
+ if (scxmlElems.getLength() > 0) {
+ writer._indentation++;
+ outfile << "digraph {" << std::endl;
+ outfile << "rankdir=TB; fontsize=10;" << std::endl;
+ writer.writeSCXMLElement(outfile, (Arabica::DOM::Element<std::string>)scxmlElems.item(0));
+ writer._indentation--;
+ outfile << "}" << std::endl;
+ }
+
+}
+
+void SCXMLDotWriter::writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
+ writeStateElement(os, elem);
+
+// std::string elemId = idForNode(elem);
+// os << getPrefix() << "subgraph \"cluster" << elemId.substr(1, elemId.length() - 1) << " {" << std::endl;
+// _indentation++;
+// os << getPrefix() << "label=\"" << nameForNode(elem) << "\"" << std::endl;
+// writeStateElement(os, (Arabica::DOM::Element<std::string>)_interpreter->getInitialState());
+// os << getPrefix() << "} " << std::endl;
+
+}
+
+void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
+
+ std::string elemId = idForNode(elem);
+ NodeList<std::string > childElems = elem.getChildNodes();
+
+ if (_knownIds.find(elemId) != _knownIds.end())
+ return;
+ _knownIds.insert(elemId);
+
+ bool subgraph = Interpreter::isCompound(elem) || Interpreter::isParallel(elem);
+ if (subgraph) {
+ _indentation++;
+ os << getPrefix() << "subgraph \"cluster_" << elemId << "\" {" << std::endl;
+ os << getPrefix() << "label=\"" << nameForNode(elem) << "\\l\"" << std::endl;
+ }
+
+ os << getPrefix() << "\"" << elemId << "\"[";
+ os << "fontsize=10,";
+ os << "label=<<b>State</b><br />" << nameForNode(elem) << ">,";
+
+ // is the state initial?
+ if (_interpreter.isInitial(elem))
+ os << "style=filled, fillcolor=lightgrey, ";
+
+ // is this state final?
+ if (_interpreter.isFinal(elem))
+ os << "shape=doublecircle,";
+
+ // is the current state in the basic configuration?
+ if (_interpreter.isMember(elem, _interpreter.getBasicConfiguration()))
+ os << "color=red, penwidth=3,";
+
+ // is the current state a target state?
+#if 0
+ for (int i = 0; i < _transitions.size(); i++) {
+ if (_interpreter.isMember(elem, _interpreter.getTargetStates(_transitions[i]))) {
+ os << "color=red, penwidth=3,";
+ break;
+ }
+ }
+#endif
+
+ os << "];" << std::endl;
+
+ std::string details = getDetailedLabel(elem);
+// std::cout << details << std::endl;
+
+ if (details.size() > 0) {
+ os << getPrefix() << "\"" << elemId << "Exec\"[";
+ os << "fontsize=8,";
+ os << "shape=box,";
+ os << "color=grey,";
+ os << "label=<" << details << ">";
+ os << "]" << std::endl;
+ os << getPrefix() << "\"" << elemId << "\" -> \"" << elemId << "Exec\" [arrowhead=none, color=grey]" << std::endl;
+ }
+
+// NodeList<std::string > childElems = elem.getChildNodes();
+// for (int i = 0; i < childElems.getLength(); i++) {
+// if (Interpreter::isState(childElems.item(i))) {
+// writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
+// }
+// }
+
+ for (int i = 0; i < childElems.getLength(); i++) {
+ if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childElems.item(i)), "transition")) {
+ writeTransitionElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
+ bool active = Interpreter::isMember(childElems.item(i), _transitions);
+ os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(childElems.item(i)) << "\" [arrowhead=none" << std::endl;
+ if (active) {
+ os << ", penwidth=3, color=red]" << std::endl;
+ } else {
+ os << "]" << std::endl;
+ }
+ }
+ if (Interpreter::isState(childElems.item(i))) {
+ writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
+ }
+ if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childElems.item(i)), "initial")) {
+ NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
+ for (int j = 0; j < grandChildElems.getLength(); j++) {
+ if (grandChildElems.item(j).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(grandChildElems.item(j)), "transition")) {
+ writeTransitionElement(os, (Arabica::DOM::Element<std::string>)grandChildElems.item(j));
+ os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(grandChildElems.item(j)) << "\"" << std::endl;
+ }
+ }
+ }
+ }
+
+ if (subgraph) {
+ _indentation--;
+ os << getPrefix() << "} " << std::endl;
+ }
+
+}
+
+void SCXMLDotWriter::writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
+ std::string elemId = idForNode(elem);
+
+ Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getTargetStates(elem);
+
+ bool active = Interpreter::isMember(elem, _transitions);
+
+ std::string label;
+ os << getPrefix() << "\"" << elemId << "\"[";
+ if (active) {
+ os << "color=red, penwidth=3, ";
+ }
+ os << "fontsize=10,";
+ os << "shape=box,";
+ os << "label=<<b>Transition</b><br align=\"left\" />";
+ if (HAS_ATTR(elem, "event"))
+ os << "event: " << ATTR(elem, "event");
+ if (HAS_ATTR(elem, "cond"))
+ os << "cond: " << dotEscape(ATTR(elem, "cond"));
+ if (!HAS_ATTR(elem, "cond") && !HAS_ATTR(elem, "event"))
+ os << "unconditional";
+ os << ">";
+ os << "]" << std::endl;
+
+ for (int i = 0; i < targetStates.size(); i++) {
+ os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(targetStates[i]) << "\"";
+ if (active) {
+ os << " [penwidth=3, color=red]" << std::endl;
+ } else {
+ os << std::endl;
+ }
+ writeStateElement(os, (Arabica::DOM::Element<std::string>)targetStates[i]);
+ }
+
+}
+
+std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::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 (int i = 0; i < childElems.getLength(); i++) {
+ if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+
+ if (Interpreter::isState(childElems.item(i)) ||
+ boost::iequals(TAGNAME(childElems.item(i)), "transition") ||
+ boost::iequals(TAGNAME(childElems.item(i)), "initial") ||
+ false)
+ continue;
+
+ struct ElemDetails details;
+ details.name = "<b>" + TAGNAME(childElems.item(i)) + ":</b>";
+
+ // provide details for special elements here
+
+ // param ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "param")) {
+ if (HAS_ATTR(childElems.item(i), "name"))
+ details.name += " " + ATTR(childElems.item(i), "name") + " = ";
+ if (HAS_ATTR(childElems.item(i), "expr"))
+ details.name += ATTR(childElems.item(i), "expr");
+ if (HAS_ATTR(childElems.item(i), "location"))
+ details.name += ATTR(childElems.item(i), "location");
+ }
+
+ // data ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "data")) {
+ if (HAS_ATTR(childElems.item(i), "id"))
+ details.name += " " + ATTR(childElems.item(i), "id");
+ if (HAS_ATTR(childElems.item(i), "src"))
+ details.name += ATTR(childElems.item(i), "src");
+ if (HAS_ATTR(childElems.item(i), "expr"))
+ details.name += " = " + ATTR(childElems.item(i), "expr");
+ NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
+ for (int j = 0; j < grandChildElems.getLength(); j++) {
+ if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) {
+ details.name += dotEscape(grandChildElems.item(j).getNodeValue());
+ }
+ }
+ }
+
+ // invoke ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "invoke")) {
+ if (HAS_ATTR(childElems.item(i), "type"))
+ details.name += "<br />type = " + ATTR(childElems.item(i), "type");
+ if (HAS_ATTR(childElems.item(i), "typeexpr"))
+ details.name += "<br />type = " + ATTR(childElems.item(i), "typeexpr");
+ if (HAS_ATTR(childElems.item(i), "src"))
+ details.name += "<br />src = " + ATTR(childElems.item(i), "src");
+ if (HAS_ATTR(childElems.item(i), "srcexpr"))
+ details.name += "<br />src = " + ATTR(childElems.item(i), "srcexpr");
+ if (HAS_ATTR(childElems.item(i), "id"))
+ details.name += "<br />id = " + ATTR(childElems.item(i), "id");
+ if (HAS_ATTR(childElems.item(i), "idlocation"))
+ details.name += "<br />id = " + ATTR(childElems.item(i), "idlocation");
+ }
+
+ // send ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "send")) {
+ if (HAS_ATTR(childElems.item(i), "type"))
+ details.name += "<br />type = " + ATTR(childElems.item(i), "type");
+ if (HAS_ATTR(childElems.item(i), "typeexpr"))
+ details.name += "<br />type = " + ATTR(childElems.item(i), "typeexpr");
+ if (HAS_ATTR(childElems.item(i), "event"))
+ details.name += "<br />event = " + ATTR(childElems.item(i), "event");
+ if (HAS_ATTR(childElems.item(i), "eventexpr"))
+ details.name += "<br />event = " + ATTR(childElems.item(i), "eventexpr");
+ if (HAS_ATTR(childElems.item(i), "target"))
+ details.name += "<br />target = " + ATTR(childElems.item(i), "target");
+ if (HAS_ATTR(childElems.item(i), "targetexpr"))
+ details.name += "<br />target = " + ATTR(childElems.item(i), "targetexpr");
+ if (HAS_ATTR(childElems.item(i), "delay"))
+ details.name += "<br />delay = " + ATTR(childElems.item(i), "delay");
+ if (HAS_ATTR(childElems.item(i), "delayexpr"))
+ details.name += "<br />delay = " + ATTR(childElems.item(i), "delayexpr");
+ }
+
+ // script ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "script")) {
+ details.name += " ";
+ if (HAS_ATTR(childElems.item(i), "src"))
+ details.name += ATTR(childElems.item(i), "src");
+ NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
+ for (int j = 0; j < grandChildElems.getLength(); j++) {
+ if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) {
+ details.name += dotEscape(grandChildElems.item(j).getNodeValue());
+ }
+ }
+ }
+
+ // if ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "if")) {
+ if (HAS_ATTR(childElems.item(i), "cond"))
+ details.name += " cond = " + dotEscape(ATTR(childElems.item(i), "cond"));
+ }
+
+ // elseif ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "elseif")) {
+ if (HAS_ATTR(childElems.item(i), "cond"))
+ details.name += " cond = " + dotEscape(ATTR(childElems.item(i), "cond"));
+ }
+
+ // log ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "log")) {
+ details.name += " ";
+ if (HAS_ATTR(childElems.item(i), "label"))
+ details.name += ATTR(childElems.item(i), "label") + " = ";
+ if (HAS_ATTR(childElems.item(i), "expr"))
+ details.name += ATTR(childElems.item(i), "expr");
+ }
+
+ // foreach ---------
+ if (boost::iequals(TAGNAME(childElems.item(i)), "foreach")) {
+ if (HAS_ATTR(childElems.item(i), "item"))
+ details.name += "<br />&nbsp;&nbsp;item = " + ATTR(childElems.item(i), "item");
+ if (HAS_ATTR(childElems.item(i), "array"))
+ details.name += "<br />&nbsp;&nbsp;array = " + ATTR(childElems.item(i), "array");
+ if (HAS_ATTR(childElems.item(i), "index"))
+ details.name += "<br />&nbsp;&nbsp;index = " + ATTR(childElems.item(i), "index");
+ }
+
+ // recurse
+ details.content = getDetailedLabel((Arabica::DOM::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\">";
+
+ 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::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 Arabica::DOM::Node<std::string>& node) {
+ std::string elemName;
+ if (node.getNodeType() == Node_base::ELEMENT_NODE) {
+ Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
+ if (elem.hasAttribute("name")) {
+ elemName = elem.getAttribute("name");
+ } else if (elem.hasAttribute("id")) {
+ elemName = elem.getAttribute("id");
+ }
+ }
+ if (elemName.size() == 0)
+ elemName = boost::lexical_cast<std::string>(node.getLocalName());
+
+ return elemName;
+
+}
+
+std::string SCXMLDotWriter::idForNode(const Arabica::DOM::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) {
+ Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
+ 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) {
+ Arabica::DOM::Node<std::string> tmpParent = node;
+ Arabica::DOM::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(tmpParent) << index << ".";
+ elemId = ssElemId.str() + elemId;
+ } while ((tmpParent = tmpParent.getParentNode()));
+// elemId = ssElemId.str();
+ }
+
+ std::replace(elemId.begin(), elemId.end(), '-', '_');
+
+ return elemId;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp.old b/src/uscxml/debug/SCXMLDotWriter.cpp.old
deleted file mode 100644
index 20d82c9..0000000
--- a/src/uscxml/debug/SCXMLDotWriter.cpp.old
+++ /dev/null
@@ -1,359 +0,0 @@
-#include "uscxml/Common.h"
-#include "SCXMLDotWriter.h"
-#include "uscxml/Interpreter.h"
-#include <boost/algorithm/string.hpp> // replace_all
-
-namespace uscxml {
-
-using namespace Arabica::DOM;
-
-int SCXMLDotWriter::_indentation = 0;
-
-SCXMLDotWriter::SCXMLDotWriter(Interpreter* interpreter) {
- _interpreter = interpreter;
-}
-
-SCXMLDotWriter::~SCXMLDotWriter() {
-
-}
-
-std::string SCXMLDotWriter::getPrefix() {
- std::string prefix = "";
- for (int i = 0; i < _indentation; i++)
- prefix += " ";
- return prefix;
-}
-
-void SCXMLDotWriter::toDot(const std::string& filename, Interpreter* interpreter) {
- std::ofstream outfile(filename.c_str());
- NodeList<std::string > scxmlElems = interpreter->getDocument().getElementsByTagName("scxml");
- SCXMLDotWriter writer(interpreter);
- if (scxmlElems.getLength() > 0) {
- _indentation++;
- outfile << "digraph {" << std::endl;
- outfile << "rankdir=LR;" << std::endl;
- writer.writeSCXMLElement(outfile, (Arabica::DOM::Element<std::string>)scxmlElems.item(0));
- _indentation--;
- outfile << "}" << std::endl;
- }
-
-}
-
-void SCXMLDotWriter::writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
- writeStateElement(os, elem);
-
-// std::string elemId = idForNode(elem);
-// os << getPrefix() << "subgraph \"cluster" << elemId.substr(1, elemId.length() - 1) << " {" << std::endl;
-// _indentation++;
-// os << getPrefix() << "label=\"" << nameForNode(elem) << "\"" << std::endl;
-// writeStateElement(os, (Arabica::DOM::Element<std::string>)_interpreter->getInitialState());
-// os << getPrefix() << "} " << std::endl;
-
-}
-
-void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
-
- std::string elemId = idForNode(elem);
- NodeList<std::string > childElems = elem.getChildNodes();
-
- if (_knownIds.find(elemId) != _knownIds.end())
- return;
- _knownIds.insert(elemId);
-
- bool subgraph = Interpreter::isCompound(elem) || Interpreter::isParallel(elem);
- if (subgraph) {
- _indentation++;
- os << getPrefix() << "subgraph \"cluster_" << elemId << "\" {" << std::endl;
- os << getPrefix() << "label=\"" << nameForNode(elem) << "\\l\"" << std::endl;
- }
-
- os << getPrefix() << "\"" << elemId << "\"[";
- os << "label=<<b>State</b><br />" << nameForNode(elem) << ">,";
- if (_interpreter->isInitial(elem))
- os << "style=filled,";
- if (_interpreter->isFinal(elem))
- os << "shape=doublecircle,";
- os << "];" << std::endl;
-
- std::string details = getDetailedLabel(elem);
-// std::cout << details << std::endl;
-
- if (details.size() > 0) {
- os << getPrefix() << "\"" << elemId << "Exec\"[";
-// os << "fontsize=10,";
- os << "shape=box,";
- os << "color=grey,";
- os << "label=<" << details << ">";
- os << "]" << std::endl;
- os << getPrefix() << "\"" << elemId << "\" -> \"" << elemId << "Exec\" [arrowhead=none, color=grey]" << std::endl;
- }
-
-// NodeList<std::string > childElems = elem.getChildNodes();
-// for (int i = 0; i < childElems.getLength(); i++) {
-// if (Interpreter::isState(childElems.item(i))) {
-// writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
-// }
-// }
-
- for (int i = 0; i < childElems.getLength(); i++) {
- if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childElems.item(i)), "transition")) {
- writeTransitionElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
- os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(childElems.item(i)) << "\"" << std::endl;
- }
- if (Interpreter::isState(childElems.item(i))) {
- writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
- }
- if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childElems.item(i)), "initial")) {
- NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
- for (int j = 0; j < grandChildElems.getLength(); j++) {
- if (grandChildElems.item(j).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(grandChildElems.item(j)), "transition")) {
- writeTransitionElement(os, (Arabica::DOM::Element<std::string>)grandChildElems.item(j));
- os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(grandChildElems.item(j)) << "\"" << std::endl;
- }
- }
- }
- }
-
- if (subgraph) {
- _indentation--;
- os << getPrefix() << "} " << std::endl;
- }
-
-}
-
-void SCXMLDotWriter::writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) {
- std::string elemId = idForNode(elem);
-
- Arabica::XPath::NodeSet<std::string> targetStates = _interpreter->getTargetStates(elem);
-
- std::string label;
- os << getPrefix() << "\"" << elemId << "\"[";
-// os << "fontsize=10,";
- os << "shape=box,";
- os << "label=<<b>Transition</b><br align=\"left\" />";
- if (HAS_ATTR(elem, "event"))
- os << "event: " << ATTR(elem, "event");
- if (HAS_ATTR(elem, "cond"))
- os << "cond: " << ATTR(elem, "cond");
- if (!HAS_ATTR(elem, "cond") && !HAS_ATTR(elem, "event"))
- os << "unconditional";
- os << ">";
- os << "]" << std::endl;
-
- for (int i = 0; i < targetStates.size(); i++) {
- os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(targetStates[i]) << "\"" << std::endl;
- writeStateElement(os, (Arabica::DOM::Element<std::string>)targetStates[i]);
- }
-
-}
-
-std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::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 (int i = 0; i < childElems.getLength(); i++) {
- if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
-
- if (Interpreter::isState(childElems.item(i)) ||
- boost::iequals(TAGNAME(childElems.item(i)), "transition") ||
- boost::iequals(TAGNAME(childElems.item(i)), "initial") ||
- false)
- continue;
-
- struct ElemDetails details;
- details.name = "<b>" + TAGNAME(childElems.item(i)) + "</b>";
-
- // provide details for special elements here
-
- // param ---------
- if (boost::iequals(TAGNAME(childElems.item(i)), "param")) {
- if (HAS_ATTR(childElems.item(i), "name"))
- details.name += " " + ATTR(childElems.item(i), "name") + " = ";
- if (HAS_ATTR(childElems.item(i), "expr"))
- details.name += ATTR(childElems.item(i), "expr");
- if (HAS_ATTR(childElems.item(i), "location"))
- details.name += ATTR(childElems.item(i), "location");
- }
-
- // data ---------
- if (boost::iequals(TAGNAME(childElems.item(i)), "data")) {
- if (HAS_ATTR(childElems.item(i), "id"))
- details.name += " " + ATTR(childElems.item(i), "id") + " = ";
- if (HAS_ATTR(childElems.item(i), "src"))
- details.name += ATTR(childElems.item(i), "src");
- if (HAS_ATTR(childElems.item(i), "expr"))
- details.name += ATTR(childElems.item(i), "expr");
- NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
- for (int j = 0; j < grandChildElems.getLength(); j++) {
- if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) {
- details.name += dotEscape(grandChildElems.item(j).getNodeValue());
- }
- }
- }
-
- // invoke ---------
- if (boost::iequals(TAGNAME(childElems.item(i)), "invoke")) {
- if (HAS_ATTR(childElems.item(i), "type"))
- details.name += "<br />type = " + ATTR(childElems.item(i), "type");
- if (HAS_ATTR(childElems.item(i), "typeexpr"))
- details.name += "<br />type = " + ATTR(childElems.item(i), "typeexpr");
- if (HAS_ATTR(childElems.item(i), "src"))
- details.name += "<br />src = " + ATTR(childElems.item(i), "src");
- if (HAS_ATTR(childElems.item(i), "srcexpr"))
- details.name += "<br />src = " + ATTR(childElems.item(i), "srcexpr");
- if (HAS_ATTR(childElems.item(i), "id"))
- details.name += "<br />id = " + ATTR(childElems.item(i), "id");
- if (HAS_ATTR(childElems.item(i), "idlocation"))
- details.name += "<br />id = " + ATTR(childElems.item(i), "idlocation");
- }
-
- // send ---------
- if (boost::iequals(TAGNAME(childElems.item(i)), "send")) {
- if (HAS_ATTR(childElems.item(i), "type"))
- details.name += "<br />type = " + ATTR(childElems.item(i), "type");
- if (HAS_ATTR(childElems.item(i), "typeexpr"))
- details.name += "<br />type = " + ATTR(childElems.item(i), "typeexpr");
- if (HAS_ATTR(childElems.item(i), "event"))
- details.name += "<br />event = " + ATTR(childElems.item(i), "event");
- if (HAS_ATTR(childElems.item(i), "eventexpr"))
- details.name += "<br />event = " + ATTR(childElems.item(i), "eventexpr");
- if (HAS_ATTR(childElems.item(i), "target"))
- details.name += "<br />target = " + ATTR(childElems.item(i), "target");
- if (HAS_ATTR(childElems.item(i), "targetexpr"))
- details.name += "<br />target = " + ATTR(childElems.item(i), "targetexpr");
- if (HAS_ATTR(childElems.item(i), "delay"))
- details.name += "<br />delay = " + ATTR(childElems.item(i), "delay");
- if (HAS_ATTR(childElems.item(i), "delayexpr"))
- details.name += "<br />delay = " + ATTR(childElems.item(i), "delayexpr");
- }
-
- // script ---------
- if (boost::iequals(TAGNAME(childElems.item(i)), "script")) {
- details.name += " ";
- if (HAS_ATTR(childElems.item(i), "src"))
- details.name += ATTR(childElems.item(i), "src");
- NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes();
- for (int j = 0; j < grandChildElems.getLength(); j++) {
- if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) {
- details.name += dotEscape(grandChildElems.item(j).getNodeValue());
- }
- }
- }
-
- // recurse
- details.content = getDetailedLabel((Arabica::DOM::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\">";
-
- 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::dotEscape(const std::string& text) {
- std::string escaped(text);
- boost::replace_all(escaped, "", "");
-
- 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 Arabica::DOM::Node<std::string>& node) {
- std::string elemName;
- if (node.getNodeType() == Node_base::ELEMENT_NODE) {
- Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
- if (elem.hasAttribute("name")) {
- elemName = elem.getAttribute("name");
- } else if (elem.hasAttribute("id")) {
- elemName = elem.getAttribute("id");
- }
- }
- if (elemName.size() == 0)
- elemName = boost::lexical_cast<std::string>(node.getLocalName());
-
- return elemName;
-
-}
-
-std::string SCXMLDotWriter::idForNode(const Arabica::DOM::Node<std::string>& node) {
- std::string elemId;
- if (node.getNodeType() == Node_base::ELEMENT_NODE) {
- Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
- if (elem.hasAttribute("name")) {
- elemId = elem.getAttribute("name");
- } else if (elem.hasAttribute("id")) {
- elemId = elem.getAttribute("id");
- }
- }
- if (elemId.size() == 0) {
- Arabica::DOM::Node<std::string> tmpParent = node;
- Arabica::DOM::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(tmpParent) << index << ".";
- elemId = ssElemId.str() + elemId;
- } while ((tmpParent = tmpParent.getParentNode()));
-// elemId = ssElemId.str();
- }
-
- std::replace(elemId.begin(), elemId.end(), '-', '_');
-// std::replace(elemId.begin(), elemId.end(), '.', '_');
-
- return elemId;
-}
-
-} \ No newline at end of file
diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h
index 0666aa5..07b34b1 100644
--- a/src/uscxml/debug/SCXMLDotWriter.h
+++ b/src/uscxml/debug/SCXMLDotWriter.h
@@ -1,7 +1,9 @@
#ifndef SCXMLDOTWRITER_H_AOP0OHXX
#define SCXMLDOTWRITER_H_AOP0OHXX
+#include "uscxml/Interpreter.h"
#include <DOM/Document.hpp>
+#include <XPath/XPath.hpp>
#include <fstream>
#include <set>
@@ -9,7 +11,28 @@ namespace uscxml {
class Interpreter;
-class SCXMLDotWriter {
+
+
+/**
+ * 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 SCXMLDotWriter : public InterpreterMonitor {
public:
struct ElemDetails {
@@ -18,25 +41,43 @@ public:
std::string content;
};
- SCXMLDotWriter(InterpreterImpl* interpreter);
+ SCXMLDotWriter();
~SCXMLDotWriter();
- static void toDot(const std::string& filename, InterpreterImpl* interpreter);
- void writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
- void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
- void writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
+ virtual void onStableConfiguration(Interpreter interpreter);
+ virtual void afterCompletion(Interpreter interpreter);
+ virtual void beforeTakingTransitions(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions);
+ virtual void beforeMicroStep(Interpreter interpreter);
+
+ static void toDot(const std::string& filename,
+ Interpreter interpreter,
+ const Arabica::XPath::NodeSet<std::string>& transitions = Arabica::XPath::NodeSet<std::string>());
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 getPrefix();
static std::string dotEscape(const std::string& text);
+protected:
+
+ SCXMLDotWriter(Interpreter interpreter,
+ const Arabica::XPath::NodeSet<std::string>& transitions);
+
+ void writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
+ void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
+ void writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
+
+ int _iteration;
std::set<std::string> _knownIds;
- static int _indentation;
+ int _indentation;
+
+ // these are only set in ephemeral instances per monitor call
+ Arabica::XPath::NodeSet<std::string> _transitions;
+ Interpreter _interpreter;
};
}