As we all know, the Generator
object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.
And according to this feature, we can describe a state machine like what mentioned here:
E ; L
L: -> 0 ---> 1 ---> 2 ---> 3
| ^
| ε |
----------------------
function* machine() {
// the start of state
let state = 0;
let action;
// simple prev checker
const _next = (prev, val) => state === prev ? val : state;
for (;;) {
/**
* get the initial state, and read "action"
* passed by `Generator.prototype.next()` each time
*/
action = yield state;
state = _next.apply(0, ({'E': [0, 1], ';': [1, 2], 'L': [2, 3], 'ε': [0, 3]})[action]);
// the end of state
if (state === 3) return state;
}
}
const generator = machine();
generator.next(); // need to call next at first for initializing states
generator.next('E'); // => {value: 1, done: false}
generator.next(';'); // => {value: 2, done: false}
generator.next('L'); // => {value: 3, done: true}
const generator = machine();
generator.next(); // need to call next at first for initializing states
generator.next('ε'); // => {value: 3, done: true}
And then, I have an idea about describing a native object like State
which extends Generator
and simplify the constructing way like this:
const state = new State({'E': [0, 1], ';': [1, 2], 'L': [2, 3], 'ε': [0, 3]}, /* startState */0, /* endState */3);
state.next(); // => {value: 0, done: false};
state.next('E'); // => {value: 1, done: false}
state.next(';'); // => {value: 2, done: false}
state.next('L'); // => {value: 3, done: true}