summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2016-02-04 22:54:49 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2016-02-04 22:54:49 (GMT)
commit9cf37e17d745a1f8533ea784a34562e67e6d7f2f (patch)
tree7caeab0086076923c46ac8f6d977a7ebb1273597
parent7afc6a257e193986c9305364701085e65c4ccea5 (diff)
downloaduscxml-9cf37e17d745a1f8533ea784a34562e67e6d7f2f.zip
uscxml-9cf37e17d745a1f8533ea784a34562e67e6d7f2f.tar.gz
uscxml-9cf37e17d745a1f8533ea784a34562e67e6d7f2f.tar.bz2
Invokers with generated C
-rw-r--r--README.md4
-rw-r--r--src/uscxml/DOMUtils.h17
-rw-r--r--src/uscxml/transform/ChartToC.cpp78
-rw-r--r--test/ctest/CTestCustom.ctest.in2
-rw-r--r--test/src/test-c-machine.cpp217
-rw-r--r--test/src/test-c-machine.machine.c526
-rw-r--r--test/w3c/ecma/test240.scxml2
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 <tt>In</tt> 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 <tt>promela</tt> and <tt>null</tt> 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 | <tt>$ ctest -L "^fsm/xpath/test"</tt> |
| | PROMELA | 147/165 | <tt>$ ctest -L "^fsm/promela/test"</tt> |
| | Lua | 165/201 | <tt>$ ctest -L "^fsm/lua/test"</tt> |
-| Generated C | ECMAScript | 140/140 | <tt>$ ctest -L "^gen/c/ecma/test"</tt> |
+| Generated C | ECMAScript | 173/176 | <tt>$ ctest -L "^gen/c/ecma/test"</tt> |
| Verification | PROMELA | 130/181 | <tt>$ ctest -L "^spin/promela/test"</tt> |
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<std::string> inPostFixOrder(const std::string& element,
+ const Arabica::DOM::Element<std::string>& root,
+ const bool includeEmbeddedDoc = false) {
+ std::set<std::string> elements;
+ elements.insert(element);
+ return inPostFixOrder(elements, root, includeEmbeddedDoc);
+ }
+
static Arabica::XPath::NodeSet<std::string> inPostFixOrder(const std::set<std::string>& elements,
const Arabica::DOM::Element<std::string>& root,
const bool includeEmbeddedDoc = false);
+
+ static Arabica::XPath::NodeSet<std::string> inDocumentOrder(const std::string& element,
+ const Arabica::DOM::Element<std::string>& root,
+ const bool includeEmbeddedDoc = false) {
+ std::set<std::string> elements;
+ elements.insert(element);
+ return inDocumentOrder(elements, root, includeEmbeddedDoc);
+ }
+
static Arabica::XPath::NodeSet<std::string> inDocumentOrder(const std::set<std::string>& elements,
const Arabica::DOM::Element<std::string>& 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<std::string> 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<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", _scxml, true);
+ NodeSet<std::string> finalizes = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "finalize", _scxml);
for (size_t i = 0; i < finalizes.size(); i++) {
Element<std::string> finalize(finalizes[i]);
NodeSet<std::string> execContent = filterChildType(Node_base::ELEMENT_NODE, finalize);
@@ -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<std::string> foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true);
+ NodeSet<std::string> 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<std::string> datas = filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true);
+ NodeSet<std::string> 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<std::string> params = filterChildElements(_nsInfo.xmlNSPrefix + "param", _scxml, true);
+ NodeSet<std::string> params = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "param", _scxml);
if (params.size() > 0) {
_hasElement.insert("param");
Node<std::string> parent;
@@ -1352,7 +1364,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
stream << std::endl;
}
- NodeSet<std::string> sends = filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true);
+ NodeSet<std::string> 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<std::string> donedatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", _scxml, true);
+ NodeSet<std::string> 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<std::string, StateMachine*> &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<std::string, StateMachine*>& 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<std::string, StateMachine*>::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<std::string, StateMachine*>::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<const scxml_elem_invoke*, std::string> invocationIds;
std::map<std::string, StateMachine*> allMachines;
StateMachine* parentMachine;
StateMachine* topMostMachine;
std::map<std::string, StateMachine* >::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<std::string> invokeIdentifiers;
std::deque<Event*> iq;
std::deque<Event*> 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. -->
<transition cond="Var1==1" target="subFinal2">
<send target="#_parent" event="success"/>
</transition>
- <transition target="subFinal1">
+ <transition target="subFinal2">
<send target="#_parent" event="failure"/>
</transition>
</state>