Skip to content

Commit

Permalink
forced transitions re-enabled. put dsl in readme.
Browse files Browse the repository at this point in the history
  • Loading branch information
StoneCypher committed Aug 13, 2017
1 parent c8ac664 commit f8c96eb
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 200 deletions.
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -22,6 +22,12 @@ A Javascript state machine with a simple API. Well tested, and typed with Flowt
## TL;DR
Specify finite state machines with a brief syntax. Run them. Derive charts from them. Save and load states. Make factories. Impress friends and loved ones. Cure corns and callouses.

```javascript
const traffic_light = sm` Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red; `;
```

You could also write that as a piece of data, for when you're generating. That's ... a bit more verbose.

```javascript
const traffic_light = new jssm.machine({

Expand All @@ -34,7 +40,11 @@ const traffic_light = new jssm.machine({
]

});
```

In either case, you'll build an executable state machine.

```
// use with actions
traffic_light.state(); // 'Red'
traffic_light.action('Proceed'); // true
Expand Down
65 changes: 41 additions & 24 deletions dist/jssm.es5.cjs.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/jssm.es5.cjs.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/lib/index.html
Expand Up @@ -2,7 +2,7 @@
<html>
<head>
<meta charset='utf-8' />
<title>jssm 4.1.18 | Documentation</title>
<title>jssm 4.2.0 | Documentation</title>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<link href='assets/bass.css' type='text/css' rel='stylesheet' />
<link href='assets/style.css' type='text/css' rel='stylesheet' />
Expand All @@ -14,7 +14,7 @@
<div class='fixed xs-hide fix-3 overflow-auto max-height-100'>
<div class='py1 px2'>
<h3 class='mb0 no-anchor'>jssm</h3>
<div class='mb1'><code>4.1.18</code></div>
<div class='mb1'><code>4.2.0</code></div>
<input
placeholder='Filter'
id='filter-input'
Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "jssm",
"version": "4.1.18",
"version": "4.2.0",
"engines": {
"node": ">=6.0.0"
},
Expand Down
5 changes: 2 additions & 3 deletions src/js/jssm-types.js
Expand Up @@ -92,9 +92,8 @@ type JssmTransition<NT, DT> = {
action? : NT,
check? : JssmTransitionPermitterMaybeArray<NT, DT>, // validate this edge's transition; usually about data
probability? : number, // for stoch modelling, would like to constrain to [0..1], dunno how
common? : boolean,
forced_only? : boolean,
main_path? : boolean
forced_only : boolean,
main_path : boolean
};

type JssmTransitions<NT, DT> = Array< JssmTransition<NT, DT> >;
Expand Down
38 changes: 25 additions & 13 deletions src/js/jssm.js
Expand Up @@ -124,18 +124,25 @@ function compile_rule_transition_step<mNT, mDT>(
uFrom.map( (f:mNT) => {
uTo.map( (t:mNT) => {

const rk : string = arrow_right_kind(this_se.kind),
lk : string = arrow_left_kind(this_se.kind);

const right : JssmTransition<mNT, mDT> = {
from : f,
to : t,
kind : arrow_right_kind(this_se.kind)
from : f,
to : t,
kind : rk,
forced_only : rk === 'forced',
main_path : rk === 'main'
};

if (right.kind !== 'none') { edges.push(right); }

const left : JssmTransition<mNT, mDT> = {
from : t,
to : f,
kind : arrow_left_kind(this_se.kind)
from : t,
to : f,
kind : lk,
forced_only : lk === 'forced',
main_path : lk === 'main'
};

if (left.kind !== 'none') { edges.push(right); }
Expand Down Expand Up @@ -605,7 +612,6 @@ class Machine<mNT, mDT> {
}
}

/* whargarbl reintroduce after valid_force_transition is re-enabled
// can leave machine in inconsistent state. generally do not use
force_transition(newState : mNT, newData? : mDT) : boolean {
// todo whargarbl implement hooks
Expand All @@ -618,7 +624,6 @@ class Machine<mNT, mDT> {
return false;
}
}
*/



Expand All @@ -644,14 +649,21 @@ class Machine<mNT, mDT> {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
return (this.lookup_transition_for(this.state(), newState) !== undefined);
const transition_for : ?JssmTransition<mNT, mDT> = this.lookup_transition_for(this.state(), newState);

if (!(transition_for)) { return false; }
if (transition_for.forced_only) { return false; }

return true;

}

/* todo whargarbl re-enable force_transition/1 after implementing this
valid_force_transition(newState : mNT, newData? : mDT) : boolean {
return false; // major todo whargarbl
valid_force_transition(newState : mNT, _newData? : mDT) : boolean { // todo comeback unignore newData
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
return (this.lookup_transition_for(this.state(), newState) !== undefined);
}
*/


}
Expand Down
18 changes: 15 additions & 3 deletions src/js/tests/array_transitions.js
Expand Up @@ -11,7 +11,9 @@ const jssm = require('../../../build/jssm.es5.js');

describe('array on left', async it => {

const aLeft = [{"from":"a","to":"d","kind":"legal"},{"from":"b","to":"d","kind":"legal"},{"from":"c","to":"d","kind":"legal"}];
const aLeft = [{main_path: false,forced_only: false,"from":"a","to":"d","kind":"legal"},
{main_path: false,forced_only: false,"from":"b","to":"d","kind":"legal"},
{main_path: false,forced_only: false,"from":"c","to":"d","kind":"legal"}];

it('[a b c]->d;', t => t.deepEqual(aLeft, jssm.compile(jssm.parse('[a b c]->d;')).transitions ));

Expand All @@ -23,7 +25,9 @@ describe('array on left', async it => {

describe('array on right', async it => {

const aRight = [{"from":"a","to":"b","kind":"legal"},{"from":"a","to":"c","kind":"legal"},{"from":"a","to":"d","kind":"legal"}];
const aRight = [{main_path: false,forced_only: false,"from":"a","to":"b","kind":"legal"},
{main_path: false,forced_only: false,"from":"a","to":"c","kind":"legal"},
{main_path: false,forced_only: false,"from":"a","to":"d","kind":"legal"}];

it('a->[b c d];', t => t.deepEqual(aRight, jssm.compile(jssm.parse('a->[b c d];')).transitions ));

Expand All @@ -35,7 +39,15 @@ describe('array on right', async it => {

describe('array on both sides', async it => {

const aBoth = [{"from":"a","to":"x","kind":"legal"},{"from":"a","to":"y","kind":"legal"},{"from":"a","to":"z","kind":"legal"},{"from":"b","to":"x","kind":"legal"},{"from":"b","to":"y","kind":"legal"},{"from":"b","to":"z","kind":"legal"},{"from":"c","to":"x","kind":"legal"},{"from":"c","to":"y","kind":"legal"},{"from":"c","to":"z","kind":"legal"}];
const aBoth = [{main_path: false,forced_only: false,"from":"a","to":"x","kind":"legal"},
{main_path: false,forced_only: false,"from":"a","to":"y","kind":"legal"},
{main_path: false,forced_only: false,"from":"a","to":"z","kind":"legal"},
{main_path: false,forced_only: false,"from":"b","to":"x","kind":"legal"},
{main_path: false,forced_only: false,"from":"b","to":"y","kind":"legal"},
{main_path: false,forced_only: false,"from":"b","to":"z","kind":"legal"},
{main_path: false,forced_only: false,"from":"c","to":"x","kind":"legal"},
{main_path: false,forced_only: false,"from":"c","to":"y","kind":"legal"},
{main_path: false,forced_only: false,"from":"c","to":"z","kind":"legal"}];

it('[a b c]->[x y z];', t => t.deepEqual(aBoth, jssm.compile(jssm.parse('[a b c]->[x y z];')).transitions ));

Expand Down
29 changes: 29 additions & 0 deletions src/js/tests/forced transitions.js
@@ -0,0 +1,29 @@

/* eslint-disable max-len */

import {describe} from 'ava-spec';

const jssm = require('../../../build/jssm.es5.js'),
sm = jssm.sm;





describe('reject and accept correctly', async it => {

const machine = sm` a ~> b -> c; `;

it('starts in a', t => t.is('a', machine.state() ));
it('rejects transition to b', t => t.is(false, machine.transition('b') ));
it('still in a', t => t.is('a', machine.state() ));
it('rejects transition to c', t => t.is(false, machine.transition('c') ));
it('still in a', t => t.is('a', machine.state() ));
it('rejects forced transition to c', t => t.is(false, machine.force_transition('c') ));
it('still in a', t => t.is('a', machine.state() ));
it('accepts forced transition to b', t => t.is(true, machine.force_transition('b') ));
it('now in b', t => t.is('b', machine.state() ));
it('accepts transition to c', t => t.is(true, machine.transition('c') ));
it('now in c', t => t.is('c', machine.state() ));

});

0 comments on commit f8c96eb

Please sign in to comment.