handle internal events also when initializing
This commit is contained in:
parent
52bfcc7ff4
commit
56c77de5bc
3 changed files with 29 additions and 30 deletions
|
|
@ -126,7 +126,6 @@ export function App() {
|
||||||
<AST {...ast}/>
|
<AST {...ast}/>
|
||||||
{rt.map((rt, idx) => <><hr/><div className={"runtimeState"+(idx===rtIdx?" active":"")} onClick={() => setRTIdx(idx)}>
|
{rt.map((rt, idx) => <><hr/><div className={"runtimeState"+(idx===rtIdx?" active":"")} onClick={() => setRTIdx(idx)}>
|
||||||
<ShowEnvironment environment={rt.environment}/>
|
<ShowEnvironment environment={rt.environment}/>
|
||||||
<br/>
|
|
||||||
<ShowMode mode={rt.mode} statechart={ast}/>
|
<ShowMode mode={rt.mode} statechart={ast}/>
|
||||||
</div></>)}
|
</div></>)}
|
||||||
</aside>
|
</aside>
|
||||||
|
|
@ -135,15 +134,15 @@ export function App() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ShowEnvironment(props: {environment: Environment}) {
|
function ShowEnvironment(props: {environment: Environment}) {
|
||||||
return <>{[...props.environment.entries()].map(([variable,value]) =>
|
return <div>{[...props.environment.entries()].map(([variable,value]) =>
|
||||||
`${variable}: ${value}`
|
`${variable}: ${value}`
|
||||||
).join(', ')}</>;
|
).join(', ')}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ShowMode(props: {mode: Mode, statechart: Statechart}) {
|
function ShowMode(props: {mode: Mode, statechart: Statechart}) {
|
||||||
const activeLeafs = getActiveLeafs(props.mode, props.statechart);
|
const activeLeafs = getActiveLeafs(props.mode, props.statechart);
|
||||||
return <>{[...activeLeafs].map(uid =>
|
return <div>{[...activeLeafs].map(uid =>
|
||||||
stateDescription(props.statechart.uid2State.get(uid)!)).join(",")}</>;
|
stateDescription(props.statechart.uid2State.get(uid)!)).join(",")}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveLeafs(mode: Mode, sc: Statechart) {
|
function getActiveLeafs(mode: Mode, sc: Statechart) {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
import { evalExpr } from "./actionlang_interpreter";
|
import { evalExpr } from "./actionlang_interpreter";
|
||||||
import { computeArena, ConcreteState, getDescendants, isAncestorOf, isOverlapping, OrState, Statechart, stateDescription, Transition } from "./ast";
|
import { computeArena, ConcreteState, getDescendants, isAncestorOf, isOverlapping, OrState, Statechart, stateDescription, Transition } from "./ast";
|
||||||
import { Action } from "./label_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 {
|
export function initialize(ast: Statechart): BigStep {
|
||||||
const {enteredStates, environment, ...raised} = enterDefault(ast.root, {
|
let {enteredStates, environment, ...raised} = enterDefault(ast.root, {
|
||||||
environment: new Map(),
|
environment: new Map(),
|
||||||
...initialRaised,
|
...initialRaised,
|
||||||
});
|
});
|
||||||
return {
|
return handleInternalEvents(ast, {mode: enteredStates, environment, ...raised});
|
||||||
mode: enteredStates,
|
|
||||||
environment,
|
|
||||||
...raised,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionScope = {
|
type ActionScope = {
|
||||||
|
|
@ -168,7 +164,7 @@ export function execAction(action: Action, rt: ActionScope): ActionScope {
|
||||||
throw new Error("should never reach here");
|
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<OrState>();
|
const arenasFired = new Set<OrState>();
|
||||||
for (const state of activeParent.children) {
|
for (const state of activeParent.children) {
|
||||||
if (mode.has(state.uid)) {
|
if (mode.has(state.uid)) {
|
||||||
|
|
@ -208,22 +204,27 @@ export function handleEvent(event: string, statechart: Statechart, activeParent:
|
||||||
return {environment, mode, ...raised};
|
return {environment, mode, ...raised};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleInputEvent(event: string, statechart: Statechart, rt: RT_Statechart): RT_Statechart {
|
export function handleInputEvent(event: string, statechart: Statechart, {mode, environment}: {mode: Mode, environment: Environment}): BigStep {
|
||||||
let {mode, environment, internalEvents, outputEvents} = handleEvent(event, statechart, statechart.root, rt);
|
let raised = initialRaised;
|
||||||
|
|
||||||
while (internalEvents.length > 0) {
|
({mode, environment, ...raised} = handleEvent(event, statechart, statechart.root, {mode, environment, ...raised}));
|
||||||
const [event, ...rest] = internalEvents;
|
|
||||||
({mode, environment, internalEvents, outputEvents} = handleEvent(event, statechart, statechart.root, {mode, environment, internalEvents: rest, outputEvents}));
|
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, outputEvents: raised.outputEvents};
|
||||||
return {mode, environment, internalEvents, outputEvents};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function transitionDescription(t: Transition) {
|
function transitionDescription(t: Transition) {
|
||||||
return stateDescription(t.src) + ' ➔ ' + stateDescription(t.tgt);
|
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});
|
// 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
|
toExit.delete(arena.uid); // do not exit the arena itself
|
||||||
const exitedMode = mode.difference(toExit);
|
const exitedMode = mode.difference(toExit);
|
||||||
|
|
||||||
// console.log('exitedMode', exitedMode);
|
|
||||||
|
|
||||||
// exec transition actions
|
// exec transition actions
|
||||||
for (const action of t.label[0].actions) {
|
for (const action of t.label[0].actions) {
|
||||||
({environment, ...raised} = execAction(action, {environment, ...raised}));
|
({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}));
|
({enteredStates, environment, ...raised} = enterPath(tgtPath.slice(1), {environment, ...raised}));
|
||||||
const enteredMode = exitedMode.union(enteredStates);
|
const enteredMode = exitedMode.union(enteredStates);
|
||||||
|
|
||||||
// console.log('enteredMode', enteredMode);
|
|
||||||
|
|
||||||
return {mode: enteredMode, environment, ...raised};
|
return {mode: enteredMode, environment, ...raised};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
// for basic states (= empty AND-states), the modal configuration is just an empty object
|
// for basic states (= empty AND-states), the modal configuration is just an empty object
|
||||||
// export type Mode = {[uid:string]: Mode};
|
// 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<string>; // set of active states
|
export type Mode = Set<string>; // set of active states
|
||||||
|
|
||||||
|
|
@ -14,7 +18,7 @@ export type RT_Statechart = {
|
||||||
mode: Mode;
|
mode: Mode;
|
||||||
environment: Environment;
|
environment: Environment;
|
||||||
// history: // TODO
|
// history: // TODO
|
||||||
} & RaisedEvents;
|
}
|
||||||
|
|
||||||
export type BigStep = {
|
export type BigStep = {
|
||||||
from: RT_Statechart;
|
from: RT_Statechart;
|
||||||
|
|
@ -28,10 +32,9 @@ export type RaisedEvents = {
|
||||||
outputEvents: string[];
|
outputEvents: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Timers = Map<string, number>; // transition uid -> timestamp
|
||||||
|
|
||||||
export const initialRaised: RaisedEvents = {
|
export const initialRaised: RaisedEvents = {
|
||||||
internalEvents: [],
|
internalEvents: [],
|
||||||
outputEvents: [],
|
outputEvents: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// export type RT_Events = {
|
|
||||||
// };
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue