summaryrefslogtreecommitdiffstats
path: root/test/src/test-c-machine.machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/src/test-c-machine.machine.c')
-rw-r--r--test/src/test-c-machine.machine.c400
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;
}