From 0bf6dfca862e7057b96237213ee91a6fa3925c6c Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sat, 6 Feb 2016 14:59:11 +0100 Subject: Fixes bugs and memory leaks with generated C state-charts --- README.md | 4 +- src/uscxml/DOMUtils.h | 30 +-- src/uscxml/transform/ChartToC.cpp | 75 +++--- test/CMakeLists.txt | 6 +- test/ctest/CTestCustom.ctest.in | 77 ++---- test/src/test-c-machine.cpp | 432 +++++++++++++++++++-------------- test/src/test-c-machine.machine.c | 488 +++++++++++--------------------------- 7 files changed, 475 insertions(+), 637 deletions(-) diff --git a/README.md b/README.md index 53d9e68..1466009 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # uSCXML ReadMe -[![Build Status](https://travis-ci.org/sradomski/uscxml.png?branch=master)](https://travis-ci.org/sradomski/uscxml) +[![Build Status](https://travis-ci.org/tklab-tud/uscxml.png?branch=master)](https://travis-ci.org/sradomski/uscxml) #### Related Documents @@ -98,7 +98,7 @@ so maybe restrict yourself to some subset. | | XPath | 107/211 | $ ctest -L "^fsm/xpath/test" | | | PROMELA | 147/165 | $ ctest -L "^fsm/promela/test" | | | Lua | 165/201 | $ ctest -L "^fsm/lua/test" | -| Generated C | ECMAScript | 173/176 | $ ctest -L "^gen/c/ecma/test" | +| Generated C | ECMAScript | 180/180 | $ ctest -L "^gen/c/ecma/test" | | Verification | PROMELA | 130/181 | $ ctest -L "^spin/promela/test" | diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h index b3b87c8..ab99759 100644 --- a/src/uscxml/DOMUtils.h +++ b/src/uscxml/DOMUtils.h @@ -50,26 +50,26 @@ public: // deprecated, use stringIsTrue from Convenience.h instead DEPRECATED static bool attributeIsTrue(const::std::string& value); - static Arabica::XPath::NodeSet inPostFixOrder(const std::string& element, - const Arabica::DOM::Element& root, - const bool includeEmbeddedDoc = false) { - std::set elements; - elements.insert(element); - return inPostFixOrder(elements, root, includeEmbeddedDoc); - } + static Arabica::XPath::NodeSet inPostFixOrder(const std::string& element, + const Arabica::DOM::Element& root, + const bool includeEmbeddedDoc = false) { + std::set elements; + elements.insert(element); + return inPostFixOrder(elements, root, includeEmbeddedDoc); + } static Arabica::XPath::NodeSet inPostFixOrder(const std::set& elements, const Arabica::DOM::Element& root, const bool includeEmbeddedDoc = false); - static Arabica::XPath::NodeSet inDocumentOrder(const std::string& element, - const Arabica::DOM::Element& root, - const bool includeEmbeddedDoc = false) { - std::set elements; - elements.insert(element); - return inDocumentOrder(elements, root, includeEmbeddedDoc); - } - + static Arabica::XPath::NodeSet inDocumentOrder(const std::string& element, + const Arabica::DOM::Element& root, + const bool includeEmbeddedDoc = false) { + std::set elements; + elements.insert(element); + return inDocumentOrder(elements, root, includeEmbeddedDoc); + } + static Arabica::XPath::NodeSet inDocumentOrder(const std::set& elements, const Arabica::DOM::Element& root, const bool includeEmbeddedDoc = false); diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp index d9f1f0e..3c92e4a 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -405,6 +405,12 @@ void ChartToC::prepare() { void ChartToC::writeTo(std::ostream& stream) { + stream << "/**" << std::endl; + stream << " Generated from source:" << std::endl; + stream << " " << _sourceURL.asString() << std::endl; + stream << "*/" << std::endl; + stream << std::endl; + writeIncludes(stream); writeMacros(stream); writeTypes(stream); @@ -439,11 +445,11 @@ void ChartToC::findNestedMachines() { ChartToC* c2c = NULL; if (HAS_ATTR(invoke, "src")) { - URL srcURL(ATTR(invoke, "src")); - if (!srcURL.toAbsolute(getBaseURLForNode(invoke))) { - LOG(ERROR) << "invoke element has relative src URL with no baseURL set."; - return; - } + URL srcURL(ATTR(invoke, "src")); + if (!srcURL.toAbsolute(getBaseURLForNode(invoke))) { + LOG(ERROR) << "invoke element has relative src URL with no baseURL set."; + return; + } c2c = new ChartToC(Interpreter::fromURL(srcURL.asString())); } else { // is there a nested scxml machine inside? @@ -556,8 +562,8 @@ void ChartToC::writeMacros(std::ostream& stream) { stream << "#define SCXML_CTX_SPONTANEOUS 0x01" << std::endl; stream << "#define SCXML_CTX_INITIALIZED 0x02" << std::endl; stream << "#define SCXML_CTX_TOP_LEVEL_FINAL 0x04" << std::endl; - stream << "#define SCXML_CTX_TRANSITION_FOUND 0x08" << std::endl; - stream << "#define SCXML_CTX_FINISHED 0x10" << std::endl; + stream << "#define SCXML_CTX_TRANSITION_FOUND 0x08" << std::endl; + stream << "#define SCXML_CTX_FINISHED 0x10" << std::endl; stream << std::endl; @@ -692,8 +698,8 @@ void ChartToC::writeTypes(std::ostream& stream) { 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* sourcename;" << std::endl; + stream << " const char* idlocation;" << std::endl; + stream << " const char* sourcename;" << std::endl; stream << " const char* namelist;" << std::endl; stream << " const uint8_t autoforward;" << std::endl; stream << " const scxml_elem_param* params;" << std::endl; @@ -1146,8 +1152,8 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { 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* sourcename;" << std::endl; + stream << " const char* idlocation;" << std::endl; + stream << " const char* sourcename;" << std::endl; stream << " const char* namelist;" << std::endl; stream << " const uint8_t autoforward;" << std::endl; stream << " const scxml_elem_param* params;" << std::endl; @@ -1197,9 +1203,9 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { stream << (HAS_ATTR(invoke, "idlocation") ? "\"" + escape(ATTR(invoke, "idlocation")) + "\"" : "NULL"); stream << ", " << std::endl; - stream << " /* sourcename */ "; - stream << (HAS_ATTR_CAST(invoke.getParentNode(), "id") ? "\"" + escape(ATTR_CAST(invoke.getParentNode(), "id")) + "\"" : "NULL"); - stream << ", " << std::endl; + stream << " /* sourcename */ "; + stream << (HAS_ATTR_CAST(invoke.getParentNode(), "id") ? "\"" + escape(ATTR_CAST(invoke.getParentNode(), "id")) + "\"" : "NULL"); + stream << ", " << std::endl; stream << " /* namelist */ "; stream << (HAS_ATTR(invoke, "namelist") ? "\"" + escape(ATTR(invoke, "namelist")) + "\"" : "NULL"); @@ -1253,7 +1259,7 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { } void ChartToC::writeElementInfo(std::ostream& stream) { - NodeSet foreachs = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "foreach", _scxml); + NodeSet foreachs = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "foreach", _scxml); if (foreachs.size() > 0) { _hasElement.insert("foreach"); stream << "static const scxml_elem_foreach " << _prefix << "_elem_foreachs[" << foreachs.size() << "] = {" << std::endl; @@ -1315,7 +1321,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { if (dataTexts.size() > 0) { if (boost::trim_copy(dataTexts[0].getNodeValue()).length() > 0) { std::string escaped = escape(dataTexts[0].getNodeValue()); - stream << "\"" << escaped << "\"" << std::endl; + stream << "\"" << escaped << "\""; } } else { stream << "NULL"; @@ -1507,7 +1513,7 @@ void ChartToC::writeMachineInfo(std::ostream& stream) { stream << " }," << std::endl; } - stream << " {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }" << std::endl; + stream << " {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }" << std::endl; stream << "};" << std::endl; stream << std::endl; } @@ -1759,18 +1765,18 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "int scxml_step(scxml_ctx* ctx) {" << std::endl; stream << 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 << " " << (_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 << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Config: \");" << std::endl; @@ -1778,9 +1784,9 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "#endif" << std::endl; stream << std::endl; - stream << " if (ctx->flags & SCXML_CTX_FINISHED)" << std::endl; - stream << " return SCXML_ERR_DONE;" << std::endl; - stream << std::endl; + stream << " if (ctx->flags & SCXML_CTX_FINISHED)" << std::endl; + stream << " return SCXML_ERR_DONE;" << std::endl; + stream << std::endl; stream << " if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) {" << std::endl; stream << " // exit all remaining states" << std::endl; @@ -1794,6 +1800,11 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " }" << std::endl; // stream << " BIT_CLEAR(i, ctx->config);" << std::endl; stream << " }" << std::endl; + stream << " if (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 << " }" << std::endl; stream << " ctx->flags |= SCXML_CTX_FINISHED;" << std::endl; stream << " return SCXML_ERR_DONE;" << std::endl; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 42e518b..c4486eb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -133,7 +133,11 @@ if (NOT BUILD_MINIMAL) # prepare directories for test classes and copy resources over foreach(W3C_RESOURCE ${W3C_RESOURCES} ) - get_filename_component(TEST_DATAMODEL ${W3C_RESOURCE} NAME) + get_filename_component(TEST_DATAMODEL ${W3C_RESOURCE} PATH) + get_filename_component(TEST_DATAMODEL ${TEST_DATAMODEL} NAME) + + # message(STATUS "W3C_RESOURCE: ${W3C_RESOURCE}") + # message(STATUS "TEST_DATAMODEL: ${TEST_DATAMODEL}") foreach(TEST_CLASS ${TEST_CLASSES}) # datamodel has to be the suffix of the test class diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in index a140476..a9a96ad 100644 --- a/test/ctest/CTestCustom.ctest.in +++ b/test/ctest/CTestCustom.ctest.in @@ -197,63 +197,24 @@ 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" // invoke srcexpr - # "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" - "gen/c/ecma/test496.scxml" - "gen/c/ecma/test500.scxml" - "gen/c/ecma/test501.scxml" - "gen/c/ecma/test509.scxml" - "gen/c/ecma/test510.scxml" - "gen/c/ecma/test518.scxml" - "gen/c/ecma/test519.scxml" - "gen/c/ecma/test520.scxml" - "gen/c/ecma/test521.scxml" - "gen/c/ecma/test522.scxml" - "gen/c/ecma/test531.scxml" - "gen/c/ecma/test532.scxml" - "gen/c/ecma/test534.scxml" - "gen/c/ecma/test567.scxml" - "gen/c/ecma/test569.scxml" - "gen/c/ecma/test577.scxml" + "gen/c/ecma/test201.scxml" # basichttp + "gen/c/ecma/test500.scxml" # _ioprocessors + "gen/c/ecma/test501.scxml" # _ioprocessors + "gen/c/ecma/test509.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test510.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test518.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test519.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test520.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test522.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test531.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test532.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test534.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test567.scxml" # _ioprocessors / basichttp + "gen/c/ecma/test569.scxml" # _ioprocessors + "gen/c/ecma/test577.scxml" # basichttp # failing is succeeding "gen/c/ecma/test301.scxml" @@ -261,13 +222,9 @@ set(CTEST_CUSTOM_TESTS_IGNORE # manual test "gen/c/ecma/test307.scxml" - # data from file - "gen/c/ecma/test446.scxml" - "gen/c/ecma/test552.scxml" - "gen/c/ecma/test557.scxml" - "gen/c/ecma/test558.scxml" - # XML DOM in data + "gen/c/ecma/test530.scxml" + "gen/c/ecma/test557.scxml" "gen/c/ecma/test561.scxml" diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp index b80ef72..85571e4 100644 --- a/test/src/test-c-machine.cpp +++ b/test/src/test-c-machine.cpp @@ -21,6 +21,7 @@ #endif #include "uscxml/Convenience.h" +#include "uscxml/URL.h" #include "uscxml/concurrency/Timer.h" //#include "uscxml/DOMUtils.h" #include "uscxml/Factory.h" @@ -40,23 +41,24 @@ using namespace uscxml; class StateMachine : public InterpreterInfo { public: - StateMachine(const scxml_machine* machine) : parentMachine(NULL), topMostMachine(NULL), invocation(NULL) { - init(machine); + StateMachine(const scxml_machine* machine) : machine(machine), parentMachine(NULL), topMostMachine(NULL), invocation(NULL) { allMachines[sessionId] = this; topMostMachine = this; currentMachine = allMachines.begin(); + init(); } - StateMachine(StateMachine* parent, const scxml_machine* machine, const scxml_elem_invoke* invoke) : invocation(invoke) { + StateMachine(StateMachine* parent, const scxml_machine* machine, const scxml_elem_invoke* invoke) : machine(machine), invocation(invoke) { parentMachine = parent; topMostMachine = parent->topMostMachine; - init(machine); + init(); } - void init(const scxml_machine* machine) { + void init() { sessionId = UUID::getUUID(); - isFinalized = false; - + isFinalized = false; + currEvent = NULL; + // clear and initialize machine context memset(&ctx, 0, sizeof(scxml_ctx)); ctx.machine = machine; @@ -84,58 +86,62 @@ public: delayQueue.start(); dataModel = Factory::getInstance()->createDataModel(machine->datamodel, this); - - if (invocation != NULL) { - /// test 226/240 - initialize from invoke request - - // TODO: Only set if there is a corresponding data element: test245 - if (invocation->params != NULL) { - const scxml_elem_param* param = invocation->params; - while(ELEM_PARAM_IS_SET(param)) { - try { - std::string identifier; - if (param->name != NULL) { - identifier = param->name; - } else if (param->location != NULL) { - identifier = param->location; - } - dataModel.init(identifier, parentMachine->dataModel.getStringAsData(param->expr)); - invokeIdentifiers.insert(identifier); - - } catch (Event e) { - execContentRaise(&ctx, e.name.c_str()); - } - param++; - } - } - - if (invocation->namelist != NULL) { - const char* cPtr = invocation->namelist; - const char* aPtr = invocation->namelist; - while(cPtr) { - while (isspace(*cPtr)) - cPtr++; - aPtr = cPtr; - while(*cPtr && !isspace(*cPtr)) - cPtr++; - - if (aPtr == cPtr) - break; - - std::string identifier = std::string(aPtr, cPtr - aPtr); - try { - dataModel.init(identifier, parentMachine->dataModel.getStringAsData(identifier)); - invokeIdentifiers.insert(identifier); - } catch (Event e) { - execContentRaise(&ctx, e.name.c_str()); - } - } - } - } + + if (invocation != NULL) { + /// test 226/240 - initialize from invoke request + if (invocation->params != NULL) { + const scxml_elem_param* param = invocation->params; + while(ELEM_PARAM_IS_SET(param)) { + std::string identifier; + if (param->name != NULL) { + identifier = param->name; + } else if (param->location != NULL) { + identifier = param->location; + } + invokeData[identifier] = parentMachine->dataModel.getStringAsData(param->expr); + param++; + } + } + + if (invocation->namelist != NULL) { + const char* cPtr = invocation->namelist; + const char* aPtr = invocation->namelist; + while(cPtr) { + while (isspace(*cPtr)) + cPtr++; + aPtr = cPtr; + while(*cPtr && !isspace(*cPtr)) + cPtr++; + + if (aPtr == cPtr) + break; + + std::string identifier = std::string(aPtr, cPtr - aPtr); + invokeData[identifier] = parentMachine->dataModel.getStringAsData(identifier); + } + } + } } virtual ~StateMachine() { + if (parentMachine != NULL) { + topMostMachine->allMachines.erase(topMostMachine->invocationIds[invocation]); + } +// finalize(); + delayQueue.stop(); + delayQueue.cancelAllEvents(); + + while(eq.size() > 0) { + delete eq.front(); + eq.pop_front(); + } + eq.clear(); + while(iq.size() > 0) { + delete iq.front(); + iq.pop_front(); + } + iq.clear(); } bool hasPendingWork() { @@ -150,27 +156,41 @@ public: return ctx.flags & SCXML_CTX_FINISHED; } - void finalize() { - if (isFinalized) - return; - - delayQueue.stop(); - if (parentMachine != NULL) { - Event* done = new Event(); - done->invokeid = invokeId; - done->name = "done.invoke." + invokeId; - parentMachine->eq.push_back(done); - } - isFinalized = true; - } + void finalize() { + if (isFinalized) + return; + + delayQueue.stop(); + delayQueue.cancelAllEvents(); + + if (parentMachine != NULL) { + tthread::lock_guard lock(mutex); + + Event* done = new Event(); + done->invokeid = invokeId; + done->name = "done.invoke." + invokeId; + parentMachine->eq.push_back(done); + } + isFinalized = true; + } void reset() { - sessionId = UUID::getUUID(); + delayQueue.stop(); + delayQueue.cancelAllEvents(); + + while(eq.size() > 0) { + delete eq.front(); + eq.pop_front(); + } + while(iq.size() > 0) { + delete iq.front(); + iq.pop_front(); + } + iq.clear(); eq.clear(); - delayQueue.cancelAllEvents(); - dataModel = Factory::getInstance()->createDataModel(ctx.machine->datamodel, this); + init(); } @@ -185,13 +205,19 @@ public: return SCXML_ERR_IDLE; } - // test 187 - if (toRun->isDone()) { - toRun->finalize(); - return SCXML_ERR_IDLE; - } - - return scxml_step(&toRun->ctx); + // test 187 + if (toRun->isDone()) { + toRun->finalize(); + return SCXML_ERR_IDLE; + } + + state = scxml_step(&toRun->ctx); + if (toRun->currEvent != NULL) { + delete toRun->currEvent; + toRun->currEvent = NULL; + } + + return state; } // InterpreterInfo @@ -238,10 +264,10 @@ public: } } - // real event but spontaneous transition - if (t->event == NULL) - return false; - + // real event but spontaneous transition + if (t->event == NULL) + return false; + // real transition, real event if (nameMatch(t->event, event->name.c_str())) { if (t->condition != NULL) @@ -261,44 +287,49 @@ public: } static int invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) { - std::map &allMachines = USER_DATA(ctx)->topMostMachine->allMachines; - StateMachine* topMachine = USER_DATA(ctx)->topMostMachine; - - if (uninvoke) { - if (invocation->machine != NULL) { - if (topMachine->invocationIds.find(invocation) != topMachine->invocationIds.end() && - allMachines.find(topMachine->invocationIds[invocation]) != allMachines.end()) { - - delete allMachines[topMachine->invocationIds[invocation]]; - topMachine->allMachines.erase(topMachine->invocationIds[invocation]); - topMachine->invocationIds.erase(invocation); - } - } else { - return SCXML_ERR_UNSUPPORTED; - } - } else { - // invocations - if (invocation->machine != NULL) { - // invoke a nested SCXML machine - StateMachine* invokedMachine = new StateMachine(USER_DATA(ctx), invocation->machine, invocation); - - if (invocation->id != NULL) { - invokedMachine->invokeId = invocation->id; - } else if (invocation->idlocation != NULL) { - // test224 - invokedMachine->invokeId = (invocation->sourcename != NULL ? std::string(invocation->sourcename) + "." : "") + UUID::getUUID(); - ctx->exec_content_assign(ctx, invocation->idlocation, std::string("\"" + invokedMachine->invokeId + "\"").c_str()); - } else { - delete invokedMachine; - return SCXML_ERR_UNSUPPORTED; - } - allMachines[invokedMachine->invokeId] = invokedMachine; - topMachine->invocationIds[invocation] = invokedMachine->invokeId; - } else { - return SCXML_ERR_UNSUPPORTED; - } - } - return SCXML_ERR_OK; + std::map &allMachines = USER_DATA(ctx)->topMostMachine->allMachines; + StateMachine* topMachine = USER_DATA(ctx)->topMostMachine; + + if (uninvoke) { + if (invocation->machine != NULL) { + if (topMachine->invocationIds.find(invocation) != topMachine->invocationIds.end() && + allMachines.find(topMachine->invocationIds[invocation]) != allMachines.end()) { + + delete allMachines[topMachine->invocationIds[invocation]]; + topMachine->allMachines.erase(topMachine->invocationIds[invocation]); + topMachine->invocationIds.erase(invocation); + } + } else { + return SCXML_ERR_UNSUPPORTED; + } + } else { + // invocations + if (invocation->machine != NULL) { + // invoke a nested SCXML machine + StateMachine* invokedMachine = NULL; + try { + invokedMachine = new StateMachine(USER_DATA(ctx), invocation->machine, invocation); + } catch (Event e) { + delete invokedMachine; + return SCXML_ERR_EXEC_CONTENT; + } + if (invocation->id != NULL) { + invokedMachine->invokeId = invocation->id; + } else if (invocation->idlocation != NULL) { + // test224 + invokedMachine->invokeId = (invocation->sourcename != NULL ? std::string(invocation->sourcename) + "." : "") + UUID::getUUID(); + ctx->exec_content_assign(ctx, invocation->idlocation, std::string("\"" + invokedMachine->invokeId + "\"").c_str()); + } else { + delete invokedMachine; + return SCXML_ERR_UNSUPPORTED; + } + allMachines[invokedMachine->invokeId] = invokedMachine; + topMachine->invocationIds[invocation] = invokedMachine->invokeId; + } else { + return SCXML_ERR_UNSUPPORTED; + } + } + return SCXML_ERR_OK; } static int raiseDoneEvent(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) { @@ -383,8 +414,8 @@ public: } e->origintype = e->type; - e->invokeid = USER_DATA(ctx)->invokeId; - + e->invokeid = USER_DATA(ctx)->invokeId; + if (send->eventexpr != NULL) { e->name = USER_DATA(ctx)->dataModel.evalAsString(send->eventexpr); } else { @@ -595,22 +626,51 @@ public: static int execContentInit(const scxml_ctx* ctx, const scxml_elem_data* data) { while(ELEM_DATA_IS_SET(data)) { - // only initialize data that was not already passed per invocation - if (USER_DATA(ctx)->invokeIdentifiers.find(data->id) == USER_DATA(ctx)->invokeIdentifiers.end()) { - 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()); - } - } + if (USER_DATA(ctx)->invokeData.find(data->id) != USER_DATA(ctx)->invokeData.end()) { + // passed via param or namelist: test245 + try { + USER_DATA(ctx)->dataModel.init(data->id, USER_DATA(ctx)->invokeData[data->id]); + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + } + } else { + Data d; + std::stringstream content; + + if (data->expr != NULL) { + d = Data(data->expr, Data::INTERPRETED); + } else if (data->content != NULL) { + content << data->content; + d = Data(content.str(), Data::INTERPRETED); + } else if (data->src != NULL) { + URL sourceURL(data->src); + if (USER_DATA(ctx)->baseURL.size() > 0) { + sourceURL.toAbsolute(USER_DATA(ctx)->baseURL); + } else { + sourceURL.toAbsoluteCwd(); + } + content << sourceURL; + d = Data(content.str(), Data::INTERPRETED); + + } else { + d = Data("undefined", Data::INTERPRETED); + } + try { + // this might fail with an unquoted string literal in content + USER_DATA(ctx)->dataModel.init(data->id, d); + } catch (Event e) { + if (content.str().size() > 0) { + try { + d = Data(escape(spaceNormalize(content.str())), Data::VERBATIM); + USER_DATA(ctx)->dataModel.init(data->id, d); + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + } + } else { + execContentRaise(ctx, e.name.c_str()); + } + } + } data++; } return SCXML_ERR_OK; @@ -632,9 +692,10 @@ public: Event* e = USER_DATA(ctx)->eq.front(); USER_DATA(ctx)->eq.pop_front(); + USER_DATA(ctx)->currEvent = e; USER_DATA(ctx)->dataModel.setEvent(*e); - std::map& allMachines = USER_DATA(ctx)->topMostMachine->allMachines; + std::map& allMachines = USER_DATA(ctx)->topMostMachine->allMachines; if (e->invokeid.size() > 0 && allMachines.find(e->invokeid) != allMachines.end()) { // we need to check for finalize content StateMachine* invokedMachine = allMachines[e->invokeid]; @@ -643,16 +704,19 @@ public: invokedMachine->invocation, e); } - - // auto forward event - for (std::map::iterator machIter = allMachines.begin(); machIter != allMachines.end(); machIter++) { - if (machIter->second->parentMachine != NULL && - machIter->second->parentMachine == USER_DATA(ctx) && - machIter->second->invocation->autoforward) { - machIter->second->eq.push_back(e); - } - } - + + // auto forward event + for (std::map::iterator machIter = allMachines.begin(); machIter != allMachines.end(); machIter++) { + if (machIter->second->parentMachine != NULL && + machIter->second->parentMachine == USER_DATA(ctx) && + machIter->second->invocation->autoforward) { + tthread::lock_guard lock(machIter->second->mutex); + + Event* ne = new Event(*e); + machIter->second->eq.push_back(ne); + } + } + #ifdef SCXML_VERBOSE printf("Popping External Event: %s\n", e->name.c_str()); #endif @@ -664,6 +728,7 @@ public: return NULL; Event* e = USER_DATA(ctx)->iq.front(); USER_DATA(ctx)->iq.pop_front(); + USER_DATA(ctx)->currEvent = e; USER_DATA(ctx)->dataModel.setEvent(*e); #ifdef SCXML_VERBOSE printf("Popping Internal Event: %s\n", e->name.c_str()); @@ -683,36 +748,44 @@ public: printf("Pushing Internal Event: %s\n", e->name.c_str()); #endif USER_DATA(ctx)->iq.push_back(e); - } else if (sr->target == "#_external") { - e->eventType = Event::EXTERNAL; + } else if (sr->target == "#_external") { + e->eventType = Event::EXTERNAL; #ifdef SCXML_VERBOSE - printf("Pushing External Event: %s\n", e->name.c_str()); + printf("Pushing External Event: %s\n", e->name.c_str()); #endif - USER_DATA(ctx)->eq.push_back(e); - } else if (sr->target == "#_parent") { + USER_DATA(ctx)->eq.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 if (sr->target.substr(0,8) == "#_scxml_") { - std::string sessionId = sr->target.substr(8); - for (std::map::iterator machIter = USER_DATA(ctx)->topMostMachine->allMachines.begin(); - machIter != USER_DATA(ctx)->topMostMachine->allMachines.end(); machIter++) { - if (machIter->second->sessionId == sessionId) { - e->eventType = Event::EXTERNAL; - machIter->second->eq.push_back(e); - break; - } - } - } else if (sr->target.substr(0,2) == "#_") { - e->eventType = Event::EXTERNAL; - std::string targetId = sr->target.substr(2); - if (USER_DATA(ctx)->topMostMachine->allMachines.find(targetId) != USER_DATA(ctx)->topMostMachine->allMachines.end()) { - USER_DATA(ctx)->topMostMachine->allMachines[targetId]->eq.push_back(e); - } + } else if (sr->target.substr(0,8) == "#_scxml_") { + std::string sessionId = sr->target.substr(8); + bool sessionFound = false; + for (std::map::iterator machIter = USER_DATA(ctx)->topMostMachine->allMachines.begin(); + machIter != USER_DATA(ctx)->topMostMachine->allMachines.end(); machIter++) { + if (machIter->second->sessionId == sessionId) { + e->eventType = Event::EXTERNAL; + machIter->second->eq.push_back(e); + sessionFound = true; + break; + } + } + if (!sessionFound) { + // test496 + execContentRaise((scxml_ctx*)ctx, "error.communication"); + } + } else if (sr->target.substr(0,2) == "#_") { + e->eventType = Event::EXTERNAL; + std::string targetId = sr->target.substr(2); + if (USER_DATA(ctx)->topMostMachine->allMachines.find(targetId) != USER_DATA(ctx)->topMostMachine->allMachines.end()) { + USER_DATA(ctx)->topMostMachine->allMachines[targetId]->eq.push_back(e); + } else { + execContentRaise((scxml_ctx*)ctx, "error.communication"); + } } else { - assert(false); + assert(false); } USER_DATA(ctx)->monitor.notify_all(); delete sr; @@ -790,24 +863,28 @@ NEXT_DESC: return false; } - std::map invocationIds; + Event* currEvent; + + std::map invocationIds; std::map allMachines; + bool isFinalized; + int state; + scxml_ctx ctx; + const scxml_machine* machine; + StateMachine* parentMachine; StateMachine* topMostMachine; std::map::iterator currentMachine; // next machine to advance - bool isFinalized; - int state; - scxml_ctx ctx; - + std::string baseURL; std::string sessionId; std::string name; // in case we were invoked std::string invokeId; const scxml_elem_invoke* invocation; - std::set invokeIdentifiers; + std::map invokeData; std::deque iq; std::deque eq; @@ -893,6 +970,7 @@ int main(int argc, char** argv) { std::cerr << "Interpreter did not end in pass" << std::endl; exit(EXIT_FAILURE); } + rootMachine.reset(); } tTotal.stop(); std::cout << benchmarkRuns << " iterations" << std::endl; diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c index f3ec413..cb9fcae 100644 --- a/test/src/test-c-machine.machine.c +++ b/test/src/test-c-machine.machine.c @@ -1,3 +1,8 @@ +/** + Generated from source: + file:///Users/sradomski/Documents/TK/Code/uscxml/test/w3c/ecma/test237.scxml +*/ + #include // explicit types #include // NULL @@ -119,7 +124,7 @@ struct scxml_machine { }; // forward declare machines to allow references -extern const scxml_machine scxml_machines[4]; +extern const scxml_machine scxml_machines[3]; struct scxml_elem_data { const char* id; @@ -236,21 +241,9 @@ struct scxml_ctx { invoke_t invoke; }; -static const scxml_elem_data _scxml_22A28DED_elem_datas[2] = { - /* id, src, expr, content */ - { "Var1", NULL, "1", NULL }, - { NULL, NULL, NULL, NULL } -}; - -static const scxml_elem_param _scxml_22A28DED_elem_params[2] = { - /* name, expr, location */ - { "Var1", "1", NULL }, - { NULL, NULL, NULL } -}; - -static const scxml_elem_send _scxml_22A28DED_elem_sends[1] = { +static const scxml_elem_send _scxml_290B2E91_elem_sends[2] = { { - /* event */ "timeout", + /* event */ "timeout1", /* eventexpr */ NULL, /* target */ NULL, /* targetexpr */ NULL, @@ -258,8 +251,24 @@ static const scxml_elem_send _scxml_22A28DED_elem_sends[1] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ "2s", - /* delayexpr */ NULL, + /* delay */ NULL, + /* delayexpr */ "'1s'", + /* namelist */ NULL, + /* content */ NULL, + /* contentexpr */ NULL, + /* params */ NULL + }, + { + /* event */ "timeout2", + /* eventexpr */ NULL, + /* target */ NULL, + /* targetexpr */ NULL, + /* type */ NULL, + /* typeexpr */ NULL, + /* id */ NULL, + /* idlocation */ NULL, + /* delay */ NULL, + /* delayexpr */ "'1.5s'", /* namelist */ NULL, /* content */ NULL, /* contentexpr */ NULL, @@ -267,72 +276,66 @@ static const scxml_elem_send _scxml_22A28DED_elem_sends[1] = { } }; -static const scxml_elem_donedata _scxml_22A28DED_elem_donedatas[1] = { +static const scxml_elem_donedata _scxml_290B2E91_elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; -static const scxml_elem_invoke _scxml_22A28DED_elem_invokes[2] = { +static const scxml_elem_invoke _scxml_290B2E91_elem_invokes[1] = { { /* machine */ &scxml_machines[1], /* type */ "http://www.w3.org/TR/scxml/", /* typeexpr */ NULL, /* src */ NULL, /* srcexpr */ NULL, - /* id */ "43b1f997-4793-4391-8786-d387b411529d", - /* idlocation */ NULL, - /* sourcename */ "s01", - /* namelist */ "Var1", - /* autoforward */ 0, - /* params */ NULL, - /* finalize */ NULL, - /* content */ NULL, - /* contentexpr */ NULL, - }, - { - /* machine */ &scxml_machines[2], - /* type */ "http://www.w3.org/TR/scxml/", - /* typeexpr */ NULL, - /* src */ NULL, - /* srcexpr */ NULL, - /* id */ "8283f07f-2eac-469d-9e43-49c655c7590f", + /* id */ "6be2e509-b4f4-4179-8cba-1e8701b5d7a8", /* idlocation */ NULL, - /* sourcename */ "s02", + /* sourcename */ "s0", /* namelist */ NULL, /* autoforward */ 0, - /* params */ &_scxml_22A28DED_elem_params[0], + /* params */ NULL, /* finalize */ NULL, /* content */ NULL, /* contentexpr */ NULL, } }; -static int _scxml_22A28DED_s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_290B2E91_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_22A28DED_elem_sends[0])) != SCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_scxml_290B2E91_elem_sends[0])) != SCXML_ERR_OK) return err; } else { return SCXML_ERR_MISSING_CALLBACK; } return SCXML_ERR_OK; } -static int _scxml_22A28DED_s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { - _scxml_22A28DED_s0_on_entry_0(ctx, state, event); +static int _scxml_290B2E91_s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_290B2E91_s0_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static int _scxml_22A28DED_s01_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) { - ctx->invoke(ctx, s, &_scxml_22A28DED_elem_invokes[0], uninvoke); +static int _scxml_290B2E91_s0_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) { + ctx->invoke(ctx, s, &_scxml_290B2E91_elem_invokes[0], uninvoke); return SCXML_ERR_OK; } -static int _scxml_22A28DED_s02_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) { - ctx->invoke(ctx, s, &_scxml_22A28DED_elem_invokes[1], uninvoke); +static int _scxml_290B2E91_s1_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_290B2E91_elem_sends[1])) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} +static int _scxml_290B2E91_s1_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_290B2E91_s1_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static int _scxml_22A28DED_pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + +static int _scxml_290B2E91_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; @@ -342,12 +345,12 @@ static int _scxml_22A28DED_pass_on_entry_0(const scxml_ctx* ctx, const scxml_sta return SCXML_ERR_OK; } -static int _scxml_22A28DED_pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { - _scxml_22A28DED_pass_on_entry_0(ctx, state, event); +static int _scxml_290B2E91_pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_290B2E91_pass_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static int _scxml_22A28DED_fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_290B2E91_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; @@ -357,183 +360,125 @@ static int _scxml_22A28DED_fail_on_entry_0(const scxml_ctx* ctx, const scxml_sta return SCXML_ERR_OK; } -static int _scxml_22A28DED_fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { - _scxml_22A28DED_fail_on_entry_0(ctx, state, event); +static int _scxml_290B2E91_fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_290B2E91_fail_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static const scxml_state _scxml_22A28DED_states[6] = { +static const scxml_state _scxml_290B2E91_states[5] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, /* onentry */ NULL, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x32 /* 010011 */ }, - /* completion */ { 0x02 /* 010000 */ }, - /* ancestors */ { 0x00 /* 000000 */ }, - /* data */ &_scxml_22A28DED_elem_datas[0], + /* children */ { 0x1e /* 01111 */ }, + /* completion */ { 0x02 /* 01000 */ }, + /* ancestors */ { 0x00 /* 00000 */ }, + /* data */ NULL, /* type */ SCXML_STATE_COMPOUND, }, { /* state number 1 */ /* name */ "s0", /* parent */ 0, - /* onentry */ _scxml_22A28DED_s0_on_entry, + /* onentry */ _scxml_290B2E91_s0_on_entry, /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x0c /* 001100 */ }, - /* completion */ { 0x04 /* 001000 */ }, - /* ancestors */ { 0x01 /* 100000 */ }, + /* invoke */ _scxml_290B2E91_s0_invoke, + /* children */ { 0x00 /* 00000 */ }, + /* completion */ { 0x00 /* 00000 */ }, + /* ancestors */ { 0x01 /* 10000 */ }, /* data */ NULL, - /* type */ SCXML_STATE_COMPOUND, + /* type */ SCXML_STATE_ATOMIC, }, { /* state number 2 */ - /* name */ "s01", - /* parent */ 1, - /* onentry */ NULL, + /* name */ "s1", + /* parent */ 0, + /* onentry */ _scxml_290B2E91_s1_on_entry, /* onexit */ NULL, - /* invoke */ _scxml_22A28DED_s01_invoke, - /* children */ { 0x00 /* 000000 */ }, - /* completion */ { 0x00 /* 000000 */ }, - /* ancestors */ { 0x03 /* 110000 */ }, + /* invoke */ NULL, + /* children */ { 0x00 /* 00000 */ }, + /* completion */ { 0x00 /* 00000 */ }, + /* ancestors */ { 0x01 /* 10000 */ }, /* data */ NULL, /* type */ SCXML_STATE_ATOMIC, }, { /* state number 3 */ - /* name */ "s02", - /* parent */ 1, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ _scxml_22A28DED_s02_invoke, - /* children */ { 0x00 /* 000000 */ }, - /* completion */ { 0x00 /* 000000 */ }, - /* ancestors */ { 0x03 /* 110000 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_ATOMIC, - }, - { /* state number 4 */ /* name */ "pass", /* parent */ 0, - /* onentry */ _scxml_22A28DED_pass_on_entry, + /* onentry */ _scxml_290B2E91_pass_on_entry, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00 /* 000000 */ }, - /* completion */ { 0x00 /* 000000 */ }, - /* ancestors */ { 0x01 /* 100000 */ }, + /* children */ { 0x00 /* 00000 */ }, + /* completion */ { 0x00 /* 00000 */ }, + /* ancestors */ { 0x01 /* 10000 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, }, - { /* state number 5 */ + { /* state number 4 */ /* name */ "fail", /* parent */ 0, - /* onentry */ _scxml_22A28DED_fail_on_entry, + /* onentry */ _scxml_290B2E91_fail_on_entry, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00 /* 000000 */ }, - /* completion */ { 0x00 /* 000000 */ }, - /* ancestors */ { 0x01 /* 100000 */ }, + /* children */ { 0x00 /* 00000 */ }, + /* completion */ { 0x00 /* 00000 */ }, + /* ancestors */ { 0x01 /* 10000 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, } }; -static const scxml_transition _scxml_22A28DED_transitions[5] = { - { /* transition number 1 with priority 0 - target: s02 +static const scxml_transition _scxml_290B2E91_transitions[3] = { + { /* transition number 0 with priority 0 + target: s1 */ - /* source */ 2, - /* target */ { 0x08 /* 000100 */ }, - /* event */ "success", + /* source */ 1, + /* target */ { 0x04 /* 00100 */ }, + /* event */ "timeout1", /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x1f /* 11111 */ }, - /* exit set */ { 0x0c /* 001100 */ } + /* conflicts */ { 0x07 /* 111 */ }, + /* exit set */ { 0x1e /* 01111 */ } }, - { /* transition number 2 with priority 1 + { /* transition number 1 with priority 1 target: fail */ /* source */ 2, - /* target */ { 0x20 /* 000001 */ }, - /* event */ "failure", + /* target */ { 0x10 /* 00001 */ }, + /* event */ "done.invoke", /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x1f /* 11111 */ }, - /* exit set */ { 0x3e /* 011111 */ } + /* conflicts */ { 0x07 /* 111 */ }, + /* exit set */ { 0x1e /* 01111 */ } }, - { /* transition number 3 with priority 2 + { /* transition number 2 with priority 2 target: pass */ - /* source */ 3, - /* target */ { 0x10 /* 000010 */ }, - /* event */ "success", - /* condition */ NULL, - /* ontrans */ NULL, - /* type */ 0, - /* conflicts */ { 0x1f /* 11111 */ }, - /* exit set */ { 0x3e /* 011111 */ } - }, - { /* transition number 4 with priority 3 - target: fail - */ - /* source */ 3, - /* target */ { 0x20 /* 000001 */ }, - /* event */ "failure", - /* condition */ NULL, - /* ontrans */ NULL, - /* type */ 0, - /* conflicts */ { 0x1f /* 11111 */ }, - /* exit set */ { 0x3e /* 011111 */ } - }, - { /* transition number 0 with priority 4 - target: fail - */ - /* source */ 1, - /* target */ { 0x20 /* 000001 */ }, - /* event */ "timeout", + /* source */ 2, + /* target */ { 0x08 /* 00010 */ }, + /* event */ "*", /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x1f /* 11111 */ }, - /* exit set */ { 0x3e /* 011111 */ } + /* conflicts */ { 0x07 /* 111 */ }, + /* exit set */ { 0x1e /* 01111 */ } } }; -static const scxml_elem_data _scxml_FD9C4306_elem_datas[2] = { - /* id, src, expr, content */ - { "Var1", NULL, "0", NULL }, - { NULL, NULL, NULL, NULL } -}; - -static const scxml_elem_send _scxml_FD9C4306_elem_sends[2] = { - { - /* event */ "success", - /* 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 */ NULL - }, +static const scxml_elem_send _scxml_740A1EEF_elem_sends[1] = { { - /* event */ "failure", + /* event */ "timeout", /* eventexpr */ NULL, - /* target */ "#_parent", + /* target */ NULL, /* targetexpr */ NULL, /* type */ NULL, /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, /* delay */ NULL, - /* delayexpr */ NULL, + /* delayexpr */ "'2s'", /* namelist */ NULL, /* content */ NULL, /* contentexpr */ NULL, @@ -541,32 +486,27 @@ static const scxml_elem_send _scxml_FD9C4306_elem_sends[2] = { } }; -static const scxml_elem_donedata _scxml_FD9C4306_elem_donedatas[1] = { +static const scxml_elem_donedata _scxml_740A1EEF_elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; -static int _scxml_FD9C4306_sub01_transition0_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_740A1EEF_sub0_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_FD9C4306_elem_sends[0])) != SCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_scxml_740A1EEF_elem_sends[0])) != SCXML_ERR_OK) return err; } else { return SCXML_ERR_MISSING_CALLBACK; } return SCXML_ERR_OK; } -static int _scxml_FD9C4306_sub01_transition1_on_trans(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_FD9C4306_elem_sends[1])) != SCXML_ERR_OK) return err; - } else { - return SCXML_ERR_MISSING_CALLBACK; - } +static int _scxml_740A1EEF_sub0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_740A1EEF_sub0_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static const scxml_state _scxml_FD9C4306_states[3] = { +static const scxml_state _scxml_740A1EEF_states[3] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, @@ -576,145 +516,13 @@ static const scxml_state _scxml_FD9C4306_states[3] = { /* children */ { 0x06 /* 011 */ }, /* completion */ { 0x02 /* 010 */ }, /* ancestors */ { 0x00 /* 000 */ }, - /* data */ &_scxml_FD9C4306_elem_datas[0], - /* type */ SCXML_STATE_COMPOUND, - }, - { /* state number 1 */ - /* name */ "sub01", - /* parent */ 0, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x00 /* 000 */ }, - /* completion */ { 0x00 /* 000 */ }, - /* ancestors */ { 0x01 /* 100 */ }, /* data */ NULL, - /* type */ SCXML_STATE_ATOMIC, - }, - { /* state number 2 */ - /* name */ "subFinal1", - /* parent */ 0, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x00 /* 000 */ }, - /* completion */ { 0x00 /* 000 */ }, - /* ancestors */ { 0x01 /* 100 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_FINAL, - } -}; - -static const scxml_transition _scxml_FD9C4306_transitions[2] = { - { /* transition number 0 with priority 0 - target: subFinal1 - */ - /* source */ 1, - /* target */ { 0x04 /* 001 */ }, - /* event */ NULL, - /* condition */ "Var1===1", - /* ontrans */ _scxml_FD9C4306_sub01_transition0_on_trans, - /* type */ SCXML_TRANS_SPONTANEOUS, - /* conflicts */ { 0x03 /* 11 */ }, - /* exit set */ { 0x06 /* 011 */ } - }, - { /* transition number 1 with priority 1 - target: subFinal1 - */ - /* source */ 1, - /* target */ { 0x04 /* 001 */ }, - /* event */ NULL, - /* condition */ NULL, - /* ontrans */ _scxml_FD9C4306_sub01_transition1_on_trans, - /* type */ SCXML_TRANS_SPONTANEOUS, - /* conflicts */ { 0x03 /* 11 */ }, - /* exit set */ { 0x06 /* 011 */ } - } -}; - -static const scxml_elem_data _scxml_50B9C583_elem_datas[2] = { - /* id, src, expr, content */ - { "Var1", NULL, "0", NULL }, - { NULL, NULL, NULL, NULL } -}; - -static const scxml_elem_send _scxml_50B9C583_elem_sends[2] = { - { - /* event */ "success", - /* 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 */ NULL - }, - { - /* event */ "failure", - /* 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 */ NULL - } -}; - -static const scxml_elem_donedata _scxml_50B9C583_elem_donedatas[1] = { - /* source, content, contentexpr, params */ - { 0, NULL, NULL, NULL } -}; - -static int _scxml_50B9C583_sub02_transition0_on_trans(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_50B9C583_elem_sends[0])) != SCXML_ERR_OK) return err; - } else { - return SCXML_ERR_MISSING_CALLBACK; - } - return SCXML_ERR_OK; -} - -static int _scxml_50B9C583_sub02_transition1_on_trans(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_50B9C583_elem_sends[1])) != SCXML_ERR_OK) return err; - } else { - return SCXML_ERR_MISSING_CALLBACK; - } - return SCXML_ERR_OK; -} - -static const scxml_state _scxml_50B9C583_states[3] = { - { /* state number 0 */ - /* name */ NULL, - /* parent */ 0, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x06 /* 011 */ }, - /* completion */ { 0x02 /* 010 */ }, - /* ancestors */ { 0x00 /* 000 */ }, - /* data */ &_scxml_50B9C583_elem_datas[0], /* type */ SCXML_STATE_COMPOUND, }, { /* state number 1 */ - /* name */ "sub02", + /* name */ "sub0", /* parent */ 0, - /* onentry */ NULL, + /* onentry */ _scxml_740A1EEF_sub0_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000 */ }, @@ -724,7 +532,7 @@ static const scxml_state _scxml_50B9C583_states[3] = { /* type */ SCXML_STATE_ATOMIC, }, { /* state number 2 */ - /* name */ "subFinal2", + /* name */ "subFinal", /* parent */ 0, /* onentry */ NULL, /* onexit */ NULL, @@ -737,74 +545,49 @@ static const scxml_state _scxml_50B9C583_states[3] = { } }; -static const scxml_transition _scxml_50B9C583_transitions[2] = { +static const scxml_transition _scxml_740A1EEF_transitions[1] = { { /* transition number 0 with priority 0 - target: subFinal2 - */ - /* source */ 1, - /* target */ { 0x04 /* 001 */ }, - /* event */ NULL, - /* condition */ "Var1==1", - /* ontrans */ _scxml_50B9C583_sub02_transition0_on_trans, - /* type */ SCXML_TRANS_SPONTANEOUS, - /* conflicts */ { 0x03 /* 11 */ }, - /* exit set */ { 0x06 /* 011 */ } - }, - { /* transition number 1 with priority 1 - target: subFinal2 + target: subFinal */ /* source */ 1, /* target */ { 0x04 /* 001 */ }, - /* event */ NULL, + /* event */ "timeout", /* condition */ NULL, - /* ontrans */ _scxml_50B9C583_sub02_transition1_on_trans, - /* type */ SCXML_TRANS_SPONTANEOUS, - /* conflicts */ { 0x03 /* 11 */ }, + /* ontrans */ NULL, + /* type */ 0, + /* conflicts */ { 0x01 /* 1 */ }, /* exit set */ { 0x06 /* 011 */ } } }; -const scxml_machine scxml_machines[4] = { +const scxml_machine scxml_machines[3] = { { /* flags */ 0, - /* nr_states */ 6, - /* nr_transitions */ 5, + /* nr_states */ 5, + /* nr_transitions */ 3, /* name */ "", /* datamodel */ "ecmascript", - /* uuid */ "22A28DEDB4EF5C2066BF1D2C022A8AD9", - /* states */ &_scxml_22A28DED_states[0], - /* transitions */ &_scxml_22A28DED_transitions[0], + /* uuid */ "290B2E91E83BC4AC61271D1C9891410E", + /* states */ &_scxml_290B2E91_states[0], + /* transitions */ &_scxml_290B2E91_transitions[0], /* parent */ NULL, - /* donedata */ &_scxml_22A28DED_elem_donedatas[0], + /* donedata */ &_scxml_290B2E91_elem_donedatas[0], /* script */ NULL }, { /* flags */ 0, /* nr_states */ 3, - /* nr_transitions */ 2, + /* nr_transitions */ 1, /* name */ "", /* datamodel */ "ecmascript", - /* uuid */ "FD9C43066AC6FCEE1EC61755B4F2ED11", - /* states */ &_scxml_FD9C4306_states[0], - /* transitions */ &_scxml_FD9C4306_transitions[0], + /* uuid */ "740A1EEF39B05367B78DF059D2C8F917", + /* states */ &_scxml_740A1EEF_states[0], + /* transitions */ &_scxml_740A1EEF_transitions[0], /* parent */ &scxml_machines[0], - /* donedata */ &_scxml_FD9C4306_elem_donedatas[0], + /* donedata */ &_scxml_740A1EEF_elem_donedatas[0], /* script */ NULL }, - { - /* flags */ 0, - /* nr_states */ 3, - /* nr_transitions */ 2, - /* name */ "", - /* datamodel */ "ecmascript", - /* uuid */ "50B9C5830D90CE26DE76391506C882A0", - /* states */ &_scxml_50B9C583_states[0], - /* transitions */ &_scxml_50B9C583_transitions[0], - /* parent */ &scxml_machines[0], - /* donedata */ &_scxml_50B9C583_elem_donedatas[0], - /* script */ NULL - }, - {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } + {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; #ifdef SCXML_VERBOSE @@ -911,6 +694,11 @@ int scxml_step(scxml_ctx* ctx) { return err; } } + if (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); + } } ctx->flags |= SCXML_CTX_FINISHED; return SCXML_ERR_DONE; -- cgit v0.12