statechart parsing and error reporting working
This commit is contained in:
parent
2adf902a7f
commit
f40e7f60b5
6 changed files with 300 additions and 115 deletions
100
src/VisualEditor/parser.ts
Normal file
100
src/VisualEditor/parser.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import { ConcreteState, OrState, Statechart, Transition } from "./ast";
|
||||
import { findNearestRountangleSide, Rountangle, VisualEditorState } from "./editor_types";
|
||||
import { isEntirelyWithin } from "./geometry";
|
||||
|
||||
export function parseStatechart(state: VisualEditorState): [Statechart, [string,string][]] {
|
||||
// implicitly, the root is always an Or-state
|
||||
const root: OrState = {
|
||||
kind: "or",
|
||||
uid: "root",
|
||||
children: [],
|
||||
initial: [],
|
||||
}
|
||||
|
||||
const uid2State = new Map<string, ConcreteState>([["root", root]]);
|
||||
|
||||
// we will always look for the smallest parent rountangle
|
||||
const parentCandidates: Rountangle[] = [{
|
||||
kind: "or",
|
||||
uid: root.uid,
|
||||
topLeft: {x: -Infinity, y: -Infinity},
|
||||
size: {x: Infinity, y: Infinity},
|
||||
}];
|
||||
|
||||
const parentLinks = new Map<string, string>();
|
||||
|
||||
// we assume that the rountangles are sorted from big to small:
|
||||
for (const rt of state.rountangles) {
|
||||
const state: ConcreteState = {
|
||||
kind: rt.kind,
|
||||
uid: rt.uid,
|
||||
children: [],
|
||||
}
|
||||
if (state.kind === "or") {
|
||||
state.initial = [];
|
||||
}
|
||||
uid2State.set(rt.uid, state);
|
||||
|
||||
// iterate in reverse:
|
||||
for (let i=parentCandidates.length-1; i>=0; i--) {
|
||||
const candidate = parentCandidates[i];
|
||||
console.log('candidate:', candidate, 'rt:', rt);
|
||||
if (candidate.uid === "root" || isEntirelyWithin(rt, candidate)) {
|
||||
// found our parent :)
|
||||
const parentState = uid2State.get(candidate.uid);
|
||||
parentState!.children.push(state);
|
||||
parentCandidates.push(rt);
|
||||
parentLinks.set(rt.uid, candidate.uid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const transitions = new Map<string, Transition[]>();
|
||||
|
||||
const errorShapes: [string, string][] = [];
|
||||
|
||||
for (const arr of state.arrows) {
|
||||
const srcUID = findNearestRountangleSide(arr, "start", state.rountangles)?.uid;
|
||||
const tgtUID = findNearestRountangleSide(arr, "end", state.rountangles)?.uid;
|
||||
if (!srcUID) {
|
||||
if (!tgtUID) {
|
||||
// dangling edge - todo: display error...
|
||||
errorShapes.push([arr.uid, "Dangling edge"]);
|
||||
}
|
||||
else {
|
||||
// target but no source, so we treat is as an 'initial' marking
|
||||
const initialState = uid2State.get(tgtUID)!;
|
||||
const ofState = uid2State.get(parentLinks.get(tgtUID)!)!;
|
||||
if (ofState.kind === "or") {
|
||||
ofState.initial.push([arr.uid, initialState]);
|
||||
}
|
||||
else {
|
||||
// and states do not have an 'initial' state - todo: display error...
|
||||
errorShapes.push([arr.uid, "AND-state cannot have an initial state"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!tgtUID) {
|
||||
errorShapes.push([arr.uid, "Needs target"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const state of uid2State.values()) {
|
||||
if (state.kind === "or") {
|
||||
if (state.initial.length > 1) {
|
||||
errorShapes.push(...state.initial.map(([uid,childState])=>[uid,"OR-state can only have 1 initial state"] as [string, string]));
|
||||
}
|
||||
else if (state.initial.length === 0) {
|
||||
errorShapes.push([state.uid, "Needs initial state"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [{
|
||||
root,
|
||||
transitions,
|
||||
}, errorShapes];
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue