summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2016-02-04 00:10:57 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2016-02-04 00:10:57 (GMT)
commit7afc6a257e193986c9305364701085e65c4ccea5 (patch)
tree4bc967a50d872e0267d5cf970ab9b88d87dee16b /test
parent0b313e00915b31c8c03980b7225f82ac2e9513e6 (diff)
downloaduscxml-7afc6a257e193986c9305364701085e65c4ccea5.zip
uscxml-7afc6a257e193986c9305364701085e65c4ccea5.tar.gz
uscxml-7afc6a257e193986c9305364701085e65c4ccea5.tar.bz2
Preliminary support for SCXML invocations in generated C machines
Diffstat (limited to 'test')
-rw-r--r--test/ctest/CTestCustom.ctest.in74
-rw-r--r--test/src/test-c-machine.cpp1067
-rw-r--r--test/src/test-c-machine.machine.c722
3 files changed, 1045 insertions, 818 deletions
diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in
index 6ba6eb1..c26b6b0 100644
--- a/test/ctest/CTestCustom.ctest.in
+++ b/test/ctest/CTestCustom.ctest.in
@@ -198,43 +198,43 @@ set(CTEST_CUSTOM_TESTS_IGNORE
### Ignore for generated C sources
# we do not support invokers yet
- "gen/c/ecma/test187.scxml"
- "gen/c/ecma/test191.scxml"
- "gen/c/ecma/test192.scxml"
- "gen/c/ecma/test207.scxml"
- "gen/c/ecma/test215.scxml"
- "gen/c/ecma/test216.scxml"
- "gen/c/ecma/test220.scxml"
- "gen/c/ecma/test223.scxml"
- "gen/c/ecma/test224.scxml"
- "gen/c/ecma/test225.scxml"
- "gen/c/ecma/test226.scxml"
- "gen/c/ecma/test228.scxml"
- "gen/c/ecma/test229.scxml"
- "gen/c/ecma/test230.scxml"
- "gen/c/ecma/test232.scxml"
- "gen/c/ecma/test233.scxml"
- "gen/c/ecma/test234.scxml"
- "gen/c/ecma/test235.scxml"
- "gen/c/ecma/test236.scxml"
- "gen/c/ecma/test237.scxml"
- "gen/c/ecma/test239.scxml"
- "gen/c/ecma/test240.scxml"
- "gen/c/ecma/test241.scxml"
- "gen/c/ecma/test242.scxml"
- "gen/c/ecma/test243.scxml"
- "gen/c/ecma/test244.scxml"
- "gen/c/ecma/test245.scxml"
- "gen/c/ecma/test247.scxml"
- "gen/c/ecma/test250.scxml"
- "gen/c/ecma/test252.scxml"
- "gen/c/ecma/test253.scxml"
- "gen/c/ecma/test276.scxml"
- "gen/c/ecma/test338.scxml"
- "gen/c/ecma/test347.scxml"
- "gen/c/ecma/test422.scxml"
- "gen/c/ecma/test530.scxml"
- "gen/c/ecma/test554.scxml"
+ # "gen/c/ecma/test187.scxml"
+ # "gen/c/ecma/test191.scxml"
+ # "gen/c/ecma/test192.scxml"
+ # "gen/c/ecma/test207.scxml"
+ # "gen/c/ecma/test215.scxml"
+ # "gen/c/ecma/test216.scxml"
+ # "gen/c/ecma/test220.scxml"
+ # "gen/c/ecma/test223.scxml"
+ # "gen/c/ecma/test224.scxml"
+ # "gen/c/ecma/test225.scxml"
+ # "gen/c/ecma/test226.scxml"
+ # "gen/c/ecma/test228.scxml"
+ # "gen/c/ecma/test229.scxml"
+ # "gen/c/ecma/test230.scxml"
+ # "gen/c/ecma/test232.scxml"
+ # "gen/c/ecma/test233.scxml"
+ # "gen/c/ecma/test234.scxml"
+ # "gen/c/ecma/test235.scxml"
+ # "gen/c/ecma/test236.scxml"
+ # "gen/c/ecma/test237.scxml"
+ # "gen/c/ecma/test239.scxml"
+ # "gen/c/ecma/test240.scxml"
+ # "gen/c/ecma/test241.scxml"
+ # "gen/c/ecma/test242.scxml"
+ # "gen/c/ecma/test243.scxml"
+ # "gen/c/ecma/test244.scxml"
+ # "gen/c/ecma/test245.scxml"
+ # "gen/c/ecma/test247.scxml"
+ # "gen/c/ecma/test250.scxml"
+ # "gen/c/ecma/test252.scxml"
+ # "gen/c/ecma/test253.scxml"
+ # "gen/c/ecma/test276.scxml"
+ # "gen/c/ecma/test338.scxml"
+ # "gen/c/ecma/test347.scxml"
+ # "gen/c/ecma/test422.scxml"
+ # "gen/c/ecma/test530.scxml"
+ # "gen/c/ecma/test554.scxml"
# we do not support io processors yet
"gen/c/ecma/test201.scxml"
diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp
index 11bb1c7..1dc95d4 100644
--- a/test/src/test-c-machine.cpp
+++ b/test/src/test-c-machine.cpp
@@ -24,7 +24,7 @@
#include "uscxml/concurrency/Timer.h"
//#include "uscxml/DOMUtils.h"
#include "uscxml/Factory.h"
-#include "uscxml/InterpreterInfo.h"
+//#include "uscxml/Interpreter.h"
#include "uscxml/UUID.h"
#include "uscxml/concurrency/DelayedEventQueue.h"
@@ -34,18 +34,98 @@
# include "uscxml/plugins/DataModel.h"
# endif
-#define USER_DATA(ctx) ((GenCInterpreterInfo*)(((scxml_ctx*)ctx)->user_data))
+#define USER_DATA(ctx) ((StateMachine*)(((scxml_ctx*)ctx)->user_data))
using namespace uscxml;
-typedef struct scxml_foreach_info scxml_foreach_info;
-struct scxml_foreach_info {
- size_t iterations;
- size_t currIteration;
-};
-
-class GenCInterpreterInfo : public InterpreterInfo {
+class StateMachine : public InterpreterInfo {
public:
+ StateMachine(const scxml_machine* machine) : parentMachine(NULL), topMostMachine(NULL) {
+ init(machine);
+ allMachines[sessionId] = this;
+ topMostMachine = this;
+ currentMachine = allMachines.begin();
+ }
+
+ StateMachine(StateMachine* parent, const scxml_machine* machine) {
+ init(machine);
+ parentMachine = parent;
+ topMostMachine = parent->topMostMachine;
+ }
+
+ void init(const scxml_machine* machine) {
+ sessionId = UUID::getUUID();
+
+ // clear and initialize machine context
+ memset(&ctx, 0, sizeof(scxml_ctx));
+ ctx.machine = machine;
+ ctx.user_data = (void*)this;
+
+ // register callbacks with scxml context
+ ctx.is_enabled = &isEnabled;
+ ctx.is_true = &isTrue;
+ ctx.raise_done_event = &raiseDoneEvent;
+ ctx.invoke = &invoke;
+ ctx.exec_content_send = &execContentSend;
+ ctx.exec_content_raise = &execContentRaise;
+ ctx.exec_content_cancel = &execContentCancel;
+ ctx.exec_content_log = &execContentLog;
+ ctx.exec_content_assign = &execContentAssign;
+ ctx.exec_content_foreach_init = &execContentForeachInit;
+ ctx.exec_content_foreach_next = &execContentForeachNext;
+ ctx.exec_content_foreach_done = &execContentForeachDone;
+ ctx.dequeue_external = &dequeueExternal;
+ ctx.dequeue_internal = &dequeueInternal;
+ ctx.exec_content_init = &execContentInit;
+ ctx.exec_content_script = &execContentScript;
+
+ name = machine->name;
+
+ delayQueue.start();
+ dataModel = Factory::getInstance()->createDataModel(machine->datamodel, this);
+ }
+
+ virtual ~StateMachine() {
+ delayQueue.stop();
+ }
+
+ bool hasPendingWork() {
+ return (iq.size() > 0 ||
+ eq.size() > 0 ||
+ ctx.flags & SCXML_CTX_SPONTANEOUS ||
+ ctx.flags == SCXML_CTX_PRISTINE ||
+ memcmp(ctx.config, ctx.invocations, sizeof(ctx.config)) != 0);
+ }
+
+ bool isDone() {
+ return ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL;
+ }
+
+ void reset() {
+ sessionId = UUID::getUUID();
+ iq.clear();
+ eq.clear();
+ delayQueue.cancelAllEvents();
+
+ dataModel = Factory::getInstance()->createDataModel(ctx.machine->datamodel, this);
+
+ }
+
+ int step() {
+ // advance current machine if there are multiple
+ currentMachine++;
+ if (currentMachine == allMachines.end())
+ currentMachine = allMachines.begin();
+
+ StateMachine* toRun = currentMachine->second;
+ if (!toRun->hasPendingWork()) {
+ return SCXML_ERR_IDLE;
+ }
+
+ return scxml_step(&toRun->ctx);
+ }
+
+ // InterpreterInfo
NameSpaceInfo getNameSpaceInfo() const {
return nsInfo;
}
@@ -58,524 +138,568 @@ public:
const std::map<std::string, IOProcessor>& getIOProcessors() {
return ioProcs;
}
- bool isInState(const std::string& stateId) {
- for (int i = 0 ; i < SCXML_NUMBER_STATES; i++) {
- if (scxml_states[i].name != NULL && BIT_HAS(i, ctx->config) && stateId == scxml_states[i].name)
- return true;
- }
- return false;
+ const std::map<std::string, Invoker>& getInvokers() {
+ return invokers;
}
Arabica::DOM::Document<std::string> getDocument() const {
return document;
}
- const std::map<std::string, Invoker>& getInvokers() {
- return invokers;
- }
-
- NameSpaceInfo nsInfo;
- std::string name;
- std::string sessionId;
- std::map<std::string, IOProcessor> ioProcs;
- std::map<std::string, Invoker> invokers;
- Arabica::DOM::Document<std::string> document;
- scxml_ctx* ctx;
- DataModel datamodel;
-
- std::map<const scxml_elem_foreach*, scxml_foreach_info*> foreachInfo;
- std::deque<Event*> iq;
- std::deque<Event*> eq;
-
- DelayedEventQueue delayQueue;
- std::map<std::string, SendRequest*> sendIds;
- tthread::condition_variable monitor;
- tthread::mutex mutex;
-};
+ bool isInState(const std::string& stateId) {
+ for (int i = 0 ; i < ctx.machine->nr_states; i++) {
+ if (ctx.machine->states[i].name != NULL && BIT_HAS(i, ctx.config) && stateId == ctx.machine->states[i].name)
+ return true;
+ }
+ return false;
+ }
-int matches(const char* desc, const char* event) {
- const char* dPtr = desc;
- const char* ePtr = event;
- while(*dPtr != 0) {
+ // callbacks for scxml context
- if (*dPtr == '*' && *ePtr != 0) // something following
- return true;
-
- // descriptor differs from event name
- if (*dPtr != *ePtr) {
- // move to next descriptor
- while(*dPtr != ' ' && *dPtr != 0) {
- dPtr++;
- }
- if (*dPtr == 0)
+ static int isEnabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) {
+ Event* event = (Event*)e;
+ if (event == NULL) {
+ if (t->event == NULL) {
+ // spontaneous transition, null event
+ if (t->condition != NULL)
+ return isTrue(ctx, t->condition);
+ return true;
+ } else {
+ // spontaneous transition, but real event
return false;
- dPtr++;
- ePtr = event;
- } else {
- // move both pointers one character
- dPtr++;
- ePtr++;
-
+ }
}
- // descriptor is done, return match
- if (((*dPtr == 0 || *dPtr == ' ') && (*ePtr == 0 || *ePtr == ' ')) || // exact match, end of string
- (*dPtr == ' ' && *ePtr == '.') || (*dPtr == 0 && *ePtr == '.')) // prefix match
+ // real transition, real event
+ if (nameMatch(t->event, event->name.c_str())) {
+ if (t->condition != NULL)
+ return isTrue(ctx, t->condition);
return true;
+ }
+ return false;
}
- return false;
-}
-
-int exec_content_raise(const scxml_ctx* ctx, const char* event) {
- Event* e = new Event();
- e->name = event;
- if (boost::starts_with(e->name, "error.")) {
- e->eventType = Event::PLATFORM;
- } else {
- e->eventType = Event::INTERNAL;
+ static int isTrue(const scxml_ctx* ctx, const char* expr) {
+ try {
+ return USER_DATA(ctx)->dataModel.evalAsBool(expr);
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ }
+ return false;
}
-#ifdef SCXML_VERBOSE
- printf("Raising Internal Event: %s\n", e->name.c_str());
-#endif
- USER_DATA(ctx)->iq.push_back(e);
- return SCXML_ERR_OK;
-}
-
-int is_true(const scxml_ctx* ctx, const char* expr) {
- try {
- return USER_DATA(ctx)->datamodel.evalAsBool(expr);
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- }
- return false;
-}
+ static int invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) {
+ if (invocation->machine != NULL) {
+ StateMachine* INSTANCE = USER_DATA(ctx);
+ // invoke a nested SCXML machine
+ StateMachine* invokedMachine = new StateMachine(INSTANCE, invocation->machine);
+ invokedMachine->invocation = invocation;
+ invokedMachine->invokeId = invocation->id;
+ assert(invocation->id != NULL);
-int is_enabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) {
- Event* event = (Event*)e;
- if (event == NULL) {
- if (t->event == NULL) {
- // spontaneous transition, null event
- if (t->condition != NULL)
- return is_true(ctx, t->condition);
- return true;
- } else {
- // spontaneous transition, but real event
- return false;
+ INSTANCE->topMostMachine->allMachines[invokedMachine->invokeId] = invokedMachine;
}
+ return SCXML_ERR_UNSUPPORTED;
}
- // real transition, real event
- if (matches(t->event, event->name.c_str())) {
- if (t->condition != NULL)
- return is_true(ctx, t->condition);
- return true;
- }
- return false;
-}
-
-int raise_done_event(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) {
- Event* e = new Event();
- e->name = std::string("done.state.") + state->name;
+ static int raiseDoneEvent(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) {
+ Event* e = new Event();
+ e->name = std::string("done.state.") + state->name;
- if (donedata) {
- if (donedata->content != NULL) {
- e->data = Data(donedata->content, Data::VERBATIM);
- } else if (donedata->contentexpr != NULL) {
- try {
- e->data = USER_DATA(ctx)->datamodel.getStringAsData(donedata->contentexpr);
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- }
- } else {
- try {
- const scxml_elem_param* param = donedata->params;
- while (param && ELEM_PARAM_IS_SET(param)) {
- Data paramValue;
- if (param->expr != NULL) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->expr);
- } else if(param->location) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->location);
+ if (donedata) {
+ if (donedata->content != NULL) {
+ e->data = Data(donedata->content, Data::VERBATIM);
+ } else if (donedata->contentexpr != NULL) {
+ try {
+ e->data = USER_DATA(ctx)->dataModel.getStringAsData(donedata->contentexpr);
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ }
+ } else {
+ try {
+ const scxml_elem_param* param = donedata->params;
+ while (param && ELEM_PARAM_IS_SET(param)) {
+ Data paramValue;
+ if (param->expr != NULL) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->expr);
+ } else if(param->location) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->location);
+ }
+ e->params.insert(std::make_pair(param->name, paramValue));
+ param++;
}
- e->params.insert(std::make_pair(param->name, paramValue));
- param++;
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
}
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
}
}
- }
-
-#ifdef SCXML_VERBOSE
- printf("Raising Done Event: %s\n", e->name.c_str());
-#endif
- USER_DATA(ctx)->iq.push_back(e);
- return SCXML_ERR_OK;
-}
-
-void delayedSend(void* ctx, std::string eventName) {
- tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
-
- SendRequest* sr = USER_DATA(ctx)->sendIds[eventName];
- Event* e = new Event(*sr);
- if (sr->target == "#_internal") {
- e->eventType = Event::INTERNAL;
#ifdef SCXML_VERBOSE
- printf("Pushing Internal Event: %s\n", e->name.c_str());
+ printf("Raising Done Event: %s\n", e->name.c_str());
#endif
USER_DATA(ctx)->iq.push_back(e);
- } else {
- e->eventType = Event::EXTERNAL;
-#ifdef SCXML_VERBOSE
- printf("Pushing External Event: %s\n", e->name.c_str());
-#endif
- USER_DATA(ctx)->eq.push_back(e);
+ return SCXML_ERR_OK;
}
- USER_DATA(ctx)->monitor.notify_all();
- delete sr;
-}
-int exec_content_cancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) {
- std::string eventId;
- if (sendid != NULL) {
- eventId = sendid;
- } else if (sendidexpr != NULL) {
- eventId = USER_DATA(ctx)->datamodel.evalAsString(sendidexpr);
- }
+ static int execContentSend(const scxml_ctx* ctx, const scxml_elem_send* send) {
+ SendRequest* e = new SendRequest();
- if (eventId.length() > 0) {
- USER_DATA(ctx)->delayQueue.cancelEvent(eventId);
- } else {
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_EXEC_CONTENT;
- }
- return SCXML_ERR_OK;
-}
-
-std::string spaceNormalize(const std::string& text) {
- std::stringstream content;
- std::string seperator;
-
- size_t start = 0;
- for (int i = 0; i < text.size(); i++) {
- if (isspace(text[i])) {
- if (i > 0 && start < i) {
- content << seperator << text.substr(start, i - start);
- seperator = " ";
- }
- while(isspace(text[++i])); // skip whitespaces
- start = i;
- } else if (i + 1 == text.size()) {
- content << seperator << text.substr(start, i + 1 - start);
+ std::string target;
+ if (send->target != NULL) {
+ e->target = send->target;
+ } else if (send->targetexpr != NULL) {
+ e->target = USER_DATA(ctx)->dataModel.evalAsString(send->targetexpr);
+ } else {
+ e->target = "#_external";
}
- }
- return content.str();
-}
+ if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) {
+ delete e;
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_INVALID_TARGET;
+ }
-int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) {
- SendRequest* e = new SendRequest();
+ e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ e->origin = e->target;
- std::string target;
- if (send->target != NULL) {
- e->target = send->target;
- } else if (send->targetexpr != NULL) {
- e->target = USER_DATA(ctx)->datamodel.evalAsString(send->targetexpr);
- } else {
- e->target = "#_external";
- }
+ try {
+ if (send->type != NULL) {
+ e->type = send->type;
+ } else if (send->typeexpr != NULL) {
+ e->type = USER_DATA(ctx)->dataModel.evalAsString(send->typeexpr);
+ } else {
+ e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ }
+ } catch (Event exc) {
+ execContentRaise(ctx, exc.name.c_str());
+ delete e;
+ return SCXML_ERR_EXEC_CONTENT;
+ }
- if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) {
- delete e;
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_INVALID_TARGET;
- }
+ // only one somewhat supported
+ if (e->type != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") {
+ delete e;
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_INVALID_TARGET;
+ }
- e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
- e->origin = e->target;
+ e->origintype = e->type;
- try {
- if (send->type != NULL) {
- e->type = send->type;
- } else if (send->typeexpr != NULL) {
- e->type = USER_DATA(ctx)->datamodel.evalAsString(send->typeexpr);
+ if (send->eventexpr != NULL) {
+ e->name = USER_DATA(ctx)->dataModel.evalAsString(send->eventexpr);
} else {
- e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ e->name = send->event;
}
- } catch (Event exc) {
- exec_content_raise(ctx, exc.name.c_str());
- delete e;
- return SCXML_ERR_EXEC_CONTENT;
- }
- // only one somewhat supported
- if (e->type != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") {
- delete e;
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_INVALID_TARGET;
- }
+ try {
+ const scxml_elem_param* param = send->params;
+ while (param && ELEM_PARAM_IS_SET(param)) {
+ Data paramValue;
+ if (param->expr != NULL) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->expr);
+ } else if(param->location) {
+ paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->location);
+ }
+ e->params.insert(std::make_pair(param->name, paramValue));
+ param++;
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
- e->origintype = e->type;
+ try {
+ if (send->namelist != NULL) {
+ const char* bPtr = &send->namelist[0];
+ const char* ePtr = bPtr;
+ while(*ePtr != '\0') {
+ ePtr++;
+ if (*ePtr == ' ' || *ePtr == '\0') {
+ std::string key(bPtr, ePtr - bPtr);
+ e->params.insert(std::make_pair(key, USER_DATA(ctx)->dataModel.getStringAsData(key)));
+ if (*ePtr == '\0')
+ break;
+ bPtr = ++ePtr;
+ }
+ }
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
- if (send->eventexpr != NULL) {
- e->name = USER_DATA(ctx)->datamodel.evalAsString(send->eventexpr);
- } else {
- e->name = send->event;
- }
+ if (send->content != NULL) {
+ // will it parse as json?
+ Data d = Data::fromJSON(send->content);
+ if (!d.empty()) {
+ e->data = d;
+ } else {
+ e->data = Data(spaceNormalize(send->content), Data::VERBATIM);
+ }
+ }
- try {
- const scxml_elem_param* param = send->params;
- while (param && ELEM_PARAM_IS_SET(param)) {
- Data paramValue;
- if (param->expr != NULL) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->expr);
- } else if(param->location) {
- paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->location);
+ std::string sendid;
+ if (send->id != NULL) {
+ sendid = send->id;
+ e->sendid = sendid;
+ } else {
+ sendid = UUID::getUUID();
+ if (send->idlocation != NULL) {
+ USER_DATA(ctx)->dataModel.assign(send->idlocation, Data(sendid, Data::VERBATIM));
+ } else {
+ e->hideSendId = true;
}
- e->params.insert(std::make_pair(param->name, paramValue));
- param++;
- }
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
- }
-
- try {
- if (send->namelist != NULL) {
- const char* bPtr = &send->namelist[0];
- const char* ePtr = bPtr;
- while(*ePtr != '\0') {
- ePtr++;
- if (*ePtr == ' ' || *ePtr == '\0') {
- std::string key(bPtr, ePtr - bPtr);
- e->params.insert(std::make_pair(key, USER_DATA(ctx)->datamodel.getStringAsData(key)));
- if (*ePtr == '\0')
- break;
- bPtr = ++ePtr;
- }
+ }
+
+ size_t delayMs = 0;
+ std::string delay;
+ if (send->delayexpr != NULL) {
+ delay = USER_DATA(ctx)->dataModel.evalAsString(send->delayexpr);
+ } else if (send->delay != NULL) {
+ delay = send->delay;
+ }
+ if (delay.size() > 0) {
+ boost::trim(delay);
+
+ NumAttr delayAttr(delay);
+ if (iequals(delayAttr.unit, "ms")) {
+ delayMs = strTo<uint32_t>(delayAttr.value);
+ } else if (iequals(delayAttr.unit, "s")) {
+ delayMs = strTo<double>(delayAttr.value) * 1000;
+ } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds
+ delayMs = strTo<uint32_t>(delayAttr.value);
+ } else {
+ std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
}
}
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
- }
- if (send->content != NULL) {
- // will it parse as json?
- Data d = Data::fromJSON(send->content);
- if (!d.empty()) {
- e->data = d;
- } else {
- e->data = Data(spaceNormalize(send->content), Data::VERBATIM);
+ if (USER_DATA(ctx)->invokeId.size() > 0) {
+ e->invokeid = USER_DATA(ctx)->invokeId;
}
- }
- std::string sendid;
- if (send->id != NULL) {
- sendid = send->id;
- e->sendid = sendid;
- } else {
- sendid = UUID::getUUID();
- if (send->idlocation != NULL) {
- USER_DATA(ctx)->datamodel.assign(send->idlocation, Data(sendid, Data::VERBATIM));
+ USER_DATA(ctx)->sendIds[sendid] = e;
+ if (delayMs > 0) {
+ USER_DATA(ctx)->delayQueue.addEvent(sendid, delayedSend, delayMs, (void*)ctx);
} else {
- e->hideSendId = true;
+ delayedSend((void*)ctx, sendid);
}
+
+ return SCXML_ERR_OK;
}
+ static int execContentRaise(const scxml_ctx* ctx, const char* event) {
+ Event* e = new Event();
+ e->name = event;
- size_t delayMs = 0;
- std::string delay;
- if (send->delayexpr != NULL) {
- delay = USER_DATA(ctx)->datamodel.evalAsString(send->delayexpr);
- } else if (send->delay != NULL) {
- delay = send->delay;
+ if (boost::starts_with(e->name, "error.")) {
+ e->eventType = Event::PLATFORM;
+ } else {
+ e->eventType = Event::INTERNAL;
+ }
+ USER_DATA(ctx)->iq.push_back(e);
+ return SCXML_ERR_OK;
}
- if (delay.size() > 0) {
- boost::trim(delay);
- NumAttr delayAttr(delay);
- if (iequals(delayAttr.unit, "ms")) {
- delayMs = strTo<uint32_t>(delayAttr.value);
- } else if (iequals(delayAttr.unit, "s")) {
- delayMs = strTo<double>(delayAttr.value) * 1000;
- } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds
- delayMs = strTo<uint32_t>(delayAttr.value);
+ static int execContentCancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) {
+ std::string eventId;
+ if (sendid != NULL) {
+ eventId = sendid;
+ } else if (sendidexpr != NULL) {
+ eventId = USER_DATA(ctx)->dataModel.evalAsString(sendidexpr);
+ }
+
+ if (eventId.length() > 0) {
+ USER_DATA(ctx)->delayQueue.cancelEvent(eventId);
} else {
- std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_EXEC_CONTENT;
}
+ return SCXML_ERR_OK;
}
- USER_DATA(ctx)->sendIds[sendid] = e;
- if (delayMs > 0) {
- USER_DATA(ctx)->delayQueue.addEvent(sendid, delayedSend, delayMs, (void*)ctx);
- } else {
- delayedSend((void*)ctx, sendid);
+ static int execContentLog(const scxml_ctx* ctx, const char* label, const char* expr) {
+ try {
+ if (label != NULL) {
+ printf("%s%s", label, (expr != NULL ? ": " : ""));
+ }
+ if (expr != NULL) {
+ std::string msg = USER_DATA(ctx)->dataModel.evalAsString(expr);
+ printf("%s", msg.c_str());
+ }
+ if (label != NULL || expr != NULL) {
+ printf("\n");
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-
-int exec_content_init(const scxml_ctx* ctx, const scxml_elem_data* data) {
- while(ELEM_DATA_IS_SET(data)) {
- Data d;
- if (data->expr != NULL) {
- d = Data(data->expr, Data::INTERPRETED);
- } else if (data->content != NULL) {
- d = Data(data->content, Data::INTERPRETED);
- } else {
- d = Data("undefined", Data::INTERPRETED);
+ static int execContentAssign(const scxml_ctx* ctx, const char* location, const char* expr) {
+ std::string key = location;
+ if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") {
+ execContentRaise(ctx, "error.execution");
+ return SCXML_ERR_EXEC_CONTENT;
}
+
try {
- USER_DATA(ctx)->datamodel.init(data->id, d);
+ Data d(expr, Data::INTERPRETED);
+ USER_DATA(ctx)->dataModel.assign(key, d);
} catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
}
- data++;
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-int exec_content_assign(const scxml_ctx* ctx, const char* location, const char* expr) {
- std::string key = location;
- if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") {
- exec_content_raise(ctx, "error.execution");
- return SCXML_ERR_EXEC_CONTENT;
- }
+ static int execContentForeachInit(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
+ try {
+ scxml_foreach_info* feInfo = (scxml_foreach_info*)malloc(sizeof(scxml_foreach_info));
+ USER_DATA(ctx)->foreachInfo[foreach] = feInfo;
- try {
- Data d(expr, Data::INTERPRETED);
- USER_DATA(ctx)->datamodel.assign(key, d);
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
+ feInfo->iterations = USER_DATA(ctx)->dataModel.getLength(foreach->array);
+ feInfo->currIteration = 0;
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ return SCXML_ERR_EXEC_CONTENT;
+ }
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-int exec_content_foreach_init(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
- try {
- scxml_foreach_info* feInfo = (scxml_foreach_info*)malloc(sizeof(scxml_foreach_info));
- USER_DATA(ctx)->foreachInfo[foreach] = feInfo;
-
- feInfo->iterations = USER_DATA(ctx)->datamodel.getLength(foreach->array);
- feInfo->currIteration = 0;
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
+ static int execContentForeachNext(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
+ try {
+ scxml_foreach_info* feInfo = USER_DATA(ctx)->foreachInfo[foreach];
+ if (feInfo->currIteration < feInfo->iterations) {
+ USER_DATA(ctx)->dataModel.setForeach((foreach->item != NULL ? foreach->item : ""),
+ (foreach->array != NULL ? foreach->array : ""),
+ (foreach->index != NULL ? foreach->index : ""),
+ feInfo->currIteration);
+ feInfo->currIteration++;
+ return SCXML_ERR_OK;
+ }
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ free(USER_DATA(ctx)->foreachInfo[foreach]);
+ USER_DATA(ctx)->foreachInfo.erase(foreach);
+ return SCXML_ERR_EXEC_CONTENT;
+ }
+ return SCXML_ERR_FOREACH_DONE;
}
- return SCXML_ERR_OK;
-}
-int exec_content_foreach_next(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
- try {
- scxml_foreach_info* feInfo = USER_DATA(ctx)->foreachInfo[foreach];
- if (feInfo->currIteration < feInfo->iterations) {
- USER_DATA(ctx)->datamodel.setForeach((foreach->item != NULL ? foreach->item : ""),
- (foreach->array != NULL ? foreach->array : ""),
- (foreach->index != NULL ? foreach->index : ""),
- feInfo->currIteration);
- feInfo->currIteration++;
- return SCXML_ERR_OK;
- }
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
+ static int execContentForeachDone(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
free(USER_DATA(ctx)->foreachInfo[foreach]);
USER_DATA(ctx)->foreachInfo.erase(foreach);
- return SCXML_ERR_EXEC_CONTENT;
+ return SCXML_ERR_OK;
+ }
+
+ static int execContentInit(const scxml_ctx* ctx, const scxml_elem_data* data) {
+ while(ELEM_DATA_IS_SET(data)) {
+ Data d;
+ if (data->expr != NULL) {
+ d = Data(data->expr, Data::INTERPRETED);
+ } else if (data->content != NULL) {
+ d = Data(data->content, Data::INTERPRETED);
+ } else {
+ d = Data("undefined", Data::INTERPRETED);
+ }
+ try {
+ USER_DATA(ctx)->dataModel.init(data->id, d);
+ } catch (Event e) {
+ execContentRaise(ctx, e.name.c_str());
+ }
+ data++;
+ }
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_FOREACH_DONE;
-}
-int exec_content_foreach_done(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) {
- free(USER_DATA(ctx)->foreachInfo[foreach]);
- USER_DATA(ctx)->foreachInfo.erase(foreach);
- return SCXML_ERR_OK;
-}
-
-int exec_content_log(const scxml_ctx* ctx, const char* label, const char* expr) {
- try {
- if (label != NULL) {
- printf("%s%s", label, (expr != NULL ? ": " : ""));
- }
- if (expr != NULL) {
- std::string msg = USER_DATA(ctx)->datamodel.evalAsString(expr);
- printf("%s", msg.c_str());
+ static int execContentScript(const scxml_ctx* ctx, const char* src, const char* content) {
+ if (content != NULL) {
+ USER_DATA(ctx)->dataModel.eval(Arabica::DOM::Element<std::string>(), content);
+ } else if (src != NULL) {
+ return SCXML_ERR_UNSUPPORTED;
}
- if (label != NULL || expr != NULL) {
- printf("\n");
- }
- } catch (Event e) {
- exec_content_raise(ctx, e.name.c_str());
- return SCXML_ERR_EXEC_CONTENT;
+ return SCXML_ERR_OK;
}
- return SCXML_ERR_OK;
-}
-int exec_content_script(const scxml_ctx* ctx, const char* src, const char* content) {
- if (content != NULL) {
- USER_DATA(ctx)->datamodel.eval(Arabica::DOM::Element<std::string>(), content);
- } else if (src != NULL) {
- return SCXML_ERR_UNSUPPORTED;
- }
- return SCXML_ERR_OK;
-}
+ static void* dequeueExternal(const scxml_ctx* ctx) {
+ tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
+ if (USER_DATA(ctx)->eq.size() == 0)
+ return NULL;
+
+ Event* e = USER_DATA(ctx)->eq.front();
+ USER_DATA(ctx)->eq.pop_front();
+ USER_DATA(ctx)->dataModel.setEvent(*e);
-void* dequeue_external(const scxml_ctx* ctx) {
- tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
- while (USER_DATA(ctx)->eq.size() == 0) {
- USER_DATA(ctx)->monitor.wait(USER_DATA(ctx)->mutex);
+ if (e->invokeid.size() > 0) {
+ // we need to check for finalize content
+ StateMachine* invokedMachine = USER_DATA(ctx)->allMachines[e->invokeid];
+ if (invokedMachine->invocation->finalize != NULL)
+ invokedMachine->invocation->finalize(ctx,
+ invokedMachine->invocation,
+ e);
+ }
+
+#ifdef SCXML_VERBOSE
+ printf("Popping External Event: %s\n", e->name.c_str());
+#endif
+ return e;
}
- Event* e = USER_DATA(ctx)->eq.front();
- USER_DATA(ctx)->eq.pop_front();
- USER_DATA(ctx)->datamodel.setEvent(*e);
+
+ static void* dequeueInternal(const scxml_ctx* ctx) {
+ if (USER_DATA(ctx)->iq.size() == 0)
+ return NULL;
+ Event* e = USER_DATA(ctx)->iq.front();
+ USER_DATA(ctx)->iq.pop_front();
+ USER_DATA(ctx)->dataModel.setEvent(*e);
#ifdef SCXML_VERBOSE
- printf("Popping External Event: %s\n", e->name.c_str());
+ printf("Popping Internal Event: %s\n", e->name.c_str());
#endif
- return e;
-}
+ return e;
+ }
+
+ static void delayedSend(void* ctx, std::string eventName) {
+ tthread::lock_guard<tthread::mutex> lock(USER_DATA(ctx)->mutex);
+
+ SendRequest* sr = USER_DATA(ctx)->sendIds[eventName];
+ Event* e = new Event(*sr);
-void* dequeue_internal(const scxml_ctx* ctx) {
- if (USER_DATA(ctx)->iq.size() == 0)
- return NULL;
- Event* e = USER_DATA(ctx)->iq.front();
- USER_DATA(ctx)->iq.pop_front();
- USER_DATA(ctx)->datamodel.setEvent(*e);
+ if (sr->target == "#_internal") {
+ e->eventType = Event::INTERNAL;
#ifdef SCXML_VERBOSE
- printf("Popping Internal Event: %s\n", e->name.c_str());
+ printf("Pushing Internal Event: %s\n", e->name.c_str());
#endif
- return e;
-}
+ USER_DATA(ctx)->iq.push_back(e);
+ } else if (sr->target == "#_parent") {
+ e->eventType = Event::EXTERNAL;
+ if (USER_DATA(ctx)->parentMachine != NULL) {
+ USER_DATA(ctx)->parentMachine->eq.push_back(e);
+ }
+ // TODO: handle invalid parent
+ } else {
+ e->eventType = Event::EXTERNAL;
+#ifdef SCXML_VERBOSE
+ printf("Pushing External Event: %s\n", e->name.c_str());
+#endif
+ USER_DATA(ctx)->eq.push_back(e);
+ }
+ USER_DATA(ctx)->monitor.notify_all();
+ delete sr;
+ }
-int main(int argc, char** argv) {
+ static std::string spaceNormalize(const std::string& text) {
+ std::stringstream content;
+ std::string seperator;
- std::cout << "sizeof(scxml_state): " << sizeof(scxml_state) << std::endl;
- std::cout << "sizeof(scxml_transition): " << sizeof(scxml_transition) << std::endl;
- std::cout << "sizeof(scxml_ctx): " << sizeof(scxml_ctx) << std::endl;
+ size_t start = 0;
+ for (int i = 0; i < text.size(); i++) {
+ if (isspace(text[i])) {
+ if (i > 0 && start < i) {
+ content << seperator << text.substr(start, i - start);
+ seperator = " ";
+ }
+ while(isspace(text[++i])); // skip whitespaces
+ start = i;
+ } else if (i + 1 == text.size()) {
+ content << seperator << text.substr(start, i + 1 - start);
+ }
+ }
+ return content.str();
+ }
-#ifdef APPLE
- mach_timebase_info_data_t timebase_info;
- mach_timebase_info(&timebase_info);
-
- const uint64_t NANOS_PER_MSEC = 1000000ULL;
- double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
-
- thread_time_constraint_policy_data_t policy;
- policy.period = 0;
- policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
- policy.constraint = (uint32_t)(10 * clock2abs);
- policy.preemptible = FALSE;
-
- int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
- THREAD_TIME_CONSTRAINT_POLICY,
- (thread_policy_t)&policy,
- THREAD_TIME_CONSTRAINT_POLICY_COUNT);
- if (kr != KERN_SUCCESS) {
- mach_error("thread_policy_set:", kr);
- exit(1);
+ // TODO: isolate InterpreterImpl to reduce header deps on libxml/parser.h
+ static bool nameMatch(const std::string& eventDescs, const std::string& eventName) {
+ if(eventDescs.length() == 0 || eventName.length() == 0)
+ return false;
+
+ // naive case of single descriptor and exact match
+ if (iequals(eventDescs, eventName))
+ return true;
+
+ size_t start = 0;
+ std::string eventDesc;
+ for (int i = 0; i < eventDescs.size(); i++) {
+ if (isspace(eventDescs[i])) {
+ if (i > 0 && start < i - 1) {
+ eventDesc = eventDescs.substr(start, i - start);
+ }
+ while(isspace(eventDescs[++i])); // skip whitespaces
+ start = i;
+ } else if (i + 1 == eventDescs.size()) {
+ eventDesc = eventDescs.substr(start, i + 1 - start);
+ }
+
+ if (eventDesc.size() > 0) {
+ // remove optional trailing .* for CCXML compatibility
+ if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+ if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+
+ // was eventDesc the * wildcard
+ if (eventDesc.size() == 0)
+ return true;
+
+ // eventDesc has to be a real prefix of event now and therefore shorter
+ if (eventDesc.size() > eventName.size())
+ goto NEXT_DESC;
+
+ // are they already equal?
+ if (iequals(eventDesc, eventName))
+ return true;
+
+ if (eventName.find(eventDesc) == 0) {
+ if (eventName.find(".", eventDesc.size()) == eventDesc.size())
+ return true;
+ }
+NEXT_DESC:
+ eventDesc = "";
+ }
+ }
+ return false;
}
-#endif
+
+ std::map<std::string, StateMachine*> allMachines;
+
+ StateMachine* parentMachine;
+ StateMachine* topMostMachine;
+ std::map<std::string, StateMachine* >::iterator currentMachine; // next machine to advance
+
+ int state;
+ scxml_ctx ctx;
+
+ std::string sessionId;
+ std::string name;
+
+ // in case we were invoked
+ std::string invokeId;
+ const scxml_elem_invoke* invocation;
+
+ std::deque<Event*> iq;
+ std::deque<Event*> eq;
+
+ DataModel dataModel;
+
+protected:
+ struct scxml_foreach_info {
+ size_t iterations;
+ size_t currIteration;
+ };
+
+ NameSpaceInfo nsInfo;
+ std::map<std::string, IOProcessor> ioProcs;
+ std::map<std::string, Invoker> invokers;
+ Arabica::DOM::Document<std::string> document;
+
+ DelayedEventQueue delayQueue;
+ std::map<std::string, SendRequest*> sendIds;
+ std::map<const scxml_elem_foreach*, scxml_foreach_info*> foreachInfo;
+
+ tthread::condition_variable monitor;
+ tthread::mutex mutex;
+};
+
+
+int main(int argc, char** argv) {
int err;
size_t benchmarkRuns = 1;
@@ -584,90 +708,56 @@ int main(int argc, char** argv) {
benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
}
-
size_t remainingRuns = benchmarkRuns;
- // setup info object required for datamodel
- GenCInterpreterInfo interpreterInfo;
- interpreterInfo.name = SCXML_MACHINE_NAME;
- interpreterInfo.sessionId = "rfwef";
- interpreterInfo.delayQueue.start();
-
- scxml_ctx ctx;
- interpreterInfo.ctx = &ctx;
-
double avg = 0;
size_t microSteps = 0;
#ifdef BUILD_PROFILING
double avgDm = 0;
#endif
+ StateMachine rootMachine(&scxml_machines[0]);
+
Timer tTotal;
tTotal.start();
while(remainingRuns-- > 0) {
- memset(&ctx, 0, sizeof(scxml_ctx));
-
- // fresh dm (expensive :( )
- interpreterInfo.datamodel = Factory::getInstance()->createDataModel("ecmascript", &interpreterInfo);
-
- // set info object as user data
- ctx.user_data = (void*)&interpreterInfo;
-
- // register callbacks with scxml context
- ctx.is_enabled = &is_enabled;
- ctx.is_true = &is_true;
- ctx.raise_done_event = &raise_done_event;
-
- ctx.exec_content_send = &exec_content_send;
- ctx.exec_content_raise = &exec_content_raise;
- ctx.exec_content_cancel = &exec_content_cancel;
- ctx.exec_content_log = &exec_content_log;
- ctx.exec_content_assign = &exec_content_assign;
- ctx.exec_content_foreach_init = &exec_content_foreach_init;
- ctx.exec_content_foreach_next = &exec_content_foreach_next;
- ctx.exec_content_foreach_done = &exec_content_foreach_done;
- ctx.dequeue_external = &dequeue_external;
- ctx.dequeue_internal = &dequeue_internal;
- ctx.exec_content_init = &exec_content_init;
- ctx.exec_content_script = &exec_content_script;
Timer t;
t.start();
-
microSteps = 0;
- while((err = scxml_step(&ctx)) == SCXML_ERR_OK) {
+
+
+ for (;;) {
+ err = rootMachine.step();
+ if (rootMachine.isDone())
+ break;
t.stop();
microSteps++;
- if (ctx.event != NULL) {
- delete ((Event*)(ctx.event));
- }
+
t.start();
}
microSteps++;
- assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL);
-
+ assert(rootMachine.ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL);
t.stop();
+
avg += t.elapsed;
#ifdef BUILD_PROFILING
- avgDm += interpreterInfo.datamodel.timer.elapsed;
- interpreterInfo.datamodel.timer.elapsed = 0;
+ avgDm += rootMachine.dataModel.timer.elapsed;
+ rootMachine.dataModel.timer.elapsed = 0;
#endif
size_t passIdx = 0;
- for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
- if (scxml_states[i].name && strcmp(scxml_states[i].name, "pass") == 0) {
+ for (int i = 0; i < rootMachine.ctx.machine->nr_states; i++) {
+ if (rootMachine.ctx.machine->states[i].name && strcmp(rootMachine.ctx.machine->states[i].name, "pass") == 0) {
passIdx = i;
break;
}
}
- if(!BIT_HAS(passIdx, ctx.config)) {
+ if(!BIT_HAS(passIdx, rootMachine.ctx.config)) {
std::cerr << "Interpreter did not end in pass" << std::endl;
exit(EXIT_FAILURE);
}
- interpreterInfo.delayQueue.cancelAllEvents();
- interpreterInfo.eq.clear();
- interpreterInfo.iq.clear();
}
tTotal.stop();
std::cout << benchmarkRuns << " iterations" << std::endl;
@@ -676,10 +766,9 @@ int main(int argc, char** argv) {
std::cout << microSteps << " microsteps per iteration" << std::endl;
std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl;
#ifdef BUILD_PROFILING
- std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
- std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl;
+ std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in dataModel" << std::endl;
+ std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo dataModel" << std::endl;
#endif
- interpreterInfo.delayQueue.stop();
tthread::this_thread::sleep_for(tthread::chrono::milliseconds(100));
return EXIT_SUCCESS;
-} \ No newline at end of file
+}
diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c
index ebacc5f..a69b7c7 100644
--- a/test/src/test-c-machine.machine.c
+++ b/test/src/test-c-machine.machine.c
@@ -13,6 +13,22 @@
#define unlikely(x) (x)
#endif
+#ifndef SCXML_NR_STATES_TYPE
+# define SCXML_NR_STATES_TYPE uint8_t
+#endif
+
+#ifndef SCXML_NR_TRANS_TYPE
+# define SCXML_NR_TRANS_TYPE uint8_t
+#endif
+
+#ifndef SCXML_MAX_NR_STATES_BYTES
+# define SCXML_MAX_NR_STATES_BYTES 1
+#endif
+
+#ifndef SCXML_MAX_NR_TRANS_BYTES
+# define SCXML_MAX_NR_TRANS_BYTES 1
+#endif
+
// error return codes
#define SCXML_ERR_OK 0
#define SCXML_ERR_IDLE 1
@@ -24,9 +40,8 @@
#define SCXML_ERR_INVALID_TYPE 7
#define SCXML_ERR_UNSUPPORTED 8
-#define SCXML_MACHINE_NAME ""
-#define SCXML_NUMBER_STATES 9
-#define SCXML_NUMBER_TRANSITIONS 6
+#define SCXML_NUMBER_STATES (ctx->machine->nr_states)
+#define SCXML_NUMBER_TRANS (ctx->machine->nr_transitions)
#define SCXML_TRANS_SPONTANEOUS 0x01
#define SCXML_TRANS_TARGETLESS 0x02
@@ -53,12 +68,14 @@
#define ELEM_DATA_IS_SET(data) (data->id != NULL)
#define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL)
#define ELEM_PARAM_IS_SET(param) (param->name != NULL)
+#define SCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0)
+typedef struct scxml_machine scxml_machine;
typedef struct scxml_transition scxml_transition;
typedef struct scxml_state scxml_state;
typedef struct scxml_ctx scxml_ctx;
-typedef struct scxml_invoke scxml_invoke;
+typedef struct scxml_elem_invoke scxml_elem_invoke;
typedef struct scxml_elem_send scxml_elem_send;
typedef struct scxml_elem_param scxml_elem_param;
@@ -72,7 +89,7 @@ typedef int (*is_enabled_t)(const scxml_ctx* ctx, const scxml_transition* transi
typedef int (*is_true_t)(const scxml_ctx* ctx, const char* expr);
typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event);
typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata);
-typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x);
+typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke);
typedef int (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr);
typedef int (*exec_content_raise_t)(const scxml_ctx* ctx, const char* event);
@@ -83,9 +100,26 @@ typedef int (*exec_content_foreach_done_t)(const scxml_ctx* ctx, const scxml_ele
typedef int (*exec_content_assign_t)(const scxml_ctx* ctx, const char* location, const char* expr);
typedef int (*exec_content_init_t)(const scxml_ctx* ctx, const scxml_elem_data* data);
typedef int (*exec_content_cancel_t)(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr);
-typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_invoke* invoker, const void* event);
+typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_elem_invoke* invoker, const void* event);
typedef int (*exec_content_script_t)(const scxml_ctx* ctx, const char* src, const char* content);
+struct scxml_machine {
+ uint8_t flags;
+ SCXML_NR_STATES_TYPE nr_states;
+ SCXML_NR_TRANS_TYPE nr_transitions;
+ const char* name;
+ const char* datamodel;
+ const char* uuid;
+ const scxml_state* states;
+ const scxml_transition* transitions;
+ const scxml_machine* parent;
+ const scxml_elem_donedata* donedata;
+ const exec_content_t script;
+};
+
+// forward declare machines to allow references
+extern const scxml_machine scxml_machines[3];
+
struct scxml_elem_data {
const char* id;
const char* src;
@@ -99,22 +133,22 @@ struct scxml_state {
const exec_content_t on_entry; // on entry handlers
const exec_content_t on_exit; // on exit handlers
const invoke_t invoke; // invocations
- const char children[2]; // all children
- const char completion[2]; // default completion
- const char ancestors[2]; // all ancestors
+ const char children[SCXML_MAX_NR_STATES_BYTES]; // all children
+ const char completion[SCXML_MAX_NR_STATES_BYTES]; // default completion
+ const char ancestors[SCXML_MAX_NR_STATES_BYTES]; // all ancestors
const scxml_elem_data* data;
const uint8_t type; // atomic, parallel, compound, final, history
};
struct scxml_transition {
const uint8_t source;
- const char target[2];
+ const char target[SCXML_MAX_NR_STATES_BYTES];
const char* event;
const char* condition;
const exec_content_t on_transition;
const uint8_t type;
- const char conflicts[1];
- const char exit_set[2];
+ const char conflicts[SCXML_MAX_NR_TRANS_BYTES];
+ const char exit_set[SCXML_MAX_NR_STATES_BYTES];
};
struct scxml_elem_foreach {
@@ -137,6 +171,7 @@ struct scxml_elem_donedata {
};
struct scxml_elem_invoke {
+ const scxml_machine* machine;
const char* type;
const char* typeexpr;
const char* src;
@@ -146,7 +181,7 @@ struct scxml_elem_invoke {
const char* namelist;
const uint8_t autoforward;
const scxml_elem_param* params;
- const exec_content_finalize_t* finalize;
+ exec_content_finalize_t finalize;
const char* content;
const char* contentexpr;
};
@@ -169,12 +204,13 @@ struct scxml_elem_send {
};
struct scxml_ctx {
- uint8_t flags;
+ uint8_t flags;
+ const scxml_machine* machine;
- char config[2];
- char history[2];
- char pending_invokes[2];
- char initialized_data[2];
+ char config[SCXML_MAX_NR_STATES_BYTES];
+ char history[SCXML_MAX_NR_STATES_BYTES];
+ char invocations[SCXML_MAX_NR_STATES_BYTES];
+ char initialized_data[SCXML_MAX_NR_STATES_BYTES];
void* user_data;
void* event;
@@ -198,30 +234,107 @@ struct scxml_ctx {
invoke_t invoke;
};
-static const scxml_elem_data scxml_elem_datas[2] = {
+static const scxml_elem_data _scxml_6A932FF1_elem_datas[2] = {
/* id, src, expr, content */
- { "Var1", NULL, "0", NULL },
+ { "Var1", NULL, "1", NULL },
{ NULL, NULL, NULL, NULL }
};
-static const scxml_elem_param scxml_elem_params[2] = {
+static const scxml_elem_param _scxml_6A932FF1_elem_params[2] = {
/* name, expr, location */
- { "Var1", "1", NULL },
+ { "aParam", "2", NULL },
{ NULL, NULL, NULL }
};
-static const scxml_elem_donedata scxml_elem_donedatas[3] = {
+static const scxml_elem_send _scxml_6A932FF1_elem_sends[2] = {
+ {
+ /* event */ "timeout",
+ /* eventexpr */ NULL,
+ /* target */ NULL,
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ "300s",
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ NULL
+ },
+ {
+ /* event */ "childToParent",
+ /* eventexpr */ NULL,
+ /* target */ "#_parent",
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ NULL,
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ &_scxml_6A932FF1_elem_params[0]
+ }
+};
+
+static const scxml_elem_donedata _scxml_6A932FF1_elem_donedatas[1] = {
/* source, content, contentexpr, params */
- { 3, NULL, NULL, &scxml_elem_params[0] },
- { 6, "foo", NULL, NULL },
{ 0, NULL, NULL, NULL }
};
-static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+static int _scxml_6A932FF1_s0_invoke0_finalize0(const scxml_ctx* ctx, const scxml_elem_invoke* invocation, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_assign != NULL) {
+ if ((ctx->exec_content_assign(ctx, "Var1", "_event.data.aParam")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static const scxml_elem_invoke _scxml_6A932FF1_elem_invokes[1] = {
+ {
+ /* machine */ &scxml_machines[1],
+ /* type */ "http://www.w3.org/TR/scxml/",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "d2170d67-da91-4aba-99a1-b1c021513e75",
+ /* idlocation */ NULL,
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ _scxml_6A932FF1_s0_invoke0_finalize0,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ }
+};
+
+static int _scxml_6A932FF1_s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &_scxml_6A932FF1_elem_sends[0])) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int _scxml_6A932FF1_s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_6A932FF1_s0_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
-static int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+static int _scxml_6A932FF1_s0_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) {
+ ctx->invoke(ctx, s, &_scxml_6A932FF1_elem_invokes[0], uninvoke);
+
+ return SCXML_ERR_OK;
+}
+static int _scxml_6A932FF1_pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
int err = SCXML_ERR_OK;
if likely(ctx->exec_content_log != NULL) {
if unlikely((ctx->exec_content_log(ctx, "Outcome", "'pass'")) != SCXML_ERR_OK) return err;
@@ -231,12 +344,12 @@ static int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const
return SCXML_ERR_OK;
}
-static int pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
- pass_on_entry_0(ctx, state, event);
+static int _scxml_6A932FF1_pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_6A932FF1_pass_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
-static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+static int _scxml_6A932FF1_fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
int err = SCXML_ERR_OK;
if likely(ctx->exec_content_log != NULL) {
if unlikely((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != SCXML_ERR_OK) return err;
@@ -246,204 +359,201 @@ static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const
return SCXML_ERR_OK;
}
-static int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
- fail_on_entry_0(ctx, state, event);
+static int _scxml_6A932FF1_fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_6A932FF1_fail_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
-static const scxml_state scxml_states[9] = {
+static const scxml_state _scxml_6A932FF1_states[4] = {
{ /* state number 0 */
/* name */ NULL,
/* parent */ 0,
/* onentry */ NULL,
/* onexit */ NULL,
/* invoke */ NULL,
- /* children */ { 0x92, 0x01 /* 010010011, 1 4 7 8 */ },
- /* completion */ { 0x02, 0x00 /* 010000000, 1 */ },
- /* ancestors */ { 0x00, 0x00 /* 000000000, */ },
- /* data */ &scxml_elem_datas[0],
+ /* children */ { 0x0e /* 0111 */ },
+ /* completion */ { 0x02 /* 0100 */ },
+ /* ancestors */ { 0x00 /* 0000 */ },
+ /* data */ &_scxml_6A932FF1_elem_datas[0],
/* type */ SCXML_STATE_COMPOUND,
},
{ /* state number 1 */
/* name */ "s0",
/* parent */ 0,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x0c, 0x00 /* 001100000, 2 3 */ },
- /* completion */ { 0x04, 0x00 /* 001000000, 2 */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_COMPOUND,
- },
- { /* state number 2 */
- /* name */ "s01",
- /* parent */ 1,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x03, 0x00 /* 110000000, 0 1 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_ATOMIC,
- },
- { /* state number 3 */
- /* name */ "s02",
- /* parent */ 1,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x03, 0x00 /* 110000000, 0 1 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_FINAL,
- },
- { /* state number 4 */
- /* name */ "s1",
- /* parent */ 0,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x60, 0x00 /* 000001100, 5 6 */ },
- /* completion */ { 0x20, 0x00 /* 000001000, 5 */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_COMPOUND,
- },
- { /* state number 5 */
- /* name */ "s11",
- /* parent */ 4,
- /* onentry */ NULL,
+ /* onentry */ _scxml_6A932FF1_s0_on_entry,
/* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x11, 0x00 /* 100010000, 0 4 */ },
+ /* invoke */ _scxml_6A932FF1_s0_invoke,
+ /* children */ { 0x00 /* 0000 */ },
+ /* completion */ { 0x00 /* 0000 */ },
+ /* ancestors */ { 0x01 /* 1000 */ },
/* data */ NULL,
/* type */ SCXML_STATE_ATOMIC,
},
- { /* state number 6 */
- /* name */ "s12",
- /* parent */ 4,
- /* onentry */ NULL,
- /* onexit */ NULL,
- /* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x11, 0x00 /* 100010000, 0 4 */ },
- /* data */ NULL,
- /* type */ SCXML_STATE_FINAL,
- },
- { /* state number 7 */
+ { /* state number 2 */
/* name */ "pass",
/* parent */ 0,
- /* onentry */ pass_on_entry,
+ /* onentry */ _scxml_6A932FF1_pass_on_entry,
/* onexit */ NULL,
/* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
+ /* children */ { 0x00 /* 0000 */ },
+ /* completion */ { 0x00 /* 0000 */ },
+ /* ancestors */ { 0x01 /* 1000 */ },
/* data */ NULL,
/* type */ SCXML_STATE_FINAL,
},
- { /* state number 8 */
+ { /* state number 3 */
/* name */ "fail",
/* parent */ 0,
- /* onentry */ fail_on_entry,
+ /* onentry */ _scxml_6A932FF1_fail_on_entry,
/* onexit */ NULL,
/* invoke */ NULL,
- /* children */ { 0x00, 0x00 /* 000000000, */ },
- /* completion */ { 0x00, 0x00 /* 000000000, */ },
- /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ },
+ /* children */ { 0x00 /* 0000 */ },
+ /* completion */ { 0x00 /* 0000 */ },
+ /* ancestors */ { 0x01 /* 1000 */ },
/* data */ NULL,
/* type */ SCXML_STATE_FINAL,
}
};
-static const scxml_transition scxml_transitions[6] = {
+static const scxml_transition _scxml_6A932FF1_transitions[2] = {
{ /* transition number 0 with priority 0
- target: s02
- */
- /* source */ 2,
- /* target */ { 0x08, 0x00 /* 000100000, 3 */ },
- /* event */ NULL,
- /* condition */ NULL,
- /* ontrans */ NULL,
- /* type */ SCXML_TRANS_SPONTANEOUS,
- /* conflicts */ { 0x37 /* 111011, 0 1 2 4 5 */ },
- /* exit set */ { 0x0c, 0x00 /* 001100000, 2 3 */ }
- },
- { /* transition number 1 with priority 1
- target: s1
+ target: pass
*/
/* source */ 1,
- /* target */ { 0x10, 0x00 /* 000010000, 4 */ },
- /* event */ "done.state.s0",
- /* condition */ "_event.data['Var1']==1",
+ /* target */ { 0x04 /* 0010 */ },
+ /* event */ "childToParent",
+ /* condition */ "Var1==2",
/* ontrans */ NULL,
/* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
+ /* conflicts */ { 0x03 /* 11 */ },
+ /* exit set */ { 0x0e /* 0111 */ }
},
- { /* transition number 2 with priority 2
+ { /* transition number 1 with priority 1
target: fail
*/
/* source */ 1,
- /* target */ { 0x00, 0x01 /* 000000001, 8 */ },
- /* event */ "done.state.s0",
+ /* target */ { 0x08 /* 0001 */ },
+ /* event */ "*",
/* condition */ NULL,
/* ontrans */ NULL,
/* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
+ /* conflicts */ { 0x03 /* 11 */ },
+ /* exit set */ { 0x0e /* 0111 */ }
+ }
+};
+
+static const scxml_elem_param _scxml_74EC8913_elem_params[2] = {
+ /* name, expr, location */
+ { "aParam", "2", NULL },
+ { NULL, NULL, NULL }
+};
+
+static const scxml_elem_send _scxml_74EC8913_elem_sends[1] = {
+ {
+ /* event */ "childToParent",
+ /* eventexpr */ NULL,
+ /* target */ "#_parent",
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ NULL,
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ &_scxml_74EC8913_elem_params[0]
+ }
+};
+
+static const scxml_elem_donedata _scxml_74EC8913_elem_donedatas[1] = {
+ /* source, content, contentexpr, params */
+ { 0, NULL, NULL, NULL }
+};
+
+static int _scxml_74EC8913_subFinal_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &_scxml_74EC8913_elem_sends[0])) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int _scxml_74EC8913_subFinal_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ _scxml_74EC8913_subFinal_on_entry_0(ctx, state, event);
+ return SCXML_ERR_OK;
+}
+
+static const scxml_state _scxml_74EC8913_states[2] = {
+ { /* state number 0 */
+ /* name */ NULL,
+ /* parent */ 0,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x02 /* 01 */ },
+ /* completion */ { 0x02 /* 01 */ },
+ /* ancestors */ { 0x00 /* 00 */ },
+ /* data */ NULL,
+ /* type */ SCXML_STATE_COMPOUND,
},
- { /* transition number 3 with priority 3
- target: s12
- */
- /* source */ 5,
- /* target */ { 0x40, 0x00 /* 000000100, 6 */ },
- /* event */ NULL,
- /* condition */ NULL,
- /* ontrans */ NULL,
- /* type */ SCXML_TRANS_SPONTANEOUS,
- /* conflicts */ { 0x3e /* 011111, 1 2 3 4 5 */ },
- /* exit set */ { 0x60, 0x00 /* 000001100, 5 6 */ }
+ { /* state number 1 */
+ /* name */ "subFinal",
+ /* parent */ 0,
+ /* onentry */ _scxml_74EC8913_subFinal_on_entry,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x00 /* 00 */ },
+ /* completion */ { 0x00 /* 00 */ },
+ /* ancestors */ { 0x01 /* 10 */ },
+ /* data */ NULL,
+ /* type */ SCXML_STATE_FINAL,
+ }
+};
+
+static const scxml_transition _scxml_74EC8913_transitions[0] = {
+};
+
+const scxml_machine scxml_machines[3] = {
+ {
+ /* flags */ 0,
+ /* nr_states */ 4,
+ /* nr_transitions */ 2,
+ /* name */ "",
+ /* datamodel */ "ecmascript",
+ /* uuid */ "6A932FF17BFF1735E3F3C77F7B54C218",
+ /* states */ &_scxml_6A932FF1_states[0],
+ /* transitions */ &_scxml_6A932FF1_transitions[0],
+ /* parent */ NULL,
+ /* donedata */ &_scxml_6A932FF1_elem_donedatas[0],
+ /* script */ NULL
},
- { /* transition number 4 with priority 4
- target: pass
- */
- /* source */ 4,
- /* target */ { 0x80, 0x00 /* 000000010, 7 */ },
- /* event */ "done.state.s1",
- /* condition */ "_event.data == 'foo'",
- /* ontrans */ NULL,
- /* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
+ {
+ /* flags */ 0,
+ /* nr_states */ 2,
+ /* nr_transitions */ 0,
+ /* name */ "",
+ /* datamodel */ "ecmascript",
+ /* uuid */ "74EC8913A9386F1A7EC5EF2A0426752B",
+ /* states */ &_scxml_74EC8913_states[0],
+ /* transitions */ &_scxml_74EC8913_transitions[0],
+ /* parent */ &scxml_machines[0],
+ /* donedata */ &_scxml_74EC8913_elem_donedatas[0],
+ /* script */ NULL
},
- { /* transition number 5 with priority 5
- target: fail
- */
- /* source */ 4,
- /* target */ { 0x00, 0x01 /* 000000001, 8 */ },
- /* event */ "done.state.s1",
- /* condition */ NULL,
- /* ontrans */ NULL,
- /* type */ 0,
- /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ },
- /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ }
- }
+ {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }
};
#ifdef SCXML_VERBOSE
-static void printStateNames(const char* a) {
+static void printStateNames(const scxml_ctx* ctx, const char* a, size_t length) {
size_t i;
const char* seperator = "";
- for (i = 0; i < SCXML_NUMBER_STATES; i++) {
+ for (i = 0; i < length; i++) {
if (BIT_HAS(i, a)) {
- printf("%s%s", seperator, (scxml_states[i].name != NULL ? scxml_states[i].name : "UNK"));
+ printf("%s%s", seperator, (ctx->machine->states[i].name != NULL ? ctx->machine->states[i].name : "UNK"));
seperator = ", ";
}
}
@@ -464,69 +574,78 @@ static void printBitsetIndices(const char* a, size_t length) {
#endif
static int bit_has_and(const char* a, const char* b, size_t i) {
- do {
- if (a[i - 1] & b[i - 1])
+ while(i--) {
+ if (a[i] & b[i])
return 1;
- } while(--i);
+ }
return 0;
}
+static void bit_clear_all(char* a, size_t i) {
+ while(i--) {
+ a[i] = 0;
+ }
+}
+
static int bit_has_any(const char* a, size_t i) {
- do {
- if (a[i - 1] > 0)
+ while(i--) {
+ if (a[i] > 0)
return 1;
- } while(--i);
+ }
return 0;
}
static void bit_or(char* dest, const char* mask, size_t i) {
- do {
- dest[i - 1] |= mask[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] |= mask[i];
+ }
}
static void bit_copy(char* dest, const char* source, size_t i) {
- do {
- dest[i - 1] = source[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] = source[i];
+ }
}
static void bit_and_not(char* dest, const char* mask, size_t i) {
- do {
- dest[i - 1] &= ~mask[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] &= ~mask[i];
+ }
}
static void bit_and(char* dest, const char* mask, size_t i) {
- do {
- dest[i - 1] &= mask[i - 1];
- } while(--i);
+ while(i--) {
+ dest[i] &= mask[i];
+ };
}
int scxml_step(scxml_ctx* ctx) {
#ifdef SCXML_VERBOSE
printf("Config: ");
- printStateNames(ctx->config);
+ printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES);
#endif
-// MACRO_STEP:
-
if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL)
return SCXML_ERR_DONE;
- size_t i, j, k;
+ SCXML_NR_STATES_TYPE i, j, k;
+ SCXML_NR_STATES_TYPE nr_states_bytes = ((SCXML_NUMBER_STATES + 7) & ~7) >> 3;
+ SCXML_NR_TRANS_TYPE nr_trans_bytes = ((SCXML_NUMBER_TRANS + 7) & ~7) >> 3;
int err = SCXML_ERR_OK;
- char conflicts[1] = {0};
- char target_set[2] = {0, 0};
- char exit_set[2] = {0, 0};
- char trans_set[1] = {0};
- char entry_set[2] = {0, 0};
- char tmp_states[2] = {0, 0};
-
+ char conflicts [SCXML_MAX_NR_TRANS_BYTES];
+ char trans_set [SCXML_MAX_NR_TRANS_BYTES];
+ char target_set [SCXML_MAX_NR_STATES_BYTES];
+ char exit_set [SCXML_MAX_NR_STATES_BYTES];
+ char entry_set [SCXML_MAX_NR_STATES_BYTES];
+ char tmp_states [SCXML_MAX_NR_STATES_BYTES];
+
+ bit_clear_all(target_set, nr_states_bytes);
+ bit_clear_all(trans_set, nr_trans_bytes);
if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {
- global_script(ctx, &scxml_states[0], NULL);
- bit_or(target_set, scxml_states[0].completion, 2);
+ if (ctx->machine->script != NULL)
+ ctx->machine->script(ctx, &ctx->machine->states[0], NULL);
+ bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes);
ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;
goto ESTABLISH_ENTRY_SET;
}
@@ -538,40 +657,59 @@ int scxml_step(scxml_ctx* ctx) {
if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
+
+ // manage invocations
+ for (i = 0; i < SCXML_NUMBER_STATES; i++) {
+ // uninvoke
+ if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) {
+ if (ctx->machine->states[i].invoke != NULL)
+ ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 1);
+ BIT_CLEAR(i, ctx->invocations)
+ }
+ // invoke
+ if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) {
+ if (ctx->machine->states[i].invoke != NULL)
+ ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 0);
+ BIT_SET_AT(i, ctx->invocations)
+ }
+ }
+
if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
SELECT_TRANSITIONS:
- for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
+ bit_clear_all(conflicts, nr_trans_bytes);
+ bit_clear_all(exit_set, nr_states_bytes);
+ for (i = 0; i < SCXML_NUMBER_TRANS; i++) {
// never select history or initial transitions automatically
- if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))
+ if unlikely(ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))
continue;
// is the transition active?
- if (BIT_HAS(scxml_transitions[i].source, ctx->config)) {
+ if (BIT_HAS(ctx->machine->transitions[i].source, ctx->config)) {
// is it non-conflicting?
if (!BIT_HAS(i, conflicts)) {
// is it enabled?
- if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {
+ if (ctx->is_enabled(ctx, &ctx->machine->transitions[i], ctx->event) > 0) {
// remember that we found a transition
ctx->flags |= SCXML_CTX_TRANSITION_FOUND;
// transitions that are pre-empted
- bit_or(conflicts, scxml_transitions[i].conflicts, 1);
+ bit_or(conflicts, ctx->machine->transitions[i].conflicts, nr_trans_bytes);
// states that are directly targeted (resolve as entry-set later)
- bit_or(target_set, scxml_transitions[i].target, 2);
+ bit_or(target_set, ctx->machine->transitions[i].target, nr_states_bytes);
// states that will be left
- bit_or(exit_set, scxml_transitions[i].exit_set, 2);
+ bit_or(exit_set, ctx->machine->transitions[i].exit_set, nr_states_bytes);
BIT_SET_AT(i, trans_set);
}
}
}
}
- bit_and(exit_set, ctx->config, 2);
+ bit_and(exit_set, ctx->config, nr_states_bytes);
if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {
ctx->flags |= SCXML_CTX_SPONTANEOUS;
@@ -582,71 +720,71 @@ SELECT_TRANSITIONS:
#ifdef SCXML_VERBOSE
printf("Targets: ");
- printStateNames(target_set);
+ printStateNames(ctx, target_set, SCXML_NUMBER_STATES);
#endif
#ifdef SCXML_VERBOSE
printf("Exiting: ");
- printStateNames(exit_set);
+ printStateNames(ctx, exit_set, SCXML_NUMBER_STATES);
#endif
#ifdef SCXML_VERBOSE
printf("History: ");
- printStateNames(ctx->history);
+ printStateNames(ctx, ctx->history, SCXML_NUMBER_STATES);
#endif
// REMEMBER_HISTORY:
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
- if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
- SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP) {
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
+ SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP) {
// a history state whose parent is about to be exited
- if unlikely(BIT_HAS(scxml_states[i].parent, exit_set)) {
- bit_copy(tmp_states, scxml_states[i].completion, 2);
+ if unlikely(BIT_HAS(ctx->machine->states[i].parent, exit_set)) {
+ bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);
// set those states who were enabled
- bit_and(tmp_states, ctx->config, 2);
+ bit_and(tmp_states, ctx->config, nr_states_bytes);
// clear current history with completion mask
- bit_and_not(ctx->history, scxml_states[i].completion, 2);
+ bit_and_not(ctx->history, ctx->machine->states[i].completion, nr_states_bytes);
// set history
- bit_or(ctx->history, tmp_states, 2);
+ bit_or(ctx->history, tmp_states, nr_states_bytes);
}
}
}
ESTABLISH_ENTRY_SET:
// calculate new entry set
- bit_copy(entry_set, target_set, 2);
+ bit_copy(entry_set, target_set, nr_states_bytes);
// iterate for ancestors
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
if (BIT_HAS(i, entry_set)) {
- bit_or(entry_set, scxml_states[i].ancestors, 2);
+ bit_or(entry_set, ctx->machine->states[i].ancestors, nr_states_bytes);
}
}
// iterate for descendants
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
if (BIT_HAS(i, entry_set)) {
- switch (SCXML_STATE_MASK(scxml_states[i].type)) {
+ switch (SCXML_STATE_MASK(ctx->machine->states[i].type)) {
case SCXML_STATE_PARALLEL: {
- bit_or(entry_set, scxml_states[i].completion, 2);
+ bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);
break;
}
case SCXML_STATE_HISTORY_SHALLOW:
case SCXML_STATE_HISTORY_DEEP: {
- if (!bit_has_and(scxml_states[i].completion, ctx->history, 2) &&
- !BIT_HAS(scxml_states[i].parent, ctx->config)) {
+ if (!bit_has_and(ctx->machine->states[i].completion, ctx->history, nr_states_bytes) &&
+ !BIT_HAS(ctx->machine->states[i].parent, ctx->config)) {
// nothing set for history, look for a default transition
- for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
- if unlikely(scxml_transitions[j].source == i) {
- bit_or(entry_set, scxml_transitions[j].target, 2);
- if(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP &&
- !bit_has_and(scxml_transitions[j].target, scxml_states[i].children, 2)) {
+ for (j = 0; j < SCXML_NUMBER_TRANS; j++) {
+ if unlikely(ctx->machine->transitions[j].source == i) {
+ bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);
+ if(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP &&
+ !bit_has_and(ctx->machine->transitions[j].target, ctx->machine->states[i].children, nr_states_bytes)) {
for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {
- if (BIT_HAS(k, scxml_transitions[j].target)) {
- bit_or(entry_set, scxml_states[k].ancestors, 2);
+ if (BIT_HAS(k, ctx->machine->transitions[j].target)) {
+ bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);
break;
}
}
@@ -657,20 +795,20 @@ ESTABLISH_ENTRY_SET:
// Note: SCXML mandates every history to have a transition!
}
} else {
- bit_copy(tmp_states, scxml_states[i].completion, 2);
- bit_and(tmp_states, ctx->history, 2);
- bit_or(entry_set, tmp_states, 2);
- if (scxml_states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {
+ bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);
+ bit_and(tmp_states, ctx->history, nr_states_bytes);
+ bit_or(entry_set, tmp_states, nr_states_bytes);
+ if (ctx->machine->states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {
// a deep history state with nested histories -> more completion
for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {
- if (BIT_HAS(j, scxml_states[i].completion) &&
+ if (BIT_HAS(j, ctx->machine->states[i].completion) &&
BIT_HAS(j, entry_set) &&
- (scxml_states[j].type & SCXML_STATE_HAS_HISTORY)) {
+ (ctx->machine->states[j].type & SCXML_STATE_HAS_HISTORY)) {
for (k = j + 1; k < SCXML_NUMBER_STATES; k++) {
// add nested history to entry_set
- if ((SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_DEEP ||
- SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&
- BIT_HAS(k, scxml_states[j].children)) {
+ if ((SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_DEEP ||
+ SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&
+ BIT_HAS(k, ctx->machine->states[j].children)) {
// a nested history state
BIT_SET_AT(k, entry_set);
}
@@ -682,14 +820,14 @@ ESTABLISH_ENTRY_SET:
break;
}
case SCXML_STATE_INITIAL: {
- for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
- if (scxml_transitions[j].source == i) {
+ for (j = 0; j < SCXML_NUMBER_TRANS; j++) {
+ if (ctx->machine->transitions[j].source == i) {
BIT_SET_AT(j, trans_set);
BIT_CLEAR(i, entry_set);
- bit_or(entry_set, scxml_transitions[j].target, 2);
+ bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);
for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {
- if (BIT_HAS(k, scxml_transitions[j].target)) {
- bit_or(entry_set, scxml_states[k].ancestors, 2);
+ if (BIT_HAS(k, ctx->machine->transitions[j].target)) {
+ bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);
}
}
}
@@ -697,16 +835,16 @@ ESTABLISH_ENTRY_SET:
break;
}
case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set
- if (!bit_has_and(entry_set, scxml_states[i].children, 2) &&
- (!bit_has_and(ctx->config, scxml_states[i].children, 2) ||
- bit_has_and(exit_set, scxml_states[i].children, 2)))
+ if (!bit_has_and(entry_set, ctx->machine->states[i].children, nr_states_bytes) &&
+ (!bit_has_and(ctx->config, ctx->machine->states[i].children, nr_states_bytes) ||
+ bit_has_and(exit_set, ctx->machine->states[i].children, nr_states_bytes)))
{
- bit_or(entry_set, scxml_states[i].completion, 2);
- if (!bit_has_and(scxml_states[i].completion, scxml_states[i].children, 2)) {
+ bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);
+ if (!bit_has_and(ctx->machine->states[i].completion, ctx->machine->states[i].children, nr_states_bytes)) {
// deep completion
for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {
- if (BIT_HAS(j, scxml_states[i].completion)) {
- bit_or(entry_set, scxml_states[j].ancestors, 2);
+ if (BIT_HAS(j, ctx->machine->states[i].completion)) {
+ bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes);
break; // completion of compound is single state
}
}
@@ -720,7 +858,7 @@ ESTABLISH_ENTRY_SET:
#ifdef SCXML_VERBOSE
printf("Transitions: ");
- printBitsetIndices(trans_set, sizeof(char) * 8 * 1);
+ printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes);
#endif
// EXIT_STATES:
@@ -728,8 +866,8 @@ ESTABLISH_ENTRY_SET:
while(i-- > 0) {
if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) {
// call all on exit handlers
- if (scxml_states[i].on_exit != NULL) {
- if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->states[i].on_exit != NULL) {
+ if unlikely((err = ctx->machine->states[i].on_exit(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)
return err;
}
BIT_CLEAR(i, ctx->config);
@@ -737,13 +875,13 @@ ESTABLISH_ENTRY_SET:
}
// TAKE_TRANSITIONS:
- for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
- if (BIT_HAS(i, trans_set) && (scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {
+ for (i = 0; i < SCXML_NUMBER_TRANS; i++) {
+ if (BIT_HAS(i, trans_set) && (ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {
// call executable content in transition
- if (scxml_transitions[i].on_transition != NULL) {
- if unlikely((err = scxml_transitions[i].on_transition(ctx,
- &scxml_states[scxml_transitions[i].source],
- ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->transitions[i].on_transition != NULL) {
+ if unlikely((err = ctx->machine->transitions[i].on_transition(ctx,
+ &ctx->machine->states[ctx->machine->transitions[i].source],
+ ctx->event)) != SCXML_ERR_OK)
return err;
}
}
@@ -751,61 +889,61 @@ ESTABLISH_ENTRY_SET:
#ifdef SCXML_VERBOSE
printf("Entering: ");
- printStateNames(entry_set);
+ printStateNames(ctx, entry_set, SCXML_NUMBER_STATES);
#endif
// ENTER_STATES:
for (i = 0; i < SCXML_NUMBER_STATES; i++) {
if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) {
// these are no proper states
- if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP ||
- SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
- SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_INITIAL)
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP ||
+ SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||
+ SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_INITIAL)
continue;
BIT_SET_AT(i, ctx->config);
// initialize data
if (!BIT_HAS(i, ctx->initialized_data)) {
- if unlikely(scxml_states[i].data != NULL && ctx->exec_content_init != NULL) {
- ctx->exec_content_init(ctx, scxml_states[i].data);
+ if unlikely(ctx->machine->states[i].data != NULL && ctx->exec_content_init != NULL) {
+ ctx->exec_content_init(ctx, ctx->machine->states[i].data);
}
BIT_SET_AT(i, ctx->initialized_data);
}
- if (scxml_states[i].on_entry != NULL) {
- if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->states[i].on_entry != NULL) {
+ if unlikely((err = ctx->machine->states[i].on_entry(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)
return err;
}
// take history and initial transitions
- for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
+ for (j = 0; j < SCXML_NUMBER_TRANS; j++) {
if unlikely(BIT_HAS(j, trans_set) &&
- (scxml_transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&
- scxml_states[scxml_transitions[j].source].parent == i) {
+ (ctx->machine->transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&
+ ctx->machine->states[ctx->machine->transitions[j].source].parent == i) {
// call executable content in transition
- if (scxml_transitions[j].on_transition != NULL) {
- if unlikely((err = scxml_transitions[j].on_transition(ctx,
- &scxml_states[i],
- ctx->event)) != SCXML_ERR_OK)
+ if (ctx->machine->transitions[j].on_transition != NULL) {
+ if unlikely((err = ctx->machine->transitions[j].on_transition(ctx,
+ &ctx->machine->states[i],
+ ctx->event)) != SCXML_ERR_OK)
return err;
}
}
}
// handle final states
- if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_FINAL) {
- if unlikely(scxml_states[i].ancestors[0] == 0x01) {
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_FINAL) {
+ if unlikely(ctx->machine->states[i].ancestors[0] == 0x01) {
ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;
} else {
// raise done event
- const scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];
+ const scxml_elem_donedata* donedata = &ctx->machine->donedata[0];
while(ELEM_DONEDATA_IS_SET(donedata)) {
if unlikely(donedata->source == i)
break;
donedata++;
}
- ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
+ ctx->raise_done_event(ctx, &ctx->machine->states[ctx->machine->states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
}
/**
@@ -816,20 +954,20 @@ ESTABLISH_ENTRY_SET:
* 4. If a state remains, not all children of a parallel are final
*/
for (j = 0; j < SCXML_NUMBER_STATES; j++) {
- if unlikely(SCXML_STATE_MASK(scxml_states[j].type) == SCXML_STATE_PARALLEL &&
- BIT_HAS(j, scxml_states[i].ancestors)) {
- bit_and_not(tmp_states, tmp_states, 2);
+ if unlikely(SCXML_STATE_MASK(ctx->machine->states[j].type) == SCXML_STATE_PARALLEL &&
+ BIT_HAS(j, ctx->machine->states[i].ancestors)) {
+ bit_clear_all(tmp_states, nr_states_bytes);
for (k = 0; k < SCXML_NUMBER_STATES; k++) {
- if unlikely(BIT_HAS(j, scxml_states[k].ancestors) && BIT_HAS(k, ctx->config)) {
- if (SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_FINAL) {
- bit_and_not(tmp_states, scxml_states[k].ancestors, 2);
+ if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {
+ if (SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_FINAL) {
+ bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes);
} else {
BIT_SET_AT(k, tmp_states);
}
}
}
- if unlikely(!bit_has_any(tmp_states, 2)) {
- ctx->raise_done_event(ctx, &scxml_states[j], NULL);
+ if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) {
+ ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL);
}
}
}