From 8306fa67cff9d5ef5877f5a3eb5f316867e078f6 Mon Sep 17 00:00:00 2001 From: Avraham Sakal Date: Mon, 15 May 2023 15:44:13 -0400 Subject: [PATCH] add `start()` and `pause()` to interpreter --- src/index.ts | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9457263..0fe9fc7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,16 +42,33 @@ export interface Interpreter_T { state: string; context: any; eventQueue:Array; + subscriptions: Record; isTransitioning: boolean; - subscriptions: Record + isPaused: boolean; } -export function interpret(machine:Machine_T, options:{state?:string, context:any}) : Interpreter_T{ - let {state, context} = options; - if(typeof state === 'undefined'){ state = machine.states[0].name; } - const interpreter = {machine, state, context, eventQueue:[], isTransitioning:false, subscriptions: {}} + +/** + * Description placeholder + * + * @export + * @param {Machine_T} machine + * @param {InitialContextFunction_T} initialContextFunction - in the form of a function rather than a direct value, so as to facilitate co-initialization of peer interpreters. Otherwise, the "parent" interpreter will start, but without a reference to a running child interpreter which it might expect to exist. + * @param {?string} [initialStateName] + * @returns {Interpreter_T} + */ +export function Interpreter(machine:Machine_T, initialContext:any, initialStateName?:string) : Interpreter_T{ + if(typeof initialStateName === 'undefined'){ initialStateName = machine.states[0].name; } + const interpreter = {machine, state: initialStateName, context:initialContext, eventQueue:[], isTransitioning:false, subscriptions: {}, isPaused: true} send(interpreter, ['entry', null] ); return interpreter; } +export function start(interpreter:Interpreter_T){ + interpreter.isPaused = false; + processEvents(interpreter); +} +export function pause(interpreter:Interpreter_T){ + interpreter.isPaused = true; +} /** Helper function for `send()` */ @@ -76,16 +93,19 @@ function getMatchingEventReactionCouplings(state : State_T, event:Event_T) : Arr export function send(interpreter : Interpreter_T, event:Event_T){ interpreter.eventQueue.push(event); if(interpreter.isTransitioning === false){ - interpreter.isTransitioning = true; - while(interpreter.eventQueue.length > 0){ - processNextEvent(interpreter); - } - interpreter.isTransitioning = false; - // only run subscriptions here, once the machine's state has settled: - Object.values(interpreter.subscriptions).forEach((subscriptionCallbackFunction)=>{ subscriptionCallbackFunction(interpreter); }); + processEvents(interpreter); } } export const enqueue = send; +function processEvents(interpreter:Interpreter_T){ + interpreter.isTransitioning = true; + while(interpreter.eventQueue.length > 0 && interpreter.isPaused===false){ + processNextEvent(interpreter); + } + interpreter.isTransitioning = false; + // only run subscriptions here, once the machine's state has settled: + Object.values(interpreter.subscriptions).forEach((subscriptionCallbackFunction)=>{ subscriptionCallbackFunction(interpreter); }); +} function processNextEvent(interpreter:Interpreter_T){ const nextEvent = interpreter.eventQueue.shift(); if(typeof nextEvent !== 'undefined'){ @@ -135,7 +155,7 @@ let subscriptionId : number = 0; export function subscribe(interpreter:Interpreter_T, callback:SubscriptionCallbackFunction_T){ subscriptionId++; interpreter.subscriptions[subscriptionId.toString()] = callback; - return subscriptionId; + return subscriptionId.toString(); } export function unsubscribe(interpreter:Interpreter_T, subscriptionId:string){ delete interpreter.subscriptions[subscriptionId.toString()];