diff --git a/src/App/App.tsx b/src/App/App.tsx index a41676a..a794fcd 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -206,7 +206,7 @@ export function App() { const plantStates = []; let ps = plant.initial(e => { - // ... + onRaise(e.name, e.param); }); for (let i=0; i ("0"+n.toString()).slice(-2); + const twoDigits = (n: number) => n < 0 ? " " : ("0"+n.toString()).slice(-2); const hhmmss = `${twoDigits(h)}:${twoDigits(m)}:${twoDigits(s)}`; return <> @@ -46,7 +43,7 @@ export function DigitalWatch({light, h, m, s, alarm, callbacks}: DigitalWatchPro : } - {hhmmss} + {hhmmss} callbacks.onTopLeftPressed()} @@ -117,11 +114,17 @@ export const DigitalWatchPlant: Plant = { if (inputEvent.name === "setS") { return { ...state, s: inputEvent.param }; } - if (inputEvent.name === "setLight") { - return { ...state, light: inputEvent.param }; + if (inputEvent.name === "lightOn") { + return { ...state, light: true }; + } + if (inputEvent.name === "lightOff") { + return { ...state, light: false }; } if (inputEvent.name === "setAlarm") { - return { ...state, alarm: inputEvent.param }; + return { ...state, alarm: true }; + } + if (inputEvent.name === "unsetAlarm") { + return { ...state, alarm: false }; } return state; // unknown event - ignore it }, diff --git a/src/VisualEditor/VisualEditor.tsx b/src/VisualEditor/VisualEditor.tsx index 529a0b3..aab1440 100644 --- a/src/VisualEditor/VisualEditor.tsx +++ b/src/VisualEditor/VisualEditor.tsx @@ -474,6 +474,7 @@ export function VisualEditor({state, setState, ast, setAST, rt, errors, setError // @ts-ignore selection: [ ...state.rountangles.map(r => ({uid: r.uid, parts: ["left", "top", "right", "bottom"]})), + ...state.diamonds.map(d => ({uid: d.uid, parts: ["left", "top", "right", "bottom"]})), ...state.arrows.map(a => ({uid: a.uid, parts: ["start", "end"]})), ...state.texts.map(t => ({uid: t.uid, parts: ["text"]})), ] diff --git a/src/statecharts/abstract_syntax.ts b/src/statecharts/abstract_syntax.ts index 574a91f..2ed2531 100644 --- a/src/statecharts/abstract_syntax.ts +++ b/src/statecharts/abstract_syntax.ts @@ -142,7 +142,7 @@ export function getPossibleTargets(t: Transition, ts: Map) export function computeArena2(t: Transition, ts: Map): OrState { const tgts = getPossibleTargets(t, ts); let lca = computeLCA2([t.src as ConcreteState, ...tgts]); - while (lca.kind !== "or") { + while (lca.kind !== "or" || lca === t.src || lca === t.tgt) { lca = lca.parent!; } return lca as OrState; diff --git a/src/statecharts/actionlang_interpreter.ts b/src/statecharts/actionlang_interpreter.ts index 7b8e8ad..5ac4b6e 100644 --- a/src/statecharts/actionlang_interpreter.ts +++ b/src/statecharts/actionlang_interpreter.ts @@ -19,6 +19,7 @@ const BINARY_OPERATOR_MAP: Map any> = new Map([ [">=", (a, b) => a >= b], ["<", (a, b) => a < b], [">", (a, b) => a > b], + ["%", (a, b) => a % b], ]); export function evalExpr(expr: Expression, environment: Environment): any { diff --git a/src/statecharts/interpreter.ts b/src/statecharts/interpreter.ts index b425bcc..ecbb219 100644 --- a/src/statecharts/interpreter.ts +++ b/src/statecharts/interpreter.ts @@ -169,6 +169,7 @@ export function enterStates(simtime: number, state: ConcreteState, toEnter: Set< // exit the given state and all its active descendants export function exitCurrent(simtime: number, state: ConcreteState, rt: EnteredScope): ActionScope { + console.log('exitCurrent', state); let {enteredStates, history, ...actionScope} = rt; if (enteredStates.has(state.uid)) { @@ -297,6 +298,8 @@ export function fireTransition(simtime: number, t: Transition, ts: Map=", false); const peg$e18 = peg$classExpectation(["<", ">"], false, false, false); const peg$e19 = peg$classExpectation(["+", "-"], false, false, false); - const peg$e20 = peg$classExpectation(["%", "*", "/"], false, false, false); - const peg$e21 = peg$classExpectation(["!", "-"], false, false, false); - const peg$e22 = peg$literalExpectation("true", false); - const peg$e23 = peg$literalExpectation("false", false); - const peg$e24 = peg$literalExpectation("\"", false); - const peg$e25 = peg$classExpectation(["\""], true, false, false); - const peg$e26 = peg$literalExpectation("^", false); - const peg$e27 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false, false); - const peg$e28 = peg$literalExpectation("//", false); - const peg$e29 = peg$anyExpectation(); - const peg$e30 = peg$literalExpectation("\n", false); + const peg$e20 = peg$literalExpectation("||", false); + const peg$e21 = peg$classExpectation(["%", "*", "/"], false, false, false); + const peg$e22 = peg$literalExpectation("&&", false); + const peg$e23 = peg$classExpectation(["!", "-"], false, false, false); + const peg$e24 = peg$literalExpectation("true", false); + const peg$e25 = peg$literalExpectation("false", false); + const peg$e26 = peg$literalExpectation("\"", false); + const peg$e27 = peg$classExpectation(["\""], true, false, false); + const peg$e28 = peg$literalExpectation("^", false); + const peg$e29 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false, false); + const peg$e30 = peg$literalExpectation("//", false); + const peg$e31 = peg$anyExpectation(); + const peg$e32 = peg$literalExpectation("\n", false); function peg$f0(trigger, guard, actions) { return { @@ -1089,6 +1093,15 @@ function peg$parse(input, options) { s5 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e19); } } + if (s5 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c16) { + s5 = peg$c16; + peg$currPos += 2; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e20); } + } + } if (s5 !== peg$FAILED) { s6 = peg$parse_(); s4 = [s4, s5, s6]; @@ -1137,7 +1150,16 @@ function peg$parse(input, options) { peg$currPos++; } else { s5 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e20); } + if (peg$silentFails === 0) { peg$fail(peg$e21); } + } + if (s5 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c17) { + s5 = peg$c17; + peg$currPos += 2; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e22); } + } } if (s5 !== peg$FAILED) { s6 = peg$parse_(); @@ -1182,7 +1204,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e21); } + if (peg$silentFails === 0) { peg$fail(peg$e23); } } if (s1 === peg$FAILED) { s1 = null; @@ -1318,20 +1340,20 @@ function peg$parse(input, options) { let s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c16) { - s1 = peg$c16; + if (input.substr(peg$currPos, 4) === peg$c18) { + s1 = peg$c18; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e22); } + if (peg$silentFails === 0) { peg$fail(peg$e24); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 5) === peg$c17) { - s1 = peg$c17; + if (input.substr(peg$currPos, 5) === peg$c19) { + s1 = peg$c19; peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } + if (peg$silentFails === 0) { peg$fail(peg$e25); } } } if (s1 !== peg$FAILED) { @@ -1348,11 +1370,11 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c18; + s1 = peg$c20; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1361,7 +1383,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e25); } + if (peg$silentFails === 0) { peg$fail(peg$e27); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -1370,15 +1392,15 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e25); } + if (peg$silentFails === 0) { peg$fail(peg$e27); } } } if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c18; + s3 = peg$c20; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; @@ -1400,11 +1422,11 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 94) { - s1 = peg$c19; + s1 = peg$c21; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e26); } + if (peg$silentFails === 0) { peg$fail(peg$e28); } } if (s1 !== peg$FAILED) { s2 = peg$parse_(); @@ -1473,7 +1495,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } } while (s2 !== peg$FAILED) { @@ -1485,7 +1507,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } } } @@ -1501,12 +1523,12 @@ function peg$parse(input, options) { let s0, s1, s2, s3, s4, s5, s6; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c20) { - s1 = peg$c20; + if (input.substr(peg$currPos, 2) === peg$c22) { + s1 = peg$c22; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } if (s1 !== peg$FAILED) { s2 = peg$parse_(); @@ -1516,7 +1538,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -1525,16 +1547,16 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } } s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 10) { - s5 = peg$c21; + s5 = peg$c23; peg$currPos++; } else { s5 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + if (peg$silentFails === 0) { peg$fail(peg$e32); } } if (s5 === peg$FAILED) { s5 = peg$currPos; @@ -1544,7 +1566,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } peg$silentFails--; if (s6 === peg$FAILED) { diff --git a/src/statecharts/transition_label.grammar b/src/statecharts/transition_label.grammar index 91a097c..865973a 100644 --- a/src/statecharts/transition_label.grammar +++ b/src/statecharts/transition_label.grammar @@ -69,7 +69,7 @@ compare = sum:sum rest:((_ ("==" / "!=" / "<=" / ">=" / "<" / ">") _) compare)? }; } -sum = prod:product rest:((_ ("+" / "-") _) sum)? { +sum = prod:product rest:((_ ("+" / "-" / "||") _) sum)? { if (rest === null) { return prod; } @@ -81,7 +81,7 @@ sum = prod:product rest:((_ ("+" / "-") _) sum)? { }; } -product = atom:unary rest:((_ ("*" / "/" / "%" ) _) product)? { +product = atom:unary rest:((_ ("*" / "/" / "%" / "&&" ) _) product)? { if (rest === null) { return atom; } diff --git a/todo.txt b/todo.txt index 6578174..7f519cb 100644 --- a/todo.txt +++ b/todo.txt @@ -35,6 +35,8 @@ TODO - usability stuff: - show internal events + - hovering over event in side panel should highlight all occurrences of the event in the SC + - hovering over error in bottom panel should highlight that rror in the SC - highlight selected shapes while making a selection - comments sometimes snap to transitions even if they belong to a state - highlight fired transitions