Skip to content

Commit

Permalink
Merge pull request #447 from StoneCypher/HookAllTransitions
Browse files Browse the repository at this point in the history
Hook all transitions
  • Loading branch information
StoneCypher committed May 8, 2022
2 parents c1200b9 + ec455c7 commit 191ce28
Show file tree
Hide file tree
Showing 21 changed files with 667 additions and 428 deletions.
1 change: 0 additions & 1 deletion .npmignore
Expand Up @@ -68,4 +68,3 @@ jest-stoch.config.js
rollup.config.iife.js
rollup.config.js
tsconfig.json
dist/jssm.es5.iife.js
14 changes: 7 additions & 7 deletions benchmark/results/general.chart.html
Expand Up @@ -28,7 +28,7 @@
</head>
<body>
<div class="container">
<canvas id="chart1651986178121" width="16" height="9"></canvas>
<canvas id="chart1651997014689" width="16" height="9"></canvas>
</div>
<script>
const format = (num) => {
Expand All @@ -51,18 +51,18 @@
chunked.map((chunk) => chunk.join('')).join(' ') + fractionStr
)
}
const ctx1651986178121 = document
.getElementById('chart1651986178121')
const ctx1651997014689 = document
.getElementById('chart1651997014689')
.getContext('2d')
const chart1651986178121 = new Chart(ctx1651986178121, {
const chart1651997014689 = new Chart(ctx1651997014689, {
type: 'bar',
data: {
labels: ["Blind cycle a traffic light 500 times by transition","Blind cycle a hooked traffic light 500 times by transition","Blind cycle a traffic light 500 times by action","Blind cycle a hooked traffic light 500 times by action"],
datasets: [
{
data: [18328,1666,14304,1325],
backgroundColor: ["hsl(120, 85%, 55%)","hsl(10.908000000000005, 85%, 55%)","hsl(93.64799999999998, 85%, 55%)","hsl(8.676000000000005, 85%, 55%)"],
borderColor: ["hsl(120, 85%, 55%)","hsl(10.908000000000005, 85%, 55%)","hsl(93.64799999999998, 85%, 55%)","hsl(8.676000000000005, 85%, 55%)"],
data: [21012,1747,14556,1488],
backgroundColor: ["hsl(120, 85%, 55%)","hsl(9.972000000000003, 85%, 55%)","hsl(83.124, 85%, 55%)","hsl(8.495999999999999, 85%, 55%)"],
borderColor: ["hsl(120, 85%, 55%)","hsl(9.972000000000003, 85%, 55%)","hsl(83.124, 85%, 55%)","hsl(8.495999999999999, 85%, 55%)"],
borderWidth: 2,
},
],
Expand Down
24 changes: 12 additions & 12 deletions benchmark/results/general.json
@@ -1,31 +1,31 @@
{
"name": "General performance suite",
"date": "2022-05-08T05:02:58.121Z",
"date": "2022-05-08T08:03:34.689Z",
"version": "1.1.0",
"results": [
{
"name": "Blind cycle a traffic light 500 times by transition",
"ops": 18328,
"margin": 6.88,
"ops": 21012,
"margin": 1.45,
"percentSlower": 0
},
{
"name": "Blind cycle a hooked traffic light 500 times by transition",
"ops": 1666,
"margin": 3.01,
"percentSlower": 90.91
"ops": 1747,
"margin": 0.62,
"percentSlower": 91.69
},
{
"name": "Blind cycle a traffic light 500 times by action",
"ops": 14304,
"margin": 1.01,
"percentSlower": 21.96
"ops": 14556,
"margin": 0.93,
"percentSlower": 30.73
},
{
"name": "Blind cycle a hooked traffic light 500 times by action",
"ops": 1325,
"margin": 5.16,
"percentSlower": 92.77
"ops": 1488,
"margin": 1.41,
"percentSlower": 92.92
}
],
"fastest": {
Expand Down
4 changes: 4 additions & 0 deletions dist/es6/jssm.d.ts
Expand Up @@ -38,8 +38,11 @@ declare class Machine<mDT> {
_theme: FslTheme;
_flow: FslDirection;
_has_hooks: boolean;
_has_basic_hooks: boolean;
_has_named_hooks: boolean;
_hooks: Map<string, Function>;
_named_hooks: Map<string, Function>;
_any_transition_hook: HookHandler | undefined;
constructor({ start_states, complete, transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, fsl_version, dot_preamble, arrange_declaration, arrange_start_declaration, arrange_end_declaration, theme, flow, graph_layout }: JssmGenericConfig<mDT>);
_new_state(state_config: JssmGenericState): StateType;
state(): StateType;
Expand Down Expand Up @@ -92,6 +95,7 @@ declare class Machine<mDT> {
set_hook(HookDesc: HookDescription): void;
hook(from: string, to: string, handler: HookHandler): Machine<mDT>;
hook_action(from: string, to: string, action: string, handler: HookHandler): Machine<mDT>;
hook_any_transition(handler: HookHandler): Machine<mDT>;
action(name: StateType, newData?: mDT): boolean;
transition(newState: StateType, newData?: mDT): boolean;
force_transition(newState: StateType, newData?: mDT): boolean;
Expand Down
38 changes: 32 additions & 6 deletions dist/es6/jssm.js
Expand Up @@ -152,13 +152,13 @@ function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
// if ((wasIndex !== undefined) && (wasList === undefined)) { throw new TypeError("Must be in a list if transition has an index"); }
/*
if (typeof edge.to === 'object') {
if (edge.to.key === 'cycle') {
if (wasList === undefined) { throw "Must have a waslist if a to is type cycle"; }
const nextIndex = wrapBy(wasIndex, edge.to.value, wasList.length);
edge.to = wasList[nextIndex];
}
}
*/
const action = isRight ? 'r_action' : 'l_action', probability = isRight ? 'r_probability' : 'l_probability';
Expand Down Expand Up @@ -346,8 +346,11 @@ class Machine {
this._flow = flow;
this._graph_layout = graph_layout;
this._has_hooks = false;
this._has_basic_hooks = false;
this._has_named_hooks = false;
this._hooks = new Map();
this._named_hooks = new Map();
this._any_transition_hook = undefined;
if (state_declaration) {
state_declaration.map((state_decl) => {
if (this._state_declarations.has(state_decl.state)) { // no repeats
Expand Down Expand Up @@ -456,7 +459,7 @@ class Machine {
}
/* whargarbl todo major
when we reimplement this, reintroduce this change to the is_final call
is_changing(): boolean {
return true; // todo whargarbl
}
Expand Down Expand Up @@ -655,7 +658,8 @@ class Machine {
return Array.from(ra_base.values())
.map((edgeId) => this._edges[edgeId])
.filter((o) => o.from === whichState)
.map((filtered) => ({ action: filtered.action,
.map((filtered) => ({
action: filtered.action,
probability: filtered.probability
}));
}
Expand Down Expand Up @@ -709,6 +713,10 @@ class Machine {
this._named_hooks.set(named_hook_name(HookDesc.from, HookDesc.to, HookDesc.action), HookDesc.handler);
this._has_hooks = true;
break;
case 'any transition':
this._any_transition_hook = HookDesc.handler;
this._has_hooks = true;
break;
// case 'entry':
// console.log('TODO: Should add entry hook here');
// throw 'TODO: Should add entry hook here';
Expand All @@ -730,6 +738,11 @@ class Machine {
this.set_hook({ kind: 'named', from, to, action, handler });
return this;
}
hook_any_transition(handler) {
// TODO: should this throw if setting the hook fails, or ignore it and continue?
this.set_hook({ kind: 'any transition', handler });
return this;
}
// remove_hook(HookDesc: HookDescription) {
// throw 'TODO: Should remove hook here';
// }
Expand All @@ -741,6 +754,11 @@ class Machine {
const edge = this.current_action_edge_for(name);
if (this._has_hooks) {
let hook_permits = undefined;
if (this._any_transition_hook !== undefined) {
if (this._any_transition_hook() === false) {
return false;
}
}
const nhn = named_hook_name(this._state, edge.to, name), maybe_hook = this._named_hooks.get(nhn);
if (maybe_hook === undefined) {
hook_permits = true;
Expand All @@ -766,12 +784,16 @@ class Machine {
}
}
transition(newState, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_transition(newState, newData)) {
if (this._has_hooks) {
let hook_permits = undefined;
if (this._any_transition_hook !== undefined) {
if (this._any_transition_hook() === false) {
return false;
}
}
const hn = hook_name(this._state, newState), maybe_hook = this._hooks.get(hn);
if (maybe_hook === undefined) {
hook_permits = true;
Expand All @@ -798,12 +820,16 @@ class Machine {
}
// can leave machine in inconsistent state. generally do not use
force_transition(newState, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_force_transition(newState, newData)) {
if (this._has_hooks) {
let hook_permits = undefined;
if (this._any_transition_hook !== undefined) {
if (this._any_transition_hook() === false) {
return false;
}
}
const hn = hook_name(this._state, newState), maybe_hook = this._hooks.get(hn);
if (maybe_hook === undefined) {
hook_permits = true;
Expand Down
6 changes: 5 additions & 1 deletion dist/es6/jssm_types.d.ts
Expand Up @@ -162,6 +162,10 @@ declare type HookDescriptionWithAction = {
action: string;
handler: HookHandler;
};
declare type AnyTransitionHook = {
kind: 'any transition';
handler: HookHandler;
};
declare type EntryHook = {
kind: 'entry';
to: string;
Expand All @@ -172,5 +176,5 @@ declare type ExitHook = {
from: string;
handler: HookHandler;
};
declare type HookDescription = BasicHookDescription | HookDescriptionWithAction | EntryHook | ExitHook;
declare type HookDescription = BasicHookDescription | HookDescriptionWithAction | AnyTransitionHook | EntryHook | ExitHook;
export { JssmColor, JssmTransition, JssmTransitions, JssmTransitionList, JssmTransitionRule, JssmArrow, JssmArrowKind, JssmArrowDirection, JssmGenericConfig, JssmGenericState, JssmGenericMachine, JssmParseTree, JssmCompileSe, JssmCompileSeStart, JssmCompileRule, JssmPermitted, JssmPermittedOpt, JssmResult, JssmStateDeclaration, JssmStateDeclarationRule, JssmLayout, JssmParseFunctionType, JssmMachineInternalState, FslDirection, FslTheme, HookDescription, HookHandler };
2 changes: 1 addition & 1 deletion dist/es6/version.js
@@ -1,2 +1,2 @@
const version = "5.48.0";
const version = "5.49.0";
export { version };
2 changes: 1 addition & 1 deletion dist/jssm.es5.cjs.js

Large diffs are not rendered by default.

40 changes: 33 additions & 7 deletions dist/jssm.es5.cjs.nonmin.js
Expand Up @@ -15887,7 +15887,7 @@ function peg$parse(input, options) {
}
}

const version = "5.48.0";
const version = "5.49.0";

// whargarbl lots of these return arrays could/should be sets
/* eslint-disable complexity */
Expand Down Expand Up @@ -16039,13 +16039,13 @@ function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
// if ((wasIndex !== undefined) && (wasList === undefined)) { throw new TypeError("Must be in a list if transition has an index"); }
/*
if (typeof edge.to === 'object') {

if (edge.to.key === 'cycle') {
if (wasList === undefined) { throw "Must have a waslist if a to is type cycle"; }
const nextIndex = wrapBy(wasIndex, edge.to.value, wasList.length);
edge.to = wasList[nextIndex];
}

}
*/
const action = isRight ? 'r_action' : 'l_action', probability = isRight ? 'r_probability' : 'l_probability';
Expand Down Expand Up @@ -16233,8 +16233,11 @@ class Machine {
this._flow = flow;
this._graph_layout = graph_layout;
this._has_hooks = false;
this._has_basic_hooks = false;
this._has_named_hooks = false;
this._hooks = new Map();
this._named_hooks = new Map();
this._any_transition_hook = undefined;
if (state_declaration) {
state_declaration.map((state_decl) => {
if (this._state_declarations.has(state_decl.state)) { // no repeats
Expand Down Expand Up @@ -16343,7 +16346,7 @@ class Machine {
}
/* whargarbl todo major
when we reimplement this, reintroduce this change to the is_final call

is_changing(): boolean {
return true; // todo whargarbl
}
Expand Down Expand Up @@ -16542,7 +16545,8 @@ class Machine {
return Array.from(ra_base.values())
.map((edgeId) => this._edges[edgeId])
.filter((o) => o.from === whichState)
.map((filtered) => ({ action: filtered.action,
.map((filtered) => ({
action: filtered.action,
probability: filtered.probability
}));
}
Expand Down Expand Up @@ -16596,6 +16600,10 @@ class Machine {
this._named_hooks.set(named_hook_name(HookDesc.from, HookDesc.to, HookDesc.action), HookDesc.handler);
this._has_hooks = true;
break;
case 'any transition':
this._any_transition_hook = HookDesc.handler;
this._has_hooks = true;
break;
// case 'entry':
// console.log('TODO: Should add entry hook here');
// throw 'TODO: Should add entry hook here';
Expand All @@ -16617,6 +16625,11 @@ class Machine {
this.set_hook({ kind: 'named', from, to, action, handler });
return this;
}
hook_any_transition(handler) {
// TODO: should this throw if setting the hook fails, or ignore it and continue?
this.set_hook({ kind: 'any transition', handler });
return this;
}
// remove_hook(HookDesc: HookDescription) {
// throw 'TODO: Should remove hook here';
// }
Expand All @@ -16628,6 +16641,11 @@ class Machine {
const edge = this.current_action_edge_for(name);
if (this._has_hooks) {
let hook_permits = undefined;
if (this._any_transition_hook !== undefined) {
if (this._any_transition_hook() === false) {
return false;
}
}
const nhn = named_hook_name(this._state, edge.to, name), maybe_hook = this._named_hooks.get(nhn);
if (maybe_hook === undefined) {
hook_permits = true;
Expand All @@ -16653,12 +16671,16 @@ class Machine {
}
}
transition(newState, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_transition(newState, newData)) {
if (this._has_hooks) {
let hook_permits = undefined;
if (this._any_transition_hook !== undefined) {
if (this._any_transition_hook() === false) {
return false;
}
}
const hn = hook_name(this._state, newState), maybe_hook = this._hooks.get(hn);
if (maybe_hook === undefined) {
hook_permits = true;
Expand All @@ -16685,12 +16707,16 @@ class Machine {
}
// can leave machine in inconsistent state. generally do not use
force_transition(newState, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_force_transition(newState, newData)) {
if (this._has_hooks) {
let hook_permits = undefined;
if (this._any_transition_hook !== undefined) {
if (this._any_transition_hook() === false) {
return false;
}
}
const hn = hook_name(this._state, newState), maybe_hook = this._hooks.get(hn);
if (maybe_hook === undefined) {
hook_permits = true;
Expand Down
2 changes: 1 addition & 1 deletion dist/jssm.es5.iife.js

Large diffs are not rendered by default.

0 comments on commit 191ce28

Please sign in to comment.