summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/uscxml-transform.cpp44
-rw-r--r--src/uscxml/DOMUtils.cpp92
-rw-r--r--src/uscxml/DOMUtils.h29
-rw-r--r--src/uscxml/Interpreter.cpp35
-rw-r--r--src/uscxml/interpreter/InterpreterFast.cpp10
-rw-r--r--src/uscxml/interpreter/InterpreterFast.h26
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp1
-rw-r--r--src/uscxml/transform/ChartToC.cpp1227
-rw-r--r--src/uscxml/transform/ChartToC.h26
-rw-r--r--src/uscxml/transform/ChartToVHDL.cpp230
-rw-r--r--src/uscxml/transform/ChartToVHDL.h19
-rw-r--r--src/uscxml/transform/Transformer.h24
-rw-r--r--test/ctest/CTestCustom.ctest.in74
-rw-r--r--test/src/test-c-machine.cpp1067
-rw-r--r--test/src/test-c-machine.machine.c722
15 files changed, 2126 insertions, 1500 deletions
diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp
index fcc9965..857a160 100644
--- a/apps/uscxml-transform.cpp
+++ b/apps/uscxml-transform.cpp
@@ -94,9 +94,9 @@ void printUsageAndExit(const char* progName) {
printf("\t verbose - comments detailling state changes and transitions for content selection (-tflat only)\n");
printf("\t progress - insert comments documenting progress in dociment (-tmin only)\n");
printf("\t nocomment - surpress the generation of comments in output\n");
- printf("\t-X {PARAMETER} : pass additional parameters to the transformation\n");
- printf("\t prefix=ID - prefix all symbols and identifiers with ID (-tc)\n");
- printf("\t-v : be verbose\n");
+ printf("\t-X {PARAMETER} : pass additional parameters to the transformation\n");
+ printf("\t prefix=ID - prefix all symbols and identifiers with ID (-tc)\n");
+ printf("\t-v : be verbose\n");
printf("\t-lN : Set loglevel to N\n");
printf("\t-i URL : Input file (defaults to STDIN)\n");
printf("\t-o FILE : Output file (defaults to STDOUT)\n");
@@ -113,8 +113,8 @@ int main(int argc, char** argv) {
std::string inputFile;
std::string outputFile;
std::list<std::string> options;
- std::multimap<std::string, std::string> extensions;
-
+ std::multimap<std::string, std::string> extensions;
+
#if defined(HAS_SIGNAL_H) && !defined(WIN32)
signal(SIGPIPE, SIG_IGN);
#endif
@@ -129,8 +129,8 @@ int main(int argc, char** argv) {
struct option longOptions[] = {
{"verbose", no_argument, 0, 'v'},
{"type", required_argument, 0, 't'},
- {"annotate", required_argument, 0, 'a'},
- {"param", required_argument, 0, 'X'},
+ {"annotate", required_argument, 0, 'a'},
+ {"param", required_argument, 0, 'X'},
{"plugin-path", required_argument, 0, 'p'},
{"input-file", required_argument, 0, 'i'},
{"output-file", required_argument, 0, 'o'},
@@ -167,15 +167,15 @@ int main(int argc, char** argv) {
case 'a':
options = InterpreterImpl::tokenize(optarg, ',');
break;
- case 'X': {
- std::list<std::string> extension = InterpreterImpl::tokenize(optarg, '=');
- if (extension.size() != 2)
- printUsageAndExit(argv[0]);
- std::string key = boost::trim_copy(*(extension.begin()));
- std::string value = boost::trim_copy(*(++extension.begin()));
- extensions.insert(std::pair<std::string, std::string>(key, value));
- }
- break;
+ case 'X': {
+ std::list<std::string> extension = InterpreterImpl::tokenize(optarg, '=');
+ if (extension.size() != 2)
+ printUsageAndExit(argv[0]);
+ std::string key = boost::trim_copy(*(extension.begin()));
+ std::string value = boost::trim_copy(*(++extension.begin()));
+ extensions.insert(std::pair<std::string, std::string>(key, value));
+ }
+ break;
case 'o':
outputFile = optarg;
break;
@@ -288,9 +288,9 @@ int main(int argc, char** argv) {
}
if (outType == "c") {
- Transformer transformer = ChartToC::transform(interpreter);
- transformer.setExtensions(extensions);
- transformer.setOptions(options);
+ Transformer transformer = ChartToC::transform(interpreter);
+ transformer.setExtensions(extensions);
+ transformer.setOptions(options);
if (outputFile.size() == 0 || outputFile == "-") {
transformer.writeTo(std::cout);
} else {
@@ -392,9 +392,9 @@ int main(int argc, char** argv) {
} catch (Event e) {
std::cout << e << std::endl;
- } catch (const std::exception &e) {
- std::cout << e.what() << std::endl;
- }
+ } catch (const std::exception &e) {
+ std::cout << e.what() << std::endl;
+ }
return EXIT_SUCCESS;
} \ No newline at end of file
diff --git a/src/uscxml/DOMUtils.cpp b/src/uscxml/DOMUtils.cpp
index 97b84c8..414b5e7 100644
--- a/src/uscxml/DOMUtils.cpp
+++ b/src/uscxml/DOMUtils.cpp
@@ -129,50 +129,66 @@ std::string DOMUtils::xPathForNode(const Arabica::DOM::Node<std::string>& node,
return xPath;
}
-NodeSet<std::string> DOMUtils::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root) {
- NodeSet<std::string> nodes;
- inPostFixOrder(elements, root, nodes);
- return nodes;
+NodeSet<std::string> DOMUtils::inPostFixOrder(const std::set<std::string>& elements,
+ const Element<std::string>& root,
+ const bool includeEmbeddedDoc) {
+ NodeSet<std::string> nodes;
+ inPostFixOrder(elements, root, includeEmbeddedDoc, nodes);
+ return nodes;
}
-void DOMUtils::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) {
- 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;
- Arabica::DOM::Element<std::string> childElem(children.item(i));
- inPostFixOrder(elements, childElem, nodes);
-
- }
- for (size_t i = 0; i < children.getLength(); i++) {
- if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- Arabica::DOM::Element<std::string> childElem(children.item(i));
-
- if (elements.find(TAGNAME(childElem)) != elements.end()) {
- nodes.push_back(childElem);
- }
- }
+void DOMUtils::inPostFixOrder(const std::set<std::string>& elements,
+ const Element<std::string>& root,
+ const bool includeEmbeddedDoc,
+ NodeSet<std::string>& nodes) {
+ 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;
+ Arabica::DOM::Element<std::string> childElem(children.item(i));
+ if (!includeEmbeddedDoc && LOCALNAME(childElem) == "scxml")
+ continue;
+ inPostFixOrder(elements, childElem, includeEmbeddedDoc, nodes);
+
+ }
+ for (size_t i = 0; i < children.getLength(); i++) {
+ if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ Arabica::DOM::Element<std::string> childElem(children.item(i));
+ if (!includeEmbeddedDoc && LOCALNAME(childElem) == "scxml")
+ continue;
+
+ if (elements.find(TAGNAME(childElem)) != elements.end()) {
+ nodes.push_back(childElem);
+ }
+ }
}
-NodeSet<std::string> DOMUtils::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root) {
- NodeSet<std::string> nodes;
- inDocumentOrder(elements, root, nodes);
- return nodes;
+NodeSet<std::string> DOMUtils::inDocumentOrder(const std::set<std::string>& elements,
+ const Element<std::string>& root,
+ const bool includeEmbeddedDoc) {
+ NodeSet<std::string> nodes;
+ inDocumentOrder(elements, root, includeEmbeddedDoc, nodes);
+ return nodes;
}
-void DOMUtils::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) {
- if (elements.find(TAGNAME(root)) != elements.end()) {
- nodes.push_back(root);
- }
-
- 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;
- Arabica::DOM::Element<std::string> childElem(children.item(i));
- inDocumentOrder(elements, childElem, nodes);
- }
+void DOMUtils::inDocumentOrder(const std::set<std::string>& elements,
+ const Element<std::string>& root,
+ const bool includeEmbeddedDoc,
+ NodeSet<std::string>& nodes) {
+ if (elements.find(TAGNAME(root)) != elements.end()) {
+ nodes.push_back(root);
+ }
+
+ 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;
+ if (!includeEmbeddedDoc && LOCALNAME_CAST(children.item(i)) == "scxml")
+ continue;
+ Arabica::DOM::Element<std::string> childElem(children.item(i));
+ inDocumentOrder(elements, childElem, includeEmbeddedDoc, nodes);
+ }
}
std::list<Arabica::DOM::Node<std::string> > DOMUtils::getElementsByType(const Arabica::DOM::Node<std::string>& root, Arabica::DOM::Node_base::Type type) {
diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h
index a94bd90..67bcd70 100644
--- a/src/uscxml/DOMUtils.h
+++ b/src/uscxml/DOMUtils.h
@@ -43,24 +43,29 @@ namespace uscxml {
class USCXML_API DOMUtils {
public:
+
static std::string xPathForNode(const Arabica::DOM::Node<std::string>& node, const std::string& ns = "");
static std::list<Arabica::DOM::Node<std::string> > getElementsByType(const Arabica::DOM::Node<std::string>& root, Arabica::DOM::Node_base::Type type);
static std::string idForNode(const Arabica::DOM::Node<std::string>& node);
// deprecated, use stringIsTrue from Convenience.h instead
DEPRECATED static bool attributeIsTrue(const::std::string& value);
-
- static Arabica::XPath::NodeSet<std::string> inPostFixOrder(const std::set<std::string>& elements,
- const Arabica::DOM::Element<std::string>& root);
- static Arabica::XPath::NodeSet<std::string> inDocumentOrder(const std::set<std::string>& elements,
- const Arabica::DOM::Element<std::string>& root);
+
+ static Arabica::XPath::NodeSet<std::string> inPostFixOrder(const std::set<std::string>& elements,
+ const Arabica::DOM::Element<std::string>& root,
+ const bool includeEmbeddedDoc = false);
+ static Arabica::XPath::NodeSet<std::string> inDocumentOrder(const std::set<std::string>& elements,
+ const Arabica::DOM::Element<std::string>& root,
+ const bool includeEmbeddedDoc = false);
protected:
- static void inPostFixOrder(const std::set<std::string>& elements,
- const Arabica::DOM::Element<std::string>& root,
- Arabica::XPath::NodeSet<std::string>& nodes);
-
- static void inDocumentOrder(const std::set<std::string>& elements,
- const Arabica::DOM::Element<std::string>& root,
- Arabica::XPath::NodeSet<std::string>& nodes);
+ static void inPostFixOrder(const std::set<std::string>& elements,
+ const Arabica::DOM::Element<std::string>& root,
+ const bool includeEmbeddedDoc,
+ Arabica::XPath::NodeSet<std::string>& nodes);
+
+ static void inDocumentOrder(const std::set<std::string>& elements,
+ const Arabica::DOM::Element<std::string>& root,
+ const bool includeEmbeddedDoc,
+ Arabica::XPath::NodeSet<std::string>& nodes);
};
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index a05fe39..2510ef4 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -779,7 +779,7 @@ NodeSet<std::string> InterpreterImpl::getDocumentInitialTransitions() {
}
return initialTransitions;
}
-
+
InterpreterState InterpreterImpl::step(int waitForMS) {
try {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
@@ -2374,6 +2374,7 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Element<std::string>& ele
// see: http://www.w3.org/TR/scxml/#EventDescriptors
bool InterpreterImpl::nameMatch(const std::string& eventDescs, const std::string& eventName) {
+#if 1
if(eventDescs.length() == 0 || eventName.length() == 0)
return false;
@@ -2422,6 +2423,38 @@ NEXT_DESC:
}
}
return false;
+#else
+ const char* dPtr = eventDescs.c_str();
+ const char* ePtr = eventName.c_str();
+ while(*dPtr != 0) {
+
+ if (*dPtr == '*' && *ePtr != 0) // something following
+ return true;
+
+ // descriptor differs from event name
+ if (*dPtr != *ePtr) {
+ // move to next descriptor
+ while(*dPtr != ' ' && *dPtr != 0) {
+ dPtr++;
+ }
+ if (*dPtr == 0)
+ return false;
+ dPtr++;
+ ePtr = eventName.c_str();
+ } else {
+ // move both pointers one character
+ dPtr++;
+ ePtr++;
+
+ }
+
+ // descriptor is done, return match
+ if (((*dPtr == 0 || *dPtr == ' ') && (*ePtr == 0 || *ePtr == ' ')) || // exact match, end of string
+ (*dPtr == ' ' && *ePtr == '.') || (*dPtr == 0 && *ePtr == '.')) // prefix match
+ return true;
+ }
+ return false;
+#endif
}
diff --git a/src/uscxml/interpreter/InterpreterFast.cpp b/src/uscxml/interpreter/InterpreterFast.cpp
index 0958c61..94fcdce 100644
--- a/src/uscxml/interpreter/InterpreterFast.cpp
+++ b/src/uscxml/interpreter/InterpreterFast.cpp
@@ -33,10 +33,10 @@ using namespace Arabica::DOM;
void InterpreterFast::handleDOMEvent(Arabica::DOM::Events::Event<std::string>& event) {
- InterpreterImpl::handleDOMEvent(event);
-
- if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes
- return;
-
+ InterpreterImpl::handleDOMEvent(event);
+
+ if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes
+ return;
+
}
} \ No newline at end of file
diff --git a/src/uscxml/interpreter/InterpreterFast.h b/src/uscxml/interpreter/InterpreterFast.h
index 589e899..5838dc0 100644
--- a/src/uscxml/interpreter/InterpreterFast.h
+++ b/src/uscxml/interpreter/InterpreterFast.h
@@ -23,25 +23,25 @@
#include "uscxml/Interpreter.h"
namespace uscxml {
-
+
class InterpreterFast : public InterpreterImpl {
protected:
- virtual void setupSets();
- virtual void handleDOMEvent(Arabica::DOM::Events::Event<std::string>& event);
-
+ virtual void setupSets();
+ virtual void handleDOMEvent(Arabica::DOM::Events::Event<std::string>& event);
+
private:
- /* TODO: use post-order and document-order per STL comparator (sorted std::set?) */
-
- std::vector<Arabica::XPath::NodeSet<std::string> > _states;
- std::vector<Arabica::XPath::NodeSet<std::string> > _transitions;
-
- std::vector<std::vector<bool> > _conflictingTransitions;
- std::vector<std::vector<bool> > _exitSets;
- std::vector<std::vector<bool> > _targetSets;
+ /* TODO: use post-order and document-order per STL comparator (sorted std::set?) */
+
+ std::vector<Arabica::XPath::NodeSet<std::string> > _states;
+ std::vector<Arabica::XPath::NodeSet<std::string> > _transitions;
+
+ std::vector<std::vector<bool> > _conflictingTransitions;
+ std::vector<std::vector<bool> > _exitSets;
+ std::vector<std::vector<bool> > _targetSets;
};
-
+
}
#endif /* end of include guard: INTERPRETERFAST_H_224A5F07 */
diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
index 53508e6..7bd40d9 100644
--- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
@@ -125,6 +125,7 @@ void USCXMLInvoker::ParentQueue::push(const SendRequest& event) {
if (_invoker->_cancelled)
return;
SendRequest copyEvent(event);
+ // this is somewhat hidden here!
copyEvent.invokeid = _invoker->_invokeId;
_invoker->_parentInterpreter->receive(copyEvent);
}
diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp
index 710a2de..ea8d5df 100644
--- a/src/uscxml/transform/ChartToC.cpp
+++ b/src/uscxml/transform/ChartToC.cpp
@@ -23,6 +23,7 @@
#include <DOM/io/Stream.hpp>
#include <iostream>
#include "uscxml/UUID.h"
+#include "uscxml/util/MD5.hpp"
#include "uscxml/DOMUtils.h"
#include <math.h>
#include <boost/algorithm/string.hpp>
@@ -44,10 +45,19 @@ Transformer ChartToC::transform(const Interpreter& other) {
return boost::shared_ptr<TransformerImpl>(c2c);
}
-ChartToC::ChartToC(const Interpreter& other) : TransformerImpl() {
+ChartToC::ChartToC(const Interpreter& other) : TransformerImpl(), _topMostMachine(NULL), _parentMachine(NULL) {
cloneFrom(other.getImpl());
+ std::stringstream ss;
+ ss << _document;
+ _md5 = md5(ss.str());
+ _prefix = "_scxml_" + _md5.substr(0, 8);
+ _allMachines.push_back(this);
+
+ prepare();
+ findNestedMachines();
+
}
-
+
void ChartToC::setHistoryCompletion() {
std::set<std::string> elements;
elements.insert(_nsInfo.xmlNSPrefix + "history");
@@ -170,239 +180,243 @@ void ChartToC::resortStates(Arabica::DOM::Node<std::string>& node) {
}
void ChartToC::setStateCompletion() {
- setHistoryCompletion();
-
- for (size_t i = 0; i < _states.size(); i++) {
- Element<std::string> state(_states[i]);
-
- if (isHistory(state)) {
- // we already did in setHistoryCompletion
- continue;
- }
-
- NodeSet<std::string> completion;
-
- if (isParallel(state)) {
- completion = getChildStates(state);
-
- } else if (state.hasAttribute("initial")) {
- completion = getStates(tokenizeIdRefs(state.getAttribute("initial")));
-
- } else {
- NodeSet<std::string> initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state);
- if(initElems.size() > 0 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) {
- // initial element is first child
- completion.push_back(initElems[0]);
- } else {
- // first child state
- Arabica::XPath::NodeSet<std::string> initStates;
- NodeList<std::string> childs = state.getChildNodes();
- for (size_t i = 0; i < childs.getLength(); i++) {
- if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (isState(Element<std::string>(childs.item(i)))) {
- completion.push_back(childs.item(i));
- break;
- }
- }
- }
- }
-
- std::string completionBools;
- for (size_t j = 0; j < _states.size(); j++) {
- if (isMember(_states[j], completion)) {
- completionBools += "1";
- } else {
- completionBools += "0";
- }
- }
- state.setAttribute("completionBools", completionBools);
- }
+ setHistoryCompletion();
+
+ for (size_t i = 0; i < _states.size(); i++) {
+ Element<std::string> state(_states[i]);
+
+ if (isHistory(state)) {
+ // we already did in setHistoryCompletion
+ continue;
+ }
+
+ NodeSet<std::string> completion;
+
+ if (isParallel(state)) {
+ completion = getChildStates(state);
+
+ } else if (state.hasAttribute("initial")) {
+ completion = getStates(tokenizeIdRefs(state.getAttribute("initial")));
+
+ } else {
+ NodeSet<std::string> initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state);
+ if(initElems.size() > 0 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) {
+ // initial element is first child
+ completion.push_back(initElems[0]);
+ } else {
+ // first child state
+ Arabica::XPath::NodeSet<std::string> initStates;
+ NodeList<std::string> childs = state.getChildNodes();
+ for (size_t i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (isState(Element<std::string>(childs.item(i)))) {
+ completion.push_back(childs.item(i));
+ break;
+ }
+ }
+ }
+ }
+
+ std::string completionBools;
+ for (size_t j = 0; j < _states.size(); j++) {
+ if (isMember(_states[j], completion)) {
+ completionBools += "1";
+ } else {
+ completionBools += "0";
+ }
+ }
+ state.setAttribute("completionBools", completionBools);
+ }
}
-
+
void ChartToC::prepare() {
- _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
- _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : "");
-
- // make sure initial and history elements always precede propoer states
- resortStates(_scxml);
-
- std::set<std::string> elements;
- elements.insert(_nsInfo.xmlNSPrefix + "scxml");
- elements.insert(_nsInfo.xmlNSPrefix + "state");
- elements.insert(_nsInfo.xmlNSPrefix + "final");
- elements.insert(_nsInfo.xmlNSPrefix + "parallel");
- elements.insert(_nsInfo.xmlNSPrefix + "history");
- elements.insert(_nsInfo.xmlNSPrefix + "initial");
- elements.insert(_nsInfo.xmlNSPrefix + "parallel");
- _states = DOMUtils::inDocumentOrder(elements, _scxml);
-
- // set states' document order and parent attribute
- for (size_t i = 0; i < _states.size(); i++) {
- Element<std::string> state(_states[i]);
- state.setAttribute("documentOrder", toStr(i));
- if (state.getParentNode().getNodeType() == Node_base::ELEMENT_NODE &&
- HAS_ATTR_CAST(state.getParentNode(), "documentOrder")) {
- state.setAttribute("parent", ATTR_CAST(state.getParentNode(), "documentOrder"));
- }
-
- // set the states' children and whether it has a history
- std::string childBools;
- bool hasHistoryChild = false;
- for (size_t j = 0; j < _states.size(); j++) {
- if (_states[j].getParentNode() == state) {
- if (isHistory(Element<std::string>(_states[j]))) {
- hasHistoryChild = true;
- }
- childBools += "1";
- } else {
- childBools += "0";
- }
- }
- state.setAttribute("childBools", childBools);
- if (hasHistoryChild) {
- state.setAttribute("hasHistoryChild", "yes");
- }
-
- // ancestors
- std::string ancBools;
- for (size_t j = 0; j < _states.size(); j++) {
- if (isDescendant(state, _states[j])) {
- ancBools += "1";
- } else {
- ancBools += "0";
- }
- }
- state.setAttribute("ancBools", ancBools);
-
- }
-
- // set transitions' document order and source attribute
- elements.clear();
- elements.insert(_nsInfo.xmlNSPrefix + "transition");
- _transitions = DOMUtils::inDocumentOrder(elements, _scxml);
- for (size_t i = 0; i < _transitions.size(); i++) {
- Element<std::string> transition(_transitions[i]);
- transition.setAttribute("documentOrder", toStr(i));
- if (transition.getParentNode().getNodeType() == Node_base::ELEMENT_NODE &&
- HAS_ATTR_CAST(transition.getParentNode(), "documentOrder")) {
- transition.setAttribute("source", ATTR_CAST(transition.getParentNode(), "documentOrder"));
- }
- }
-
- // set transitions' postfix order attribute
- _transitions = DOMUtils::inPostFixOrder(elements, _scxml);
- for (size_t i = 0; i < _transitions.size(); i++) {
- Element<std::string> transition(_transitions[i]);
- transition.setAttribute("postFixOrder", toStr(i));
-
- // and exit set
- std::string exitSetBools;
- NodeSet<std::string> exitSet = computeExitSet(transition);
- for (unsigned int j = 0; j < _states.size(); j++) {
- Element<std::string> state(_states[j]);
- if (isMember(state, exitSet)) {
- exitSetBools += "1";
- } else {
- exitSetBools += "0";
- }
- }
- transition.setAttribute("exitSetBools", exitSetBools);
-
- // and conflicts
- std::string conflictBools;
- for (unsigned int j = 0; j < _transitions.size(); j++) {
- Element<std::string> t2(_transitions[j]);
- if (hasIntersection(computeExitSet(transition), computeExitSet(t2)) ||
- (getSourceState(transition) == getSourceState(t2)) ||
- (isDescendant(getSourceState(transition), getSourceState(t2))) ||
- (isDescendant(getSourceState(t2), getSourceState(transition)))) {
- conflictBools += "1";
- } else {
- conflictBools += "0";
- }
- }
- transition.setAttribute("conflictBools", conflictBools);
-
- // and target
- if (HAS_ATTR(transition, "target")) {
- std::list<std::string> targets = tokenize(ATTR(transition, "target"));
-
- std::string targetBools;
- for (size_t j = 0; j < _states.size(); j++) {
- Element<std::string> state(_states[j]);
-
- if (HAS_ATTR(state, "id") &&
- std::find(targets.begin(), targets.end(), escape(ATTR(state, "id"))) != targets.end()) {
- targetBools += "1";
- } else {
- targetBools += "0";
- }
- }
- transition.setAttribute("targetBools", targetBools);
-
- }
- }
- // leave transitions in postfix order
-
-
-
- // set the completion of states and responsibility of history elements
- setStateCompletion();
-
- // how many bits do we need to represent the state array?
- std::string seperator;
- _stateCharArraySize = ceil((float)_states.size() / (float)8);
- _stateCharArrayInit = "{";
- for (size_t i = 0; i < _stateCharArraySize; i++) {
- _stateCharArrayInit += seperator + "0";
- seperator = ", ";
- }
- _stateCharArrayInit += "}";
-
- if (false) {
- } else if (_states.size() < (1UL << 8)) {
- _stateDataType = "uint8_t";
- } else if (_states.size() < (1UL << 16)) {
- _stateDataType = "uint16_t";
- } else if (_states.size() < (1UL << 32)) {
- _stateDataType = "uint32_t";
- } else {
- _stateDataType = "uint64_t";
- }
-
- seperator = "";
- _transCharArraySize = ceil((float)_transitions.size() / (float)8);
- _transCharArrayInit = "{";
- for (size_t i = 0; i < _transCharArraySize; i++) {
- _transCharArrayInit += seperator + "0";
- seperator = ", ";
- }
- _transCharArrayInit += "}";
-
- if (false) {
- } else if (_transitions.size() < (1UL << 8)) {
- _transDataType = "uint8_t";
- } else if (_transitions.size() < (1UL << 16)) {
- _transDataType = "uint16_t";
- } else if (_transitions.size() < (1UL << 32)) {
- _transDataType = "uint32_t";
- } else {
- _transDataType = "uint64_t";
- }
-
+ _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : "");
+
+ // make sure initial and history elements always precede propoer states
+ resortStates(_scxml);
+
+ std::set<std::string> elements;
+ elements.insert(_nsInfo.xmlNSPrefix + "scxml");
+ elements.insert(_nsInfo.xmlNSPrefix + "state");
+ elements.insert(_nsInfo.xmlNSPrefix + "final");
+ elements.insert(_nsInfo.xmlNSPrefix + "parallel");
+ elements.insert(_nsInfo.xmlNSPrefix + "history");
+ elements.insert(_nsInfo.xmlNSPrefix + "initial");
+ elements.insert(_nsInfo.xmlNSPrefix + "parallel");
+ _states = DOMUtils::inDocumentOrder(elements, _scxml);
+
+ // set states' document order and parent attribute
+ for (size_t i = 0; i < _states.size(); i++) {
+ Element<std::string> state(_states[i]);
+ state.setAttribute("documentOrder", toStr(i));
+ if (state.getParentNode().getNodeType() == Node_base::ELEMENT_NODE &&
+ HAS_ATTR_CAST(state.getParentNode(), "documentOrder")) {
+ state.setAttribute("parent", ATTR_CAST(state.getParentNode(), "documentOrder"));
+ }
+
+ // set the states' children and whether it has a history
+ std::string childBools;
+ bool hasHistoryChild = false;
+ for (size_t j = 0; j < _states.size(); j++) {
+ if (_states[j].getParentNode() == state) {
+ if (isHistory(Element<std::string>(_states[j]))) {
+ hasHistoryChild = true;
+ }
+ childBools += "1";
+ } else {
+ childBools += "0";
+ }
+ }
+ state.setAttribute("childBools", childBools);
+ if (hasHistoryChild) {
+ state.setAttribute("hasHistoryChild", "yes");
+ }
+
+ // ancestors
+ std::string ancBools;
+ for (size_t j = 0; j < _states.size(); j++) {
+ if (isDescendant(state, _states[j])) {
+ ancBools += "1";
+ } else {
+ ancBools += "0";
+ }
+ }
+ state.setAttribute("ancBools", ancBools);
+
+ }
+
+ // set transitions' document order and source attribute
+ elements.clear();
+ elements.insert(_nsInfo.xmlNSPrefix + "transition");
+ _transitions = DOMUtils::inDocumentOrder(elements, _scxml);
+ for (size_t i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ transition.setAttribute("documentOrder", toStr(i));
+ if (transition.getParentNode().getNodeType() == Node_base::ELEMENT_NODE &&
+ HAS_ATTR_CAST(transition.getParentNode(), "documentOrder")) {
+ transition.setAttribute("source", ATTR_CAST(transition.getParentNode(), "documentOrder"));
+ }
+ }
+
+ // set transitions' postfix order attribute
+ _transitions = DOMUtils::inPostFixOrder(elements, _scxml);
+ for (size_t i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ transition.setAttribute("postFixOrder", toStr(i));
+
+ // and exit set
+ std::string exitSetBools;
+ NodeSet<std::string> exitSet = computeExitSet(transition);
+ for (unsigned int j = 0; j < _states.size(); j++) {
+ Element<std::string> state(_states[j]);
+ if (isMember(state, exitSet)) {
+ exitSetBools += "1";
+ } else {
+ exitSetBools += "0";
+ }
+ }
+ transition.setAttribute("exitSetBools", exitSetBools);
+
+ // and conflicts
+ std::string conflictBools;
+ for (unsigned int j = 0; j < _transitions.size(); j++) {
+ Element<std::string> t2(_transitions[j]);
+ if (hasIntersection(computeExitSet(transition), computeExitSet(t2)) ||
+ (getSourceState(transition) == getSourceState(t2)) ||
+ (isDescendant(getSourceState(transition), getSourceState(t2))) ||
+ (isDescendant(getSourceState(t2), getSourceState(transition)))) {
+ conflictBools += "1";
+ } else {
+ conflictBools += "0";
+ }
+ }
+ transition.setAttribute("conflictBools", conflictBools);
+
+ // and target
+ if (HAS_ATTR(transition, "target")) {
+ std::list<std::string> targets = tokenize(ATTR(transition, "target"));
+
+ std::string targetBools;
+ for (size_t j = 0; j < _states.size(); j++) {
+ Element<std::string> state(_states[j]);
+
+ if (HAS_ATTR(state, "id") &&
+ std::find(targets.begin(), targets.end(), escape(ATTR(state, "id"))) != targets.end()) {
+ targetBools += "1";
+ } else {
+ targetBools += "0";
+ }
+ }
+ transition.setAttribute("targetBools", targetBools);
+
+ }
+ }
+ // leave transitions in postfix order
+
+
+
+ // set the completion of states and responsibility of history elements
+ setStateCompletion();
+
+ // how many bits do we need to represent the state array?
+ std::string seperator;
+ _stateCharArraySize = ceil((float)_states.size() / (float)8);
+ _stateCharArrayInit = "{";
+ for (size_t i = 0; i < _stateCharArraySize; i++) {
+ _stateCharArrayInit += seperator + "0";
+ seperator = ", ";
+ }
+ _stateCharArrayInit += "}";
+
+ if (false) {
+ } else if (_states.size() < (1UL << 8)) {
+ _stateDataType = "uint8_t";
+ } else if (_states.size() < (1UL << 16)) {
+ _stateDataType = "uint16_t";
+ } else if (_states.size() < (1UL << 32)) {
+ _stateDataType = "uint32_t";
+ } else {
+ _stateDataType = "uint64_t";
+ }
+
+ seperator = "";
+ _transCharArraySize = ceil((float)_transitions.size() / (float)8);
+ _transCharArrayInit = "{";
+ for (size_t i = 0; i < _transCharArraySize; i++) {
+ _transCharArrayInit += seperator + "0";
+ seperator = ", ";
+ }
+ _transCharArrayInit += "}";
+
+ if (false) {
+ } else if (_transitions.size() < (1UL << 8)) {
+ _transDataType = "uint8_t";
+ } else if (_transitions.size() < (1UL << 16)) {
+ _transDataType = "uint16_t";
+ } else if (_transitions.size() < (1UL << 32)) {
+ _transDataType = "uint32_t";
+ } else {
+ _transDataType = "uint64_t";
+ }
+
}
void ChartToC::writeTo(std::ostream& stream) {
- prepare();
writeIncludes(stream);
writeMacros(stream);
writeTypes(stream);
- writeElementInfo(stream);
- writeExecContent(stream);
- writeStates(stream);
- writeTransitions(stream);
+ for (std::list<ChartToC*>::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++) {
+ (*machIter)->writeElementInfo(stream);
+ (*machIter)->writeExecContentFinalize(stream);
+ (*machIter)->writeElementInfoInvocation(stream);
+ (*machIter)->writeExecContent(stream);
+ (*machIter)->writeStates(stream);
+ (*machIter)->writeTransitions(stream);
+ }
+ writeMachineInfo(stream);
writeHelpers(stream);
writeFSM(stream);
@@ -410,6 +424,50 @@ void ChartToC::writeTo(std::ostream& stream) {
}
+void ChartToC::findNestedMachines() {
+ NodeSet<std::string> invokes = InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true);
+
+ for (size_t i = 0; i < invokes.size(); i++) {
+ if(isInEmbeddedDocument(invokes[i]))
+ continue;
+
+ Element<std::string> invoke(invokes[i]);
+ if (HAS_ATTR(invoke, "type") &&
+ ATTR(invoke, "type") != "scxml" &&
+ ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/")
+ continue;
+
+ ChartToC* c2c = NULL;
+ if (HAS_ATTR(invoke, "src")) {
+ c2c = new ChartToC(Interpreter::fromURL(ATTR(invoke, "src")));
+ } else {
+ // is there a nested scxml machine inside?
+ NodeSet<std::string> contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", invoke);
+ if (contents.size() == 0)
+ continue;
+ NodeSet<std::string> scxmls = filterChildElements(_nsInfo.xmlNSPrefix + "scxml", contents[0]);
+ if (scxmls.size() == 0)
+ continue;
+
+ DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Arabica::DOM::Document<std::string> doc = domFactory.createDocument(_document.getNamespaceURI(), "", 0);
+ Node<std::string> imported = doc.importNode(scxmls[0], true);
+ doc.appendChild(imported);
+// std::cout << doc << std::endl;
+ c2c = new ChartToC(Interpreter::fromDOM(doc, _nsInfo, _sourceURL));
+ }
+
+ if (c2c != NULL) {
+ invoke.setAttribute("md5sum", c2c->_md5);
+ ChartToC* topMostMachine = (_topMostMachine == NULL ? this : _topMostMachine);
+ c2c->_topMostMachine = topMostMachine;
+ c2c->_parentMachine = this;
+ _nestedMachines.push_back(c2c);
+ topMostMachine->_allMachines.push_back(c2c);
+ }
+ }
+}
+
void ChartToC::writeIncludes(std::ostream& stream) {
stream << "#include <stdint.h> // explicit types" << std::endl;
stream << "#include <stddef.h> // NULL" << std::endl;
@@ -431,6 +489,26 @@ void ChartToC::writeMacros(std::ostream& stream) {
stream << "#endif" << std::endl;
stream << std::endl;
+ stream << "#ifndef SCXML_NR_STATES_TYPE " << std::endl;
+ stream << "# define SCXML_NR_STATES_TYPE " << _stateDataType << std::endl;
+ stream << "#endif " << std::endl;
+ stream << std::endl;
+
+ stream << "#ifndef SCXML_NR_TRANS_TYPE " << std::endl;
+ stream << "# define SCXML_NR_TRANS_TYPE " << _stateDataType << std::endl;
+ stream << "#endif " << std::endl;
+ stream << std::endl;
+
+ stream << "#ifndef SCXML_MAX_NR_STATES_BYTES " << std::endl;
+ stream << "# define SCXML_MAX_NR_STATES_BYTES " << _stateCharArraySize << std::endl;
+ stream << "#endif " << std::endl;
+ stream << std::endl;
+
+ stream << "#ifndef SCXML_MAX_NR_TRANS_BYTES " << std::endl;
+ stream << "# define SCXML_MAX_NR_TRANS_BYTES " << _transCharArraySize << std::endl;
+ stream << "#endif " << std::endl;
+ stream << std::endl;
+
stream << "// error return codes" << std::endl;
stream << "#define SCXML_ERR_OK 0" << std::endl;
stream << "#define SCXML_ERR_IDLE 1" << std::endl;
@@ -443,9 +521,12 @@ void ChartToC::writeMacros(std::ostream& stream) {
stream << "#define SCXML_ERR_UNSUPPORTED 8" << std::endl;
stream << std::endl;
- stream << "#define SCXML_MACHINE_NAME \"" << _name << "\"" << std::endl;
- stream << "#define SCXML_NUMBER_STATES " << _states.size() << std::endl;
- stream << "#define SCXML_NUMBER_TRANSITIONS " << _transitions.size() << std::endl;
+// stream << "#define SCXML_NUMBER_STATES " << _states.size() << std::endl;
+// stream << "#define SCXML_NUMBER_TRANS " << _transitions.size() << std::endl;
+
+ stream << "#define SCXML_NUMBER_STATES (ctx->machine->nr_states)" << std::endl;
+ stream << "#define SCXML_NUMBER_TRANS (ctx->machine->nr_transitions)" << std::endl;
+
stream << std::endl;
stream << "#define SCXML_TRANS_SPONTANEOUS 0x01" << std::endl;
@@ -473,20 +554,23 @@ void ChartToC::writeMacros(std::ostream& stream) {
stream << "#define SCXML_CTX_TRANSITION_FOUND 0x08" << std::endl;
stream << std::endl;
+
+
stream << "#define ELEM_DATA_IS_SET(data) (data->id != NULL)" << std::endl;
stream << "#define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL)" << std::endl;
stream << "#define ELEM_PARAM_IS_SET(param) (param->name != NULL)" << std::endl;
+ stream << "#define SCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0)" << std::endl;
stream << std::endl;
}
void ChartToC::writeTypes(std::ostream& stream) {
stream << std::endl;
- stream << "typedef struct scxml_machine scxml_machine;" << std::endl;
- stream << "typedef struct scxml_transition scxml_transition;" << std::endl;
+ stream << "typedef struct scxml_machine scxml_machine;" << std::endl;
+ stream << "typedef struct scxml_transition scxml_transition;" << std::endl;
stream << "typedef struct scxml_state scxml_state;" << std::endl;
stream << "typedef struct scxml_ctx scxml_ctx;" << std::endl;
- stream << "typedef struct scxml_invoke scxml_invoke;" << std::endl;
+ stream << "typedef struct scxml_elem_invoke scxml_elem_invoke;" << std::endl;
stream << std::endl;
stream << "typedef struct scxml_elem_send scxml_elem_send;" << std::endl;
@@ -502,7 +586,7 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << "typedef int (*is_true_t)(const scxml_ctx* ctx, const char* expr);" << std::endl;
stream << "typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event);" << std::endl;
stream << "typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata);" << std::endl;
- stream << "typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x);" << std::endl;
+ stream << "typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke);" << std::endl;
stream << std::endl;
stream << "typedef int (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr);" << std::endl;
@@ -514,30 +598,31 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << "typedef int (*exec_content_assign_t)(const scxml_ctx* ctx, const char* location, const char* expr);" << std::endl;
stream << "typedef int (*exec_content_init_t)(const scxml_ctx* ctx, const scxml_elem_data* data);" << std::endl;
stream << "typedef int (*exec_content_cancel_t)(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr);" << std::endl;
- stream << "typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_invoke* invoker, const void* event);" << std::endl;
+ stream << "typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_elem_invoke* invoker, const void* event);" << std::endl;
stream << "typedef int (*exec_content_script_t)(const scxml_ctx* ctx, const char* src, const char* content);" << std::endl;
stream << std::endl;
-#if 0
- stream << "struct scxml_machine {" << std::endl;
- stream << " uint8_t flags;" << std::endl;
- stream << " uint32_t nr_states;" << std::endl;
- stream << " uint32_t nr_transitions;" << std::endl;
- stream << " const char* name;" << std::endl;
- stream << " const char* datamodel;" << std::endl;
- stream << " const char* uuid;" << std::endl;
- stream << " const scxml_elem_data* datas;" << std::endl;
- stream << " const scxml_state* states;" << std::endl;
- stream << " const scxml_transition* transitions;" << std::endl;
- stream << " const scxml_foreach* foreachs;" << std::endl;
- stream << " const scxml_elem_param* params;" << std::endl;
- stream << " const scxml_elem_donedata* donedatas;" << std::endl;
- stream << " const scxml_elem_invoke* invokes;" << std::endl;
- stream << " const scxml_elem_send* sends;" << std::endl;
- stream << "};" << std::endl;
- stream << std::endl;
+#if 1
+ stream << "struct scxml_machine {" << std::endl;
+ stream << " uint8_t flags;" << std::endl;
+ stream << " SCXML_NR_STATES_TYPE nr_states;" << std::endl;
+ stream << " SCXML_NR_TRANS_TYPE nr_transitions;" << std::endl;
+ stream << " const char* name;" << std::endl;
+ stream << " const char* datamodel;" << std::endl;
+ stream << " const char* uuid;" << std::endl;
+ stream << " const scxml_state* states;" << std::endl;
+ stream << " const scxml_transition* transitions;" << std::endl;
+ stream << " const scxml_machine* parent;" << std::endl;
+ stream << " const scxml_elem_donedata* donedata;" << std::endl;
+ stream << " const exec_content_t script;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "// forward declare machines to allow references" << std::endl;
+ stream << "extern const scxml_machine scxml_machines[" << toStr(_allMachines.size() + 1) << "];" << std::endl;
+ stream << std::endl;
#endif
-
+
stream << "struct scxml_elem_data {" << std::endl;
stream << " const char* id;" << std::endl;
stream << " const char* src;" << std::endl;
@@ -552,9 +637,9 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << " const exec_content_t on_entry; // on entry handlers" << std::endl;
stream << " const exec_content_t on_exit; // on exit handlers" << std::endl;
stream << " const invoke_t invoke; // invocations" << std::endl;
- stream << " const char children[" << _stateCharArraySize << "]; // all children" << std::endl;
- stream << " const char completion[" << _stateCharArraySize << "]; // default completion" << std::endl;
- stream << " const char ancestors[" << _stateCharArraySize << "]; // all ancestors" << std::endl;
+ stream << " const char children[SCXML_MAX_NR_STATES_BYTES]; // all children" << std::endl;
+ stream << " const char completion[SCXML_MAX_NR_STATES_BYTES]; // default completion" << std::endl;
+ stream << " const char ancestors[SCXML_MAX_NR_STATES_BYTES]; // all ancestors" << std::endl;
stream << " const scxml_elem_data* data;" << std::endl;
stream << " const uint8_t type; // atomic, parallel, compound, final, history" << std::endl;
stream << "};" << std::endl;
@@ -562,13 +647,13 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << "struct scxml_transition {" << std::endl;
stream << " const " << _stateDataType << " source;" << std::endl;
- stream << " const char target[" << _stateCharArraySize << "];" << std::endl;
+ stream << " const char target[SCXML_MAX_NR_STATES_BYTES];" << std::endl;
stream << " const char* event;" << std::endl;
stream << " const char* condition;" << std::endl;
stream << " const exec_content_t on_transition;" << std::endl;
stream << " const uint8_t type;" << std::endl;
- stream << " const char conflicts[" << _transCharArraySize << "];" << std::endl;
- stream << " const char exit_set[" << _stateCharArraySize << "];" << std::endl;
+ stream << " const char conflicts[SCXML_MAX_NR_TRANS_BYTES];" << std::endl;
+ stream << " const char exit_set[SCXML_MAX_NR_STATES_BYTES];" << std::endl;
stream << "};" << std::endl;
stream << std::endl;
@@ -595,8 +680,8 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << std::endl;
stream << "struct scxml_elem_invoke {" << std::endl;
- stream << " const char* uuid;" << std::endl;
- stream << " const char* type;" << std::endl;
+ stream << " const scxml_machine* machine;" << std::endl;
+ stream << " const char* type;" << std::endl;
stream << " const char* typeexpr;" << std::endl;
stream << " const char* src;" << std::endl;
stream << " const char* srcexpr;" << std::endl;
@@ -605,7 +690,7 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << " const char* namelist;" << std::endl;
stream << " const uint8_t autoforward;" << std::endl;
stream << " const scxml_elem_param* params;" << std::endl;
- stream << " const exec_content_finalize_t* finalize;" << std::endl;
+ stream << " exec_content_finalize_t finalize;" << std::endl;
stream << " const char* content;" << std::endl;
stream << " const char* contentexpr;" << std::endl;
stream << "};" << std::endl;
@@ -630,12 +715,13 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << std::endl;
stream << "struct scxml_ctx {" << std::endl;
- stream << " uint8_t flags;" << std::endl;
+ stream << " uint8_t flags;" << std::endl;
+ stream << " const scxml_machine* machine;" << std::endl;
stream << std::endl;
- stream << " char config[" << _stateCharArraySize << "];" << std::endl;
- stream << " char history[" << _stateCharArraySize << "];" << std::endl;
- stream << " char pending_invokes[" << _stateCharArraySize << "];" << std::endl;
- stream << " char initialized_data[" << _stateCharArraySize << "];" << std::endl;
+ stream << " char config[SCXML_MAX_NR_STATES_BYTES];" << std::endl;
+ stream << " char history[SCXML_MAX_NR_STATES_BYTES];" << std::endl;
+ stream << " char invocations[SCXML_MAX_NR_STATES_BYTES];" << std::endl;
+ stream << " char initialized_data[SCXML_MAX_NR_STATES_BYTES];" << std::endl;
stream << std::endl;
stream << " void* user_data;" << std::endl;
stream << " void* event;" << std::endl;
@@ -663,12 +749,12 @@ void ChartToC::writeTypes(std::ostream& stream) {
void ChartToC::writeHelpers(std::ostream& stream) {
stream << "#ifdef SCXML_VERBOSE" << std::endl;
- stream << "static void printStateNames(const char* a) {" << std::endl;
- stream << " size_t i;" << std::endl;
- stream << " const char* seperator = \"\";" << std::endl;
- stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << "static void printStateNames(const scxml_ctx* ctx, const char* a, size_t length) {" << std::endl;
+ stream << " size_t i;" << std::endl;
+ stream << " const char* seperator = \"\";" << std::endl;
+ stream << " for (i = 0; i < length; i++) {" << std::endl;
stream << " if (BIT_HAS(i, a)) {" << std::endl;
- stream << " printf(\"%s%s\", seperator, (scxml_states[i].name != NULL ? scxml_states[i].name : \"UNK\"));" << std::endl;
+ stream << " printf(\"%s%s\", seperator, (ctx->machine->states[i].name != NULL ? ctx->machine->states[i].name : \"UNK\"));" << std::endl;
stream << " seperator = \", \";" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -677,7 +763,7 @@ void ChartToC::writeHelpers(std::ostream& stream) {
stream << std::endl;
stream << "static void printBitsetIndices(const char* a, size_t length) {" << std::endl;
- stream << " size_t i;" << std::endl;
+ stream << " size_t i;" << std::endl;
stream << " const char* seperator = \"\";" << std::endl;
stream << " for (i = 0; i < length; i++) {" << std::endl;
stream << " if (BIT_HAS(i, a)) {" << std::endl;
@@ -692,53 +778,81 @@ void ChartToC::writeHelpers(std::ostream& stream) {
stream << std::endl;
stream << "static int bit_has_and(const char* a, const char* b, size_t i) {" << std::endl;
- stream << " do {" << std::endl;
- stream << " if (a[i - 1] & b[i - 1])" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " if (a[i] & b[i])" << std::endl;
stream << " return 1;" << std::endl;
- stream << " } while(--i);" << std::endl;
+ stream << " }" << std::endl;
stream << " return 0;" << std::endl;
stream << "}" << std::endl;
stream << std::endl;
+ stream << "static void bit_clear_all(char* a, size_t i) {" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " a[i] = 0;" << std::endl;
+ stream << " }" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
stream << "static int bit_has_any(const char* a, size_t i) {" << std::endl;
- stream << " do {" << std::endl;
- stream << " if (a[i - 1] > 0)" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " if (a[i] > 0)" << std::endl;
stream << " return 1;" << std::endl;
- stream << " } while(--i);" << std::endl;
+ stream << " }" << std::endl;
stream << " return 0;" << std::endl;
stream << "}" << std::endl;
stream << std::endl;
stream << "static void bit_or(char* dest, const char* mask, size_t i) {" << std::endl;
- stream << " do {" << std::endl;
- stream << " dest[i - 1] |= mask[i - 1];" << std::endl;
- stream << " } while(--i);" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " dest[i] |= mask[i];" << std::endl;
+ stream << " }" << std::endl;
stream << "}" << std::endl;
stream << std::endl;
stream << "static void bit_copy(char* dest, const char* source, size_t i) {" << std::endl;
- stream << " do {" << std::endl;
- stream << " dest[i - 1] = source[i - 1];" << std::endl;
- stream << " } while(--i);" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " dest[i] = source[i];" << std::endl;
+ stream << " }" << std::endl;
stream << "}" << std::endl;
stream << std::endl;
stream << "static void bit_and_not(char* dest, const char* mask, size_t i) {" << std::endl;
- stream << " do {" << std::endl;
- stream << " dest[i - 1] &= ~mask[i - 1];" << std::endl;
- stream << " } while(--i);" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " dest[i] &= ~mask[i];" << std::endl;
+ stream << " }" << std::endl;
stream << "}" << std::endl;
stream << std::endl;
stream << "static void bit_and(char* dest, const char* mask, size_t i) {" << std::endl;
- stream << " do {" << std::endl;
- stream << " dest[i - 1] &= mask[i - 1];" << std::endl;
- stream << " } while(--i);" << std::endl;
+ stream << " while(i--) {" << std::endl;
+ stream << " dest[i] &= mask[i];" << std::endl;
+ stream << " };" << std::endl;
stream << "}" << std::endl;
stream << std::endl;
}
+void ChartToC::writeExecContentFinalize(std::ostream& stream) {
+ // needs to be written prior to invocation elem info
+ NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", _scxml, true);
+ for (size_t i = 0; i < finalizes.size(); i++) {
+ Element<std::string> finalize(finalizes[i]);
+ NodeSet<std::string> execContent = filterChildType(Node_base::ELEMENT_NODE, finalize);
+
+ if (execContent.size() > 0) {
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(finalize) << "(const scxml_ctx* ctx, const scxml_elem_invoke* invocation, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ for (size_t j = 0; j < execContent.size(); j++) {
+ writeExecContent(stream, Element<std::string>(execContent[j]), 1);
+ }
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+ }
+
+}
+
void ChartToC::writeExecContent(std::ostream& stream) {
for (size_t i = 0; i < _states.size(); i++) {
Element<std::string> state(_states[i]);
@@ -746,26 +860,28 @@ void ChartToC::writeExecContent(std::ostream& stream) {
if (i == 0) {
// root state - we need to perform some initialization here
NodeSet<std::string> globalScripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", state);
- for (size_t j = 0; j < globalScripts.size(); j++) {
- stream << "static int global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
- stream << " int err = SCXML_ERR_OK;" << std::endl;
- writeExecContent(stream, globalScripts[j], 1);
+ if (globalScripts.size() > 0) {
+ for (size_t j = 0; j < globalScripts.size(); j++) {
+ stream << "static int " << _prefix << "_global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ writeExecContent(stream, globalScripts[j], 1);
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ }
+
+ stream << "static int " << _prefix << "_global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ for (size_t j = 0; j < globalScripts.size(); j++) {
+ stream << " " << _prefix << "_global_script_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ }
stream << " return SCXML_ERR_OK;" << std::endl;
stream << "}" << std::endl;
+ stream << std::endl;
}
-
- stream << "static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
- for (size_t j = 0; j < globalScripts.size(); j++) {
- stream << " global_script_" << toStr(j) << "(ctx, state, event);" << std::endl;
- }
- stream << " return SCXML_ERR_OK;" << std::endl;
- stream << "}" << std::endl;
- stream << std::endl;
}
NodeSet<std::string> onexit = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state);
for (size_t j = 0; j < onexit.size(); j++) {
- stream << "static int " << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
stream << " int err = SCXML_ERR_OK;" << std::endl;
writeExecContent(stream, onexit[j], 1);
stream << " return SCXML_ERR_OK;" << std::endl;
@@ -774,9 +890,9 @@ void ChartToC::writeExecContent(std::ostream& stream) {
}
if (onexit.size() > 0) {
- stream << "static int " << DOMUtils::idForNode(state) << "_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
for (size_t j = 0; j < onexit.size(); j++) {
- stream << " " << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ stream << " " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(ctx, state, event);" << std::endl;
}
stream << " return SCXML_ERR_OK;" << std::endl;
stream << "}" << std::endl;
@@ -786,7 +902,7 @@ void ChartToC::writeExecContent(std::ostream& stream) {
NodeSet<std::string> onentry = filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state);
for (size_t j = 0; j < onentry.size(); j++) {
- stream << "static int " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
stream << " int err = SCXML_ERR_OK;" << std::endl;
writeExecContent(stream, onentry[j], 1);
stream << " return SCXML_ERR_OK;" << std::endl;
@@ -794,31 +910,10 @@ void ChartToC::writeExecContent(std::ostream& stream) {
stream << std::endl;
}
- /*
- gen/c/ecma/test412.scxml (Failed)
- gen/c/ecma/test579.scxml (Failed)
- */
-#if 0
- bool hasInitialState = false;
- NodeSet<std::string> initial = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state);
- if (initial.size() > 0) {
- NodeSet<std::string> initialTransition = filterChildElements(_nsInfo.xmlNSPrefix + "transition", initial);
- if (initialTransition.size() > 0) {
- hasInitialState = true;
- stream << "static int " << DOMUtils::idForNode(state) << "_initial" << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
- stream << " int err = SCXML_ERR_OK;" << std::endl;
- writeExecContent(stream, initialTransition[0], 1);
- stream << " return SCXML_ERR_OK;" << std::endl;
- stream << "}" << std::endl;
- stream << std::endl;
- }
- }
-#endif
-
if (onentry.size() > 0) {
- stream << "static int " << DOMUtils::idForNode(state) << "_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
for (size_t j = 0; j < onentry.size(); j++) {
- stream << " " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ stream << " " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(ctx, state, event);" << std::endl;
}
stream << " return SCXML_ERR_OK;" << std::endl;
@@ -827,25 +922,25 @@ void ChartToC::writeExecContent(std::ostream& stream) {
}
- NodeSet<std::string> invoke = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state);
- if (invoke.size() > 0) {
- stream << "static int " << DOMUtils::idForNode(state) << "_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x) {" << std::endl;
- for (size_t j = 0; j < invoke.size(); j++) {
- stream << " ctx->invoke(ctx, s, x);" << std::endl;
- stream << " return SCXML_ERR_OK;" << std::endl;
+ NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state);
+ if (invokes.size() > 0) {
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) {" << std::endl;
+ for (size_t j = 0; j < invokes.size(); j++) {
+ Element<std::string> invoke(invokes[j]);
+ stream << " ctx->invoke(ctx, s, &" << _prefix << "_elem_invokes[" << ATTR(invoke, "documentOrder") << "], uninvoke);" << std::endl;
stream << std::endl;
}
+ stream << " return SCXML_ERR_OK;" << std::endl;
stream << "}" << std::endl;
}
}
for (size_t i = 0; i < _transitions.size(); i++) {
Element<std::string> transition(_transitions[i]);
-
NodeSet<std::string> execContent = filterChildType(Node_base::ELEMENT_NODE, transition);
if (execContent.size() > 0) {
- stream << "static int " << DOMUtils::idForNode(transition) << "_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << "static int " << _prefix << "_" << DOMUtils::idForNode(transition) << "_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
stream << " int err = SCXML_ERR_OK;" << std::endl;
for (size_t j = 0; j < execContent.size(); j++) {
writeExecContent(stream, Element<std::string>(execContent[j]), 1);
@@ -855,6 +950,7 @@ void ChartToC::writeExecContent(std::ostream& stream) {
stream << std::endl;
}
}
+
}
void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<std::string>& node, int indent) {
@@ -927,15 +1023,15 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<s
stream << padding << " ctx->exec_content_foreach_done != NULL) {" << std::endl;
stream << std::endl;
- stream << padding << " if unlikely((ctx->exec_content_foreach_init(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl;
- stream << padding << " while (ctx->exec_content_foreach_next(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "]) == SCXML_ERR_OK) {" << std::endl;
+ stream << padding << " if unlikely((ctx->exec_content_foreach_init(ctx, &" << _prefix << "_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << " while (ctx->exec_content_foreach_next(ctx, &" << _prefix << "_elem_foreachs[" << ATTR(elem, "documentOrder") << "]) == SCXML_ERR_OK) {" << std::endl;
Arabica::DOM::Node<std::string> child = node.getFirstChild();
while(child) {
writeExecContent(stream, child, indent + 2);
child = child.getNextSibling();
}
stream << padding << " }" << std::endl;
- stream << padding << " if ((ctx->exec_content_foreach_done(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << " if ((ctx->exec_content_foreach_done(ctx, &" << _prefix << "_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl;
stream << padding << "} else {" << std::endl;
stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
stream << padding << "}" << std::endl;
@@ -1002,7 +1098,7 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<s
stream << padding;
stream << "if likely(ctx->exec_content_send != NULL) {" << std::endl;
stream << padding;
- stream << " if ((ctx->exec_content_send(ctx, &scxml_elem_sends[" << ATTR(elem, "documentOrder") << "]";
+ stream << " if ((ctx->exec_content_send(ctx, &" << _prefix << "_elem_sends[" << ATTR(elem, "documentOrder") << "]";
stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
stream << padding << "} else {" << std::endl;
stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
@@ -1027,10 +1123,128 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<s
}
+void ChartToC::writeElementInfoInvocation(std::ostream& stream) {
+ NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true);
+ if (invokes.size() > 0) {
+ _hasElement.insert("invoke");
+ stream << "static const scxml_elem_invoke " << _prefix << "_elem_invokes[" << invokes.size() << "] = {" << std::endl;
+ for (size_t i = 0; i < invokes.size(); i++) {
+ Element<std::string> invoke(invokes[i]);
+
+ /*
+ stream << "struct scxml_elem_invoke {" << std::endl;
+ stream << " const char* machine;" << std::endl;
+ stream << " const char* type;" << std::endl;
+ stream << " const char* typeexpr;" << std::endl;
+ stream << " const char* src;" << std::endl;
+ stream << " const char* srcexpr;" << std::endl;
+ stream << " const char* id;" << std::endl;
+ stream << " const char* idlocation;" << std::endl;
+ stream << " const char* namelist;" << std::endl;
+ stream << " const uint8_t autoforward;" << std::endl;
+ stream << " const scxml_elem_param* params;" << std::endl;
+ stream << " const exec_content_finalize_t* finalize;" << std::endl;
+ stream << " const char* content;" << std::endl;
+ stream << " const char* contentexpr;" << std::endl;
+ stream << "};" << std::endl;
+ */
+
+ stream << " { " << std::endl;
+
+ stream << " /* machine */ ";
+ if (HAS_ATTR(invoke, "md5sum")) {
+ size_t machIdx = 0;
+ for (std::list<ChartToC*>::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++, machIdx++) {
+ if ((*machIter)->_md5 == ATTR(invoke, "md5sum")) {
+ stream << "&scxml_machines[" << toStr(machIdx) << "]";
+ break;
+ }
+ }
+ } else {
+ stream << "NULL";
+ }
+ stream << ", " << std::endl;
+
+ stream << " /* type */ ";
+ stream << (HAS_ATTR(invoke, "type") ? "\"" + escape(ATTR(invoke, "type")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* typeexpr */ ";
+ stream << (HAS_ATTR(invoke, "typeexpr") ? "\"" + escape(ATTR(invoke, "typeexpr")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* src */ ";
+ stream << (HAS_ATTR(invoke, "src") ? "\"" + escape(ATTR(invoke, "src")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* srcexpr */ ";
+ stream << (HAS_ATTR(invoke, "srcexpr") ? "\"" + escape(ATTR(invoke, "srcexpr")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* id */ ";
+ stream << (HAS_ATTR(invoke, "id") ? "\"" + escape(ATTR(invoke, "id")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* idlocation */ ";
+ stream << (HAS_ATTR(invoke, "idlocation") ? "\"" + escape(ATTR(invoke, "idlocation")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* namelist */ ";
+ stream << (HAS_ATTR(invoke, "namelist") ? "\"" + escape(ATTR(invoke, "namelist")) + "\"" : "NULL");
+ stream << ", " << std::endl;
+
+ stream << " /* autoforward */ ";
+ stream << (HAS_ATTR(invoke, "autoforward") && stringIsTrue(ATTR(invoke, "autoforward")) ? "1" : "0");
+ stream << ", " << std::endl;
+
+ stream << " /* params */ ";
+ if (HAS_ATTR(invoke, "paramIndex")) {
+ stream << "&" << _prefix << "_elem_params[" << escape(ATTR(invoke, "paramIndex")) << "]";
+ } else {
+ stream << "NULL";
+ }
+ stream << ", " << std::endl;
+
+ stream << " /* finalize */ ";
+ NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invoke);
+ if (finalizes.size() > 0) {
+ stream << _prefix << "_" << DOMUtils::idForNode(finalizes[0]);
+ } else {
+ stream << "NULL";
+ }
+ stream << ", " << std::endl;
+
+ NodeSet<std::string> contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", invoke);
+ if (contents.size() > 0 && !HAS_ATTR(invoke, "md5sum")) {
+ std::stringstream ss;
+ NodeList<std::string> cChilds = contents[0].getChildNodes();
+ for (size_t j = 0; j < cChilds.getLength(); j++) {
+ ss << cChilds.item(j);
+ }
+ stream << " /* content */ ";
+ stream << (ss.str().size() > 0 ? "\"" + escape(ss.str()) + "\", " : "NULL, ") << std::endl;
+ stream << " /* contentexpr */ ";
+ stream << (HAS_ATTR_CAST(contents[0], "expr") ? "\"" + ATTR_CAST(contents[0], "expr") + "\", " : "NULL, ") << std::endl;
+ } else {
+ stream << " /* content */ NULL," << std::endl;
+ stream << " /* contentexpr */ NULL," << std::endl;
+ }
+
+ stream << " }" << (i + 1 < invokes.size() ? ",": "") << std::endl;
+ invoke.setAttribute("documentOrder", toStr(i));
+
+ }
+ stream << "};" << std::endl;
+ stream << std::endl;
+ }
+
+}
+
void ChartToC::writeElementInfo(std::ostream& stream) {
NodeSet<std::string> foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true);
if (foreachs.size() > 0) {
- stream << "static const scxml_elem_foreach scxml_elem_foreachs[" << foreachs.size() << "] = {" << std::endl;
+ _hasElement.insert("foreach");
+ stream << "static const scxml_elem_foreach " << _prefix << "_elem_foreachs[" << foreachs.size() << "] = {" << std::endl;
stream << " /* array, item, index */" << std::endl;
for (size_t i = 0; i < foreachs.size(); i++) {
Element<std::string> foreach(foreachs[i]);
@@ -1047,6 +1261,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
NodeSet<std::string> datas = filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true);
if (datas.size() > 0) {
+ _hasElement.insert("data");
size_t dataIndexOffset = 0;
Node<std::string> parent;
size_t distinctParents = 0;
@@ -1065,7 +1280,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
parent = Node<std::string>();
- stream << "static const scxml_elem_data scxml_elem_datas[" << datas.size() + distinctParents << "] = {" << std::endl;
+ stream << "static const scxml_elem_data " << _prefix << "_elem_datas[" << datas.size() + distinctParents << "] = {" << std::endl;
stream << " /* id, src, expr, content */" << std::endl;
for (size_t i = 0; i < datas.size(); i++) {
Element<std::string> data(datas[i]);
@@ -1103,6 +1318,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
NodeSet<std::string> params = filterChildElements(_nsInfo.xmlNSPrefix + "param", _scxml, true);
if (params.size() > 0) {
+ _hasElement.insert("param");
Node<std::string> parent;
size_t distinctParents = 0;
for (size_t i = 0; i < params.size(); i++) {
@@ -1113,7 +1329,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
}
parent = Node<std::string>();
- stream << "static const scxml_elem_param scxml_elem_params[" << params.size() + distinctParents << "] = {" << std::endl;
+ stream << "static const scxml_elem_param " << _prefix << "_elem_params[" << params.size() + distinctParents << "] = {" << std::endl;
stream << " /* name, expr, location */" << std::endl;
for (size_t i = 0; i < params.size(); i++) {
Element<std::string> param(params[i]);
@@ -1138,7 +1354,8 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
NodeSet<std::string> sends = filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true);
if (sends.size() > 0) {
- stream << "static const scxml_elem_send scxml_elem_sends[" << sends.size() << "] = {" << std::endl;
+ _hasElement.insert("send");
+ stream << "static const scxml_elem_send " << _prefix << "_elem_sends[" << sends.size() << "] = {" << std::endl;
for (size_t i = 0; i < sends.size(); i++) {
Element<std::string> send(sends[i]);
stream << " { ";
@@ -1186,7 +1403,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
stream << std::endl << " /* params */ ";
if (HAS_ATTR(send, "paramIndex")) {
- stream << "&scxml_elem_params[" << escape(ATTR(send, "paramIndex")) << "] ";
+ stream << "&" << _prefix << "_elem_params[" << escape(ATTR(send, "paramIndex")) << "] ";
} else {
stream << "NULL ";
}
@@ -1199,9 +1416,10 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
}
NodeSet<std::string> donedatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", _scxml, true);
- stream << "static const scxml_elem_donedata scxml_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl;
+ stream << "static const scxml_elem_donedata " << _prefix << "_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl;
stream << " /* source, content, contentexpr, params */" << std::endl;
for (size_t i = 0; i < donedatas.size(); i++) {
+ _hasElement.insert("donedata");
Element<std::string> donedata(donedatas[i]);
stream << " { ";
@@ -1222,7 +1440,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
}
if (HAS_ATTR(donedata, "paramIndex")) {
- stream << "&scxml_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]";
+ stream << "&" << _prefix << "_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]";
} else {
stream << "NULL";
}
@@ -1236,11 +1454,57 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
}
+void ChartToC::writeMachineInfo(std::ostream& stream) {
+ if (_topMostMachine != NULL)
+ return;
+
+ stream << "const scxml_machine scxml_machines[" << _allMachines.size() + 1<< "] = {" << std::endl;
+ for (std::list<ChartToC*>::iterator machineIter = _allMachines.begin(); machineIter != _allMachines.end(); machineIter++) {
+ ChartToC* m = (*machineIter);
+ stream << " {" << std::endl;
+ stream << " /* flags */ 0," << std::endl;
+ stream << " /* nr_states */ " << m->_states.size() << "," << std::endl;
+ stream << " /* nr_transitions */ " << m->_transitions.size() << "," << std::endl;
+ stream << " /* name */ \"" << escape(m->_name) << "\"," << std::endl;
+ stream << " /* datamodel */ \"" << (HAS_ATTR(m->_scxml, "datamodel") ? ATTR(m->_scxml, "datamodel") : "null") << "\"," << std::endl;
+ stream << " /* uuid */ \"" << m->_md5 << "\"," << std::endl;
+ stream << " /* states */ " << "&" << m->_prefix << "_states[0], " << std::endl;
+ stream << " /* transitions */ " << "&" << m->_prefix << "_transitions[0], " << std::endl;
+ stream << " /* parent */ ";
+ if (m->_parentMachine != NULL) {
+ size_t parentIndex = 0;
+ for (std::list<ChartToC*>::iterator parentIter = _allMachines.begin(); parentIter != _allMachines.end(); parentIter++, parentIndex++) {
+ if (*parentIter == m->_parentMachine) {
+ stream << "&scxml_machines[" << toStr(parentIndex) << "]";
+ }
+ }
+ } else {
+ stream << "NULL";
+ }
+ stream << "," << std::endl;
+
+ stream << " /* donedata */ " << "&" << m->_prefix << "_elem_donedatas[0], " << std::endl;
+ stream << " /* script */ ";
+ if (filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml).size() > 0) {
+ stream << m->_prefix << "_global_script" << std::endl;
+ } else {
+ stream << "NULL";
+ }
+ stream << std::endl;
+
+ stream << " }," << std::endl;
+
+ }
+ stream << " {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+}
+
void ChartToC::writeStates(std::ostream& stream) {
- stream << "static const scxml_state scxml_states[" << toStr(_states.size()) << "] = {" << std::endl;
+ stream << "static const scxml_state " << _prefix << "_states[" << toStr(_states.size()) << "] = {" << std::endl;
for (size_t i = 0; i < _states.size(); i++) {
Element<std::string> state(_states[i]);
-
+
stream << " { /* state number " << toStr(i) << " */" << std::endl;
// name
@@ -1255,17 +1519,17 @@ void ChartToC::writeStates(std::ostream& stream) {
// onentry
stream << " /* onentry */ ";
- stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state).size() > 0 ? DOMUtils::idForNode(state) + "_on_entry" : "NULL");
+ stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state).size() > 0 ? _prefix + "_" + DOMUtils::idForNode(state) + "_on_entry" : "NULL");
stream << "," << std::endl;
// onexit
stream << " /* onexit */ ";
- stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state).size() > 0 ? DOMUtils::idForNode(state) + "_on_exit" : "NULL");
+ stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state).size() > 0 ? _prefix + "_" + DOMUtils::idForNode(state) + "_on_exit" : "NULL");
stream << "," << std::endl;
// invokers
stream << " /* invoke */ ";
- stream << (filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state).size() > 0 ? DOMUtils::idForNode(state) + "_invoke" : "NULL");
+ stream << (filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state).size() > 0 ? _prefix + "_" + DOMUtils::idForNode(state) + "_invoke" : "NULL");
stream << "," << std::endl;
// children
@@ -1279,15 +1543,15 @@ void ChartToC::writeStates(std::ostream& stream) {
stream << " /* " << ATTR(state, "completionBools") << " */ }, \t" << std::endl;
stream << " /* ancestors */ { ";
- writeCharArrayInitList(stream, ATTR(state, "ancBools"));
+ writeCharArrayInitList(stream, ATTR(state, "ancBools"));
stream << " /* " << ATTR(state, "ancBools") << " */ }," << std::endl;
stream << " /* data */ ";
- stream << (HAS_ATTR(state, "dataIndex") ? "&scxml_elem_datas[" + escape(ATTR(state, "dataIndex")) + "]" : "NULL");
+ stream << (HAS_ATTR(state, "dataIndex") ? "&" + _prefix + "_elem_datas[" + escape(ATTR(state, "dataIndex")) + "]" : "NULL");
stream << "," << std::endl;
stream << " /* type */ ";
-
+
if (false) {
} else if (iequals(TAGNAME(state), "initial")) {
stream << "SCXML_STATE_INITIAL";
@@ -1328,25 +1592,14 @@ void ChartToC::writeTransitions(std::ostream& stream) {
elements.insert(_nsInfo.xmlNSPrefix + "transition");
NodeSet<std::string> transDocOrder = DOMUtils::inDocumentOrder(elements, _scxml);
- stream << "static const scxml_transition scxml_transitions[" << toStr(_transitions.size()) << "] = {" << std::endl;
+ stream << "static const scxml_transition " << _prefix << "_transitions[" << toStr(_transitions.size()) << "] = {" << std::endl;
for (size_t i = 0; i < _transitions.size(); i++) {
Element<std::string> transition(_transitions[i]);
-
+
stream << " { /* transition number " << ATTR(transition, "documentOrder") << " with priority " << toStr(i) << std::endl;
stream << " target: " << ATTR(transition, "target") << std::endl;
stream << " */" << std::endl;
- /**
- uint16_t source;
- target[SCXML_NUMBER_STATES / 8 + 1];
- const char* event;
- const char* condition;
- exec_content_t on_transition;
- uint8_t type;
- char conflicts[SCXML_NUMBER_STATES / 8 + 1];
- char exit_set[SCXML_NUMBER_STATES / 8 + 1];
- */
-
// source
stream << " /* source */ ";
stream << ATTR_CAST(transition.getParentNode(), "documentOrder");
@@ -1375,7 +1628,7 @@ void ChartToC::writeTransitions(std::ostream& stream) {
// on transition handlers
stream << " /* ontrans */ ";
if (filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, transition).size() > 0) {
- stream << DOMUtils::idForNode(transition) + "_on_trans";
+ stream << _prefix << "_" << DOMUtils::idForNode(transition) + "_on_trans";
} else {
stream << "NULL";
}
@@ -1481,10 +1734,13 @@ void ChartToC::writeCharArrayInitList(std::ostream& stream, const std::string& b
}
std::string seperator = "";
+ std::ios::fmtflags f(stream.flags());
+
for (std::string::const_iterator cIter = charArray.begin(); cIter != charArray.end(); cIter++) {
stream << seperator << "0x" << std::setw(2) << std::setfill('0') << std::hex << int(*cIter & 0xFF);
seperator = ", ";
}
+ stream.flags(f);
}
void ChartToC::writeFSM(std::ostream& stream) {
@@ -1493,31 +1749,33 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"Config: \");" << std::endl;
- stream << " printStateNames(ctx->config);" << std::endl;
+ stream << " printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
- stream << "// MACRO_STEP:" << std::endl;
-// stream << " ctx->flags &= ~SCXML_CTX_TRANSITION_FOUND;" << std::endl;
- stream << std::endl;
-
stream << " if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) " << std::endl;
stream << " return SCXML_ERR_DONE; " << std::endl;
stream << std::endl;
- stream << " size_t i, j, k;" << std::endl;
- stream << " int err = SCXML_ERR_OK;" << std::endl;
- stream << " char conflicts[" << _transCharArraySize << "] = " << _transCharArrayInit << ";" << std::endl;
- stream << " char target_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
- stream << " char exit_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
- stream << " char trans_set[" << _transCharArraySize << "] = " << _transCharArrayInit << ";" << std::endl;
- stream << " char entry_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
- stream << " char tmp_states[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " " << (_states.size() > _transitions.size() ? "SCXML_NR_STATES_TYPE" : "SCXML_NR_TRANS_TYPE") << " i, j, k;" << std::endl;
+ stream << " SCXML_NR_STATES_TYPE nr_states_bytes = ((SCXML_NUMBER_STATES + 7) & ~7) >> 3;" << std::endl;
+ stream << " SCXML_NR_TRANS_TYPE nr_trans_bytes = ((SCXML_NUMBER_TRANS + 7) & ~7) >> 3;" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+
+ stream << " char conflicts [SCXML_MAX_NR_TRANS_BYTES];" << std::endl;
+ stream << " char trans_set [SCXML_MAX_NR_TRANS_BYTES];" << std::endl;
+ stream << " char target_set [SCXML_MAX_NR_STATES_BYTES];" << std::endl;
+ stream << " char exit_set [SCXML_MAX_NR_STATES_BYTES];" << std::endl;
+ stream << " char entry_set [SCXML_MAX_NR_STATES_BYTES];" << std::endl;
+ stream << " char tmp_states [SCXML_MAX_NR_STATES_BYTES];" << std::endl;
stream << std::endl;
+ stream << " bit_clear_all(target_set, nr_states_bytes);" << std::endl;
+ stream << " bit_clear_all(trans_set, nr_trans_bytes);" << std::endl;
stream << " if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {" << std::endl;
- stream << " global_script(ctx, &scxml_states[0], NULL);" << std::endl;
- stream << " bit_or(target_set, scxml_states[0].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if (ctx->machine->script != NULL)" << std::endl;
+ stream << " ctx->machine->script(ctx, &ctx->machine->states[0], NULL);" << std::endl;
+ stream << " bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes);" << std::endl;
stream << " ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;" << std::endl;
stream << " goto ESTABLISH_ENTRY_SET;" << std::endl;
stream << " }" << std::endl;
@@ -1530,42 +1788,63 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl;
stream << " goto SELECT_TRANSITIONS;" << std::endl;
stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " // manage invocations" << std::endl;
+ stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " // uninvoke" << std::endl;
+ stream << " if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) {" << std::endl;
+ stream << " if (ctx->machine->states[i].invoke != NULL)" << std::endl;
+ stream << " ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 1);" << std::endl;
+ stream << " BIT_CLEAR(i, ctx->invocations)" << std::endl;
+ stream << " }" << std::endl;
+ stream << " // invoke" << std::endl;
+ stream << " if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) {" << std::endl;
+ stream << " if (ctx->machine->states[i].invoke != NULL)" << std::endl;
+ stream << " ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 0);" << std::endl;
+ stream << " BIT_SET_AT(i, ctx->invocations)" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
stream << " if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl;
stream << " goto SELECT_TRANSITIONS;" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
stream << "SELECT_TRANSITIONS:" << std::endl;
- stream << " for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
+ stream << " bit_clear_all(conflicts, nr_trans_bytes);" << std::endl;
+ stream << " bit_clear_all(exit_set, nr_states_bytes);" << std::endl;
+ stream << " for (i = 0; i < SCXML_NUMBER_TRANS; i++) {" << std::endl;
stream << " // never select history or initial transitions automatically" << std::endl;
- stream << " if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))" << std::endl;
+ stream << " if unlikely(ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))" << std::endl;
stream << " continue;" << std::endl;
stream << std::endl;
stream << " // is the transition active?" << std::endl;
- stream << " if (BIT_HAS(scxml_transitions[i].source, ctx->config)) {" << std::endl;
+ stream << " if (BIT_HAS(ctx->machine->transitions[i].source, ctx->config)) {" << std::endl;
stream << " // is it non-conflicting?" << std::endl;
stream << " if (!BIT_HAS(i, conflicts)) {" << std::endl;
stream << " // is it enabled?" << std::endl;
- stream << " if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {" << std::endl;
+ stream << " if (ctx->is_enabled(ctx, &ctx->machine->transitions[i], ctx->event) > 0) {" << std::endl;
stream << " // remember that we found a transition" << std::endl;
stream << " ctx->flags |= SCXML_CTX_TRANSITION_FOUND;" << std::endl;
stream << std::endl;
stream << " // transitions that are pre-empted" << std::endl;
- stream << " bit_or(conflicts, scxml_transitions[i].conflicts, " << _transCharArraySize << ");" << std::endl;
+ stream << " bit_or(conflicts, ctx->machine->transitions[i].conflicts, nr_trans_bytes);" << std::endl;
stream << std::endl;
stream << " // states that are directly targeted (resolve as entry-set later)" << std::endl;
- stream << " bit_or(target_set, scxml_transitions[i].target, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(target_set, ctx->machine->transitions[i].target, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " // states that will be left" << std::endl;
- stream << " bit_or(exit_set, scxml_transitions[i].exit_set, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(exit_set, ctx->machine->transitions[i].exit_set, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " BIT_SET_AT(i, trans_set);" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
- stream << " bit_and(exit_set, ctx->config, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_and(exit_set, ctx->config, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {" << std::endl;
@@ -1579,38 +1858,38 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"Targets: \");" << std::endl;
- stream << " printStateNames(target_set);" << std::endl;
+ stream << " printStateNames(ctx, target_set, SCXML_NUMBER_STATES);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"Exiting: \");" << std::endl;
- stream << " printStateNames(exit_set);" << std::endl;
+ stream << " printStateNames(ctx, exit_set, SCXML_NUMBER_STATES);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"History: \");" << std::endl;
- stream << " printStateNames(ctx->history);" << std::endl;
+ stream << " printStateNames(ctx, ctx->history, SCXML_NUMBER_STATES);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
stream << "// REMEMBER_HISTORY:" << std::endl;
stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
- stream << " if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl;
- stream << " SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP) {" << std::endl;
+ stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl;
+ stream << " SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP) {" << std::endl;
stream << " // a history state whose parent is about to be exited" << std::endl;
- stream << " if unlikely(BIT_HAS(scxml_states[i].parent, exit_set)) {" << std::endl;
- stream << " bit_copy(tmp_states, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if unlikely(BIT_HAS(ctx->machine->states[i].parent, exit_set)) {" << std::endl;
+ stream << " bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " // set those states who were enabled" << std::endl;
- stream << " bit_and(tmp_states, ctx->config, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_and(tmp_states, ctx->config, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " // clear current history with completion mask" << std::endl;
- stream << " bit_and_not(ctx->history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_and_not(ctx->history, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " // set history" << std::endl;
- stream << " bit_or(ctx->history, tmp_states, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(ctx->history, tmp_states, nr_states_bytes);" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1618,12 +1897,12 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "ESTABLISH_ENTRY_SET:" << std::endl;
stream << " // calculate new entry set" << std::endl;
- stream << " bit_copy(entry_set, target_set, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_copy(entry_set, target_set, nr_states_bytes);" << std::endl;
stream << std::endl;
stream << " // iterate for ancestors" << std::endl;
stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
stream << " if (BIT_HAS(i, entry_set)) {" << std::endl;
- stream << " bit_or(entry_set, scxml_states[i].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->states[i].ancestors, nr_states_bytes);" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
@@ -1631,24 +1910,24 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " // iterate for descendants" << std::endl;
stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
stream << " if (BIT_HAS(i, entry_set)) {" << std::endl;
- stream << " switch (SCXML_STATE_MASK(scxml_states[i].type)) {" << std::endl;
+ stream << " switch (SCXML_STATE_MASK(ctx->machine->states[i].type)) {" << std::endl;
stream << " case SCXML_STATE_PARALLEL: {" << std::endl;
- stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl;
stream << " break;" << std::endl;
stream << " }" << std::endl;
stream << " case SCXML_STATE_HISTORY_SHALLOW:" << std::endl;
stream << " case SCXML_STATE_HISTORY_DEEP: {" << std::endl;
- stream << " if (!bit_has_and(scxml_states[i].completion, ctx->history, " << _stateCharArraySize << ") &&" << std::endl;
- stream << " !BIT_HAS(scxml_states[i].parent, ctx->config)) {" << std::endl;
+ stream << " if (!bit_has_and(ctx->machine->states[i].completion, ctx->history, nr_states_bytes) &&" << std::endl;
+ stream << " !BIT_HAS(ctx->machine->states[i].parent, ctx->config)) {" << std::endl;
stream << " // nothing set for history, look for a default transition" << std::endl;
- stream << " for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
- stream << " if unlikely(scxml_transitions[j].source == i) {" << std::endl;
- stream << " bit_or(entry_set, scxml_transitions[j].target, " << _stateCharArraySize << ");" << std::endl;
- stream << " if(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP &&" << std::endl;
- stream << " !bit_has_and(scxml_transitions[j].target, scxml_states[i].children, " << _stateCharArraySize << ")) {" << std::endl;
+ stream << " for (j = 0; j < SCXML_NUMBER_TRANS; j++) {" << std::endl;
+ stream << " if unlikely(ctx->machine->transitions[j].source == i) {" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl;
+ stream << " if(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP &&" << std::endl;
+ stream << " !bit_has_and(ctx->machine->transitions[j].target, ctx->machine->states[i].children, nr_states_bytes)) {" << std::endl;
stream << " for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {" << std::endl;
- stream << " if (BIT_HAS(k, scxml_transitions[j].target)) {" << std::endl;
- stream << " bit_or(entry_set, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if (BIT_HAS(k, ctx->machine->transitions[j].target)) {" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl;
stream << " break;" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1659,20 +1938,20 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " // Note: SCXML mandates every history to have a transition!" << std::endl;
stream << " }" << std::endl;
stream << " } else {" << std::endl;
- stream << " bit_copy(tmp_states, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
- stream << " bit_and(tmp_states, ctx->history, " << _stateCharArraySize << ");" << std::endl;
- stream << " bit_or(entry_set, tmp_states, " << _stateCharArraySize << ");" << std::endl;
- stream << " if (scxml_states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {" << std::endl;
+ stream << " bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl;
+ stream << " bit_and(tmp_states, ctx->history, nr_states_bytes);" << std::endl;
+ stream << " bit_or(entry_set, tmp_states, nr_states_bytes);" << std::endl;
+ stream << " if (ctx->machine->states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {" << std::endl;
stream << " // a deep history state with nested histories -> more completion" << std::endl;
stream << " for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {" << std::endl;
- stream << " if (BIT_HAS(j, scxml_states[i].completion) &&" << std::endl;
+ stream << " if (BIT_HAS(j, ctx->machine->states[i].completion) &&" << std::endl;
stream << " BIT_HAS(j, entry_set) &&" << std::endl;
- stream << " (scxml_states[j].type & SCXML_STATE_HAS_HISTORY)) {" << std::endl;
+ stream << " (ctx->machine->states[j].type & SCXML_STATE_HAS_HISTORY)) {" << std::endl;
stream << " for (k = j + 1; k < SCXML_NUMBER_STATES; k++) {" << std::endl;
stream << " // add nested history to entry_set" << std::endl;
- stream << " if ((SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl;
- stream << " SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&" << std::endl;
- stream << " BIT_HAS(k, scxml_states[j].children)) {" << std::endl;
+ stream << " if ((SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl;
+ stream << " SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&" << std::endl;
+ stream << " BIT_HAS(k, ctx->machine->states[j].children)) {" << std::endl;
stream << " // a nested history state" << std::endl;
stream << " BIT_SET_AT(k, entry_set);" << std::endl;
stream << " }" << std::endl;
@@ -1684,14 +1963,14 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " break;" << std::endl;
stream << " }" << std::endl;
stream << " case SCXML_STATE_INITIAL: {" << std::endl;
- stream << " for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
- stream << " if (scxml_transitions[j].source == i) {" << std::endl;
+ stream << " for (j = 0; j < SCXML_NUMBER_TRANS; j++) {" << std::endl;
+ stream << " if (ctx->machine->transitions[j].source == i) {" << std::endl;
stream << " BIT_SET_AT(j, trans_set);" << std::endl;
stream << " BIT_CLEAR(i, entry_set);" << std::endl;
- stream << " bit_or(entry_set, scxml_transitions[j].target, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl;
stream << " for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {" << std::endl;
- stream << " if (BIT_HAS(k, scxml_transitions[j].target)) {" << std::endl;
- stream << " bit_or(entry_set, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if (BIT_HAS(k, ctx->machine->transitions[j].target)) {" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1699,16 +1978,16 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " break;" << std::endl;
stream << " }" << std::endl;
stream << " case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set" << std::endl;
- stream << " if (!bit_has_and(entry_set, scxml_states[i].children, " << _stateCharArraySize << ") &&" << std::endl;
- stream << " (!bit_has_and(ctx->config, scxml_states[i].children, " << _stateCharArraySize << ") ||" << std::endl;
- stream << " bit_has_and(exit_set, scxml_states[i].children, " << _stateCharArraySize << ")))" << std::endl;
+ stream << " if (!bit_has_and(entry_set, ctx->machine->states[i].children, nr_states_bytes) &&" << std::endl;
+ stream << " (!bit_has_and(ctx->config, ctx->machine->states[i].children, nr_states_bytes) ||" << std::endl;
+ stream << " bit_has_and(exit_set, ctx->machine->states[i].children, nr_states_bytes)))" << std::endl;
stream << " {" << std::endl;
- stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
- stream << " if (!bit_has_and(scxml_states[i].completion, scxml_states[i].children, " << _stateCharArraySize << ")) {" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl;
+ stream << " if (!bit_has_and(ctx->machine->states[i].completion, ctx->machine->states[i].children, nr_states_bytes)) {" << std::endl;
stream << " // deep completion" << std::endl;
stream << " for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {" << std::endl;
- stream << " if (BIT_HAS(j, scxml_states[i].completion)) {" << std::endl;
- stream << " bit_or(entry_set, scxml_states[j].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if (BIT_HAS(j, ctx->machine->states[i].completion)) {" << std::endl;
+ stream << " bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes);" << std::endl;
stream << " break; // completion of compound is single state" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1723,7 +2002,7 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"Transitions: \");" << std::endl;
- stream << " printBitsetIndices(trans_set, sizeof(char) * 8 * " << _transCharArraySize << ");" << std::endl;
+ stream << " printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
@@ -1732,8 +2011,8 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " while(i-- > 0) {" << std::endl;
stream << " if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) {" << std::endl;
stream << " // call all on exit handlers" << std::endl;
- stream << " if (scxml_states[i].on_exit != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " if (ctx->machine->states[i].on_exit != NULL) {" << std::endl;
+ stream << " if unlikely((err = ctx->machine->states[i].on_exit(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
stream << " return err;" << std::endl;
stream << " }" << std::endl;
stream << " BIT_CLEAR(i, ctx->config);" << std::endl;
@@ -1742,13 +2021,13 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << std::endl;
stream << "// TAKE_TRANSITIONS:" << std::endl;
- stream << " for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
- stream << " if (BIT_HAS(i, trans_set) && (scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {" << std::endl;
+ stream << " for (i = 0; i < SCXML_NUMBER_TRANS; i++) {" << std::endl;
+ stream << " if (BIT_HAS(i, trans_set) && (ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {" << std::endl;
stream << " // call executable content in transition" << std::endl;
- stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl;
- stream << " &scxml_states[scxml_transitions[i].source]," << std::endl;
- stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " if (ctx->machine->transitions[i].on_transition != NULL) {" << std::endl;
+ stream << " if unlikely((err = ctx->machine->transitions[i].on_transition(ctx," << std::endl;
+ stream << " &ctx->machine->states[ctx->machine->transitions[i].source]," << std::endl;
+ stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
stream << " return err;" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1757,7 +2036,7 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"Entering: \");" << std::endl;
- stream << " printStateNames(entry_set);" << std::endl;
+ stream << " printStateNames(ctx, entry_set, SCXML_NUMBER_STATES);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
@@ -1765,9 +2044,9 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
stream << " if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) {" << std::endl;
stream << " // these are no proper states" << std::endl;
- stream << " if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl;
- stream << " SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl;
- stream << " SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_INITIAL)" << std::endl;
+ stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl;
+ stream << " SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl;
+ stream << " SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_INITIAL)" << std::endl;
stream << " continue;" << std::endl;
stream << std::endl;
@@ -1776,29 +2055,29 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " // initialize data" << std::endl;
stream << " if (!BIT_HAS(i, ctx->initialized_data)) {" << std::endl;
- stream << " if unlikely(scxml_states[i].data != NULL && ctx->exec_content_init != NULL) {" << std::endl;
- stream << " ctx->exec_content_init(ctx, scxml_states[i].data);" << std::endl;
+ stream << " if unlikely(ctx->machine->states[i].data != NULL && ctx->exec_content_init != NULL) {" << std::endl;
+ stream << " ctx->exec_content_init(ctx, ctx->machine->states[i].data);" << std::endl;
stream << " }" << std::endl;
stream << " BIT_SET_AT(i, ctx->initialized_data);" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
- stream << " if (scxml_states[i].on_entry != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " if (ctx->machine->states[i].on_entry != NULL) {" << std::endl;
+ stream << " if unlikely((err = ctx->machine->states[i].on_entry(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
stream << " return err;" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
stream << " // take history and initial transitions" << std::endl;
- stream << " for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
+ stream << " for (j = 0; j < SCXML_NUMBER_TRANS; j++) {" << std::endl;
stream << " if unlikely(BIT_HAS(j, trans_set) &&" << std::endl;
- stream << " (scxml_transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&" << std::endl;
- stream << " scxml_states[scxml_transitions[j].source].parent == i) {" << std::endl;
+ stream << " (ctx->machine->transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&" << std::endl;
+ stream << " ctx->machine->states[ctx->machine->transitions[j].source].parent == i) {" << std::endl;
stream << " // call executable content in transition" << std::endl;
- stream << " if (scxml_transitions[j].on_transition != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_transitions[j].on_transition(ctx," << std::endl;
- stream << " &scxml_states[i]," << std::endl;
- stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " if (ctx->machine->transitions[j].on_transition != NULL) {" << std::endl;
+ stream << " if unlikely((err = ctx->machine->transitions[j].on_transition(ctx," << std::endl;
+ stream << " &ctx->machine->states[i]," << std::endl;
+ stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
stream << " return err;" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1806,18 +2085,18 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << std::endl;
stream << " // handle final states" << std::endl;
- stream << " if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_FINAL) {" << std::endl;
- stream << " if unlikely(scxml_states[i].ancestors[0] == 0x01) {" << std::endl;
+ stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_FINAL) {" << std::endl;
+ stream << " if unlikely(ctx->machine->states[i].ancestors[0] == 0x01) {" << std::endl;
stream << " ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;" << std::endl;
stream << " } else {" << std::endl;
stream << " // raise done event" << std::endl;
- stream << " const scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];" << std::endl;
+ stream << " const scxml_elem_donedata* donedata = &ctx->machine->donedata[0];" << std::endl;
stream << " while(ELEM_DONEDATA_IS_SET(donedata)) {" << std::endl;
stream << " if unlikely(donedata->source == i)" << std::endl;
stream << " break;" << std::endl;
stream << " donedata++;" << std::endl;
stream << " }" << std::endl;
- stream << " ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl;
+ stream << " ctx->raise_done_event(ctx, &ctx->machine->states[ctx->machine->states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
@@ -1829,20 +2108,20 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl;
stream << " */" << std::endl;
stream << " for (j = 0; j < SCXML_NUMBER_STATES; j++) {" << std::endl;
- stream << " if unlikely(SCXML_STATE_MASK(scxml_states[j].type) == SCXML_STATE_PARALLEL &&" << std::endl;
- stream << " BIT_HAS(j, scxml_states[i].ancestors)) {" << std::endl;
- stream << " bit_and_not(tmp_states, tmp_states, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[j].type) == SCXML_STATE_PARALLEL &&" << std::endl;
+ stream << " BIT_HAS(j, ctx->machine->states[i].ancestors)) {" << std::endl;
+ stream << " bit_clear_all(tmp_states, nr_states_bytes);" << std::endl;
stream << " for (k = 0; k < SCXML_NUMBER_STATES; k++) {" << std::endl;
- stream << " if unlikely(BIT_HAS(j, scxml_states[k].ancestors) && BIT_HAS(k, ctx->config)) {" << std::endl;
- stream << " if (SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_FINAL) {" << std::endl;
- stream << " bit_and_not(tmp_states, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {" << std::endl;
+ stream << " if (SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_FINAL) {" << std::endl;
+ stream << " bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl;
stream << " } else {" << std::endl;
stream << " BIT_SET_AT(k, tmp_states);" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
- stream << " if unlikely(!bit_has_any(tmp_states, " << _stateCharArraySize << ")) {" << std::endl;
- stream << " ctx->raise_done_event(ctx, &scxml_states[j], NULL);" << std::endl;
+ stream << " if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) {" << std::endl;
+ stream << " ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL);" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
diff --git a/src/uscxml/transform/ChartToC.h b/src/uscxml/transform/ChartToC.h
index 1ac59f3..f9b9599 100644
--- a/src/uscxml/transform/ChartToC.h
+++ b/src/uscxml/transform/ChartToC.h
@@ -29,6 +29,7 @@
#include <DOM/Node.hpp>
#include <XPath/XPath.hpp>
#include <ostream>
+#include <set>
namespace uscxml {
@@ -42,14 +43,18 @@ public:
protected:
ChartToC(const Interpreter& other);
-
+
void writeIncludes(std::ostream& stream);
void writeMacros(std::ostream& stream);
void writeTypes(std::ostream& stream);
void writeHelpers(std::ostream& stream);
void writeExecContent(std::ostream& stream);
+ void writeExecContentFinalize(std::ostream& stream);
+ void writeElementInfoInvocation(std::ostream& stream);
+
void writeElementInfo(std::ostream& stream);
+ void writeMachineInfo(std::ostream& stream);
void writeStates(std::ostream& stream);
void writeTransitions(std::ostream& stream);
void writeFSM(std::ostream& stream);
@@ -61,16 +66,20 @@ protected:
void resortStates(Arabica::DOM::Node<std::string>& node);
void setHistoryCompletion();
- void setStateCompletion();
- void prepare();
-
+ void setStateCompletion();
+ void prepare();
+
+ void findNestedMachines();
+
Interpreter interpreter;
Arabica::XPath::NodeSet<std::string> _states;
Arabica::XPath::NodeSet<std::string> _transitions;
-// std::string md5sum;
-
+ std::string _md5;
+ std::string _prefix;
+ std::set<std::string> _hasElement;
+
size_t _transCharArraySize;
std::string _transCharArrayInit;
std::string _transDataType;
@@ -78,6 +87,11 @@ protected:
size_t _stateCharArraySize;
std::string _stateCharArrayInit;
std::string _stateDataType;
+
+ ChartToC* _topMostMachine;
+ ChartToC* _parentMachine;
+ std::list<ChartToC*> _nestedMachines;
+ std::list<ChartToC*> _allMachines;
};
}
diff --git a/src/uscxml/transform/ChartToVHDL.cpp b/src/uscxml/transform/ChartToVHDL.cpp
index 7631619..8e7f43f 100644
--- a/src/uscxml/transform/ChartToVHDL.cpp
+++ b/src/uscxml/transform/ChartToVHDL.cpp
@@ -53,89 +53,93 @@ ChartToVHDL::~ChartToVHDL() {
}
void ChartToVHDL::checkDocument() {
- // filter unsupported stuff
- Arabica::XPath::NodeSet<std::string> unsupported;
-
- std::set<std::string> elements;
- elements.insert(_nsInfo.xmlNSPrefix + "datamodel");
- elements.insert(_nsInfo.xmlNSPrefix + "data");
- elements.insert(_nsInfo.xmlNSPrefix + "assign");
- elements.insert(_nsInfo.xmlNSPrefix + "donedata");
- elements.insert(_nsInfo.xmlNSPrefix + "content");
- elements.insert(_nsInfo.xmlNSPrefix + "param");
- elements.insert(_nsInfo.xmlNSPrefix + "script");
-
- elements.insert(_nsInfo.xmlNSPrefix + "parallel");
- elements.insert(_nsInfo.xmlNSPrefix + "history");
-
- elements.insert(_nsInfo.xmlNSPrefix + "if"); // implicit elseif und else
- elements.insert(_nsInfo.xmlNSPrefix + "foreach");
- elements.insert(_nsInfo.xmlNSPrefix + "send");
- elements.insert(_nsInfo.xmlNSPrefix + "cancel");
- elements.insert(_nsInfo.xmlNSPrefix + "invoke");
- elements.insert(_nsInfo.xmlNSPrefix + "finalize");
- unsupported = DOMUtils::inDocumentOrder(elements, _scxml);
-
- std::stringstream ss;
- if (unsupported.size() > 0) {
- for (int i = 0; i < unsupported.size(); i++) {
- ss << " " << DOMUtils::xPathForNode(unsupported[i]) << " unsupported" << std::endl;
- }
- throw std::runtime_error("Unsupported elements found:\n" + ss.str());
- }
-
- elements.clear();
- elements.insert(_nsInfo.xmlNSPrefix + "transition");
- unsupported = DOMUtils::inDocumentOrder(elements, _scxml);
-
- for (int i = 0; i < unsupported.size(); i++) {
- Element<std::string> transition(unsupported[i]);
- if (HAS_ATTR(transition, "cond")) {
- ERROR_PLATFORM_THROW("transition with conditions not supported!");
- }
- if (!HAS_ATTR(transition, "target")) {
- ERROR_PLATFORM_THROW("targetless transition not supported!");
- }
- }
+ // filter unsupported stuff
+ Arabica::XPath::NodeSet<std::string> unsupported;
+
+ std::set<std::string> elements;
+ elements.insert(_nsInfo.xmlNSPrefix + "datamodel");
+ elements.insert(_nsInfo.xmlNSPrefix + "data");
+ elements.insert(_nsInfo.xmlNSPrefix + "assign");
+ elements.insert(_nsInfo.xmlNSPrefix + "donedata");
+ elements.insert(_nsInfo.xmlNSPrefix + "content");
+ elements.insert(_nsInfo.xmlNSPrefix + "param");
+ elements.insert(_nsInfo.xmlNSPrefix + "script");
+
+ elements.insert(_nsInfo.xmlNSPrefix + "parallel");
+ elements.insert(_nsInfo.xmlNSPrefix + "history");
+
+ elements.insert(_nsInfo.xmlNSPrefix + "if"); // implicit elseif und else
+ elements.insert(_nsInfo.xmlNSPrefix + "foreach");
+ elements.insert(_nsInfo.xmlNSPrefix + "send");
+ elements.insert(_nsInfo.xmlNSPrefix + "cancel");
+ elements.insert(_nsInfo.xmlNSPrefix + "invoke");
+ elements.insert(_nsInfo.xmlNSPrefix + "finalize");
+ unsupported = DOMUtils::inDocumentOrder(elements, _scxml);
+
+ std::stringstream ss;
+ if (unsupported.size() > 0) {
+ for (int i = 0; i < unsupported.size(); i++) {
+ ss << " " << DOMUtils::xPathForNode(unsupported[i]) << " unsupported" << std::endl;
+ }
+ throw std::runtime_error("Unsupported elements found:\n" + ss.str());
+ }
+
+ elements.clear();
+ elements.insert(_nsInfo.xmlNSPrefix + "transition");
+ unsupported = DOMUtils::inDocumentOrder(elements, _scxml);
+
+ for (int i = 0; i < unsupported.size(); i++) {
+ Element<std::string> transition(unsupported[i]);
+ if (HAS_ATTR(transition, "cond")) {
+ ERROR_PLATFORM_THROW("transition with conditions not supported!");
+ }
+ if (!HAS_ATTR(transition, "target")) {
+ ERROR_PLATFORM_THROW("targetless transition not supported!");
+ }
+ }
}
void ChartToVHDL::findEvents() {
- // elements with an event attribute
- NodeSet<std::string> withEvent;
- withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "raise", _scxml, true));
- withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true));
- withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true));
-
- for (size_t i = 0; i < withEvent.size(); i++) {
- if (HAS_ATTR_CAST(withEvent[i], "event")) {
- _eventTrie.addWord(ATTR_CAST(withEvent[i], "event"));
- }
- }
+ // elements with an event attribute
+ NodeSet<std::string> withEvent;
+ withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "raise", _scxml, true));
+ withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true));
+ withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true));
+
+ for (size_t i = 0; i < withEvent.size(); i++) {
+ if (HAS_ATTR_CAST(withEvent[i], "event")) {
+ // TODO: tokenize!
+ if (ATTR_CAST(withEvent[i], "event") != "*")
+ _eventTrie.addWord(ATTR_CAST(withEvent[i], "event"));
+ }
+ }
}
-
+
void ChartToVHDL::writeTo(std::ostream& stream) {
- // same preparations as the C transformation
- prepare();
-
+ // same preparations as the C transformation
+ prepare();
+
// checkDocument();
- findEvents();
- _eventTrie.dump();
-
+ findEvents();
+// _eventTrie.dump();
+
+
+ writeOptimalTransitionSetSelection(stream);
writeTypes(stream);
- writeFiFo(stream);
- writeTransitionSet(stream);
- writeExitSet(stream);
- writeEntrySet(stream);
+ writeFiFo(stream);
+ writeTransitionSet(stream);
+ writeExitSet(stream);
+ writeEntrySet(stream);
writeFSM(stream);
}
void ChartToVHDL::writeTransitionSet(std::ostream & stream) {
- for (size_t i = 0; i < _transitions.size(); i++) {
- Element<std::string> transition(_transitions[i]);
- std::string name = DOMUtils::idForNode(transition);
-
- }
+ for (size_t i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ std::string name = DOMUtils::idForNode(transition);
+
+ }
}
void ChartToVHDL::writeExitSet(std::ostream & stream) {
@@ -188,6 +192,7 @@ void ChartToVHDL::writeFSM(std::ostream & stream) {
stream << "-- END FSM Logic" << std::endl;
}
+#if 0
void ChartToVHDL::writeTopDown(std::ostream & stream) {
// create hardware top level
stream << "-- top level" << std::endl;
@@ -224,15 +229,16 @@ void ChartToVHDL::writeTopDown(std::ostream & stream) {
stream << std::endl;
stream << "end behavioral; " << std::endl;
}
+#endif
void ChartToVHDL::writeTypes(std::ostream & stream) {
std::string seperator = "";
- stream << "-- needed global types" << std::endl;
+ stream << "-- required global types" << std::endl;
stream << "library IEEE;" << std::endl;
stream << "use IEEE.std_logic_1164.all;" << std::endl;
stream << std::endl;
- stream << "package generated_p1 is" << std::endl;
+ stream << "package machine" << _md5 << " is" << std::endl;
// create state type
stream << " type state_type is std_logic_vector( ";
stream << _states.size() - 1;
@@ -252,7 +258,7 @@ void ChartToVHDL::writeTypes(std::ostream & stream) {
}
stream << ");" << std::endl;
- stream << "end generated_p1;" << std::endl;
+ stream << "end machine" << _md5 << ";" << std::endl;
stream << std::endl;
stream << "-- END needed global types" << std::endl;
}
@@ -261,7 +267,7 @@ void ChartToVHDL::writeIncludes(std::ostream & stream) {
// Add controler specific stuff here
stream << "library IEEE;" << std::endl;
stream << "use IEEE.std_logic_1164.all;" << std::endl;
- stream << "use work.generated_p1.all;" << std::endl;
+ stream << "use work.machine" << _md5 << ".all;" << std::endl;
stream << std::endl;
}
@@ -392,7 +398,7 @@ void ChartToVHDL::writeSignals(std::ostream & stream) {
for (int i = 0; i < _transitions.size(); i++) {
Element<std::string> transition(_transitions[i]);
- stream << "signal " << ATTR(transition, "id") << "_sig : std_logic;"
+ stream << "signal in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig : std_logic;"
<< std::endl;
}
@@ -462,6 +468,46 @@ void ChartToVHDL::writeErrorHandler(std::ostream & stream) {
stream << std::endl;
}
+std::string ChartToVHDL::eventNameEscape(const std::string& eventName) {
+ std::string escaped = escape(eventName);
+ boost::replace_all(escaped, ".", "_");
+ return escaped;
+}
+
+void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream & stream) {
+ stream << "-- write optimal transition set selection" << std::endl;
+ for (size_t i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ std::string conflicts = ATTR(transition, "conflictBools");
+
+ stream << "in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig "
+ << "<= " << (HAS_ATTR(transition, "event") ? "(not spontaneous_sig)" : "spontaneous_sig") << " and " << std::endl
+ << " state_active_" << ATTR(transition, "source") << "_sig and not ( 0 " << std::endl;
+ for (size_t j = 0; j < i; j++) {
+ if (conflicts[j] == '1') {
+ stream << " or in_optimal_transition_set_" << toStr(j) << "_sig" << std::endl;
+ }
+ }
+ stream << " )";
+ if (HAS_ATTR(transition, "event")) {
+ stream << " and ( 0 " << std::endl;;
+
+ // find all matching event literals
+ std::list<std::string> eventDescs = tokenizeIdRefs(ATTR(transition, "event"));
+ for (std::list<std::string>::iterator descIter = eventDescs.begin(); descIter != eventDescs.end(); descIter++) {
+ std::list<TrieNode*> eventNames = _eventTrie.getWordsWithPrefix((*descIter) == "*" ? "" : *descIter);
+ for (std::list<TrieNode*>::iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) {
+ stream << " or event_" << eventNameEscape((*eventIter)->value) << "_sig" << std::endl;
+ }
+ }
+ stream << " )";
+
+ }
+ stream << ";" << std::endl;
+ }
+
+}
+
//TODO write event generator
// wie die letzten beiden states erkennen
// process bauen der bei fail 0 ausgibt und bei accept 1
@@ -476,16 +522,16 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
for (int i = 0; i < _states.size(); i++) {
Element<std::string> state(_states[i]);
- // calculate event choises
+ // calculate event choices
// _transitions is sorted in Postfix order
// by stating with smalest index the most important
// will be written first
- std::vector< Element<std::string> > choises;
+ std::vector< Element<std::string> > choices;
std::string spntaneous_trans_sig = "";
for (int j = 0; j < _transitions.size(); j++) {
Element<std::string> transition(_transitions[j]);
if (ATTR_CAST(transition.getParentNode(), "id") == ATTR(state, "id")) {
- choises.push_back(transition);
+ choices.push_back(transition);
if (ATTR(transition, "event") == CONST_TRANS_SPONTANIOUS) {
spntaneous_trans_sig = ATTR(transition, "id");
// FIXME hofully there are just single spntaneous transitions allowed
@@ -503,13 +549,13 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
}
}
- if (choises.size() > 0) {// if no outgoing transitions (maybe final state :D) we don't write anything
+ if (choices.size() > 0) {// if no outgoing transitions (maybe final state :D) we don't write anything
stream << " if ( " << ATTR(state, "id") << " = '1' ) then" << std::endl;
stream << " if ( transition_spntaneous_en = '1' ) then" << std::endl;
// enable spntaneous transition (if any) and disable all other
- for (int j = 0; j < choises.size(); j++) {
- Element<std::string> transition(choises[j]);
+ for (int j = 0; j < choices.size(); j++) {
+ Element<std::string> transition(choices[j]);
if (ATTR(transition, "id") == spntaneous_trans_sig) {
stream << " " << ATTR(transition, "id") << "_sig <= '1';" << std::endl;
} else {
@@ -524,8 +570,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
// FIXME hopefully there is just one transition per state and event at a time
stream << " case next_event is" << std::endl;
bool hasWildcardTransition = false;
- for (int j = 0; j < choises.size(); j++) {
- Element<std::string> transition(choises[j]);
+ for (int j = 0; j < choices.size(); j++) {
+ Element<std::string> transition(choices[j]);
std::string eventName = ATTR(transition, "event");
if (eventName == CONST_EVENT_ANY) {
eventName = "others";
@@ -533,8 +579,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
}
stream << " when " << eventName << " =>" << std::endl;
// activate transition and deactivete others
- for (int k = 0; k < choises.size(); k++) {
- Element<std::string> tmp_t(choises[k]);
+ for (int k = 0; k < choices.size(); k++) {
+ Element<std::string> tmp_t(choices[k]);
if (ATTR(tmp_t, "event") == ATTR(transition, "event")) {
stream << " " << ATTR(tmp_t, "id") << "_sig <= '1';" << std::endl;
} else {
@@ -545,8 +591,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
if (!hasWildcardTransition) {
// if there is no others we create one for deactivating everything
stream << " when others =>" << std::endl;
- for (int j = 0; j < choises.size(); j++) {
- Element<std::string> tmp_t(choises[j]);
+ for (int j = 0; j < choices.size(); j++) {
+ Element<std::string> tmp_t(choices[j]);
stream << " " << ATTR(tmp_t, "id") << "_sig <= '0';" << std::endl;
}
}
@@ -557,8 +603,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
stream << " else" << std::endl;
// no enabled event ? disable all transitions (looks like we have to wait)
- for (int j = 0; j < choises.size(); j++) {
- Element<std::string> transition(choises[j]);
+ for (int j = 0; j < choices.size(); j++) {
+ Element<std::string> transition(choices[j]);
stream << " " << ATTR(transition, "id") << "_sig <= '0';" << std::endl;
}
stream << " end if;" << std::endl;
@@ -575,9 +621,9 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) {
nextStateBuffer << " ) or ";
nextStateBuffer << "( ( not ( '0'";
seperator = " or ";
- for (int j = 0; j < choises.size(); j++) {
+ for (int j = 0; j < choices.size(); j++) {
nextStateBuffer << seperator
- << ATTR(choises[j], "id") << "_sig";
+ << ATTR(choices[j], "id") << "_sig";
}
nextStateBuffer << " ) ) and " << ATTR(state, "id")
<< "_curr ));" << std::endl;
diff --git a/src/uscxml/transform/ChartToVHDL.h b/src/uscxml/transform/ChartToVHDL.h
index a2cbac7..64cf444 100644
--- a/src/uscxml/transform/ChartToVHDL.h
+++ b/src/uscxml/transform/ChartToVHDL.h
@@ -44,13 +44,14 @@ public:
protected:
ChartToVHDL(const Interpreter& other);
- void checkDocument();
- void findEvents();
-
+ void checkDocument();
+ void findEvents();
+
void writeIncludes(std::ostream& stream);
void writeTopDown(std::ostream& stream);
void writeTypes(std::ostream& stream);
+ void writeOptimalTransitionSetSelection(std::ostream& stream);
void writeNextStateLogic(std::ostream& stream);
void writeOutputLogic(std::ostream& stream);
void writeSignals(std::ostream& stream);
@@ -59,11 +60,15 @@ protected:
void writeErrorHandler(std::ostream& stream);
void writeFSM(std::ostream& stream);
- void writeTransitionSet(std::ostream & stream);
- void writeExitSet(std::ostream & stream);
- void writeEntrySet(std::ostream & stream);
+ void writeTransitionSet(std::ostream & stream);
+ void writeExitSet(std::ostream & stream);
+ void writeEntrySet(std::ostream & stream);
+
+ Trie _eventTrie;
+
+private:
+ std::string eventNameEscape(const std::string& eventName);
- Trie _eventTrie;
};
diff --git a/src/uscxml/transform/Transformer.h b/src/uscxml/transform/Transformer.h
index c88015b..3751c00 100644
--- a/src/uscxml/transform/Transformer.h
+++ b/src/uscxml/transform/Transformer.h
@@ -36,10 +36,10 @@ public:
}
protected:
- std::multimap<std::string, std::string> _extensions;
- std::list<std::string> _options;
-
- friend class Transformer;
+ std::multimap<std::string, std::string> _extensions;
+ std::list<std::string> _options;
+
+ friend class Transformer;
};
class USCXML_API Transformer : public boost::enable_shared_from_this<Transformer> {
@@ -79,14 +79,14 @@ public:
return _impl;
}
- void setExtensions(const std::multimap<std::string, std::string>& extensions) {
- _impl->_extensions = extensions;
- }
-
- void setOptions(const std::list<std::string>& options) {
- _impl->_options = options;
- }
-
+ void setExtensions(const std::multimap<std::string, std::string>& extensions) {
+ _impl->_extensions = extensions;
+ }
+
+ void setOptions(const std::list<std::string>& options) {
+ _impl->_options = options;
+ }
+
protected:
boost::shared_ptr<TransformerImpl> _impl;
diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in
index 6ba6eb1..c26b6b0 100644
--- a/test/ctest/CTestCustom.ctest.in
+++ b/test/ctest/CTestCustom.ctest.in
@@ -198,43 +198,43 @@ set(CTEST_CUSTOM_TESTS_IGNORE
### Ignore for generated C sources
# we do not support invokers yet
- "gen/c/ecma/test187.scxml"
- "gen/c/ecma/test191.scxml"
- "gen/c/ecma/test192.scxml"
- "gen/c/ecma/test207.scxml"
- "gen/c/ecma/test215.scxml"
- "gen/c/ecma/test216.scxml"
- "gen/c/ecma/test220.scxml"
- "gen/c/ecma/test223.scxml"
- "gen/c/ecma/test224.scxml"
- "gen/c/ecma/test225.scxml"
- "gen/c/ecma/test226.scxml"
- "gen/c/ecma/test228.scxml"
- "gen/c/ecma/test229.scxml"
- "gen/c/ecma/test230.scxml"
- "gen/c/ecma/test232.scxml"
- "gen/c/ecma/test233.scxml"
- "gen/c/ecma/test234.scxml"
- "gen/c/ecma/test235.scxml"
- "gen/c/ecma/test236.scxml"
- "gen/c/ecma/test237.scxml"
- "gen/c/ecma/test239.scxml"
- "gen/c/ecma/test240.scxml"
- "gen/c/ecma/test241.scxml"
- "gen/c/ecma/test242.scxml"
- "gen/c/ecma/test243.scxml"
- "gen/c/ecma/test244.scxml"
- "gen/c/ecma/test245.scxml"
- "gen/c/ecma/test247.scxml"
- "gen/c/ecma/test250.scxml"
- "gen/c/ecma/test252.scxml"
- "gen/c/ecma/test253.scxml"
- "gen/c/ecma/test276.scxml"
- "gen/c/ecma/test338.scxml"
- "gen/c/ecma/test347.scxml"
- "gen/c/ecma/test422.scxml"
- "gen/c/ecma/test530.scxml"
- "gen/c/ecma/test554.scxml"
+ # "gen/c/ecma/test187.scxml"
+ # "gen/c/ecma/test191.scxml"
+ # "gen/c/ecma/test192.scxml"
+ # "gen/c/ecma/test207.scxml"
+ # "gen/c/ecma/test215.scxml"
+ # "gen/c/ecma/test216.scxml"
+ # "gen/c/ecma/test220.scxml"
+ # "gen/c/ecma/test223.scxml"
+ # "gen/c/ecma/test224.scxml"
+ # "gen/c/ecma/test225.scxml"
+ # "gen/c/ecma/test226.scxml"
+ # "gen/c/ecma/test228.scxml"
+ # "gen/c/ecma/test229.scxml"
+ # "gen/c/ecma/test230.scxml"
+ # "gen/c/ecma/test232.scxml"
+ # "gen/c/ecma/test233.scxml"
+ # "gen/c/ecma/test234.scxml"
+ # "gen/c/ecma/test235.scxml"
+ # "gen/c/ecma/test236.scxml"
+ # "gen/c/ecma/test237.scxml"
+ # "gen/c/ecma/test239.scxml"
+ # "gen/c/ecma/test240.scxml"
+ # "gen/c/ecma/test241.scxml"
+ # "gen/c/ecma/test242.scxml"
+ # "gen/c/ecma/test243.scxml"
+ # "gen/c/ecma/test244.scxml"
+ # "gen/c/ecma/test245.scxml"
+ # "gen/c/ecma/test247.scxml"
+ # "gen/c/ecma/test250.scxml"
+ # "gen/c/ecma/test252.scxml"
+ # "gen/c/ecma/test253.scxml"
+ # "gen/c/ecma/test276.scxml"
+ # "gen/c/ecma/test338.scxml"
+ # "gen/c/ecma/test347.scxml"
+ # "gen/c/ecma/test422.scxml"
+ # "gen/c/ecma/test530.scxml"
+ # "gen/c/ecma/test554.scxml"
# we do not support io processors yet
"gen/c/ecma/test201.scxml"
diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp
index 11bb1c7..1dc95d4 100644
--- a/test/src/test-c-machine.cpp
+++ b/test/src/test-c-machine.cpp
@@ -24,7 +24,7 @@
#include "uscxml/concurrency/Timer.h"
//#include "uscxml/DOMUtils.h"
#include "uscxml/Factory.h"
-#include "uscxml/InterpreterInfo.h"
+//#include "uscxml/Interpreter.h"
#include "uscxml/UUID.h"
#include "uscxml/concurrency/DelayedEventQueue.h"
@@ -34,18 +34,98 @@
# include "uscxml/plugins/DataModel.h"
# endif
-#define USER_DATA(ctx) ((GenCInterpreterInfo*)(((scxml_ctx*)ctx)->user_data))
+#define USER_DATA(ctx) ((StateMachine*)(((scxml_ctx*)ctx)->user_data))
using namespace uscxml;
-typedef struct scxml_foreach_info scxml_foreach_info;
-struct scxml_foreach_info {
- size_t iterations;
- size_t currIteration;
-};
-
-class GenCInterpreterInfo : public InterpreterInfo {
+class StateMachine : public InterpreterInfo {
public:
+ StateMachine(const scxml_machine* machine) : parentMachine(NULL), topMostMachine(NULL) {
+ init(machine);
+ allMachines[sessionId] = this;
+ topMostMachine = this;
+ currentMachine = allMachines.begin();
+ }
+
+ StateMachine(StateMachine* parent, const scxml_machine* machine) {
+ init(machine);
+ parentMachine = parent;
+ topMostMachine = parent->topMostMachine;
+ }
+
+ void init(const scxml_machine* machine) {
+ sessionId = UUID::getUUID();
+
+ // clear and initialize machine context
+ memset(&ctx, 0, sizeof(scxml_ctx));
+ ctx.machine = machine;
+ ctx.user_data = (void*)this;
+
+ // register callbacks with scxml context
+ ctx.is_enabled = &isEnabled;
+ ctx.is_true = &isTrue;
+ ctx.raise_done_event = &raiseDoneEvent;
+ ctx.invoke = &invoke;
+ ctx.exec_content_send = &execContentSend;
+ ctx.exec_content_raise = &execContentRaise;
+ ctx.exec_content_cancel = &execContentCancel;
+ ctx.exec_content_log = &execContentLog;
+ ctx.exec_content_assign = &execContentAssign;
+ ctx.exec_content_foreach_init = &execContentForeachInit;
+ ctx.exec_content_foreach_next = &execContentForeachNext;
+ ctx.exec_content_foreach_done = &execContentForeachDone;
+ ctx.dequeue_external = &dequeueExternal;
+ ctx.dequeue_internal = &dequeueInternal;
+ ctx.exec_content_init = &execContentInit;
+ ctx.exec_content_script = &execContentScript;
+
+ name = machine->name;
+
+ delayQueue.start();
+ dataModel = Factory::getInstance()->createDataModel(machine->datamodel, this);
+ }
+
+ virtual ~StateMachine() {
+ delayQueue.stop();
+ }
+
+ bool hasPendingWork() {
+ return (iq.size() > 0 ||
+ eq.size() > 0 ||
+ ctx.flags & SCXML_CTX_SPONTANEOUS ||
+ ctx.flags == SCXML_CTX_PRISTINE ||
+ memcmp(ctx.config, ctx.invocations, sizeof(ctx.config)) != 0);
+ }
+
+ bool isDone() {
+ return ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL;
+ }
+
+ void reset() {
+ sessionId = UUID::getUUID();
+ iq.clear();
+ eq.clear();
+ delayQueue.cancelAllEvents();
+
+ dataModel = Factory::getInstance()->createDataModel(ctx.machine->datamodel, this);
+
+ }
+
+ int step() {
+ // advance current machine if there are multiple
+ currentMachine++;
+ if (currentMachine == allMachines.end())
+ currentMachine = allMachines.begin();
+
+ StateMachine* toRun = currentMachine->second;
+ if (!toRun->hasPendingWork()) {
+ return SCXML_ERR_IDLE;
+ }
+
+ return scxml_step(&toRun->ctx);
+ }
+
+ // InterpreterInfo
NameSpaceInfo getNameSpaceInfo() const {
return nsInfo;
}
@@ -58,524 +138,568 @@ public:
const std::map<std::string, IOProcessor>& getIOProcessors() {
return ioProcs;
}
- bool isInState(const std::string& stateId) {
- for (int i = 0 ; i < SCXML_NUMBER_STATES; i++) {
- if (scxml_states[i].name != NULL && BIT_HAS(i, ctx->config) && stateId == scxml_states[i].name)
- return true;
- }
- return false;
+ const std::map<std::string, Invoker>& getInvokers() {
+ return invokers;
}
Arabica::DOM::Document<std::string> getDocument() const {
return document;
}
- const std::map<std::string, Invoker>& getInvokers() {
- return invokers;
- }
-
- NameSpaceInfo nsInfo;
- std::string name;
- std::string sessionId;
- std::map<std::string, IOProcessor> ioProcs;
- std::map<std::string, Invoker> invokers;
- Arabica::DOM::Document<std::string> document;
- scxml_ctx* ctx;
- DataModel datamodel;
-
- std::map<const scxml_elem_foreach*, scxml_foreach_info*> foreachInfo;
- std::deque<Event*> iq;
- std::deque<Event*> eq;
-
- DelayedEventQueue delayQueue;
- std::map<std::string, SendRequest*> sendIds;
- tthread::condition_variable monitor;
- tthread::mutex mutex;
-};
+ bool isInState(const std::string& stateId) {
+ for (int i = 0 ; i < ctx.machine->nr_states; i++) {
+ if (ctx.machine->states[i].name != NULL && BIT_HAS(i, ctx.config) && stateId == ctx.machine->states[i].name)
+ return true;
+ }
+ return false;
+ }
-int matches(const char* desc, const char* event) {
- const char* dPtr = desc;
- const char* ePtr = event;
- while(*dPtr != 0) {
+ // callbacks for scxml context
- if (*dPtr == '*' && *ePtr != 0) // something following
- return true;
-
- // descriptor differs from event name
- if (*dPtr != *ePtr) {
- // move to next descriptor
- while(*dPtr != ' ' && *dPtr != 0) {
- dPtr++;
- }
- if (*dPtr == 0)
+ static int isEnabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) {
+ Event* event = (Event*)e;
+ if (event == NULL) {
+ if (t->event == NULL) {
+ // spontaneous transition, null event
+ if (t->condition != NULL)
+ return isTrue(ctx, t->condition);
+ return true;
+ } else {
+ // spontaneous transition, but real event
return false;
- dPtr++;
- ePtr = event;
- } else {
- // move both pointers one character
- dPtr++;
- ePtr++;
-
+ }
}
- // descriptor is done, return match
- if (((*dPtr == 0 || *dPtr == ' ') && (*ePtr == 0 || *ePtr == ' ')) || // exact match, end of string
- (*dPtr == ' ' && *ePtr == '.') || (*dPtr == 0 && *ePtr == '.')) // prefix match
+ // real transition, real event
+ if (nameMatch(t->event, event->name.c_str())) {
+ if (t->condition != NULL)
+ return isTrue(ctx, t->condition);
return true;
+ }
+ return false;
}
- return false;
-}
-
-int exec_content_raise(const scxml_ctx* ctx, const char* event) {
- Event* e = new Event();
- e->name = event;
- if (boost::starts_with(e->name, "error.")) {
- e->eventType = Event::PLATFORM;
- } else {
- e->eventType = Event::INTERNAL;
+ static int isTrue(const scxml_ctx* ctx, const char* expr) {
+ try {
+ return USER_DATA(ctx)->dataModel.evalAsBool(expr);
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ }
+ return false;
}
-#ifdef SCXML_VERBOSE
- printf("Raising Internal Event: %s\n", e->name.c_str());
-#endif
- USER_DATA(ctx)->iq.push_back(e);
- return SCXML_ERR_OK;
-}
-
-int is_true(const scxml_ctx* ctx, const char* expr) {
- try {
- return USER_DATA(ctx)->datamodel.evalAsBool(expr);
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- }
- return false;
-}
+ static int invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) {
+ if (invocation->machine != NULL) {
+ StateMachine* INSTANCE = USER_DATA(ctx);
+ // invoke a nested SCXML machine
+ StateMachine* invokedMachine = new StateMachine(INSTANCE, invocation->machine);
+ invokedMachine->invocation = invocation;
+ invokedMachine->invokeId = invocation->id;
+ assert(invocation->id != NULL);
-int is_enabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) {
- Event* event = (Event*)e;
- if (event == NULL) {
- if (t->event == NULL) {
- // spontaneous transition, null event
- if (t->condition != NULL)
- return is_true(ctx, t->condition);
- return true;
- } else {
- // spontaneous transition, but real event
- return false;
+ INSTANCE->topMostMachine->allMachines[invokedMachine->invokeId] = invokedMachine;
}
+ return SCXML_ERR_UNSUPPORTED;
}
- // real transition, real event
- if (matches(t->event, event->name.c_str())) {
- if (t->condition != NULL)
- return is_true(ctx, t->condition);
- return true;
- }
- return false;
-}
-
-int raise_done_event(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) {
- Event* e = new Event();
- e->name = std::string("done.state.") + state->name;
+ static int raiseDoneEvent(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) {
+ Event* e = new Event();
+ e->name = std::string("done.state.") + state->name;
- if (donedata) {
- if (donedata->content != NULL) {
- e->data = Data(donedata->content, Data::VERBATIM);
- } else if (donedata->contentexpr != NULL) {
- try {
- e->data = USER_DATA(ctx)->datamodel.getStringAsData(donedata->contentexpr);
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- }
- } else {
- try {
- const scxml_elem_param* param = donedata->params;
- while (param && ELEM_PARAM_IS_SET(param)) {
- Data paramValue;
- if (param->expr != NULL) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->expr);
- } else if(param->location) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->location);
+ if (donedata) {
+ if (donedata->content != NULL) {
+ e->data = Data(donedata->content, Data::VERBATIM);
+ } else if (donedata->contentexpr != NULL) {
+ try {
+ e->data = USER_DATA(ctx)->dataModel.getStringAsData(donedata->contentexpr);
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ }
+ } else {
+ try {
+ const scxml_elem_param* param = donedata->params;
+ while (param && ELEM_PARAM_IS_SET(param)) {
+ Data paramValue;
+ if (param->expr != NULL) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->expr);
+ } else if(param->location) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->location);
+ }
+ e->params.insert(std::make_pair(param->name, paramValue));
+ param++;
}
- e->params.insert(std::make_pair(param->name, paramValue));
- param++;
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
}
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
}
}
- }
-
-#ifdef SCXML_VERBOSE
- printf("Raising Done Event: %s\n", e->name.c_str());
-#endif
- USER_DATA(ctx)->iq.push_back(e);
- return SCXML_ERR_OK;
-}
-
-void delayedSend(void* ctx, std::string eventName) {
- tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
-
- SendRequest* sr = USER_DATA(ctx)->sendIds[eventName];
- Event* e = new Event(*sr);
- if (sr->target == "#_internal") {
- e->eventType = Event::INTERNAL;
#ifdef SCXML_VERBOSE
- printf("Pushing Internal Event: %s\n", e->name.c_str());
+ printf("Raising Done Event: %s\n", e->name.c_str());
#endif
USER_DATA(ctx)->iq.push_back(e);
- } else {
- e->eventType = Event::EXTERNAL;
-#ifdef SCXML_VERBOSE
- printf("Pushing External Event: %s\n", e->name.c_str());
-#endif
- USER_DATA(ctx)->eq.push_back(e);
+ return SCXML_ERR_OK;
}
- USER_DATA(ctx)->monitor.notify_all();
- delete sr;
-}
-int exec_content_cancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) {
- std::string eventId;
- if (sendid != NULL) {
- eventId = sendid;
- } else if (sendidexpr != NULL) {
- eventId = USER_DATA(ctx)->datamodel.evalAsString(sendidexpr);
- }
+ static int execContentSend(const scxml_ctx* ctx, const scxml_elem_send* send) {
+ SendRequest* e = new SendRequest();
- if (eventId.length() > 0) {
- USER_DATA(ctx)->delayQueue.cancelEvent(eventId);
- } else {
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_EXEC_CONTENT;
- }
- return SCXML_ERR_OK;
-}
-
-std::string spaceNormalize(const std::string& text) {
- std::stringstream content;
- std::string seperator;
-
- size_t start = 0;
- for (int i = 0; i < text.size(); i++) {
- if (isspace(text[i])) {
- if (i > 0 && start < i) {
- content << seperator << text.substr(start, i - start);
- seperator = " ";
- }
- while(isspace(text[++i])); // skip whitespaces
- start = i;
- } else if (i + 1 == text.size()) {
- content << seperator << text.substr(start, i + 1 - start);
+ std::string target;
+ if (send->target != NULL) {
+ e->target = send->target;
+ } else if (send->targetexpr != NULL) {
+ e->target = USER_DATA(ctx)->dataModel.evalAsString(send->targetexpr);
+ } else {
+ e->target = "#_external";
}
- }
- return content.str();
-}
+ if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) {
+ delete e;
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_INVALID_TARGET;
+ }
-int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) {
- SendRequest* e = new SendRequest();
+ e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ e->origin = e->target;
- std::string target;
- if (send->target != NULL) {
- e->target = send->target;
- } else if (send->targetexpr != NULL) {
- e->target = USER_DATA(ctx)->datamodel.evalAsString(send->targetexpr);
- } else {
- e->target = "#_external";
- }
+ try {
+ if (send->type != NULL) {
+ e->type = send->type;
+ } else if (send->typeexpr != NULL) {
+ e->type = USER_DATA(ctx)->dataModel.evalAsString(send->typeexpr);
+ } else {
+ e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ }
+ } catch (Event exc) {
+ execContentRaise(ctx, exc.name.c_str());
+ delete e;
+ return SCXML_ERR_EXEC_CONTENT;
+ }
- if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) {
- delete e;
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_INVALID_TARGET;
- }
+ // only one somewhat supported
+ if (e->type != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") {
+ delete e;
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_INVALID_TARGET;
+ }
- e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
- e->origin = e->target;
+ e->origintype = e->type;
- try {
- if (send->type != NULL) {
- e->type = send->type;
- } else if (send->typeexpr != NULL) {
- e->type = USER_DATA(ctx)->datamodel.evalAsString(send->typeexpr);
+ if (send->eventexpr != NULL) {
+ e->name = USER_DATA(ctx)->dataModel.evalAsString(send->eventexpr);
} else {
- e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ e->name = send->event;
}
- } catch (Event exc) {
- exec_content_raise(ctx, exc.name.c_str());
- delete e;
- return SCXML_ERR_EXEC_CONTENT;
- }
- // only one somewhat supported
- if (e->type != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") {
- delete e;
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_INVALID_TARGET;
- }
+ try {
+ const scxml_elem_param* param = send->params;
+ while (param && ELEM_PARAM_IS_SET(param)) {
+ Data paramValue;
+ if (param->expr != NULL) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->expr);
+ } else if(param->location) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->location);
+ }
+ e->params.insert(std::make_pair(param->name, paramValue));
+ param++;
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
- e->origintype = e->type;
+ try {
+ if (send->namelist != NULL) {
+ const char* bPtr = &send->namelist[0];
+ const char* ePtr = bPtr;
+ while(*ePtr != '\0') {
+ ePtr++;
+ if (*ePtr == ' ' || *ePtr == '\0') {
+ std::string key(bPtr, ePtr - bPtr);
+ e->params.insert(std::make_pair(key, USER_DATA(ctx)->dataModel.getStringAsData(key)));
+ if (*ePtr == '\0')
+ break;
+ bPtr = ++ePtr;
+ }
+ }
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
- if (send->eventexpr != NULL) {
- e->name = USER_DATA(ctx)->datamodel.evalAsString(send->eventexpr);
- } else {
- e->name = send->event;
- }
+ if (send->content != NULL) {
+ // will it parse as json?
+ Data d = Data::fromJSON(send->content);
+ if (!d.empty()) {
+ e->data = d;
+ } else {
+ e->data = Data(spaceNormalize(send->content), Data::VERBATIM);
+ }
+ }
- try {
- const scxml_elem_param* param = send->params;
- while (param && ELEM_PARAM_IS_SET(param)) {
- Data paramValue;
- if (param->expr != NULL) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->expr);
- } else if(param->location) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->location);
+ std::string sendid;
+ if (send->id != NULL) {
+ sendid = send->id;
+ e->sendid = sendid;
+ } else {
+ sendid = UUID::getUUID();
+ if (send->idlocation != NULL) {
+ USER_DATA(ctx)->dataModel.assign(send->idlocation, Data(sendid, Data::VERBATIM));
+ } else {
+ e->hideSendId = true;
}
- e->params.insert(std::make_pair(param->name, paramValue));
- param++;
- }
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
- }
-
- try {
- if (send->namelist != NULL) {
- const char* bPtr = &send->namelist[0];
- const char* ePtr = bPtr;
- while(*ePtr != '\0') {
- ePtr++;
- if (*ePtr == ' ' || *ePtr == '\0') {
- std::string key(bPtr, ePtr - bPtr);
- e->params.insert(std::make_pair(key, USER_DATA(ctx)->datamodel.getStringAsData(key)));
- if (*ePtr == '\0')
- break;
- bPtr = ++ePtr;
- }
+ }
+
+ size_t delayMs = 0;
+ std::string delay;
+ if (send->delayexpr != NULL) {
+ delay = USER_DATA(ctx)->dataModel.evalAsString(send->delayexpr);
+ } else if (send->delay != NULL) {
+ delay = send->delay;
+ }
+ if (delay.size() > 0) {
+ boost::trim(delay);
+
+ NumAttr delayAttr(delay);
+ if (iequals(delayAttr.unit, "ms")) {
+ delayMs = strTo<uint32_t>(delayAttr.value);
+ } else if (iequals(delayAttr.unit, "s")) {
+ delayMs = strTo<double>(delayAttr.value) * 1000;
+ } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds
+ delayMs = strTo<uint32_t>(delayAttr.value);
+ } else {
+ std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
}
}
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
- }
- if (send->content != NULL) {
- // will it parse as json?
- Data d = Data::fromJSON(send->content);
- if (!d.empty()) {
- e->data = d;
- } else {
- e->data = Data(spaceNormalize(send->content), Data::VERBATIM);
+ if (USER_DATA(ctx)->invokeId.size() > 0) {
+ e->invokeid = USER_DATA(ctx)->invokeId;
}
- }
- std::string sendid;
- if (send->id != NULL) {
- sendid = send->id;
- e->sendid = sendid;
- } else {
- sendid = UUID::getUUID();
- if (send->idlocation != NULL) {
- USER_DATA(ctx)->datamodel.assign(send->idlocation, Data(sendid, Data::VERBATIM));
+ USER_DATA(ctx)->sendIds[sendid] = e;
+ if (delayMs > 0) {
+ USER_DATA(ctx)->delayQueue.addEvent(sendid, delayedSend, delayMs, (void*)ctx);
} else {
- e->hideSendId = true;
+ delayedSend((void*)ctx, sendid);
}
+
+ return SCXML_ERR_OK;
}
+ static int execContentRaise(const scxml_ctx* ctx, const char* event) {
+ Event* e = new Event();
+ e->name = event;
- size_t delayMs = 0;
- std::string delay;
- if (send->delayexpr != NULL) {
- delay = USER_DATA(ctx)->datamodel.evalAsString(send->delayexpr);
- } else if (send->delay != NULL) {
- delay = send->delay;
+ if (boost::starts_with(e->name, "error.")) {
+ e->eventType = Event::PLATFORM;
+ } else {
+ e->eventType = Event::INTERNAL;
+ }
+ USER_DATA(ctx)->iq.push_back(e);
+ return SCXML_ERR_OK;
}
- if (delay.size() > 0) {
- boost::trim(delay);
- NumAttr delayAttr(delay);
- if (iequals(delayAttr.unit, "ms")) {
- delayMs = strTo<uint32_t>(delayAttr.value);
- } else if (iequals(delayAttr.unit, "s")) {
- delayMs = strTo<double>(delayAttr.value) * 1000;
- } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds
- delayMs = strTo<uint32_t>(delayAttr.value);
+ static int execContentCancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) {
+ std::string eventId;
+ if (sendid != NULL) {
+ eventId = sendid;
+ } else if (sendidexpr != NULL) {
+ eventId = USER_DATA(ctx)->dataModel.evalAsString(sendidexpr);
+ }
+
+ if (eventId.length() > 0) {
+ USER_DATA(ctx)->delayQueue.cancelEvent(eventId);
} else {
- std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_EXEC_CONTENT;
}
+ return SCXML_ERR_OK;
}
- USER_DATA(ctx)->sendIds[sendid] = e;
- if (delayMs > 0) {
- USER_DATA(ctx)->delayQueue.addEvent(sendid, delayedSend, delayMs, (void*)ctx);
- } else {
- delayedSend((void*)ctx, sendid);
+ static int execContentLog(const scxml_ctx* ctx, const char* label, const char* expr) {
+ try {
+ if (label != NULL) {
+ printf("%s%s", label, (expr != NULL ? ": " : ""));
+ }
+ if (expr != NULL) {
+ std::string msg = USER_DATA(ctx)->dataModel.evalAsString(expr);
+ printf("%s", msg.c_str());
+ }
+ if (label != NULL || expr != NULL) {
+ printf("\n");
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-
-int exec_content_init(const scxml_ctx* ctx, const scxml_elem_data* data) {
- while(ELEM_DATA_IS_SET(data)) {
- Data d;
- if (data->expr != NULL) {
- d = Data(data->expr, Data::INTERPRETED);
- } else if (data->content != NULL) {
- d = Data(data->content, Data::INTERPRETED);
- } else {
- d = Data("undefined", Data::INTERPRETED);
+ static int execContentAssign(const scxml_ctx* ctx, const char* location, const char* expr) {
+ std::string key = location;
+ if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") {
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_EXEC_CONTENT;
}
+
try {
- USER_DATA(ctx)->datamodel.init(data->id, d);
+ Data d(expr, Data::INTERPRETED);
+ USER_DATA(ctx)->dataModel.assign(key, d);
} catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
}
- data++;
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-int exec_content_assign(const scxml_ctx* ctx, const char* location, const char* expr) {
- std::string key = location;
- if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") {
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_EXEC_CONTENT;
- }
+ static int execContentForeachInit(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
+ try {
+ scxml_foreach_info* feInfo = (scxml_foreach_info*)malloc(sizeof(scxml_foreach_info));
+ USER_DATA(ctx)->foreachInfo[foreach] = feInfo;
- try {
- Data d(expr, Data::INTERPRETED);
- USER_DATA(ctx)->datamodel.assign(key, d);
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
+ feInfo->iterations = USER_DATA(ctx)->dataModel.getLength(foreach->array);
+ feInfo->currIteration = 0;
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-int exec_content_foreach_init(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
- try {
- scxml_foreach_info* feInfo = (scxml_foreach_info*)malloc(sizeof(scxml_foreach_info));
- USER_DATA(ctx)->foreachInfo[foreach] = feInfo;
-
- feInfo->iterations = USER_DATA(ctx)->datamodel.getLength(foreach->array);
- feInfo->currIteration = 0;
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
+ static int execContentForeachNext(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
+ try {
+ scxml_foreach_info* feInfo = USER_DATA(ctx)->foreachInfo[foreach];
+ if (feInfo->currIteration < feInfo->iterations) {
+ USER_DATA(ctx)->dataModel.setForeach((foreach->item != NULL ? foreach->item : ""),
+ (foreach->array != NULL ? foreach->array : ""),
+ (foreach->index != NULL ? foreach->index : ""),
+ feInfo->currIteration);
+ feInfo->currIteration++;
+ return SCXML_ERR_OK;
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ free(USER_DATA(ctx)->foreachInfo[foreach]);
+ USER_DATA(ctx)->foreachInfo.erase(foreach);
+ return SCXML_ERR_EXEC_CONTENT;
+ }
+ return SCXML_ERR_FOREACH_DONE;
}
- return SCXML_ERR_OK;
-}
-int exec_content_foreach_next(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
- try {
- scxml_foreach_info* feInfo = USER_DATA(ctx)->foreachInfo[foreach];
- if (feInfo->currIteration < feInfo->iterations) {
- USER_DATA(ctx)->datamodel.setForeach((foreach->item != NULL ? foreach->item : ""),
- (foreach->array != NULL ? foreach->array : ""),
- (foreach->index != NULL ? foreach->index : ""),
- feInfo->currIteration);
- feInfo->currIteration++;
- return SCXML_ERR_OK;
- }
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
+ static int execContentForeachDone(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
free(USER_DATA(ctx)->foreachInfo[foreach]);
USER_DATA(ctx)->foreachInfo.erase(foreach);
- return SCXML_ERR_EXEC_CONTENT;
+ return SCXML_ERR_OK;
+ }
+
+ static int execContentInit(const scxml_ctx* ctx, const scxml_elem_data* data) {
+ while(ELEM_DATA_IS_SET(data)) {
+ Data d;
+ if (data->expr != NULL) {
+ d = Data(data->expr, Data::INTERPRETED);
+ } else if (data->content != NULL) {
+ d = Data(data->content, Data::INTERPRETED);
+ } else {
+ d = Data("undefined", Data::INTERPRETED);
+ }
+ try {
+ USER_DATA(ctx)->dataModel.init(data->id, d);
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ }
+ data++;
+ }
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_FOREACH_DONE;
-}
-int exec_content_foreach_done(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
- free(USER_DATA(ctx)->foreachInfo[foreach]);
- USER_DATA(ctx)->foreachInfo.erase(foreach);
- return SCXML_ERR_OK;
-}
-
-int exec_content_log(const scxml_ctx* ctx, const char* label, const char* expr) {
- try {
- if (label != NULL) {
- printf("%s%s", label, (expr != NULL ? ": " : ""));
- }
- if (expr != NULL) {
- std::string msg = USER_DATA(ctx)->datamodel.evalAsString(expr);
- printf("%s", msg.c_str());
+ static int execContentScript(const scxml_ctx* ctx, const char* src, const char* content) {
+ if (content != NULL) {
+ USER_DATA(ctx)->dataModel.eval(Arabica::DOM::Element<std::string>(), content);
+ } else if (src != NULL) {
+ return SCXML_ERR_UNSUPPORTED;
}
- if (label != NULL || expr != NULL) {
- printf("\n");
- }
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-int exec_content_script(const scxml_ctx* ctx, const char* src, const char* content) {
- if (content != NULL) {
- USER_DATA(ctx)->datamodel.eval(Arabica::DOM::Element<std::string>(), content);
- } else if (src != NULL) {
- return SCXML_ERR_UNSUPPORTED;
- }
- return SCXML_ERR_OK;
-}
+ static void* dequeueExternal(const scxml_ctx* ctx) {
+ tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
+ if (USER_DATA(ctx)->eq.size() == 0)
+ return NULL;
+
+ Event* e = USER_DATA(ctx)->eq.front();
+ USER_DATA(ctx)->eq.pop_front();
+ USER_DATA(ctx)->dataModel.setEvent(*e);
-void* dequeue_external(const scxml_ctx* ctx) {
- tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
- while (USER_DATA(ctx)->eq.size() == 0) {
- USER_DATA(ctx)->monitor.wait(USER_DATA(ctx)->mutex);
+ if (e->invokeid.size() > 0) {
+ // we need to check for finalize content
+ StateMachine* invokedMachine = USER_DATA(ctx)->allMachines[e->invokeid];
+ if (invokedMachine->invocation->finalize != NULL)
+ invokedMachine->invocation->finalize(ctx,
+ invokedMachine->invocation,
+ e);
+ }
+
+#ifdef SCXML_VERBOSE
+ printf("Popping External Event: %s\n", e->name.c_str());
+#endif
+ return e;
}
- Event* e = USER_DATA(ctx)->eq.front();
- USER_DATA(ctx)->eq.pop_front();
- USER_DATA(ctx)->datamodel.setEvent(*e);
+
+ static void* dequeueInternal(const scxml_ctx* ctx) {
+ if (USER_DATA(ctx)->iq.size() == 0)
+ return NULL;
+ Event* e = USER_DATA(ctx)->iq.front();
+ USER_DATA(ctx)->iq.pop_front();
+ USER_DATA(ctx)->dataModel.setEvent(*e);
#ifdef SCXML_VERBOSE
- printf("Popping External Event: %s\n", e->name.c_str());
+ printf("Popping Internal Event: %s\n", e->name.c_str());
#endif
- return e;
-}
+ return e;
+ }
+
+ static void delayedSend(void* ctx, std::string eventName) {
+ tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
+
+ SendRequest* sr = USER_DATA(ctx)->sendIds[eventName];
+ Event* e = new Event(*sr);
-void* dequeue_internal(const scxml_ctx* ctx) {
- if (USER_DATA(ctx)->iq.size() == 0)
- return NULL;
- Event* e = USER_DATA(ctx)->iq.front();
- USER_DATA(ctx)->iq.pop_front();
- USER_DATA(ctx)->datamodel.setEvent(*e);
+ if (sr->target == "#_internal") {
+ e->eventType = Event::INTERNAL;
#ifdef SCXML_VERBOSE
- printf("Popping Internal Event: %s\n", e->name.c_str());
+ printf("Pushing Internal Event: %s\n", e->name.c_str());
#endif
- return e;
-}
+ USER_DATA(ctx)->iq.push_back(e);
+ } else if (sr->target == "#_parent") {
+ e->eventType = Event::EXTERNAL;
+ if (USER_DATA(ctx)->parentMachine != NULL) {
+ USER_DATA(ctx)->parentMachine->eq.push_back(e);
+ }
+ // TODO: handle invalid parent
+ } else {
+ e->eventType = Event::EXTERNAL;
+#ifdef SCXML_VERBOSE
+ printf("Pushing External Event: %s\n", e->name.c_str());
+#endif
+ USER_DATA(ctx)->eq.push_back(e);
+ }
+ USER_DATA(ctx)->monitor.notify_all();
+ delete sr;
+ }
-int main(int argc, char** argv) {
+ static std::string spaceNormalize(const std::string& text) {
+ std::stringstream content;
+ std::string seperator;
- std::cout << "sizeof(scxml_state): " << sizeof(scxml_state) << std::endl;
- std::cout << "sizeof(scxml_transition): " << sizeof(scxml_transition) << std::endl;
- std::cout << "sizeof(scxml_ctx): " << sizeof(scxml_ctx) << std::endl;
+ size_t start = 0;
+ for (int i = 0; i < text.size(); i++) {
+ if (isspace(text[i])) {
+ if (i > 0 && start < i) {
+ content << seperator << text.substr(start, i - start);
+ seperator = " ";
+ }
+ while(isspace(text[++i])); // skip whitespaces
+ start = i;
+ } else if (i + 1 == text.size()) {
+ content << seperator << text.substr(start, i + 1 - start);
+ }
+ }
+ return content.str();
+ }
-#ifdef APPLE
- mach_timebase_info_data_t timebase_info;
- mach_timebase_info(&timebase_info);
-
- const uint64_t NANOS_PER_MSEC = 1000000ULL;
- double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
-
- thread_time_constraint_policy_data_t policy;
- policy.period = 0;
- policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
- policy.constraint = (uint32_t)(10 * clock2abs);
- policy.preemptible = FALSE;
-
- int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
- THREAD_TIME_CONSTRAINT_POLICY,
- (thread_policy_t)&policy,
- THREAD_TIME_CONSTRAINT_POLICY_COUNT);
- if (kr != KERN_SUCCESS) {
- mach_error("thread_policy_set:", kr);
- exit(1);
+ // TODO: isolate InterpreterImpl to reduce header deps on libxml/parser.h
+ static bool nameMatch(const std::string& eventDescs, const std::string& eventName) {
+ if(eventDescs.length() == 0 || eventName.length() == 0)
+ return false;
+
+ // naive case of single descriptor and exact match
+ if (iequals(eventDescs, eventName))
+ return true;
+
+ size_t start = 0;
+ std::string eventDesc;
+ for (int i = 0; i < eventDescs.size(); i++) {
+ if (isspace(eventDescs[i])) {
+ if (i > 0 && start < i - 1) {
+ eventDesc = eventDescs.substr(start, i - start);
+ }
+ while(isspace(eventDescs[++i])); // skip whitespaces
+ start = i;
+ } else if (i + 1 == eventDescs.size()) {
+ eventDesc = eventDescs.substr(start, i + 1 - start);
+ }
+
+ if (eventDesc.size() > 0) {
+ // remove optional trailing .* for CCXML compatibility
+ if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+ if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+
+ // was eventDesc the * wildcard
+ if (eventDesc.size() == 0)
+ return true;
+
+ // eventDesc has to be a real prefix of event now and therefore shorter
+ if (eventDesc.size() > eventName.size())
+ goto NEXT_DESC;
+
+ // are they already equal?
+ if (iequals(eventDesc, eventName))
+ return true;
+
+ if (eventName.find(eventDesc) == 0) {
+ if (eventName.find(".", eventDesc.size()) == eventDesc.size())
+ return true;
+ }
+NEXT_DESC:
+ eventDesc = "";
+ }
+ }
+ return false;
}
-#endif
+
+ std::map<std::string, StateMachine*> allMachines;
+
+ StateMachine* parentMachine;
+ StateMachine* topMostMachine;
+ std::map<std::string, StateMachine* >::iterator currentMachine; // next machine to advance
+
+ int state;
+ scxml_ctx ctx;
+
+ std::string sessionId;
+ std::string name;
+
+ // in case we were invoked
+ std::string invokeId;
+ const scxml_elem_invoke* invocation;
+
+ std::deque<Event*> iq;
+ std::deque<Event*> eq;
+
+ DataModel dataModel;
+
+protected:
+ struct scxml_foreach_info {
+ size_t iterations;
+ size_t currIteration;
+ };
+
+ NameSpaceInfo nsInfo;
+ std::map<std::string, IOProcessor> ioProcs;
+ std::map<std::string, Invoker> invokers;
+ Arabica::DOM::Document<std::string> document;
+
+ DelayedEventQueue delayQueue;
+ std::map<std::string, SendRequest*> sendIds;
+ std::map<const scxml_elem_foreach*, scxml_foreach_info*> foreachInfo;
+
+ tthread::condition_variable monitor;
+ tthread::mutex mutex;
+};
+
+
+int main(int argc, char** argv) {
int err;
size_t benchmarkRuns = 1;
@@ -584,90 +708,56 @@ int main(int argc, char** argv) {
benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
}
-
size_t remainingRuns = benchmarkRuns;
- // setup info object required for datamodel
- GenCInterpreterInfo interpreterInfo;
- interpreterInfo.name = SCXML_MACHINE_NAME;
- interpreterInfo.sessionId = "rfwef";
- interpreterInfo.delayQueue.start();
-
- scxml_ctx ctx;
- interpreterInfo.ctx = &ctx;
-
double avg = 0;
size_t microSteps = 0;
#ifdef BUILD_PROFILING
double avgDm = 0;
#endif
+ StateMachine rootMachine(&scxml_machines[0]);
+
Timer tTotal;
tTotal.start();
while(remainingRuns-- > 0) {
- memset(&ctx, 0, sizeof(scxml_ctx));
-
- // fresh dm (expensive :( )
- interpreterInfo.datamodel = Factory::getInstance()->createDataModel("ecmascript", &interpreterInfo);
-
- // set info object as user data
- ctx.user_data = (void*)&interpreterInfo;
-
- // register callbacks with scxml context
- ctx.is_enabled = &is_enabled;
- ctx.is_true = &is_true;
- ctx.raise_done_event = &raise_done_event;
-
- ctx.exec_content_send = &exec_content_send;
- ctx.exec_content_raise = &exec_content_raise;
- ctx.exec_content_cancel = &exec_content_cancel;
- ctx.exec_content_log = &exec_content_log;
- ctx.exec_content_assign = &exec_content_assign;
- ctx.exec_content_foreach_init = &exec_content_foreach_init;
- ctx.exec_content_foreach_next = &exec_content_foreach_next;
- ctx.exec_content_foreach_done = &exec_content_foreach_done;
- ctx.dequeue_external = &dequeue_external;
- ctx.dequeue_internal = &dequeue_internal;
- ctx.exec_content_init = &exec_content_init;
- ctx.exec_content_script = &exec_content_script;
Timer t;
t.start();
-
microSteps = 0;
- while((err = scxml_step(&ctx)) == SCXML_ERR_OK) {
+
+
+ for (;;) {
+ err = rootMachine.step();
+ if (rootMachine.isDone())
+ break;
t.stop();
microSteps++;
- if (ctx.event != NULL) {
- delete ((Event*)(ctx.event));
- }
+
t.start();
}
microSteps++;
- assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL);
-
+ assert(rootMachine.ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL);
t.stop();
+
avg += t.elapsed;
#ifdef BUILD_PROFILING
- avgDm += interpreterInfo.datamodel.timer.elapsed;
- interpreterInfo.datamodel.timer.elapsed = 0;
+ avgDm += rootMachine.dataModel.timer.elapsed;
+ rootMachine.dataModel.timer.elapsed = 0;
#endif
size_t passIdx = 0;
- for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
- if (scxml_states[i].name && strcmp(scxml_states[i].name, "pass") == 0) {
+ for (int i = 0; i < rootMachine.ctx.machine->nr_states; i++) {
+ if (rootMachine.ctx.machine->states[i].name && strcmp(rootMachine.ctx.machine->states[i].name, "pass") == 0) {
passIdx = i;
break;
}
}
- if(!BIT_HAS(passIdx, ctx.config)) {
+ if(!BIT_HAS(passIdx, rootMachine.ctx.config)) {
std::cerr << "Interpreter did not end in pass" << std::endl;
exit(EXIT_FAILURE);
}
- interpreterInfo.delayQueue.cancelAllEvents();
- interpreterInfo.eq.clear();
- interpreterInfo.iq.clear();
}
tTotal.stop();
std::cout << benchmarkRuns << " iterations" << std::endl;
@@ -676,10 +766,9 @@ int main(int argc, char** argv) {
std::cout << microSteps << " microsteps per iteration" << std::endl;
std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl;
#ifdef BUILD_PROFILING
- std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
- std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl;
+ std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in dataModel" << std::endl;
+ std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo dataModel" << std::endl;
#endif
- interpreterInfo.delayQueue.stop();
tthread::this_thread::sleep_for(tthread::chrono::milliseconds(100));
return EXIT_SUCCESS;
-} \ No newline at end of file
+}
diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c
index ebacc5f..a69b7c7 100644
--- a/test/src/test-c-machine.machine.c
+++ b/test/src/test-c-machine.machine.c
@@ -13,6 +13,22 @@
#define unlikely(x) (x)
#endif
+#ifndef SCXML_NR_STATES_TYPE
+# define SCXML_NR_STATES_TYPE uint8_t
+#endif
+
+#ifndef SCXML_NR_TRANS_TYPE
+# define SCXML_NR_TRANS_TYPE uint8_t
+#endif
+
+#ifndef SCXML_MAX_NR_STATES_BYTES
+# define SCXML_MAX_NR_STATES_BYTES 1
+#endif
+
+#ifndef SCXML_MAX_NR_TRANS_BYTES
+# define SCXML_MAX_NR_TRANS_BYTES 1
+#endif
+
// error return codes
#define SCXML_ERR_OK 0
#define SCXML_ERR_IDLE 1
@@ -24,9 +40,8 @@
#define SCXML_ERR_INVALID_TYPE 7
#define SCXML_ERR_UNSUPPORTED 8
-#define SCXML_MACHINE_NAME ""
-#define SCXML_NUMBER_STATES 9
-#define SCXML_NUMBER_TRANSITIONS 6
+#define SCXML_NUMBER_STATES (ctx->machine->nr_states)
+#define SCXML_NUMBER_TRANS (ctx->machine->nr_transitions)
#define SCXML_TRANS_SPONTANEOUS 0x01
#define SCXML_TRANS_TARGETLESS 0x02
@@ -53,12 +68,14 @@
#define ELEM_DATA_IS_SET(data) (data->id != NULL)
#define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL)
#define ELEM_PARAM_IS_SET(param) (param->name != NULL)
+#define SCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0)
+typedef struct scxml_machine scxml_machine;
typedef struct scxml_transition scxml_transition;
typedef struct scxml_state scxml_state;
typedef struct scxml_ctx scxml_ctx;
-typedef struct scxml_invoke scxml_invoke;
+typedef struct scxml_elem_invoke scxml_elem_invoke;
typedef struct scxml_elem_send scxml_elem_send;
typedef struct scxml_elem_param scxml_elem_param;
@@ -72,7 +89,7 @@ typedef int (*is_enabled_t)(const scxml_ctx* ctx, const scxml_transition* transi
typedef int (*is_true_t)(const scxml_ctx* ctx, const char* expr);
typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event);
typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata);
-typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x);
+typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke);
typedef int (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr);
typedef int (*exec_content_raise_t)(const scxml_ctx* ctx, const char* event);
@@ -83,9 +100,26 @@ typedef int (*exec_content_foreach_done_t)(const scxml_ctx* ctx, const scxml_ele
typedef int (*exec_content_assign_t)(const scxml_ctx* ctx, const char* location, const char* expr);
typedef int (*exec_content_init_t)(const scxml_ctx* ctx, const scxml_elem_data* data);
typedef int (*exec_content_cancel_t)(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr);
-typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_invoke* invoker, const void* event);
+typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_elem_invoke* invoker, const void* event);
typedef int (*exec_content_script_t)(const scxml_ctx* ctx, const char* src, const char* content);
+struct scxml_machine {
+ uint8_t flags;
+ SCXML_NR_STATES_TYPE nr_states;
+ SCXML_NR_TRANS_TYPE nr_transitions;
+ const char* name;
+ const char* datamodel;
+ const char* uuid;
+ const scxml_state* states;
+ const scxml_transition* transitions;
+ const scxml_machine* parent;
+ const scxml_elem_donedata* donedata;
+ const exec_content_t script;
+};
+
+// forward declare machines to allow references
+extern const scxml_machine scxml_machines[3];
+
struct scxml_elem_data {
const char* id;
const char* src;
@@ -99,22 +133,22 @@ struct scxml_state {
const exec_content_t on_entry; // on entry handlers
const exec_content_t on_exit; // on exit handlers
const invoke_t invoke; // invocations
- const char children[2]; // all children
- const char completion[2]; // default completion
- const char ancestors[2]; // all ancestors
+ const char children[SCXML_MAX_NR_STATES_BYTES]; // all children
+ const char completion[SCXML_MAX_NR_STATES_BYTES]; // default completion
+ const char ancestors[SCXML_MAX_NR_STATES_BYTES]; // all ancestors
const scxml_elem_data* data;
const uint8_t type; // atomic, parallel, compound, final, history
};
struct scxml_transition {
const uint8_t source;
- const char target[2];
+ const char target[SCXML_MAX_NR_STATES_BYTES];
const char* event;
const char* condition;
const exec_content_t on_transition;
const uint8_t type;
- const char conflicts[1];
- const char exit_set[2];
+ const char conflicts[SCXML_MAX_NR_TRANS_BYTES];
+ const char exit_set[SCXML_MAX_NR_STATES_BYTES];
};
struct scxml_elem_foreach {
@@ -137,6 +171,7 @@ struct scxml_elem_donedata {
};
struct scxml_elem_invoke {
+ const scxml_machine* machine;
const char* type;
const char* typeexpr;
const char* src;
@@ -146,7 +181,7 @@ struct scxml_elem_invoke {
const char* namelist;
const uint8_t autoforward;
const scxml_elem_param* params;
- const exec_content_finalize_t* finalize;
+ exec_content_finalize_t finalize;
const char* content;
const char* contentexpr;
};
@@ -169,12 +204,13 @@ struct scxml_elem_send {
};
struct scxml_ctx {
- uint8_t flags;
+ uint8_t flags;
+ const scxml_machine* machine;
- char config[2];
- char history[2];
- char pending_invokes[2];
- char initialized_data[2];
+ char config[SCXML_MAX_NR_STATES_BYTES];
+ char history[SCXML_MAX_NR_STATES_BYTES];
+ char invocations[SCXML_MAX_NR_STATES_BYTES];
+ char initialized_data[SCXML_MAX_NR_STATES_BYTES];
void* user_data;
void* event;
@@ -198,30 +234,107 @@ struct scxml_ctx {
invoke_t invoke;
};
-static const scxml_elem_data scxml_elem_datas[2] = {
+static const scxml_elem_data _scxml_6A932FF1_elem_datas[2] = {
/* id, src, expr, content */
- { "Var1", NULL, "0", NULL },
+ { "Var1", NULL, "1", NULL },
{ NULL, NULL, NULL, NULL }
};
-static const scxml_elem_param scxml_elem_params[2] = {
+static const scxml_elem_param _scxml_6A932FF1_elem_params[2] = {
/* name, expr, location */
- { "Var1", "1", NULL },
+ { "aParam", "2", NULL },
{ NULL, NULL, NULL }
};
-static const scxml_elem_donedata scxml_elem_donedatas[3] = {
+static const scxml_elem_send _scxml_6A932FF1_elem_sends[2] = {
+ {
+ /* event */ "timeout",
+ /* eventexpr */ NULL,
+ /* target */ NULL,
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ "300s",
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ NULL
+ },
+ {
+ /* event */ "childToParent",
+ /* eventexpr */ NULL,
+ /* target */ "#_parent",
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ NULL,
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ &_scxml_6A932FF1_elem_params[0]
+ }
+};
+
+static const scxml_elem_donedata _scxml_6A932FF1_elem_donedatas[1] = {
/* source, content, contentexpr, params */
- { 3, NULL, NULL, &scxml_elem_params[0] },
- { 6, "foo", NULL, NULL },
{ 0, NULL, NULL, NULL }
};
-static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+static int _scxml_6A932FF1_s0_invoke0_finalize0(const scxml_ctx* ctx, const scxml_elem_invoke* invocation, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_assign != NULL) {
+ if ((ctx->exec_content_assign(ctx, "Var1", "_event.data.aParam")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static const scxml_elem_invoke _scxml_6A932FF1_elem_invokes[1] = {
+ {
+ /* machine */ &scxml_machines[1],
+ /* type */ "http://www.w3.org/TR/scxml/",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "d2170d67-da91-4aba-99a1-b1c021513e75",
+ /* idlocation */ NULL,
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ _scxml_6A932FF1_s0_invoke0_finalize0,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ }
+};
+
+static int _scxml_6A932FF1_s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &_scxml_6A932FF1_elem_sends[0])) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int _scxml_6A932FF1_s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_6A932FF1_s0_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
-static int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+static int _scxml_6A932FF1_s0_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) {
+ ctx->invoke(ctx, s, &_scxml_6A932FF1_elem_invokes[0], uninvoke);
+
+ return SCXML_ERR_OK;
+}
+static int _scxml_6A932FF1_pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
int err = SCXML_ERR_OK;
if likely(ctx->exec_content_log != NULL) {
if unlikely((ctx->exec_content_log(ctx, "Outcome", "'pass'")) != SCXML_ERR_OK) return err;
@@ -231,12 +344,12 @@ static int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const
return SCXML_ERR_OK;
}
-static int pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
- pass_on_entry_0(ctx, state, event);
+static int _scxml_6A932FF1_pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_6A932FF1_pass_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
-static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+static int _scxml_6A932FF1_fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
int err = SCXML_ERR_OK;
if likely(ctx->exec_content_log != NULL) {
if unlikely((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != SCXML_ERR_OK) return err;
@@ -246,204 +359,201 @@ static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const
return SCXML_ERR_OK;
}
-static int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
- fail_on_entry_0(ctx, state, event);
+static int _scxml_6A932FF1_fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_6A932FF1_fail_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
-static const scxml_state scxml_states[9] = {
+static const scxml_state _scxml_6A932FF1_states[4] = {
{ /* state number 0 */
/* name */ NULL,
/* parent */ 0,
/* onentry */ NULL,
/* onexit */ NULL,
/* invoke */ NULL,
- /* children */ { 0x92, 0x01 /* 010010011, 1 4 7 8 */ },
- /* completion */ { 0x02, 0x00 /* 010000000, 1 */ },
- /* ancestors */ { 0x00, 0x00 /* 000000000, */ },
- /* data */ &scxml_elem_datas[0],
+ /* children */ { 0x0e /* 0111 */ },
+ /* completion */ { 0x02 /* 0100 */ },
+ /* ancestors */ { 0x00 /* 0000 */ },
+ /* data */ &_scxml_6A932FF1_elem_datas[0],
/* type */ SCXML_STATE_COMPOUND,
},
{ /* state number 1 */
/* name */ "s0",
/* parent */ 0,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x0c, 0x00 /* 001100000, 2 3 */ },
- /* completion */ { 0x04, 0x00 /* 001000000, 2 */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_COMPOUND,
- },
- { /* state number 2 */
- /* name */ "s01",
- /* parent */ 1,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x03, 0x00 /* 110000000, 0 1 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_ATOMIC,
- },
- { /* state number 3 */
- /* name */ "s02",
- /* parent */ 1,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x03, 0x00 /* 110000000, 0 1 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_FINAL,
- },
- { /* state number 4 */
- /* name */ "s1",
- /* parent */ 0,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x60, 0x00 /* 000001100, 5 6 */ },
- /* completion */ { 0x20, 0x00 /* 000001000, 5 */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_COMPOUND,
- },
- { /* state number 5 */
- /* name */ "s11",
- /* parent */ 4,
- /* onentry */ NULL,
+ /* onentry */ _scxml_6A932FF1_s0_on_entry,
/* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x11, 0x00 /* 100010000, 0 4 */ },
+ /* invoke */ _scxml_6A932FF1_s0_invoke,
+ /* children */ { 0x00 /* 0000 */ },
+ /* completion */ { 0x00 /* 0000 */ },
+ /* ancestors */ { 0x01 /* 1000 */ },
/* data */ NULL,
/* type */ SCXML_STATE_ATOMIC,
},
- { /* state number 6 */
- /* name */ "s12",
- /* parent */ 4,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x11, 0x00 /* 100010000, 0 4 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_FINAL,
- },
- { /* state number 7 */
+ { /* state number 2 */
/* name */ "pass",
/* parent */ 0,
- /* onentry */ pass_on_entry,
+ /* onentry */ _scxml_6A932FF1_pass_on_entry,
/* onexit */ NULL,
/* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
+ /* children */ { 0x00 /* 0000 */ },
+ /* completion */ { 0x00 /* 0000 */ },
+ /* ancestors */ { 0x01 /* 1000 */ },
/* data */ NULL,
/* type */ SCXML_STATE_FINAL,
},
- { /* state number 8 */
+ { /* state number 3 */
/* name */ "fail",
/* parent */ 0,
- /* onentry */ fail_on_entry,
+ /* onentry */ _scxml_6A932FF1_fail_on_entry,
/* onexit */ NULL,
/* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
+ /* children */ { 0x00 /* 0000 */ },
+ /* completion */ { 0x00 /* 0000 */ },
+ /* ancestors */ { 0x01 /* 1000 */ },
/* data */ NULL,
/* type */ SCXML_STATE_FINAL,
}
};
-static const scxml_transition scxml_transitions[6] = {
+static const scxml_transition _scxml_6A932FF1_transitions[2] = {
{ /* transition number 0 with priority 0
- target: s02
- */
- /* source */ 2,
- /* target */ { 0x08, 0x00 /* 000100000, 3 */ },
- /* event */ NULL,
- /* condition */ NULL,
- /* ontrans */ NULL,
- /* type */ SCXML_TRANS_SPONTANEOUS,
- /* conflicts */ { 0x37 /* 111011, 0 1 2 4 5 */ },
- /* exit set */ { 0x0c, 0x00 /* 001100000, 2 3 */ }
- },
- { /* transition number 1 with priority 1
- target: s1
+ target: pass
*/
/* source */ 1,
- /* target */ { 0x10, 0x00 /* 000010000, 4 */ },
- /* event */ "done.state.s0",
- /* condition */ "_event.data['Var1']==1",
+ /* target */ { 0x04 /* 0010 */ },
+ /* event */ "childToParent",
+ /* condition */ "Var1==2",
/* ontrans */ NULL,
/* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
+ /* conflicts */ { 0x03 /* 11 */ },
+ /* exit set */ { 0x0e /* 0111 */ }
},
- { /* transition number 2 with priority 2
+ { /* transition number 1 with priority 1
target: fail
*/
/* source */ 1,
- /* target */ { 0x00, 0x01 /* 000000001, 8 */ },
- /* event */ "done.state.s0",
+ /* target */ { 0x08 /* 0001 */ },
+ /* event */ "*",
/* condition */ NULL,
/* ontrans */ NULL,
/* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
+ /* conflicts */ { 0x03 /* 11 */ },
+ /* exit set */ { 0x0e /* 0111 */ }
+ }
+};
+
+static const scxml_elem_param _scxml_74EC8913_elem_params[2] = {
+ /* name, expr, location */
+ { "aParam", "2", NULL },
+ { NULL, NULL, NULL }
+};
+
+static const scxml_elem_send _scxml_74EC8913_elem_sends[1] = {
+ {
+ /* event */ "childToParent",
+ /* eventexpr */ NULL,
+ /* target */ "#_parent",
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ NULL,
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ &_scxml_74EC8913_elem_params[0]
+ }
+};
+
+static const scxml_elem_donedata _scxml_74EC8913_elem_donedatas[1] = {
+ /* source, content, contentexpr, params */
+ { 0, NULL, NULL, NULL }
+};
+
+static int _scxml_74EC8913_subFinal_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &_scxml_74EC8913_elem_sends[0])) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int _scxml_74EC8913_subFinal_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_74EC8913_subFinal_on_entry_0(ctx, state, event);
+ return SCXML_ERR_OK;
+}
+
+static const scxml_state _scxml_74EC8913_states[2] = {
+ { /* state number 0 */
+ /* name */ NULL,
+ /* parent */ 0,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x02 /* 01 */ },
+ /* completion */ { 0x02 /* 01 */ },
+ /* ancestors */ { 0x00 /* 00 */ },
+ /* data */ NULL,
+ /* type */ SCXML_STATE_COMPOUND,
},
- { /* transition number 3 with priority 3
- target: s12
- */
- /* source */ 5,
- /* target */ { 0x40, 0x00 /* 000000100, 6 */ },
- /* event */ NULL,
- /* condition */ NULL,
- /* ontrans */ NULL,
- /* type */ SCXML_TRANS_SPONTANEOUS,
- /* conflicts */ { 0x3e /* 011111, 1 2 3 4 5 */ },
- /* exit set */ { 0x60, 0x00 /* 000001100, 5 6 */ }
+ { /* state number 1 */
+ /* name */ "subFinal",
+ /* parent */ 0,
+ /* onentry */ _scxml_74EC8913_subFinal_on_entry,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x00 /* 00 */ },
+ /* completion */ { 0x00 /* 00 */ },
+ /* ancestors */ { 0x01 /* 10 */ },
+ /* data */ NULL,
+ /* type */ SCXML_STATE_FINAL,
+ }
+};
+
+static const scxml_transition _scxml_74EC8913_transitions[0] = {
+};
+
+const scxml_machine scxml_machines[3] = {
+ {
+ /* flags */ 0,
+ /* nr_states */ 4,
+ /* nr_transitions */ 2,
+ /* name */ "",
+ /* datamodel */ "ecmascript",
+ /* uuid */ "6A932FF17BFF1735E3F3C77F7B54C218",
+ /* states */ &_scxml_6A932FF1_states[0],
+ /* transitions */ &_scxml_6A932FF1_transitions[0],
+ /* parent */ NULL,
+ /* donedata */ &_scxml_6A932FF1_elem_donedatas[0],
+ /* script */ NULL
},
- { /* transition number 4 with priority 4
- target: pass
- */
- /* source */ 4,
- /* target */ { 0x80, 0x00 /* 000000010, 7 */ },
- /* event */ "done.state.s1",
- /* condition */ "_event.data == 'foo'",
- /* ontrans */ NULL,
- /* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
+ {
+ /* flags */ 0,
+ /* nr_states */ 2,
+ /* nr_transitions */ 0,
+ /* name */ "",
+ /* datamodel */ "ecmascript",
+ /* uuid */ "74EC8913A9386F1A7EC5EF2A0426752B",
+ /* states */ &_scxml_74EC8913_states[0],
+ /* transitions */ &_scxml_74EC8913_transitions[0],
+ /* parent */ &scxml_machines[0],
+ /* donedata */ &_scxml_74EC8913_elem_donedatas[0],
+ /* script */ NULL
},
- { /* transition number 5 with priority 5
- target: fail
- */
- /* source */ 4,
- /* target */ { 0x00, 0x01 /* 000000001, 8 */ },
- /* event */ "done.state.s1",
- /* condition */ NULL,
- /* ontrans */ NULL,
- /* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
- }
+ {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }
};
#ifdef SCXML_VERBOSE
-static void printStateNames(const char* a) {
+static void printStateNames(const scxml_ctx* ctx, const char* a, size_t length) {
size_t i;
const char* seperator = "";
- for (i = 0; i < SCXML_NUMBER_STATES; i++) {
+ for (i = 0; i < length; i++) {
if (BIT_HAS(i, a)) {
- printf("%s%s", seperator, (scxml_states[i].name != NULL ? scxml_states[i].name : "UNK"));
+ printf("%s%s", seperator, (ctx->machine->states[i].name != NULL ? ctx->machine->states[i].name : "UNK"));
seperator = ", ";
}
}
@@ -464,69 +574,78 @@ static void printBitsetIndices(const char* a, size_t length) {
#endif
static int bit_has_and(const char* a, const char* b, size_t i) {
- do {
- if (a[i - 1] & b[i - 1])
+ while(i--) {
+ if (a[i] & b[i])
return 1;
- } while(--i);
+ }
return 0;
}
+static void bit_clear_all(char* a, size_t i) {
+ while(i--) {
+ a[i] = 0;
+ }
+}
+
static int bit_has_any(const char* a, size_t i) {
- do {
- if (a[i - 1] > 0)
+ while(i--) {
+ if (a[i] > 0)
return 1;
- } while(--i);
+ }
return 0;
}
static void bit_or(char* dest, const char* mask, size_t i) {
- do {
- dest[i - 1] |= mask[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] |= mask[i];
+ }
}
static void bit_copy(char* dest, const char* source, size_t i) {
- do {
- dest[i - 1] = source[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] = source[i];
+ }
}
static void bit_and_not(char* dest, const char* mask, size_t i) {
- do {
- dest[i - 1] &= ~mask[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] &= ~mask[i];
+ }
}
static void bit_and(char* dest, const char* mask, size_t i) {
- do {
- dest[i - 1] &= mask[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] &= mask[i];
+ };
}
int scxml_step(scxml_ctx* ctx) {
#ifdef SCXML_VERBOSE
printf("Config: ");
- printStateNames(ctx->config);
+ printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES);
#endif
-// MACRO_STEP:
-
if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL)
return SCXML_ERR_DONE;
- size_t i, j, k;
+ SCXML_NR_STATES_TYPE i, j, k;
+ SCXML_NR_STATES_TYPE nr_states_bytes = ((SCXML_NUMBER_STATES + 7) & ~7) >> 3;
+ SCXML_NR_TRANS_TYPE nr_trans_bytes = ((SCXML_NUMBER_TRANS + 7) & ~7) >> 3;
int err = SCXML_ERR_OK;
- char conflicts[1] = {0};
- char target_set[2] = {0, 0};
- char exit_set[2] = {0, 0};
- char trans_set[1] = {0};
- char entry_set[2] = {0, 0};
- char tmp_states[2] = {0, 0};
-
+ char conflicts [SCXML_MAX_NR_TRANS_BYTES];
+ char trans_set [SCXML_MAX_NR_TRANS_BYTES];
+ char target_set [SCXML_MAX_NR_STATES_BYTES];
+ char exit_set [SCXML_MAX_NR_STATES_BYTES];
+ char entry_set [SCXML_MAX_NR_STATES_BYTES];
+ char tmp_states [SCXML_MAX_NR_STATES_BYTES];
+
+ bit_clear_all(target_set, nr_states_bytes);
+ bit_clear_all(trans_set, nr_trans_bytes);
if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {
- global_script(ctx, &scxml_states[0], NULL);
- bit_or(target_set, scxml_states[0].completion, 2);
+ if (ctx->machine->script != NULL)
+ ctx->machine->script(ctx, &ctx->machine->states[0], NULL);
+ bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes);
ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;
goto ESTABLISH_ENTRY_SET;
}
@@ -538,40 +657,59 @@ int scxml_step(scxml_ctx* ctx) {
if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
+
+ // manage invocations
+ for (i = 0; i < SCXML_NUMBER_STATES; i++) {
+ // uninvoke
+ if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) {
+ if (ctx->machine->states[i].invoke != NULL)
+ ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 1);
+ BIT_CLEAR(i, ctx->invocations)
+ }
+ // invoke
+ if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) {
+ if (ctx->machine->states[i].invoke != NULL)
+ ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 0);
+ BIT_SET_AT(i, ctx->invocations)
+ }
+ }
+
if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
SELECT_TRANSITIONS:
- for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
+ bit_clear_all(conflicts, nr_trans_bytes);
+ bit_clear_all(exit_set, nr_states_bytes);
+ for (i = 0; i < SCXML_NUMBER_TRANS; i++) {
// never select history or initial transitions automatically
- if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))
+ if unlikely(ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))
continue;
// is the transition active?
- if (BIT_HAS(scxml_transitions[i].source, ctx->config)) {
+ if (BIT_HAS(ctx->machine->transitions[i].source, ctx->config)) {
// is it non-conflicting?
if (!BIT_HAS(i, conflicts)) {
// is it enabled?
- if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {
+ if (ctx->is_enabled(ctx, &ctx->machine->transitions[i], ctx->event) > 0) {
// remember that we found a transition
ctx->flags |= SCXML_CTX_TRANSITION_FOUND;
// transitions that are pre-empted
- bit_or(conflicts, scxml_transitions[i].conflicts, 1);
+ bit_or(conflicts, ctx->machine->transitions[i].conflicts, nr_trans_bytes);
// states that are directly targeted (resolve as entry-set later)
- bit_or(target_set, scxml_transitions[i].target, 2);
+ bit_or(target_set, ctx->machine->transitions[i].target, nr_states_bytes);
// states that will be left
- bit_or(exit_set, scxml_transitions[i].exit_set, 2);
+ bit_or(exit_set, ctx->machine->transitions[i].exit_set, nr_states_bytes);
BIT_SET_AT(i, trans_set);
}
}
}
}
- bit_and(exit_set, ctx->config, 2);
+ bit_and(exit_set, ctx->config, nr_states_bytes);
if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {
ctx->flags |= SCXML_CTX_SPONTANEOUS;
@@ -582,71 +720,71 @@ SELECT_TRANSITIONS:
#ifdef SCXML_VERBOSE
printf("Targets: ");
- printStateNames(target_set);
+ printStateNames(ctx, target_set, SCXML_NUMBER_STATES);
#endif
#ifdef SCXML_VERBOSE
printf("Exiting: ");
- printStateNames(exit_set);
+ printStateNames(ctx, exit_set, SCXML_NUMBER_STATES);
#endif
#ifdef SCXML_VERBOSE
printf("History: ");
- printStateNames(ctx->history);
+ printStateNames(ctx, ctx->history, SCXML_NUMBER_STATES);
#endif
// REMEMBER_HISTORY:
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
- if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
- SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP) {
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
+ SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP) {
// a history state whose parent is about to be exited
- if unlikely(BIT_HAS(scxml_states[i].parent, exit_set)) {
- bit_copy(tmp_states, scxml_states[i].completion, 2);
+ if unlikely(BIT_HAS(ctx->machine->states[i].parent, exit_set)) {
+ bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);
// set those states who were enabled
- bit_and(tmp_states, ctx->config, 2);
+ bit_and(tmp_states, ctx->config, nr_states_bytes);
// clear current history with completion mask
- bit_and_not(ctx->history, scxml_states[i].completion, 2);
+ bit_and_not(ctx->history, ctx->machine->states[i].completion, nr_states_bytes);
// set history
- bit_or(ctx->history, tmp_states, 2);
+ bit_or(ctx->history, tmp_states, nr_states_bytes);
}
}
}
ESTABLISH_ENTRY_SET:
// calculate new entry set
- bit_copy(entry_set, target_set, 2);
+ bit_copy(entry_set, target_set, nr_states_bytes);
// iterate for ancestors
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
if (BIT_HAS(i, entry_set)) {
- bit_or(entry_set, scxml_states[i].ancestors, 2);
+ bit_or(entry_set, ctx->machine->states[i].ancestors, nr_states_bytes);
}
}
// iterate for descendants
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
if (BIT_HAS(i, entry_set)) {
- switch (SCXML_STATE_MASK(scxml_states[i].type)) {
+ switch (SCXML_STATE_MASK(ctx->machine->states[i].type)) {
case SCXML_STATE_PARALLEL: {
- bit_or(entry_set, scxml_states[i].completion, 2);
+ bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);
break;
}
case SCXML_STATE_HISTORY_SHALLOW:
case SCXML_STATE_HISTORY_DEEP: {
- if (!bit_has_and(scxml_states[i].completion, ctx->history, 2) &&
- !BIT_HAS(scxml_states[i].parent, ctx->config)) {
+ if (!bit_has_and(ctx->machine->states[i].completion, ctx->history, nr_states_bytes) &&
+ !BIT_HAS(ctx->machine->states[i].parent, ctx->config)) {
// nothing set for history, look for a default transition
- for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
- if unlikely(scxml_transitions[j].source == i) {
- bit_or(entry_set, scxml_transitions[j].target, 2);
- if(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP &&
- !bit_has_and(scxml_transitions[j].target, scxml_states[i].children, 2)) {
+ for (j = 0; j < SCXML_NUMBER_TRANS; j++) {
+ if unlikely(ctx->machine->transitions[j].source == i) {
+ bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);
+ if(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP &&
+ !bit_has_and(ctx->machine->transitions[j].target, ctx->machine->states[i].children, nr_states_bytes)) {
for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {
- if (BIT_HAS(k, scxml_transitions[j].target)) {
- bit_or(entry_set, scxml_states[k].ancestors, 2);
+ if (BIT_HAS(k, ctx->machine->transitions[j].target)) {
+ bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);
break;
}
}
@@ -657,20 +795,20 @@ ESTABLISH_ENTRY_SET:
// Note: SCXML mandates every history to have a transition!
}
} else {
- bit_copy(tmp_states, scxml_states[i].completion, 2);
- bit_and(tmp_states, ctx->history, 2);
- bit_or(entry_set, tmp_states, 2);
- if (scxml_states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {
+ bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);
+ bit_and(tmp_states, ctx->history, nr_states_bytes);
+ bit_or(entry_set, tmp_states, nr_states_bytes);
+ if (ctx->machine->states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {
// a deep history state with nested histories -> more completion
for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {
- if (BIT_HAS(j, scxml_states[i].completion) &&
+ if (BIT_HAS(j, ctx->machine->states[i].completion) &&
BIT_HAS(j, entry_set) &&
- (scxml_states[j].type & SCXML_STATE_HAS_HISTORY)) {
+ (ctx->machine->states[j].type & SCXML_STATE_HAS_HISTORY)) {
for (k = j + 1; k < SCXML_NUMBER_STATES; k++) {
// add nested history to entry_set
- if ((SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_DEEP ||
- SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&
- BIT_HAS(k, scxml_states[j].children)) {
+ if ((SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_DEEP ||
+ SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&
+ BIT_HAS(k, ctx->machine->states[j].children)) {
// a nested history state
BIT_SET_AT(k, entry_set);
}
@@ -682,14 +820,14 @@ ESTABLISH_ENTRY_SET:
break;
}
case SCXML_STATE_INITIAL: {
- for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
- if (scxml_transitions[j].source == i) {
+ for (j = 0; j < SCXML_NUMBER_TRANS; j++) {
+ if (ctx->machine->transitions[j].source == i) {
BIT_SET_AT(j, trans_set);
BIT_CLEAR(i, entry_set);
- bit_or(entry_set, scxml_transitions[j].target, 2);
+ bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);
for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {
- if (BIT_HAS(k, scxml_transitions[j].target)) {
- bit_or(entry_set, scxml_states[k].ancestors, 2);
+ if (BIT_HAS(k, ctx->machine->transitions[j].target)) {
+ bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);
}
}
}
@@ -697,16 +835,16 @@ ESTABLISH_ENTRY_SET:
break;
}
case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set
- if (!bit_has_and(entry_set, scxml_states[i].children, 2) &&
- (!bit_has_and(ctx->config, scxml_states[i].children, 2) ||
- bit_has_and(exit_set, scxml_states[i].children, 2)))
+ if (!bit_has_and(entry_set, ctx->machine->states[i].children, nr_states_bytes) &&
+ (!bit_has_and(ctx->config, ctx->machine->states[i].children, nr_states_bytes) ||
+ bit_has_and(exit_set, ctx->machine->states[i].children, nr_states_bytes)))
{
- bit_or(entry_set, scxml_states[i].completion, 2);
- if (!bit_has_and(scxml_states[i].completion, scxml_states[i].children, 2)) {
+ bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);
+ if (!bit_has_and(ctx->machine->states[i].completion, ctx->machine->states[i].children, nr_states_bytes)) {
// deep completion
for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {
- if (BIT_HAS(j, scxml_states[i].completion)) {
- bit_or(entry_set, scxml_states[j].ancestors, 2);
+ if (BIT_HAS(j, ctx->machine->states[i].completion)) {
+ bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes);
break; // completion of compound is single state
}
}
@@ -720,7 +858,7 @@ ESTABLISH_ENTRY_SET:
#ifdef SCXML_VERBOSE
printf("Transitions: ");
- printBitsetIndices(trans_set, sizeof(char) * 8 * 1);
+ printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes);
#endif
// EXIT_STATES:
@@ -728,8 +866,8 @@ ESTABLISH_ENTRY_SET:
while(i-- > 0) {
if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) {
// call all on exit handlers
- if (scxml_states[i].on_exit != NULL) {
- if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->states[i].on_exit != NULL) {
+ if unlikely((err = ctx->machine->states[i].on_exit(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)
return err;
}
BIT_CLEAR(i, ctx->config);
@@ -737,13 +875,13 @@ ESTABLISH_ENTRY_SET:
}
// TAKE_TRANSITIONS:
- for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
- if (BIT_HAS(i, trans_set) && (scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {
+ for (i = 0; i < SCXML_NUMBER_TRANS; i++) {
+ if (BIT_HAS(i, trans_set) && (ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {
// call executable content in transition
- if (scxml_transitions[i].on_transition != NULL) {
- if unlikely((err = scxml_transitions[i].on_transition(ctx,
- &scxml_states[scxml_transitions[i].source],
- ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->transitions[i].on_transition != NULL) {
+ if unlikely((err = ctx->machine->transitions[i].on_transition(ctx,
+ &ctx->machine->states[ctx->machine->transitions[i].source],
+ ctx->event)) != SCXML_ERR_OK)
return err;
}
}
@@ -751,61 +889,61 @@ ESTABLISH_ENTRY_SET:
#ifdef SCXML_VERBOSE
printf("Entering: ");
- printStateNames(entry_set);
+ printStateNames(ctx, entry_set, SCXML_NUMBER_STATES);
#endif
// ENTER_STATES:
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) {
// these are no proper states
- if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP ||
- SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
- SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_INITIAL)
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP ||
+ SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
+ SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_INITIAL)
continue;
BIT_SET_AT(i, ctx->config);
// initialize data
if (!BIT_HAS(i, ctx->initialized_data)) {
- if unlikely(scxml_states[i].data != NULL && ctx->exec_content_init != NULL) {
- ctx->exec_content_init(ctx, scxml_states[i].data);
+ if unlikely(ctx->machine->states[i].data != NULL && ctx->exec_content_init != NULL) {
+ ctx->exec_content_init(ctx, ctx->machine->states[i].data);
}
BIT_SET_AT(i, ctx->initialized_data);
}
- if (scxml_states[i].on_entry != NULL) {
- if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->states[i].on_entry != NULL) {
+ if unlikely((err = ctx->machine->states[i].on_entry(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)
return err;
}
// take history and initial transitions
- for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
+ for (j = 0; j < SCXML_NUMBER_TRANS; j++) {
if unlikely(BIT_HAS(j, trans_set) &&
- (scxml_transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&
- scxml_states[scxml_transitions[j].source].parent == i) {
+ (ctx->machine->transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&
+ ctx->machine->states[ctx->machine->transitions[j].source].parent == i) {
// call executable content in transition
- if (scxml_transitions[j].on_transition != NULL) {
- if unlikely((err = scxml_transitions[j].on_transition(ctx,
- &scxml_states[i],
- ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->transitions[j].on_transition != NULL) {
+ if unlikely((err = ctx->machine->transitions[j].on_transition(ctx,
+ &ctx->machine->states[i],
+ ctx->event)) != SCXML_ERR_OK)
return err;
}
}
}
// handle final states
- if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_FINAL) {
- if unlikely(scxml_states[i].ancestors[0] == 0x01) {
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_FINAL) {
+ if unlikely(ctx->machine->states[i].ancestors[0] == 0x01) {
ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;
} else {
// raise done event
- const scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];
+ const scxml_elem_donedata* donedata = &ctx->machine->donedata[0];
while(ELEM_DONEDATA_IS_SET(donedata)) {
if unlikely(donedata->source == i)
break;
donedata++;
}
- ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
+ ctx->raise_done_event(ctx, &ctx->machine->states[ctx->machine->states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
}
/**
@@ -816,20 +954,20 @@ ESTABLISH_ENTRY_SET:
* 4. If a state remains, not all children of a parallel are final
*/
for (j = 0; j < SCXML_NUMBER_STATES; j++) {
- if unlikely(SCXML_STATE_MASK(scxml_states[j].type) == SCXML_STATE_PARALLEL &&
- BIT_HAS(j, scxml_states[i].ancestors)) {
- bit_and_not(tmp_states, tmp_states, 2);
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[j].type) == SCXML_STATE_PARALLEL &&
+ BIT_HAS(j, ctx->machine->states[i].ancestors)) {
+ bit_clear_all(tmp_states, nr_states_bytes);
for (k = 0; k < SCXML_NUMBER_STATES; k++) {
- if unlikely(BIT_HAS(j, scxml_states[k].ancestors) && BIT_HAS(k, ctx->config)) {
- if (SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_FINAL) {
- bit_and_not(tmp_states, scxml_states[k].ancestors, 2);
+ if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {
+ if (SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_FINAL) {
+ bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes);
} else {
BIT_SET_AT(k, tmp_states);
}
}
}
- if unlikely(!bit_has_any(tmp_states, 2)) {
- ctx->raise_done_event(ctx, &scxml_states[j], NULL);
+ if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) {
+ ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL);
}
}
}