Last active
July 22, 2018 03:03
-
-
Save breeko/3e93bf376b285b178fff7e32ff3e7eb1 to your computer and use it in GitHub Desktop.
getDisplay and evaluate for OpenCalc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| getResult(): string { | |
| const numbers: Array<Operation> = this.queue.filter(op => op.operationType === OperationType.Constant); | |
| const operatorsWithParenthesis = CalcUtils.getOperatorsWithParenthesis(this.queue); | |
| const evaluatedOps = this.evaluateParenthesis(operatorsWithParenthesis); | |
| try { | |
| const out = this.evaluate(numbers, evaluatedOps, null); | |
| if (out !== null && out !== undefined) { | |
| return numberWithCommas(out.toString()); | |
| } else { | |
| const first: ?Operation = numbers[0]; | |
| if (first && first.operationArgs.has(OperationArgs.PrintAlone)) { | |
| return numberWithCommas(first.val); | |
| } | |
| return ' '; | |
| } | |
| } catch (e) { | |
| return e.message; | |
| } | |
| } | |
| evaluateParenthesis(operators: Array<Operation>, parenthesisPriority:number = 0): Array<Operation> { | |
| // Returns operators with updated priority based on parenthesis | |
| if (operators.length == 0) { | |
| return operators; | |
| } | |
| const op: Operation = operators[0]; | |
| const remainingOps: Array<Operation> = operators.slice(1, operators.length); | |
| let evaluatedOps: Array<Operation> = []; | |
| if (op.operationType === OperationType.Parenthesis) { | |
| parenthesisPriority += op.priority; | |
| parenthesisPriority = Math.max(0, parenthesisPriority); | |
| } else { | |
| const newOp = op.copy(); | |
| newOp.priority += parenthesisPriority; | |
| evaluatedOps.push(newOp); | |
| } | |
| const remaining: Array<Operation> = this.evaluateParenthesis(remainingOps, parenthesisPriority); | |
| return evaluatedOps.concat(remaining); | |
| } | |
| getDisplay(): string { | |
| if (this.queue.length === 0) { | |
| return ' ' | |
| } | |
| return this.queue.map(x => ( | |
| x.operationType == OperationType.Constant && | |
| !x.operationArgs.has(OperationArgs.PrintAsString)) ? | |
| numberWithCommas(x.stringVal, false) : | |
| x.stringVal).join(' ') | |
| } | |
| evaluate(numbers: Array<Operation>, ops: Array<Operation>, acc: ?number): ?number { | |
| if (ops.length === 0) { | |
| return acc; | |
| } | |
| let zippedOps: Array<[number,number,Operation]> = zipWithIndexTwice(ops); // e.g. 1 + 2 + 3 => returns (0, 0, +) (0, 0, -) | |
| let numUnary: number = 0; | |
| for (let idx = 0; idx < zippedOps.length; idx++) { | |
| // adjust for unary ops | |
| // e.g. sin cos 1 => | |
| // zippedOps = ((0, 0, sin), (1, 1, cos)) numbers = (1) | |
| // adjustedZippedOps = ((0, 0, sin), (1, 0 cos)) | |
| zippedOps[idx][1] -= numUnary; | |
| if (zippedOps[idx][2].operationSubType === OperationSubType.UnaryOp) { | |
| numUnary += 1; | |
| } | |
| } | |
| let maxPriority: [number,number,Operation] = zippedOps.reduce(function(a, b) { | |
| if (a[2].operationSubType === OperationSubType.UnaryOp) { | |
| // right to left on unary ops two unary ops | |
| // e.g. sin cos 1, evaluate cos(1) first | |
| return a[2].priority > b[2].priority ? a : b; | |
| } | |
| return a[2].priority >= b[2].priority ? a : b;}); | |
| const opIdx: number = maxPriority[0]; | |
| const numIdx: number = maxPriority[1]; | |
| const op: Operation = maxPriority[2]; | |
| const num1: ?Operation = numbers[numIdx]; | |
| const num2: ?Operation = numbers[numIdx + 1]; | |
| let head: Array<Operation> = numbers.slice(0, numIdx); | |
| let tail: Array<Operation> = numbers.slice(numIdx, numbers.length); | |
| let evaluatedNumber: boolean = false; | |
| if (num1) { | |
| if (op.operationSubType === OperationSubType.BackwardUnaryOp) { | |
| if (isNaN(num1.val)) { | |
| throw 'Number too long'; | |
| } | |
| acc = op.val(num1.val); | |
| tail = numbers.slice(numIdx + 1, numbers.length); | |
| evaluatedNumber = true; | |
| } else if (isInArray(op.operationSubType, Array(OperationSubType.UnaryOp, OperationSubType.BackwardUnaryOp))) { | |
| acc = op.val(num1.val); | |
| tail = numbers.slice(numIdx + 1, numbers.length); | |
| evaluatedNumber = true; | |
| } else if (op.operationSubType === OperationSubType.BinaryOp) { | |
| if (num2) { | |
| if (isNaN(num2.val)) { | |
| throw 'Number too long'; | |
| } | |
| acc = op.val(num1.val, num2.val); | |
| tail = numbers.slice(numIdx + 2, numbers.length); | |
| evaluatedNumber = true; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment