Loading calc.html +30 −2 Original line number Diff line number Diff line Loading @@ -182,6 +182,12 @@ <td title="divide" data-bt-name="divide">÷</td> <td title="confirm or duplicate number" data-bt-name="return">⏎</td> </tr> <tr> <td title="sum all numbers in stack" data-bt-name="sum-all">Σ</td> <td title="square root" data-bt-name="square-root">√</td> <td title="power" data-bt-name="power">^</td> <td></td> </tr> </table> </div> </div> Loading Loading @@ -330,7 +336,7 @@ console.assert(m.numberStack[0] === -9); console.assert(m.numberStack[1] === 29 * 2); }; const rpnBackspaceOperator = function () { const rpnTestBackspaceOperator = function () { const m = new fsm.RPNCalculator(); m.sendKey("num1"); m.sendKey("num2"); Loading @@ -346,6 +352,27 @@ m.sendKey("backspace"); // delete last number in stack. console.assert(m.numberStack.length === 0); }; const rpnTestSumAllOperator = function () { const m = new fsm.RPNCalculator(); m.sendKey("sum-all"); console.assert(m.lastError !== null); m.sendKey("num1"); m.sendKey("sum-all"); console.assert(m.numberStack.length === 1); console.assert(m.numberStack[0] === 1); m.sendKey("num1"); m.sendKey("return"); m.sendKey("num2"); m.sendKey("return"); m.sendKey("num3"); m.sendKey("return"); m.sendKey("num1"); m.sendKey("change-sign"); m.sendKey("return"); m.sendKey("sum-all"); console.assert(m.numberStack.length === 1); console.assert(m.numberStack[0] === 5); }; const rpnTestNumberErrorHandling = function () { var m = new fsm.RPNCalculator(); m.sendKey("num0"); Loading Loading @@ -481,7 +508,8 @@ rpnTestNumberErrorHandling(); rpnTestNotEnoughElementOnStack(); rpnBackspaceOperator(); rpnTestBackspaceOperator(); rpnTestSumAllOperator(); rpnTestUndo(); rpnTestUndoWithErrors(); Loading fsm.js +50 −2 Original line number Diff line number Diff line Loading @@ -96,6 +96,9 @@ var fsm = function () { divide: "divide", plus: "plus", minus: "minus", sum_all: "sum-all", square_root: "square-root", power: "power", swap: "swap", undo: "undo", "return": "return", Loading @@ -119,6 +122,9 @@ var fsm = function () { "divide": "/", "plus": "+", "minus": "-", "sum-all": "Σ", "square-root": "sqrt", "power": "pow", "swap": "swap", "undo": "undo", "return": "ret", Loading Loading @@ -222,7 +228,8 @@ var fsm = function () { const operatorKeyList = [ keyNames.change_sign, keyNames.plus, keyNames.minus, keyNames.times, keyNames.divide, keyNames.swap, keyNames.undo, keyNames.swap, keyNames.undo, keyNames.sum_all, keyNames.square_root, keyNames.power, ]; const isOperator = function (keyName) { return operatorKeyList.indexOf(keyName) !== -1; Loading Loading @@ -342,9 +349,28 @@ var fsm = function () { return; } this.numberStack.push(-num); console.log("trail push " + [keyName, shortKeyName(keyName), -num]); debug("trail push " + [keyName, shortKeyName(keyName), -num]); this.trail.push([shortKeyName(keyName), -num]); break; case keyNames.square_root: this.snapshots.push(this.save()); num = this.numberStack.pop(); if (num === undefined) { this.setErrorMsg(msgTooFewElementsOnStack); this.snapshots.pop(); return; } if (num < 0) { // consumes the number and show error to user. this.setErrorMsg("square root of negative not supported"); this.snapshots.pop(); return; } r = num ** 0.5; this.numberStack.push(r); debug("trail push " + [keyName, shortKeyName(keyName), r]); this.trail.push([shortKeyName(keyName), r]); break; case keyNames.plus: if (! this.doBinaryOperator(keyName, (lhs, rhs) => lhs + rhs)) { return; Loading @@ -371,6 +397,11 @@ var fsm = function () { return; } break; case keyNames.power: if (! this.doBinaryOperator(keyName, (lhs, rhs) => lhs ** rhs)) { return; } break; case keyNames.swap: this.snapshots.push(this.save()); num2 = this.numberStack.pop(); Loading Loading @@ -413,6 +444,23 @@ var fsm = function () { return; } break; case keyNames.sum_all: // sum all numbers of stack this.snapshots.push(this.save()); r = 0; num = this.numberStack.pop(); if (num === undefined) { this.setErrorMsg(msgTooFewElementsOnStack); this.snapshots.pop(); return; } while (num !== undefined) { r += num; num = this.numberStack.pop(); } this.numberStack.push(r); this.trail.push([shortKeyName(keyName), r]); break; case keyNames.undo: printSnapshots(this.snapshots); Loading operational +18 −5 Original line number Diff line number Diff line Loading @@ -3,6 +3,19 @@ Time-stamp: <2017-01-27> #+STARTUP: content * notes :entry: ** 2017-01-27 steps to add new operator button. :doc: - add button in UI HTML. - update fsm.js keyNames, shortKeyNames, operatorKeyList. - add operator handling code. If you can use this.doBinaryOperator(), use that is easier. General steps: - take snapshot. - manipulate numberStack. - if there is error, call this.setErrorMsg(), pop snapshot and do early return. - if there is no error, push result in numberStack, push new op and result to this.trail. ** 2017-01-26 design data structure for the calculator. - this can be written and tested independently from the web UI. - basic data: Loading Loading @@ -58,11 +71,6 @@ the parent DOM. * current :entry: ** ** 2017-01-27 add a button: sqrt :featurereq: ** 2017-01-27 add a button: sum-all, it will sum all numbers on stack. :featurereq: - make UI auto height based on keyboard height. - ** 2017-01-27 accept keyboard event as well. :low:featurereq: - num0 to num9 - dot Loading @@ -89,6 +97,11 @@ doesn't work with <td> in firefox. ** 2017-01-26 make it work offline, add sw.js * done :entry: ** 2017-01-27 add a button: sum-all, it will sum all numbers on stack. :featurereq: - make UI auto height based on keyboard height. - add three buttons: sum-all, square-root, power ** 2017-01-27 add a button: sqrt :featurereq: ** 2017-01-26 make undo work - action based or snapshot based? - how does "undo" fit in the FSM states? Loading Loading
calc.html +30 −2 Original line number Diff line number Diff line Loading @@ -182,6 +182,12 @@ <td title="divide" data-bt-name="divide">÷</td> <td title="confirm or duplicate number" data-bt-name="return">⏎</td> </tr> <tr> <td title="sum all numbers in stack" data-bt-name="sum-all">Σ</td> <td title="square root" data-bt-name="square-root">√</td> <td title="power" data-bt-name="power">^</td> <td></td> </tr> </table> </div> </div> Loading Loading @@ -330,7 +336,7 @@ console.assert(m.numberStack[0] === -9); console.assert(m.numberStack[1] === 29 * 2); }; const rpnBackspaceOperator = function () { const rpnTestBackspaceOperator = function () { const m = new fsm.RPNCalculator(); m.sendKey("num1"); m.sendKey("num2"); Loading @@ -346,6 +352,27 @@ m.sendKey("backspace"); // delete last number in stack. console.assert(m.numberStack.length === 0); }; const rpnTestSumAllOperator = function () { const m = new fsm.RPNCalculator(); m.sendKey("sum-all"); console.assert(m.lastError !== null); m.sendKey("num1"); m.sendKey("sum-all"); console.assert(m.numberStack.length === 1); console.assert(m.numberStack[0] === 1); m.sendKey("num1"); m.sendKey("return"); m.sendKey("num2"); m.sendKey("return"); m.sendKey("num3"); m.sendKey("return"); m.sendKey("num1"); m.sendKey("change-sign"); m.sendKey("return"); m.sendKey("sum-all"); console.assert(m.numberStack.length === 1); console.assert(m.numberStack[0] === 5); }; const rpnTestNumberErrorHandling = function () { var m = new fsm.RPNCalculator(); m.sendKey("num0"); Loading Loading @@ -481,7 +508,8 @@ rpnTestNumberErrorHandling(); rpnTestNotEnoughElementOnStack(); rpnBackspaceOperator(); rpnTestBackspaceOperator(); rpnTestSumAllOperator(); rpnTestUndo(); rpnTestUndoWithErrors(); Loading
fsm.js +50 −2 Original line number Diff line number Diff line Loading @@ -96,6 +96,9 @@ var fsm = function () { divide: "divide", plus: "plus", minus: "minus", sum_all: "sum-all", square_root: "square-root", power: "power", swap: "swap", undo: "undo", "return": "return", Loading @@ -119,6 +122,9 @@ var fsm = function () { "divide": "/", "plus": "+", "minus": "-", "sum-all": "Σ", "square-root": "sqrt", "power": "pow", "swap": "swap", "undo": "undo", "return": "ret", Loading Loading @@ -222,7 +228,8 @@ var fsm = function () { const operatorKeyList = [ keyNames.change_sign, keyNames.plus, keyNames.minus, keyNames.times, keyNames.divide, keyNames.swap, keyNames.undo, keyNames.swap, keyNames.undo, keyNames.sum_all, keyNames.square_root, keyNames.power, ]; const isOperator = function (keyName) { return operatorKeyList.indexOf(keyName) !== -1; Loading Loading @@ -342,9 +349,28 @@ var fsm = function () { return; } this.numberStack.push(-num); console.log("trail push " + [keyName, shortKeyName(keyName), -num]); debug("trail push " + [keyName, shortKeyName(keyName), -num]); this.trail.push([shortKeyName(keyName), -num]); break; case keyNames.square_root: this.snapshots.push(this.save()); num = this.numberStack.pop(); if (num === undefined) { this.setErrorMsg(msgTooFewElementsOnStack); this.snapshots.pop(); return; } if (num < 0) { // consumes the number and show error to user. this.setErrorMsg("square root of negative not supported"); this.snapshots.pop(); return; } r = num ** 0.5; this.numberStack.push(r); debug("trail push " + [keyName, shortKeyName(keyName), r]); this.trail.push([shortKeyName(keyName), r]); break; case keyNames.plus: if (! this.doBinaryOperator(keyName, (lhs, rhs) => lhs + rhs)) { return; Loading @@ -371,6 +397,11 @@ var fsm = function () { return; } break; case keyNames.power: if (! this.doBinaryOperator(keyName, (lhs, rhs) => lhs ** rhs)) { return; } break; case keyNames.swap: this.snapshots.push(this.save()); num2 = this.numberStack.pop(); Loading Loading @@ -413,6 +444,23 @@ var fsm = function () { return; } break; case keyNames.sum_all: // sum all numbers of stack this.snapshots.push(this.save()); r = 0; num = this.numberStack.pop(); if (num === undefined) { this.setErrorMsg(msgTooFewElementsOnStack); this.snapshots.pop(); return; } while (num !== undefined) { r += num; num = this.numberStack.pop(); } this.numberStack.push(r); this.trail.push([shortKeyName(keyName), r]); break; case keyNames.undo: printSnapshots(this.snapshots); Loading
operational +18 −5 Original line number Diff line number Diff line Loading @@ -3,6 +3,19 @@ Time-stamp: <2017-01-27> #+STARTUP: content * notes :entry: ** 2017-01-27 steps to add new operator button. :doc: - add button in UI HTML. - update fsm.js keyNames, shortKeyNames, operatorKeyList. - add operator handling code. If you can use this.doBinaryOperator(), use that is easier. General steps: - take snapshot. - manipulate numberStack. - if there is error, call this.setErrorMsg(), pop snapshot and do early return. - if there is no error, push result in numberStack, push new op and result to this.trail. ** 2017-01-26 design data structure for the calculator. - this can be written and tested independently from the web UI. - basic data: Loading Loading @@ -58,11 +71,6 @@ the parent DOM. * current :entry: ** ** 2017-01-27 add a button: sqrt :featurereq: ** 2017-01-27 add a button: sum-all, it will sum all numbers on stack. :featurereq: - make UI auto height based on keyboard height. - ** 2017-01-27 accept keyboard event as well. :low:featurereq: - num0 to num9 - dot Loading @@ -89,6 +97,11 @@ doesn't work with <td> in firefox. ** 2017-01-26 make it work offline, add sw.js * done :entry: ** 2017-01-27 add a button: sum-all, it will sum all numbers on stack. :featurereq: - make UI auto height based on keyboard height. - add three buttons: sum-all, square-root, power ** 2017-01-27 add a button: sqrt :featurereq: ** 2017-01-26 make undo work - action based or snapshot based? - how does "undo" fit in the FSM states? Loading