From 56c77de5bca75bc8eaca6910b3d6e166dfa25311 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 10 Oct 2025 11:07:42 +0200 Subject: [PATCH] handle internal events also when initializing --- src/App/App.tsx | 9 ++++--- src/VisualEditor/interpreter.ts | 39 ++++++++++++++----------------- src/VisualEditor/runtime_types.ts | 11 +++++---- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/App/App.tsx b/src/App/App.tsx index 9423dd9..3c01e62 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -126,7 +126,6 @@ export function App() { {rt.map((rt, idx) => <>
setRTIdx(idx)}> -
)} @@ -135,15 +134,15 @@ export function App() { } function ShowEnvironment(props: {environment: Environment}) { - return <>{[...props.environment.entries()].map(([variable,value]) => + return
{[...props.environment.entries()].map(([variable,value]) => `${variable}: ${value}` - ).join(', ')}; + ).join(', ')}
; } function ShowMode(props: {mode: Mode, statechart: Statechart}) { const activeLeafs = getActiveLeafs(props.mode, props.statechart); - return <>{[...activeLeafs].map(uid => - stateDescription(props.statechart.uid2State.get(uid)!)).join(",")}; + return
{[...activeLeafs].map(uid => + stateDescription(props.statechart.uid2State.get(uid)!)).join(",")}
; } function getActiveLeafs(mode: Mode, sc: Statechart) { diff --git a/src/VisualEditor/interpreter.ts b/src/VisualEditor/interpreter.ts index 9a9ed0d..878bdbb 100644 --- a/src/VisualEditor/interpreter.ts +++ b/src/VisualEditor/interpreter.ts @@ -1,18 +1,14 @@ import { evalExpr } from "./actionlang_interpreter"; import { computeArena, ConcreteState, getDescendants, isAncestorOf, isOverlapping, OrState, Statechart, stateDescription, Transition } from "./ast"; import { Action } from "./label_ast"; -import { Environment, RaisedEvents, Mode, RT_Statechart, initialRaised } from "./runtime_types"; +import { Environment, RaisedEvents, Mode, RT_Statechart, initialRaised, BigStep } from "./runtime_types"; -export function initialize(ast: Statechart): RT_Statechart { - const {enteredStates, environment, ...raised} = enterDefault(ast.root, { +export function initialize(ast: Statechart): BigStep { + let {enteredStates, environment, ...raised} = enterDefault(ast.root, { environment: new Map(), ...initialRaised, }); - return { - mode: enteredStates, - environment, - ...raised, - }; + return handleInternalEvents(ast, {mode: enteredStates, environment, ...raised}); } type ActionScope = { @@ -168,7 +164,7 @@ export function execAction(action: Action, rt: ActionScope): ActionScope { throw new Error("should never reach here"); } -export function handleEvent(event: string, statechart: Statechart, activeParent: ConcreteState, {environment, mode, ...raised}: RT_Statechart): RT_Statechart { +export function handleEvent(event: string, statechart: Statechart, activeParent: ConcreteState, {environment, mode, ...raised}: RT_Statechart & RaisedEvents): RT_Statechart & RaisedEvents { const arenasFired = new Set(); for (const state of activeParent.children) { if (mode.has(state.uid)) { @@ -208,22 +204,27 @@ export function handleEvent(event: string, statechart: Statechart, activeParent: return {environment, mode, ...raised}; } -export function handleInputEvent(event: string, statechart: Statechart, rt: RT_Statechart): RT_Statechart { - let {mode, environment, internalEvents, outputEvents} = handleEvent(event, statechart, statechart.root, rt); +export function handleInputEvent(event: string, statechart: Statechart, {mode, environment}: {mode: Mode, environment: Environment}): BigStep { + let raised = initialRaised; - while (internalEvents.length > 0) { - const [event, ...rest] = internalEvents; - ({mode, environment, internalEvents, outputEvents} = handleEvent(event, statechart, statechart.root, {mode, environment, internalEvents: rest, outputEvents})); + ({mode, environment, ...raised} = handleEvent(event, statechart, statechart.root, {mode, environment, ...raised})); + + return handleInternalEvents(statechart, {mode, environment, ...raised}); +} + +export function handleInternalEvents(statechart: Statechart, {mode, environment, ...raised}: RT_Statechart & RaisedEvents): BigStep { + while (raised.internalEvents.length > 0) { + const [internalEvent, ...rest] = raised.internalEvents; + ({mode, environment, ...raised} = handleEvent(internalEvent, statechart, statechart.root, {mode, environment, internalEvents: rest, outputEvents: raised.outputEvents})); } - - return {mode, environment, internalEvents, outputEvents}; + return {mode, environment, outputEvents: raised.outputEvents}; } function transitionDescription(t: Transition) { return stateDescription(t.src) + ' ➔ ' + stateDescription(t.tgt); } -export function fireTransition(t: Transition, arena: OrState, srcPath: ConcreteState[], tgtPath: ConcreteState[], {mode, environment, ...raised}: RT_Statechart): RT_Statechart { +export function fireTransition(t: Transition, arena: OrState, srcPath: ConcreteState[], tgtPath: ConcreteState[], {mode, environment, ...raised}: RT_Statechart & RaisedEvents): RT_Statechart & RaisedEvents { // console.log('fire ', transitionDescription(t), {arena, srcPath, tgtPath}); @@ -233,8 +234,6 @@ export function fireTransition(t: Transition, arena: OrState, srcPath: ConcreteS toExit.delete(arena.uid); // do not exit the arena itself const exitedMode = mode.difference(toExit); - // console.log('exitedMode', exitedMode); - // exec transition actions for (const action of t.label[0].actions) { ({environment, ...raised} = execAction(action, {environment, ...raised})); @@ -245,7 +244,5 @@ export function fireTransition(t: Transition, arena: OrState, srcPath: ConcreteS ({enteredStates, environment, ...raised} = enterPath(tgtPath.slice(1), {environment, ...raised})); const enteredMode = exitedMode.union(enteredStates); - // console.log('enteredMode', enteredMode); - return {mode: enteredMode, environment, ...raised}; } diff --git a/src/VisualEditor/runtime_types.ts b/src/VisualEditor/runtime_types.ts index d665de6..1f1c483 100644 --- a/src/VisualEditor/runtime_types.ts +++ b/src/VisualEditor/runtime_types.ts @@ -4,6 +4,10 @@ // for basic states (= empty AND-states), the modal configuration is just an empty object // export type Mode = {[uid:string]: Mode}; +import { Transition } from "./ast"; + +export type Timestamp = number; // milliseconds since begin of simulation +export type Event = string; export type Mode = Set; // set of active states @@ -14,7 +18,7 @@ export type RT_Statechart = { mode: Mode; environment: Environment; // history: // TODO -} & RaisedEvents; +} export type BigStep = { from: RT_Statechart; @@ -28,10 +32,9 @@ export type RaisedEvents = { outputEvents: string[]; }; +export type Timers = Map; // transition uid -> timestamp + export const initialRaised: RaisedEvents = { internalEvents: [], outputEvents: [], } - -// export type RT_Events = { -// };