From 9cf37e17d745a1f8533ea784a34562e67e6d7f2f Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Thu, 4 Feb 2016 23:54:49 +0100 Subject: Invokers with generated C --- README.md | 4 +- src/uscxml/DOMUtils.h | 17 ++ src/uscxml/transform/ChartToC.cpp | 78 ++++-- test/ctest/CTestCustom.ctest.in | 2 +- test/src/test-c-machine.cpp | 217 +++++++++++++--- test/src/test-c-machine.machine.c | 526 +++++++++++++++++++++++++++++--------- test/w3c/ecma/test240.scxml | 2 +- 7 files changed, 652 insertions(+), 194 deletions(-) diff --git a/README.md b/README.md index 155d568..53d9e68 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ for SCXML documents and currently implements the following features: * Resulting documents require slight adaptations to a compliant interpreter for donedata, the In predicate and invokers. * Semantic equivalence is shown via IRP tests. * [ANSI C native code](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToC.cpp) for easy embedding of SCXML state-charts in C and C++ programs - * No invokers are implemented at the moment and only a single SCXML state-chart can be given in a given document. + * No custom I/O processors implemented in scaffolding just yet. * [PROMELA programs](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToPromela.cpp) for model-checking via linear temporal logic with the SPIN model-checker. * Only defined for the promela and null datamodel. * [Minimized SCXML documents](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToMinimalSCXML.cpp) with dead states and executable content removed @@ -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 | 140/140 | $ ctest -L "^gen/c/ecma/test" | +| Generated C | ECMAScript | 173/176 | $ 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 67bcd70..b3b87c8 100644 --- a/src/uscxml/DOMUtils.h +++ b/src/uscxml/DOMUtils.h @@ -50,9 +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::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::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 ea8d5df..d9f1f0e 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -439,7 +439,12 @@ void ChartToC::findNestedMachines() { ChartToC* c2c = NULL; if (HAS_ATTR(invoke, "src")) { - c2c = new ChartToC(Interpreter::fromURL(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; + } + c2c = new ChartToC(Interpreter::fromURL(srcURL.asString())); } else { // is there a nested scxml machine inside? NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", invoke); @@ -551,7 +556,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_TRANSITION_FOUND 0x08" << std::endl; + stream << "#define SCXML_CTX_FINISHED 0x10" << std::endl; stream << std::endl; @@ -686,7 +692,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* 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; @@ -834,7 +841,7 @@ void ChartToC::writeHelpers(std::ostream& stream) { void ChartToC::writeExecContentFinalize(std::ostream& stream) { // needs to be written prior to invocation elem info - NodeSet finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", _scxml, true); + NodeSet finalizes = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "finalize", _scxml); for (size_t i = 0; i < finalizes.size(); i++) { Element finalize(finalizes[i]); NodeSet execContent = filterChildType(Node_base::ELEMENT_NODE, finalize); @@ -1139,7 +1146,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* 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; @@ -1189,6 +1197,10 @@ 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 << " /* namelist */ "; stream << (HAS_ATTR(invoke, "namelist") ? "\"" + escape(ATTR(invoke, "namelist")) + "\"" : "NULL"); stream << ", " << std::endl; @@ -1241,7 +1253,7 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { } void ChartToC::writeElementInfo(std::ostream& stream) { - NodeSet foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true); + 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; @@ -1259,7 +1271,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << std::endl; } - NodeSet datas = filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true); + NodeSet datas = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "data", _scxml); if (datas.size() > 0) { _hasElement.insert("data"); size_t dataIndexOffset = 0; @@ -1316,7 +1328,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << std::endl; } - NodeSet params = filterChildElements(_nsInfo.xmlNSPrefix + "param", _scxml, true); + NodeSet params = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "param", _scxml); if (params.size() > 0) { _hasElement.insert("param"); Node parent; @@ -1352,7 +1364,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << std::endl; } - NodeSet sends = filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true); + NodeSet sends = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "send", _scxml); if (sends.size() > 0) { _hasElement.insert("send"); stream << "static const scxml_elem_send " << _prefix << "_elem_sends[" << sends.size() << "] = {" << std::endl; @@ -1415,7 +1427,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << std::endl; } - NodeSet donedatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", _scxml, true); + NodeSet donedatas = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "donedata", _scxml); 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++) { @@ -1747,27 +1759,45 @@ 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 << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Config: \");" << std::endl; stream << " printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES);" << std::endl; stream << "#endif" << 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 << " " << (_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 << " if (ctx->flags & SCXML_CTX_FINISHED)" << std::endl; + stream << " return SCXML_ERR_DONE;" << std::endl; + stream << 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 << " if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) {" << std::endl; + stream << " // exit all remaining states" << std::endl; + stream << " i = SCXML_NUMBER_STATES;" << std::endl; + stream << " while(i-- > 0) {" << std::endl; + stream << " if (BIT_HAS(i, ctx->config)) {" << std::endl; + stream << " // call all on exit handlers" << 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; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " ctx->flags |= SCXML_CTX_FINISHED;" << std::endl; + stream << " return SCXML_ERR_DONE;" << std::endl; + stream << " }" << std::endl; stream << std::endl; stream << " bit_clear_all(target_set, nr_states_bytes);" << std::endl; diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in index c26b6b0..a140476 100644 --- a/test/ctest/CTestCustom.ctest.in +++ b/test/ctest/CTestCustom.ctest.in @@ -203,7 +203,7 @@ set(CTEST_CUSTOM_TESTS_IGNORE # "gen/c/ecma/test192.scxml" # "gen/c/ecma/test207.scxml" # "gen/c/ecma/test215.scxml" - # "gen/c/ecma/test216.scxml" + "gen/c/ecma/test216.scxml" // invoke srcexpr # "gen/c/ecma/test220.scxml" # "gen/c/ecma/test223.scxml" # "gen/c/ecma/test224.scxml" diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp index 1dc95d4..b80ef72 100644 --- a/test/src/test-c-machine.cpp +++ b/test/src/test-c-machine.cpp @@ -40,22 +40,23 @@ using namespace uscxml; class StateMachine : public InterpreterInfo { public: - StateMachine(const scxml_machine* machine) : parentMachine(NULL), topMostMachine(NULL) { + StateMachine(const scxml_machine* machine) : parentMachine(NULL), topMostMachine(NULL), invocation(NULL) { init(machine); allMachines[sessionId] = this; topMostMachine = this; currentMachine = allMachines.begin(); } - StateMachine(StateMachine* parent, const scxml_machine* machine) { - init(machine); + StateMachine(StateMachine* parent, const scxml_machine* machine, const scxml_elem_invoke* invoke) : invocation(invoke) { parentMachine = parent; topMostMachine = parent->topMostMachine; + init(machine); } void init(const scxml_machine* machine) { sessionId = UUID::getUUID(); - + isFinalized = false; + // clear and initialize machine context memset(&ctx, 0, sizeof(scxml_ctx)); ctx.machine = machine; @@ -83,6 +84,54 @@ 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()); + } + } + } + } } virtual ~StateMachine() { @@ -98,8 +147,22 @@ public: } bool isDone() { - return ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL; - } + 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 reset() { sessionId = UUID::getUUID(); @@ -122,6 +185,12 @@ public: return SCXML_ERR_IDLE; } + // test 187 + if (toRun->isDone()) { + toRun->finalize(); + return SCXML_ERR_IDLE; + } + return scxml_step(&toRun->ctx); } @@ -169,6 +238,10 @@ public: } } + // 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) @@ -188,17 +261,44 @@ public: } 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); - - INSTANCE->topMostMachine->allMachines[invokedMachine->invokeId] = invokedMachine; - } - return SCXML_ERR_UNSUPPORTED; + 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; } static int raiseDoneEvent(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) { @@ -283,7 +383,8 @@ public: } e->origintype = e->type; - + e->invokeid = USER_DATA(ctx)->invokeId; + if (send->eventexpr != NULL) { e->name = USER_DATA(ctx)->dataModel.evalAsString(send->eventexpr); } else { @@ -494,19 +595,22 @@ public: 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()); - } + // 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()); + } + } data++; } return SCXML_ERR_OK; @@ -530,15 +634,25 @@ public: USER_DATA(ctx)->eq.pop_front(); USER_DATA(ctx)->dataModel.setEvent(*e); - if (e->invokeid.size() > 0) { + 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 = USER_DATA(ctx)->allMachines[e->invokeid]; - if (invokedMachine->invocation->finalize != NULL) + StateMachine* invokedMachine = allMachines[e->invokeid]; + if (invokedMachine->invocation != NULL && invokedMachine->invocation->finalize != NULL) invokedMachine->invocation->finalize(ctx, 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); + } + } + #ifdef SCXML_VERBOSE printf("Popping External Event: %s\n", e->name.c_str()); #endif @@ -569,18 +683,36 @@ public: printf("Pushing Internal Event: %s\n", e->name.c_str()); #endif USER_DATA(ctx)->iq.push_back(e); - } else if (sr->target == "#_parent") { + } else if (sr->target == "#_external") { + 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); + } 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 { - 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); + assert(false); } USER_DATA(ctx)->monitor.notify_all(); delete sr; @@ -658,12 +790,14 @@ NEXT_DESC: return false; } + std::map invocationIds; std::map allMachines; StateMachine* parentMachine; StateMachine* topMostMachine; std::map::iterator currentMachine; // next machine to advance + bool isFinalized; int state; scxml_ctx ctx; @@ -673,6 +807,7 @@ NEXT_DESC: // in case we were invoked std::string invokeId; const scxml_elem_invoke* invocation; + std::set invokeIdentifiers; std::deque iq; std::deque eq; diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c index a69b7c7..f3ec413 100644 --- a/test/src/test-c-machine.machine.c +++ b/test/src/test-c-machine.machine.c @@ -64,6 +64,7 @@ #define SCXML_CTX_INITIALIZED 0x02 #define SCXML_CTX_TOP_LEVEL_FINAL 0x04 #define SCXML_CTX_TRANSITION_FOUND 0x08 +#define SCXML_CTX_FINISHED 0x10 #define ELEM_DATA_IS_SET(data) (data->id != NULL) #define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL) @@ -118,7 +119,7 @@ struct scxml_machine { }; // forward declare machines to allow references -extern const scxml_machine scxml_machines[3]; +extern const scxml_machine scxml_machines[4]; struct scxml_elem_data { const char* id; @@ -178,6 +179,7 @@ struct scxml_elem_invoke { const char* srcexpr; const char* id; const char* idlocation; + const char* sourcename; const char* namelist; const uint8_t autoforward; const scxml_elem_param* params; @@ -234,19 +236,19 @@ struct scxml_ctx { invoke_t invoke; }; -static const scxml_elem_data _scxml_6A932FF1_elem_datas[2] = { +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_6A932FF1_elem_params[2] = { +static const scxml_elem_param _scxml_22A28DED_elem_params[2] = { /* name, expr, location */ - { "aParam", "2", NULL }, + { "Var1", "1", NULL }, { NULL, NULL, NULL } }; -static const scxml_elem_send _scxml_6A932FF1_elem_sends[2] = { +static const scxml_elem_send _scxml_22A28DED_elem_sends[1] = { { /* event */ "timeout", /* eventexpr */ NULL, @@ -256,85 +258,81 @@ static const scxml_elem_send _scxml_6A932FF1_elem_sends[2] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ "300s", + /* delay */ "2s", /* 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] = { +static const scxml_elem_donedata _scxml_22A28DED_elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; -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] = { +static const scxml_elem_invoke _scxml_22A28DED_elem_invokes[2] = { { /* machine */ &scxml_machines[1], /* type */ "http://www.w3.org/TR/scxml/", /* typeexpr */ NULL, /* src */ NULL, /* srcexpr */ NULL, - /* id */ "d2170d67-da91-4aba-99a1-b1c021513e75", + /* id */ "43b1f997-4793-4391-8786-d387b411529d", /* idlocation */ NULL, - /* namelist */ NULL, + /* sourcename */ "s01", + /* namelist */ "Var1", /* autoforward */ 0, /* params */ NULL, - /* finalize */ _scxml_6A932FF1_s0_invoke0_finalize0, + /* 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", + /* idlocation */ NULL, + /* sourcename */ "s02", + /* namelist */ NULL, + /* autoforward */ 0, + /* params */ &_scxml_22A28DED_elem_params[0], + /* finalize */ NULL, /* content */ NULL, /* contentexpr */ NULL, } }; -static int _scxml_6A932FF1_s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_22A28DED_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; + if ((ctx->exec_content_send(ctx, &_scxml_22A28DED_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); +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); return SCXML_ERR_OK; } -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); +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); + + 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); return SCXML_ERR_OK; } -static int _scxml_6A932FF1_pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_22A28DED_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; @@ -344,12 +342,12 @@ static int _scxml_6A932FF1_pass_on_entry_0(const scxml_ctx* ctx, const scxml_sta return SCXML_ERR_OK; } -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); +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); return SCXML_ERR_OK; } -static int _scxml_6A932FF1_fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_22A28DED_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; @@ -359,98 +357,174 @@ static int _scxml_6A932FF1_fail_on_entry_0(const scxml_ctx* ctx, const scxml_sta return SCXML_ERR_OK; } -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); +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); return SCXML_ERR_OK; } -static const scxml_state _scxml_6A932FF1_states[4] = { +static const scxml_state _scxml_22A28DED_states[6] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, /* onentry */ NULL, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x0e /* 0111 */ }, - /* completion */ { 0x02 /* 0100 */ }, - /* ancestors */ { 0x00 /* 0000 */ }, - /* data */ &_scxml_6A932FF1_elem_datas[0], + /* children */ { 0x32 /* 010011 */ }, + /* completion */ { 0x02 /* 010000 */ }, + /* ancestors */ { 0x00 /* 000000 */ }, + /* data */ &_scxml_22A28DED_elem_datas[0], /* type */ SCXML_STATE_COMPOUND, }, { /* state number 1 */ /* name */ "s0", /* parent */ 0, - /* onentry */ _scxml_6A932FF1_s0_on_entry, + /* onentry */ _scxml_22A28DED_s0_on_entry, /* onexit */ NULL, - /* invoke */ _scxml_6A932FF1_s0_invoke, - /* children */ { 0x00 /* 0000 */ }, - /* completion */ { 0x00 /* 0000 */ }, - /* ancestors */ { 0x01 /* 1000 */ }, + /* invoke */ NULL, + /* children */ { 0x0c /* 001100 */ }, + /* completion */ { 0x04 /* 001000 */ }, + /* ancestors */ { 0x01 /* 100000 */ }, /* data */ NULL, - /* type */ SCXML_STATE_ATOMIC, + /* type */ SCXML_STATE_COMPOUND, }, { /* state number 2 */ + /* name */ "s01", + /* parent */ 1, + /* onentry */ NULL, + /* onexit */ NULL, + /* invoke */ _scxml_22A28DED_s01_invoke, + /* children */ { 0x00 /* 000000 */ }, + /* completion */ { 0x00 /* 000000 */ }, + /* ancestors */ { 0x03 /* 110000 */ }, + /* 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_6A932FF1_pass_on_entry, + /* onentry */ _scxml_22A28DED_pass_on_entry, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00 /* 0000 */ }, - /* completion */ { 0x00 /* 0000 */ }, - /* ancestors */ { 0x01 /* 1000 */ }, + /* children */ { 0x00 /* 000000 */ }, + /* completion */ { 0x00 /* 000000 */ }, + /* ancestors */ { 0x01 /* 100000 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, }, - { /* state number 3 */ + { /* state number 5 */ /* name */ "fail", /* parent */ 0, - /* onentry */ _scxml_6A932FF1_fail_on_entry, + /* onentry */ _scxml_22A28DED_fail_on_entry, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00 /* 0000 */ }, - /* completion */ { 0x00 /* 0000 */ }, - /* ancestors */ { 0x01 /* 1000 */ }, + /* children */ { 0x00 /* 000000 */ }, + /* completion */ { 0x00 /* 000000 */ }, + /* ancestors */ { 0x01 /* 100000 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, } }; -static const scxml_transition _scxml_6A932FF1_transitions[2] = { - { /* transition number 0 with priority 0 +static const scxml_transition _scxml_22A28DED_transitions[5] = { + { /* transition number 1 with priority 0 + target: s02 + */ + /* source */ 2, + /* target */ { 0x08 /* 000100 */ }, + /* event */ "success", + /* condition */ NULL, + /* ontrans */ NULL, + /* type */ 0, + /* conflicts */ { 0x1f /* 11111 */ }, + /* exit set */ { 0x0c /* 001100 */ } + }, + { /* transition number 2 with priority 1 + target: fail + */ + /* source */ 2, + /* target */ { 0x20 /* 000001 */ }, + /* event */ "failure", + /* condition */ NULL, + /* ontrans */ NULL, + /* type */ 0, + /* conflicts */ { 0x1f /* 11111 */ }, + /* exit set */ { 0x3e /* 011111 */ } + }, + { /* transition number 3 with priority 2 target: pass */ - /* source */ 1, - /* target */ { 0x04 /* 0010 */ }, - /* event */ "childToParent", - /* condition */ "Var1==2", + /* source */ 3, + /* target */ { 0x10 /* 000010 */ }, + /* event */ "success", + /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x03 /* 11 */ }, - /* exit set */ { 0x0e /* 0111 */ } + /* conflicts */ { 0x1f /* 11111 */ }, + /* exit set */ { 0x3e /* 011111 */ } }, - { /* transition number 1 with priority 1 + { /* 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 */ { 0x08 /* 0001 */ }, - /* event */ "*", + /* target */ { 0x20 /* 000001 */ }, + /* event */ "timeout", /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x03 /* 11 */ }, - /* exit set */ { 0x0e /* 0111 */ } + /* conflicts */ { 0x1f /* 11111 */ }, + /* exit set */ { 0x3e /* 011111 */ } } }; -static const scxml_elem_param _scxml_74EC8913_elem_params[2] = { - /* name, expr, location */ - { "aParam", "2", NULL }, - { NULL, NULL, NULL } +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_74EC8913_elem_sends[1] = { +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 + }, { - /* event */ "childToParent", + /* event */ "failure", /* eventexpr */ NULL, /* target */ "#_parent", /* targetexpr */ NULL, @@ -463,85 +537,271 @@ static const scxml_elem_send _scxml_74EC8913_elem_sends[1] = { /* namelist */ NULL, /* content */ NULL, /* contentexpr */ NULL, - /* params */ &_scxml_74EC8913_elem_params[0] + /* params */ NULL } }; -static const scxml_elem_donedata _scxml_74EC8913_elem_donedatas[1] = { +static const scxml_elem_donedata _scxml_FD9C4306_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) { +static int _scxml_FD9C4306_sub01_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_74EC8913_elem_sends[0])) != SCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_scxml_FD9C4306_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); +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; + } return SCXML_ERR_OK; } -static const scxml_state _scxml_74EC8913_states[2] = { +static const scxml_state _scxml_FD9C4306_states[3] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, /* onentry */ NULL, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x02 /* 01 */ }, - /* completion */ { 0x02 /* 01 */ }, - /* ancestors */ { 0x00 /* 00 */ }, + /* 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 */ "subFinal", + /* name */ "sub02", + /* 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 */ "subFinal2", /* parent */ 0, - /* onentry */ _scxml_74EC8913_subFinal_on_entry, + /* onentry */ NULL, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00 /* 00 */ }, - /* completion */ { 0x00 /* 00 */ }, - /* ancestors */ { 0x01 /* 10 */ }, + /* children */ { 0x00 /* 000 */ }, + /* completion */ { 0x00 /* 000 */ }, + /* ancestors */ { 0x01 /* 100 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, } }; -static const scxml_transition _scxml_74EC8913_transitions[0] = { +static const scxml_transition _scxml_50B9C583_transitions[2] = { + { /* 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 + */ + /* source */ 1, + /* target */ { 0x04 /* 001 */ }, + /* event */ NULL, + /* condition */ NULL, + /* ontrans */ _scxml_50B9C583_sub02_transition1_on_trans, + /* type */ SCXML_TRANS_SPONTANEOUS, + /* conflicts */ { 0x03 /* 11 */ }, + /* exit set */ { 0x06 /* 011 */ } + } }; -const scxml_machine scxml_machines[3] = { +const scxml_machine scxml_machines[4] = { { /* flags */ 0, - /* nr_states */ 4, - /* nr_transitions */ 2, + /* nr_states */ 6, + /* nr_transitions */ 5, /* name */ "", /* datamodel */ "ecmascript", - /* uuid */ "6A932FF17BFF1735E3F3C77F7B54C218", - /* states */ &_scxml_6A932FF1_states[0], - /* transitions */ &_scxml_6A932FF1_transitions[0], + /* uuid */ "22A28DEDB4EF5C2066BF1D2C022A8AD9", + /* states */ &_scxml_22A28DED_states[0], + /* transitions */ &_scxml_22A28DED_transitions[0], /* parent */ NULL, - /* donedata */ &_scxml_6A932FF1_elem_donedatas[0], + /* donedata */ &_scxml_22A28DED_elem_donedatas[0], /* script */ NULL }, { /* flags */ 0, - /* nr_states */ 2, - /* nr_transitions */ 0, + /* nr_states */ 3, + /* nr_transitions */ 2, /* name */ "", /* datamodel */ "ecmascript", - /* uuid */ "74EC8913A9386F1A7EC5EF2A0426752B", - /* states */ &_scxml_74EC8913_states[0], - /* transitions */ &_scxml_74EC8913_transitions[0], + /* uuid */ "FD9C43066AC6FCEE1EC61755B4F2ED11", + /* states */ &_scxml_FD9C4306_states[0], + /* transitions */ &_scxml_FD9C4306_transitions[0], /* parent */ &scxml_machines[0], - /* donedata */ &_scxml_74EC8913_elem_donedatas[0], + /* donedata */ &_scxml_FD9C4306_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 } @@ -621,14 +881,6 @@ static void bit_and(char* dest, const char* mask, size_t i) { int scxml_step(scxml_ctx* ctx) { -#ifdef SCXML_VERBOSE - printf("Config: "); - printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES); -#endif - - if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) - return SCXML_ERR_DONE; - 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; @@ -640,6 +892,30 @@ int scxml_step(scxml_ctx* ctx) { char entry_set [SCXML_MAX_NR_STATES_BYTES]; char tmp_states [SCXML_MAX_NR_STATES_BYTES]; +#ifdef SCXML_VERBOSE + printf("Config: "); + printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES); +#endif + + if (ctx->flags & SCXML_CTX_FINISHED) + return SCXML_ERR_DONE; + + if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) { + // exit all remaining states + i = SCXML_NUMBER_STATES; + while(i-- > 0) { + if (BIT_HAS(i, ctx->config)) { + // call all on exit handlers + 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; + } + } + } + ctx->flags |= SCXML_CTX_FINISHED; + return SCXML_ERR_DONE; + } + bit_clear_all(target_set, nr_states_bytes); bit_clear_all(trans_set, nr_trans_bytes); if unlikely(ctx->flags == SCXML_CTX_PRISTINE) { diff --git a/test/w3c/ecma/test240.scxml b/test/w3c/ecma/test240.scxml index 381b04b..00e8c5b 100644 --- a/test/w3c/ecma/test240.scxml +++ b/test/w3c/ecma/test240.scxml @@ -46,7 +46,7 @@ should run correctly. --> - + -- cgit v0.12