diff options
Diffstat (limited to 'test/src/test-c-machine.machine.c')
-rw-r--r-- | test/src/test-c-machine.machine.c | 400 |
1 files changed, 289 insertions, 111 deletions
diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c index d4c924d..3663eac 100644 --- a/test/src/test-c-machine.machine.c +++ b/test/src/test-c-machine.machine.c @@ -5,6 +5,9 @@ #define SET_BIT(idx, bitset) bitset[idx >> 3] |= (1 << (idx & 7)); #define CLEARBIT(idx, bitset) bitset[idx >> 3] &= (1 << (idx & 7)) ^ 0xFF; +#define likely(x) (__builtin_expect (!!(x), 1)) +#define unlikely(x) (__builtin_expect (!!(x), 0)) + // error return codes #define SCXML_ERR_OK 0 #define SCXML_ERR_IDLE 1 @@ -14,13 +17,16 @@ #define SCXML_ERR_EXEC_CONTENT 5 #define SCXML_ERR_INVALID_TARGET 6 #define SCXML_ERR_INVALID_TYPE 7 +#define SCXML_ERR_UNSUPPORTED 8 -#define SCXML_NUMBER_STATES 5 -#define SCXML_NUMBER_TRANSITIONS 4 +#define SCXML_MACHINE_NAME "" +#define SCXML_NUMBER_STATES 14 +#define SCXML_NUMBER_TRANSITIONS 10 #define SCXML_TRANS_SPONTANEOUS 0x01 #define SCXML_TRANS_TARGETLESS 0x02 #define SCXML_TRANS_INTERNAL 0x04 +#define SCXML_TRANS_HISTORY 0x08 #define SCXML_STATE_ATOMIC 0x01 #define SCXML_STATE_PARALLEL 0x02 @@ -37,6 +43,7 @@ #define SCXML_CTX_TRANSITION_FOUND 0x08 #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) @@ -48,6 +55,7 @@ typedef struct scxml_invoke scxml_invoke; typedef struct scxml_elem_send scxml_elem_send; typedef struct scxml_elem_param scxml_elem_param; typedef struct scxml_elem_data scxml_elem_data; +typedef struct scxml_elem_donedata scxml_elem_donedata; typedef struct scxml_elem_foreach scxml_elem_foreach; typedef void* (*dequeue_internal_cb_t)(const scxml_ctx* ctx); @@ -55,7 +63,7 @@ typedef void* (*dequeue_external_cb_t)(const scxml_ctx* ctx); typedef int (*is_enabled_cb_t)(const scxml_ctx* ctx, const scxml_transition* transition, const void* event); typedef int (*is_true_cb_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); +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 (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr); @@ -79,25 +87,26 @@ struct scxml_elem_data { struct scxml_state { const char* name; // eventual name + uint16_t source; // parent exec_content_t on_entry; // on entry handlers exec_content_t on_exit; // on exit handlers invoke_t invoke; // invocations - char children[1]; // all children - char completion[1]; // default completion - char ancestors[1]; // all ancestors + char children[2]; // all children + char completion[2]; // default completion + char ancestors[2]; // all ancestors const scxml_elem_data* data; uint8_t type; // atomic, parallel, compound, final, history }; struct scxml_transition { uint16_t source; - char target[1]; + char target[2]; const char* event; const char* condition; exec_content_t on_transition; uint8_t type; - char conflicts[1]; - char exit_set[1]; + char conflicts[2]; + char exit_set[2]; }; struct scxml_elem_foreach { @@ -112,6 +121,13 @@ struct scxml_elem_param { const char* location; }; +struct scxml_elem_donedata { + uint16_t source; + const char* content; + const char* contentexpr; + const scxml_elem_param* params; +}; + struct scxml_elem_invoke { const char* type; const char* typeexpr; @@ -124,6 +140,7 @@ struct scxml_elem_invoke { const scxml_elem_param* params; const exec_content_finalize_t* finalize; const char* content; + const char* contentexpr; void* user_data; }; @@ -140,6 +157,7 @@ struct scxml_elem_send { const char* delayexpr; const char* namelist; const char* content; + const char* contentexpr; const scxml_elem_param* params; void* user_data; }; @@ -147,10 +165,10 @@ struct scxml_elem_send { struct scxml_ctx { uint8_t flags; - char config[1]; - char history[1]; - char pending_invokes[1]; - char initialized_data[1]; + char config[2]; + char history[2]; + char pending_invokes[2]; + char initialized_data[2]; void* user_data; @@ -173,75 +191,162 @@ struct scxml_ctx { invoke_t invoke; }; -scxml_elem_data scxml_elem_datas[4] = { - { "Var1", NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL }, - { "Var2", NULL, "1", NULL }, +static scxml_elem_data scxml_elem_datas[2] = { + { "Var1", NULL, "0", NULL }, { NULL, NULL, NULL, NULL } }; -int s1_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static scxml_elem_send scxml_elem_sends[1] = { + { "timeout", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2s", NULL, NULL, NULL, NULL, NULL, NULL } +}; + +static int 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_assign != NULL) { + if ((ctx->exec_content_assign(ctx, "Var1", "Var1 + 1")) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static int s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + s0_on_entry_0(ctx, state, event); + return SCXML_ERR_OK; +} + +static int s011_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + int err = SCXML_ERR_OK; + if likely(ctx->exec_content_raise != NULL) { + if ((ctx->exec_content_raise(ctx, "entering.s011")) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static int s011_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + s011_on_entry_0(ctx, state, event); + return SCXML_ERR_OK; +} + +static int s012_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + int err = SCXML_ERR_OK; + if likely(ctx->exec_content_raise != NULL) { + if ((ctx->exec_content_raise(ctx, "entering.s012")) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static int s012_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + s012_on_entry_0(ctx, state, event); + return SCXML_ERR_OK; +} + +static int s021_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { int err = SCXML_ERR_OK; - if (ctx->exec_content_assign != NULL) { - if ((ctx->exec_content_assign(ctx, "Var1", "Var2")) != SCXML_ERR_OK) return err; + if likely(ctx->exec_content_raise != NULL) { + if ((ctx->exec_content_raise(ctx, "entering.s021")) != SCXML_ERR_OK) return err; } else { return SCXML_ERR_MISSING_CALLBACK; } return SCXML_ERR_OK; } -int s1_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { - s1_on_entry_0(ctx, state, event); +static int s021_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + s021_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int s022_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { int err = SCXML_ERR_OK; - if (ctx->exec_content_log != NULL) { - if ((ctx->exec_content_log(ctx, "Outcome", "'pass'")) != SCXML_ERR_OK) return err; + if likely(ctx->exec_content_raise != NULL) { + if ((ctx->exec_content_raise(ctx, "entering.s022")) != SCXML_ERR_OK) return err; } else { return SCXML_ERR_MISSING_CALLBACK; } return SCXML_ERR_OK; } -int pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int s022_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + s022_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) { + 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; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + 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); return SCXML_ERR_OK; } -int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { int err = SCXML_ERR_OK; - if (ctx->exec_content_log != NULL) { - if ((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != SCXML_ERR_OK) return err; + if likely(ctx->exec_content_log != NULL) { + if unlikely((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != SCXML_ERR_OK) return err; } else { return SCXML_ERR_MISSING_CALLBACK; } return SCXML_ERR_OK; } -int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { fail_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -scxml_state scxml_states[5] = { - { NULL, NULL, NULL, NULL, { 0x1e /* 01111, 1 2 3 4 */ }, { 0x02 /* 01000, 1 */ }, { 0x00 /* 00000, */ }, (const scxml_elem_data*)&scxml_elem_datas[0], SCXML_STATE_COMPOUND }, - { "s0", NULL, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_ATOMIC }, - { "s1", s1_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, (const scxml_elem_data*)&scxml_elem_datas[1], SCXML_STATE_ATOMIC }, - { "pass", pass_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_FINAL }, - { "fail", fail_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_FINAL } +static int s0_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_elem_sends[0])) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static scxml_state scxml_states[14] = { + { NULL, 0, NULL, NULL, NULL, { 0x02, 0x3c /* 01000000001111, 1 10 11 12 13 */ }, { 0x40, 0x00 /* 00000010000000, 6 */ }, { 0x00, 0x00 /* 00000000000000, */ }, (const scxml_elem_data*)&scxml_elem_datas[0], SCXML_STATE_COMPOUND }, + { "s0", 0, s0_on_entry, NULL, NULL, { 0x9c, 0x00 /* 00111001000000, 2 3 4 7 */ }, { 0x10, 0x00 /* 00001000000000, 4 */ }, { 0x01, 0x00 /* 10000000000000, 0 */ }, NULL, SCXML_STATE_COMPOUND }, + { "s0HistShallow", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x90, 0x00 /* 00001001000000, 4 7 */ }, { 0x03, 0x00 /* 11000000000000, 0 1 */ }, NULL, SCXML_STATE_HISTORY_SHALLOW }, + { "s0HistDeep", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0xf0, 0x03 /* 00001111110000, 4 5 6 7 8 9 */ }, { 0x03, 0x00 /* 11000000000000, 0 1 */ }, NULL, SCXML_STATE_HISTORY_DEEP }, + { "s01", 1, NULL, NULL, NULL, { 0x60, 0x00 /* 00000110000000, 5 6 */ }, { 0x20, 0x00 /* 00000100000000, 5 */ }, { 0x03, 0x00 /* 11000000000000, 0 1 */ }, NULL, SCXML_STATE_COMPOUND }, + { "s011", 4, s011_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x13, 0x00 /* 11001000000000, 0 1 4 */ }, NULL, SCXML_STATE_ATOMIC }, + { "s012", 4, s012_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x13, 0x00 /* 11001000000000, 0 1 4 */ }, NULL, SCXML_STATE_ATOMIC }, + { "s02", 1, NULL, NULL, NULL, { 0x00, 0x03 /* 00000000110000, 8 9 */ }, { 0x00, 0x01 /* 00000000100000, 8 */ }, { 0x03, 0x00 /* 11000000000000, 0 1 */ }, NULL, SCXML_STATE_COMPOUND }, + { "s021", 7, s021_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x83, 0x00 /* 11000001000000, 0 1 7 */ }, NULL, SCXML_STATE_ATOMIC }, + { "s022", 7, s022_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x83, 0x00 /* 11000001000000, 0 1 7 */ }, NULL, SCXML_STATE_ATOMIC }, + { "s1", 0, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x01, 0x00 /* 10000000000000, 0 */ }, NULL, SCXML_STATE_ATOMIC }, + { "s2", 0, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x01, 0x00 /* 10000000000000, 0 */ }, NULL, SCXML_STATE_ATOMIC }, + { "pass", 0, pass_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x01, 0x00 /* 10000000000000, 0 */ }, NULL, SCXML_STATE_FINAL }, + { "fail", 0, fail_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000000, */ }, { 0x00, 0x00 /* 00000000000000, */ }, { 0x01, 0x00 /* 10000000000000, 0 */ }, NULL, SCXML_STATE_FINAL } }; -scxml_transition scxml_transitions[4] = { - { 1, { 0x04 /* 00100 */ }, NULL, "typeof Var2 === 'undefined' ", NULL, SCXML_TRANS_SPONTANEOUS, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } }, - { 1, { 0x10 /* 00001 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } }, - { 2, { 0x08 /* 00010 */ }, NULL, "Var1===Var2", NULL, SCXML_TRANS_SPONTANEOUS, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } }, - { 2, { 0x10 /* 00001 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } } +static scxml_transition scxml_transitions[10] = { + { 2, { 0x80, 0x00 /* 00000001000000 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS | SCXML_TRANS_HISTORY, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 3, { 0x00, 0x02 /* 00000000010000 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS | SCXML_TRANS_HISTORY, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 1, { 0x00, 0x04 /* 00000000001000 */ }, "entering.s012", "Var1==1", s0_transition0_on_trans, 0, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 1, { 0x00, 0x08 /* 00000000000100 */ }, "entering.s012", "Var1==2", NULL, 0, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 1, { 0x00, 0x20 /* 00000000000001 */ }, "entering", "Var1==2", NULL, 0, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 1, { 0x00, 0x10 /* 00000000000010 */ }, "entering.s011", "Var1==3", NULL, 0, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 1, { 0x00, 0x20 /* 00000000000001 */ }, "entering", "Var1==3", NULL, 0, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 1, { 0x00, 0x20 /* 00000000000001 */ }, "timeout", NULL, NULL, 0, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 10, { 0x08, 0x00 /* 00010000000000 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } }, + { 11, { 0x04, 0x00 /* 00100000000000 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS, { 0xff, 0x03 /* 1111111111 */ }, { 0xfe, 0x3f /* 01111111111111 */ } } }; #ifdef SCXML_VERBOSE -void printStateNames(const char* a) { +static void printStateNames(const char* a) { const char* seperator = ""; for (int i = 0; i < SCXML_NUMBER_STATES; i++) { if (IS_SET(i, a)) { @@ -252,7 +357,7 @@ void printStateNames(const char* a) { printf("\n"); } -void printBitsetIndices(const char* a, size_t length) { +static void printBitsetIndices(const char* a, size_t length) { const char* seperator = ""; for (int i = 0; i < length; i++) { if (IS_SET(i, a)) { @@ -264,43 +369,50 @@ void printBitsetIndices(const char* a, size_t length) { } #endif -void bit_or(char* dest, const char* mask, size_t length) { - for (int i = 0; i < length; ++i) { - dest[i] |= mask[i]; - } +static void bit_or(char* dest, const char* mask, size_t i) { + do { + dest[i - 1] |= mask[i - 1]; + } while(--i); } -void bit_copy(char* dest, const char* source, size_t length) { - for (int i = 0; i < length; ++i) { - dest[i] = source[i]; - } +static void bit_copy(char* dest, const char* source, size_t i) { + do { + dest[i - 1] = source[i - 1]; + } while(--i); } -int bit_has_and(const char* a, const char* b, size_t length) { - for (int i = 0; i < length; ++i) { - if (a[i] & b[i]) +static int bit_has_and(const char* a, const char* b, size_t i) { + do { + if (a[i - 1] & b[i - 1]) return true; - } + } while(--i); return false; } -void bit_and_not(char* dest, const char* mask, size_t length) { - for (int i = 0; i < length; ++i) { - dest[i] &= ~mask[i]; - } +static void bit_and_not(char* dest, const char* mask, size_t i) { + do { + dest[i - 1] &= ~mask[i - 1]; + } while(--i); +} + +static void bit_and(char* dest, const char* mask, size_t i) { + do { + dest[i - 1] &= mask[i - 1]; + } while(--i); } -int bit_any_set(const char* a, size_t length) { - for (int i = 0; i < length; ++i) { - if (a[i] > 0) +static int bit_any_set(const char* a, size_t i) { + do { + if (a[i - 1] > 0) return true; - } + } while(--i); return false; } -int scxml_step(scxml_ctx* ctx) { +static int scxml_step(scxml_ctx* ctx) { #ifdef SCXML_VERBOSE + printf("Config: "); printStateNames(ctx->config); #endif @@ -311,15 +423,15 @@ MACRO_STEP: return SCXML_ERR_DONE; int err = SCXML_ERR_OK; - char conflicts[1] = {0}; - char target_set[1] = {0}; - char exit_set[1] = {0}; - char trans_set[1] = {0}; - char entry_set[1] = {0}; + char conflicts[2] = {0, 0}; + char target_set[2] = {0, 0}; + char exit_set[2] = {0, 0}; + char trans_set[2] = {0, 0}; + char entry_set[2] = {0, 0}; void* event; - if (ctx->flags == SCXML_CTX_PRISTINE) { - bit_or(target_set, scxml_states[0].completion, 1); + if unlikely(ctx->flags == SCXML_CTX_PRISTINE) { + bit_or(target_set, scxml_states[0].completion, 2); ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED; goto COMPLETE_CONFIG; } @@ -337,6 +449,10 @@ MACRO_STEP: SELECT_TRANSITIONS: for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) { + // never select history or initial transitions automatically + if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_HISTORY)) + continue; + // is the transition active? if (IS_SET(scxml_transitions[i].source, ctx->config)) { // is it non-conflicting? @@ -347,46 +463,69 @@ SELECT_TRANSITIONS: ctx->flags |= SCXML_CTX_TRANSITION_FOUND; // transitions that are pre-empted - bit_or(conflicts, scxml_transitions[i].conflicts, 1); + bit_or(conflicts, scxml_transitions[i].conflicts, 2); // states that are directly targeted (resolve as entry-set later) - bit_or(target_set, scxml_transitions[i].target, 1); + bit_or(target_set, scxml_transitions[i].target, 2); // states that will be left - bit_or(exit_set, scxml_transitions[i].exit_set, 1); + bit_or(exit_set, scxml_transitions[i].exit_set, 2); SET_BIT(i, trans_set); } } } } + bit_and(exit_set, ctx->config, 2); if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) { ctx->flags |= SCXML_CTX_SPONTANEOUS; } else { ctx->flags &= ~SCXML_CTX_SPONTANEOUS; - goto MACRO_STEP; + // goto MACRO_STEP; + return SCXML_ERR_OK; } +#ifdef SCXML_VERBOSE + printf("Targets: "); + printStateNames(target_set); +#endif + REMEMBER_HISTORY: - // are my ancestors in the exit set? for (int i = 0; i < SCXML_NUMBER_STATES; i++) { - if (IS_SET(i, ctx->config) && bit_has_and(exit_set, scxml_states[i].ancestors, 1)) { - SET_BIT(i, ctx->history); + if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) { + // a history state whose parent is about to be exited + if unlikely(IS_SET(scxml_states[i].source, exit_set)) { + char history[2] = {0, 0}; + bit_copy(history, scxml_states[i].completion, 2); + + // set those states who were enabled + bit_and(history, ctx->config, 2); + + // clear current history with completion mask + bit_and_not(ctx->history, scxml_states[i].completion, 2); + + // set history + bit_or(ctx->history, history, 2); + } } } - #ifdef SCXML_VERBOSE printf("Exiting: "); printStateNames(exit_set); #endif +#ifdef SCXML_VERBOSE + printf("History: "); + printStateNames(ctx->history); +#endif + EXIT_STATES: for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) { if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) { // call all on exit handlers if (scxml_states[i].on_exit != NULL) { - if((err = scxml_states[i].on_exit(ctx, &scxml_states[i], event)) != SCXML_ERR_OK) + if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], event)) != SCXML_ERR_OK) return err; } CLEARBIT(i, ctx->config); @@ -395,12 +534,12 @@ EXIT_STATES: COMPLETE_CONFIG: // calculate new entry set - bit_copy(entry_set, target_set, 1); + bit_copy(entry_set, target_set, 2); // iterate for ancestors for (int i = 0; i < SCXML_NUMBER_STATES; i++) { if (IS_SET(i, entry_set)) { - bit_or(entry_set, scxml_states[i].ancestors, 1); + bit_or(entry_set, scxml_states[i].ancestors, 2); } } @@ -410,7 +549,27 @@ ADD_DESCENDANTS: if (IS_SET(i, entry_set)) { switch (scxml_states[i].type) { case SCXML_STATE_PARALLEL: { - bit_or(entry_set, scxml_states[i].completion, 1); + bit_or(entry_set, scxml_states[i].completion, 2); + break; + } + case SCXML_STATE_HISTORY_SHALLOW: + case SCXML_STATE_HISTORY_DEEP: { + char history_targets[2] = {0, 0}; + if (!bit_has_and(scxml_states[i].completion, ctx->history, 2)) { + // nothing set for history, look for a default transition or enter parents completion + for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) { + if unlikely(scxml_transitions[j].source == i) { + bit_or(entry_set, scxml_transitions[j].target, 2); + SET_BIT(j, trans_set); + break; + } + } + // TODO: enter parents default completion here + } else { + bit_copy(history_targets, scxml_states[i].completion, 2); + bit_and(history_targets, ctx->history, 2); + bit_or(entry_set, history_targets, 2); + } break; } case SCXML_STATE_INITIAL: { @@ -418,16 +577,18 @@ ADD_DESCENDANTS: if (scxml_transitions[j].source == i) { SET_BIT(j, trans_set); CLEARBIT(i, entry_set); - bit_or(entry_set, scxml_transitions[j].target, 1); + bit_or(entry_set, scxml_transitions[j].target, 2); // one target may have been above, reestablish completion - goto ADD_DESCENDANTS; + // goto ADD_DESCENDANTS; // initial will have to be first! } } 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, 1)) { - bit_or(entry_set, scxml_states[i].completion, 1); + if (!bit_has_and(entry_set, scxml_states[i].children, 2) && + !bit_has_and(ctx->config, scxml_states[i].children, 2)) + { + bit_or(entry_set, scxml_states[i].completion, 2); } break; } @@ -437,15 +598,15 @@ ADD_DESCENDANTS: #ifdef SCXML_VERBOSE printf("Transitions: "); - printBitsetIndices(trans_set, sizeof(char) * 8 * 1); + printBitsetIndices(trans_set, sizeof(char) * 8 * 2); #endif TAKE_TRANSITIONS: for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) { - if (IS_SET(i, trans_set)) { + if (IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY) == 0) { // call executable content in transition if (scxml_transitions[i].on_transition != NULL) { - if((err = scxml_transitions[i].on_transition(ctx, + if unlikely((err = scxml_transitions[i].on_transition(ctx, &scxml_states[scxml_transitions[i].source], event)) != SCXML_ERR_OK) return err; @@ -461,39 +622,43 @@ TAKE_TRANSITIONS: ENTER_STATES: for (int i = 0; i < SCXML_NUMBER_STATES; i++) { if (IS_SET(i, entry_set) && !IS_SET(i, ctx->config)) { + // these are no proper states + if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_DEEP || + scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || + scxml_states[i].type == SCXML_STATE_INITIAL) + continue; + SET_BIT(i, ctx->config); - if (scxml_states[i].on_entry != NULL) { - if((err = scxml_states[i].on_entry(ctx, &scxml_states[i], event)) != SCXML_ERR_OK) - return err; - } // initialize data - if(!IS_SET(i, ctx->initialized_data)) { - if (scxml_states[i].data != NULL && ctx->exec_content_init != NULL) { + if (!IS_SET(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); } SET_BIT(i, ctx->initialized_data); } + if (scxml_states[i].on_entry != NULL) { + if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], event)) != SCXML_ERR_OK) + return err; + } + // handle final states - if (scxml_states[i].type == SCXML_STATE_FINAL) { - if (scxml_states[i].ancestors[0] == 0x01) { + if unlikely(scxml_states[i].type == SCXML_STATE_FINAL) { + if unlikely(scxml_states[i].ancestors[0] == 0x01) { ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL; } else { // raise done event size_t parent = 0; - for (int j = 0; j < SCXML_NUMBER_STATES; j++) { + for (int j = SCXML_NUMBER_STATES - 1; j >= 0; j--) { // we could trade runtime for memory here by saving the parent index - if (!IS_SET(j, scxml_states[i].ancestors)) { - if (parent != 0) { - break; - } - continue; - } else { - parent = j; + if unlikely(IS_SET(j, scxml_states[i].ancestors)) { + parent = j; + break; } } - ctx->raise_done_event(ctx, &scxml_states[parent]); + // is this raised for toplevel final as well? + ctx->raise_done_event(ctx, &scxml_states[parent], NULL); } /** @@ -504,11 +669,11 @@ ENTER_STATES: * 4. If a state remains, not all children of a parallel are final */ for (int j = 0; j < SCXML_NUMBER_STATES; j++) { - if (scxml_states[j].type == SCXML_STATE_PARALLEL) { + if unlikely(scxml_states[j].type == SCXML_STATE_PARALLEL) { char parallel_children[2] = {0, 0}; size_t parallel = j; for (int k = 0; k < SCXML_NUMBER_STATES; k++) { - if (IS_SET(parallel, scxml_states[k].ancestors) && IS_SET(k, ctx->config)) { + if unlikely(IS_SET(parallel, scxml_states[k].ancestors) && IS_SET(k, ctx->config)) { if (scxml_states[k].type == SCXML_STATE_FINAL) { bit_and_not(parallel_children, scxml_states[k].ancestors, 2); } else { @@ -516,8 +681,8 @@ ENTER_STATES: } } } - if (!bit_any_set(parallel_children, 2)) { - ctx->raise_done_event(ctx, &scxml_states[parallel]); + if unlikely(!bit_any_set(parallel_children, 2)) { + ctx->raise_done_event(ctx, &scxml_states[parallel], NULL); } } } @@ -527,6 +692,19 @@ ENTER_STATES: } } +HISTORY_TRANSITIONS: + for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) { + if unlikely(IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY)) { + // 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], + event)) != SCXML_ERR_OK) + return err; + } + } + } + return SCXML_ERR_OK; } |