show execution history
This commit is contained in:
parent
a8b522fdd8
commit
d5272e30f3
6 changed files with 90 additions and 42 deletions
|
|
@ -1,9 +1,9 @@
|
|||
import { useState } from "react";
|
||||
|
||||
import { ConcreteState, emptyStatechart, Statechart, stateDescription, Transition } from "../VisualEditor/ast";
|
||||
import { ConcreteState, emptyStatechart, isAncestorOf, Statechart, stateDescription, Transition } from "../VisualEditor/ast";
|
||||
import { VisualEditor } from "../VisualEditor/VisualEditor";
|
||||
import { RT_Statechart } from "../VisualEditor/runtime_types";
|
||||
import { initialize, handleEvent } from "../VisualEditor/interpreter";
|
||||
import { Environment, Mode, RT_Statechart } from "../VisualEditor/runtime_types";
|
||||
import { initialize, handleEvent, handleInputEvent } from "../VisualEditor/interpreter";
|
||||
import { Action, Expression } from "../VisualEditor/label_ast";
|
||||
|
||||
import "../index.css";
|
||||
|
|
@ -69,7 +69,9 @@ export function AST(props: {root: ConcreteState, transitions: Map<string, Transi
|
|||
export function App() {
|
||||
const [ast, setAST] = useState<Statechart>(emptyStatechart);
|
||||
const [errors, setErrors] = useState<[string,string][]>([]);
|
||||
const [rt, setRT] = useState<RT_Statechart|null>(null);
|
||||
const [rt, setRT] = useState<RT_Statechart[]>([]);
|
||||
const [rtIdx, setRTIdx] = useState<number|null>(null);
|
||||
const [timeMs, setTimeMs] = useState(0);
|
||||
|
||||
const [paused, setPaused] = useState(true);
|
||||
const [timescale, setTimescale] = useState(1);
|
||||
|
|
@ -77,61 +79,83 @@ export function App() {
|
|||
function restart() {
|
||||
const rt = initialize(ast);
|
||||
console.log('runtime: ', rt);
|
||||
setRT(rt);
|
||||
setRT([rt]);
|
||||
setRTIdx(0);
|
||||
}
|
||||
|
||||
function stop() {
|
||||
setRT(null);
|
||||
setRT([]);
|
||||
setRTIdx(null);
|
||||
}
|
||||
|
||||
function raise(event: string) {
|
||||
if (rt && ast.inputEvents.has(event)) {
|
||||
const nextConfig = handleEvent(event, ast, ast.root, rt);
|
||||
setRT(nextConfig);
|
||||
// console.log({nextConfigs});
|
||||
// if (nextConfigs.length > 0) {
|
||||
// if (nextConfigs.length > 1) {
|
||||
// console.warn('non-determinism, blindly selecting first next run-time state!');
|
||||
// }
|
||||
// setRT(nextConfigs[0]);
|
||||
// }
|
||||
console.log(rtIdx);
|
||||
if (rt.length>0 && rtIdx!==null && ast.inputEvents.has(event)) {
|
||||
const nextConfig = handleInputEvent(event, ast, rt[rtIdx]!);
|
||||
setRT([...rt.slice(0, rtIdx+1), nextConfig]);
|
||||
setRTIdx(rtIdx+1);
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="layoutVertical">
|
||||
<div className="panel">
|
||||
|
||||
</div>
|
||||
<div className="panel">
|
||||
<button onClick={restart}>(re)start</button>
|
||||
<select disabled={rt===null} value="raise event..." onChange={e => raise(e.target.value)}>
|
||||
<option value="">raise event...</option>
|
||||
{[...ast.inputEvents].map(event =>
|
||||
<option value={event}>{event}</option>
|
||||
)}
|
||||
</select>
|
||||
<button onClick={stop} >stop</button>
|
||||
<button onClick={stop} disabled={rt===null}>stop</button>
|
||||
 
|
||||
<input type="radio" name="paused" id="radio-paused" checked={paused} disabled={rt===null} onChange={e => setPaused(e.target.checked)}/>
|
||||
raise
|
||||
{[...ast.inputEvents].map(event => <button disabled={rtIdx===null} onClick={() => raise(event)}>{event}</button>)}
|
||||
 
|
||||
<input type="radio" name="paused" id="radio-paused" checked={paused} disabled={rtIdx===null} onChange={e => setPaused(e.target.checked)}/>
|
||||
<label htmlFor="radio-paused">paused</label>
|
||||
<input type="radio" name="realtime" id="radio-realtime" checked={!paused} disabled={rt===null} onChange={e => setPaused(!e.target.checked)}/>
|
||||
<input type="radio" name="realtime" id="radio-realtime" checked={!paused} disabled={rtIdx===null} onChange={e => setPaused(!e.target.checked)}/>
|
||||
<label htmlFor="radio-realtime">real-time</label>
|
||||
 
|
||||
<label htmlFor="number-timescale">timescale</label>
|
||||
<input type="number" id="number-timescale" disabled={rt===null} value={timescale} style={{width:40}}/>
|
||||
<input type="number" id="number-timescale" disabled={rtIdx===null} value={timescale} style={{width:40}}/>
|
||||
 
|
||||
time is {timeMs} ms
|
||||
</div>
|
||||
<div className="layout">
|
||||
<main className="content">
|
||||
<VisualEditor {...{ast, setAST, rt, setRT, errors, setErrors}}/>
|
||||
<VisualEditor {...{ast, setAST, rt: rt.at(rtIdx!), setRT, errors, setErrors}}/>
|
||||
</main>
|
||||
<aside className="sidebar">
|
||||
<AST {...ast}/>
|
||||
<hr/>
|
||||
{rt &&
|
||||
[...rt.environment.entries()].map(([variable,value]) => <>
|
||||
{variable}: {value}<br/>
|
||||
</>)
|
||||
}
|
||||
{rt.map((rt, idx) => <><hr/><div className={"runtimeState"+(idx===rtIdx?" active":"")} onClick={() => setRTIdx(idx)}>
|
||||
<ShowEnvironment environment={rt.environment}/>
|
||||
<br/>
|
||||
<ShowMode mode={rt.mode} statechart={ast}/>
|
||||
</div></>)}
|
||||
</aside>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function ShowEnvironment(props: {environment: Environment}) {
|
||||
return <>{[...props.environment.entries()].map(([variable,value]) =>
|
||||
`${variable}: ${value}`
|
||||
).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(",")}</>;
|
||||
}
|
||||
|
||||
function getActiveLeafs(mode: Mode, sc: Statechart) {
|
||||
const toDelete = [];
|
||||
for (const stateA of mode) {
|
||||
for (const stateB of mode) {
|
||||
if (sc.uid2State.get(stateA)!.parent === sc.uid2State.get(stateB)) {
|
||||
toDelete.push(stateB);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mode.difference(new Set(toDelete));
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue