Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(fsm): add support for lookahead-1, add docs
- Loading branch information
1 parent
f9cece7
commit 4a9bb3d
Showing
6 changed files
with
111 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,68 @@ | ||
import { IObjectOf } from "@thi.ng/api"; | ||
import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; | ||
import { illegalState } from "@thi.ng/errors/illegal-state"; | ||
import { reduced } from "@thi.ng/transducers/reduced"; | ||
import { mapcat } from "@thi.ng/transducers/xform/mapcat"; | ||
import { Reducer, Transducer } from "@thi.ng/transducers/api"; | ||
import { reduced, unreduced, isReduced, ensureReduced } from "@thi.ng/transducers/reduced"; | ||
import { Match, Matcher } from "./api"; | ||
|
||
/** | ||
* Finite-state machine transducer w/ support for single lookahead | ||
* value. Takes an object of `states` and their matchers, an arbitrary | ||
* context object and an `initial` state ID. | ||
* | ||
* The returned transducer consumes inputs of type `T` and produces | ||
* results of type `R`. The results are produced by callbacks of the | ||
* given state matchers. Each can produce any number of values. If a | ||
* callback returns a result wrapped w/ `reduced()`, the FSM causes | ||
* early termination of the overall transducer pipeline. | ||
* | ||
* @param states | ||
* @param ctx | ||
* @param initialState | ||
*/ | ||
export const fsm = <T, C, R>( | ||
states: IObjectOf<Matcher<T, C, R>>, | ||
ctx: C, | ||
init: string | number = "start" | ||
) => { | ||
let currID = init; | ||
let curr = states[init](); | ||
return mapcat<T, R>((x) => { | ||
const { type, body } = curr(ctx, x); | ||
if (type === Match.FULL) { | ||
const next = states[body[0]]; | ||
if (next) { | ||
currID = body[0]; | ||
curr = next(); | ||
} else { | ||
illegalState(`unknown tx: ${currID} -> ${body && body[0]}`); | ||
initialState: string | number = "start" | ||
): Transducer<T, R> => | ||
([init, complete, reduce]: Reducer<any, R>) => { | ||
let currID = initialState; | ||
let curr = states[initialState] ? | ||
states[initialState]() : | ||
illegalArgs(`invalid initial state: ${initialState}`); | ||
return [ | ||
init, | ||
complete, | ||
(acc, x) => { | ||
while (true) { | ||
const { type, body } = curr(ctx, x); | ||
if (type >= Match.FULL) { | ||
const next = body && states[body[0]]; | ||
if (next) { | ||
currID = body[0]; | ||
curr = next(); | ||
} else { | ||
illegalState(`unknown tx: ${currID} -> ${body && body[0]}`); | ||
} | ||
const res = body[1]; | ||
if (res) { | ||
for (let y of unreduced(res)) { | ||
acc = reduce(acc, y); | ||
if (isReduced(acc)) { | ||
break; | ||
} | ||
} | ||
isReduced(res) && (acc = ensureReduced(acc)); | ||
} | ||
if (type === Match.FULL_NC && !isReduced(acc)) { | ||
continue; | ||
} | ||
} else if (type === Match.FAIL) { | ||
return reduced(acc); | ||
} | ||
break; | ||
} | ||
return acc; | ||
} | ||
return body[1]; | ||
} else if (type === Match.FAIL) { | ||
return reduced([]); | ||
} | ||
}); | ||
}; | ||
]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters