Commit a20f9d71 authored by Yuanle Song's avatar Yuanle Song
Browse files

add three operators: sum-all, square-root, power.

added doc on how to add new operator button.
parent 93962cb5
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -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>
@@ -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");
@@ -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");
@@ -481,7 +508,8 @@

	      rpnTestNumberErrorHandling();
	      rpnTestNotEnoughElementOnStack();
	      rpnBackspaceOperator();
	      rpnTestBackspaceOperator();
	      rpnTestSumAllOperator();

	      rpnTestUndo();
	      rpnTestUndoWithErrors();
+50 −2
Original line number Diff line number Diff line
@@ -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",
@@ -119,6 +122,9 @@ var fsm = function () {
	    "divide": "/",
	    "plus": "+",
	    "minus": "-",
	    "sum-all": "Σ",
	    "square-root": "sqrt",
	    "power": "pow",
	    "swap": "swap",
	    "undo": "undo",
	    "return": "ret",
@@ -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;
@@ -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;
@@ -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();
@@ -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);

+18 −5
Original line number Diff line number Diff line
@@ -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:
@@ -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
@@ -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?