UNPKG

rpn-cli

Version:

Command line RPN calculator using math.js engine. example: '$ rpn 1 2 +'

299 lines (290 loc) 8.14 kB
// Generated by CoffeeScript 2.4.1 /* jshint -W083 */ var E, T, all, create, display, displayElement, math, rpn; ({create, all} = require('mathjs')); //math=require 'mathjs' //math.evaluate=math.evaluateuate math = create(all); T = console.log; E = console.error; displayElement = function(x) { if (typeof x === 'string') { return math.evaluate(x).toString(); } else { return x.toString(); } }; display = function(stack) { return stack.map(displayElement); }; rpn = function(formulaOrOptions) { var applyAll, debugConsole, debugText, f, f1, f2, formula, i, l, nElements, p, precision, r, ref, ref1, ref2, registerNumber, registers, stack, step, v; formula = []; debugConsole = null; precision = 14; switch (false) { case !Array.isArray(formulaOrOptions): formula = formulaOrOptions; break; case !(typeof formulaOrOptions === 'object' && Array.isArray(formulaOrOptions.formula)): formula = (ref = formulaOrOptions.formula) != null ? ref : formula; debugConsole = (ref1 = formulaOrOptions.debugConsole) != null ? ref1 : debugConsole; precision = (ref2 = formulaOrOptions.precision) != null ? ref2 : precision; break; default: throw 'rpn:invalid formula'; } math.config({ number: 'BigNumber', precision: precision }); step = 0; stack = []; registers = {}; applyAll = false; while (formula.length > 0) { p = formula.shift(); switch (false) { case typeof p !== 'number': stack.push(math.evaluate(p)); break; case p !== '+' && p !== '-' && p !== 'x' && p !== '/' && p !== '%' && p !== '^' && p !== '*' && p !== 'v': if (stack.length < 2) { throw `'${p}' needs 2 values`; } r = stack.pop(); f2 = function(p, l, r) { var ex; ex = ''; switch (p) { case '+': ex = `${l} + ${r}`; break; case '-': ex = `${l} - ${r}`; break; case 'x': case '*': ex = `${l} * ${r}`; break; case '/': ex = `${l} / ${r}`; break; case '%': ex = `${l} % ${r}`; break; case '^': ex = `pow(${l},${r})`; break; case 'v': ex = `nthRoot(${l},${r})`; } return math.evaluate(ex); }; if (applyAll) { stack = stack.map(function(l) { return f2(p, l, r); }); applyAll = false; } else { l = stack.pop(); stack.push(f2(p, l, r)); } break; case p !== 'n' && p !== 'i' && p !== 'a' && p !== '_' && p !== '=' && p !== 'f' && p !== '!' && p !== 'l' && p !== 'L' && p !== 's' && p !== 'S' && p !== 'c' && p !== 'C' && p !== 't' && p !== 'T': if (stack.length < 1) { throw `'${p}' needs 1 values`; } f1 = function(p, l) { var ex; ex = ''; switch (p) { case 'n': ex = `0-${l}`; break; case 'i': ex = `1/${l}`; break; case 'a': ex = `abs(${l})`; break; case 'l': ex = `log(${l})`; break; case 'L': ex = `exp(${l})`; break; case '_': ex = `floor(${l})`; break; case '=': ex = `round(${l})`; break; case 'f': case '!': ex = `factorial(${l})`; break; case 's': ex = `sin(${l})`; break; case 'c': ex = `cos(${l})`; break; case 't': ex = `tan(${l})`; break; case 'S': ex = `asin(${l})`; break; case 'C': ex = `acos(${l})`; break; case 'T': ex = `atan(${l})`; } return math.evaluate(ex); }; if (applyAll) { stack = stack.map(function(l) { return f1(p, l); }); applyAll = false; } else { l = stack.pop(); stack.push(f1(p, l)); } break; case p !== 'w': if (stack.length < 2) { throw `'${p}' needs 2 values`; } switch (p) { case 'w': r = stack.pop(); l = stack.pop(); stack.push(r); stack.push(l); } break; case p !== 'r' && p !== 'R' && p !== 'd' && p !== 'p' && p !== 'D' && p !== 'V': if (stack.length < 1) { throw `'${p}' needs 1 values`; } switch (p) { case 'r': r = stack.pop(); stack.unshift(r); break; case 'R': r = stack.shift(); stack.push(r); break; case 'd': r = stack.pop(); break; case 'p': r = stack.pop(); stack.push(math.clone(r)); stack.push(r); break; case 'D': stack = []; break; case 'V': stack = [stack.pop()]; } break; case p !== 'P': stack.push('PI'); break; case p !== 'F': applyAll = true; break; case p !== 'q' && p !== 'Q' && p !== 'y' && p !== 'Y': nElements = { 'q': 1, 'Q': 2, 'y': 0, 'Y': 1 }; if (stack.length < nElements[p]) { throw `'${p}' needs ${nElements[p]} values`; } registerNumber = '0'; if (p === 'q' || p === 'Q') { registerNumber = displayElement(stack.pop()); } switch (false) { case p !== 'Q' && p !== 'Y': registers[registerNumber] = stack.pop(); break; case p !== 'q' && p !== 'y': if (!registers.hasOwnProperty(registerNumber)) { throw `Register ${registerNumber} is empty`; } stack.push(math.clone(registers[registerNumber])); } break; case p !== 'N' && p !== 'M' && p !== 'm' && p !== 'A' && p !== 'X': if (stack.length < 1) { throw `'${p}' needs 1 values`; } switch (p) { case 'N': f = function(i, x) { return i.add(1); }; i = math.evaluate(0); break; case 'M': f = function(i, x) { return math.max(i, x); }; i = math.evaluate('-Infinity'); break; case 'm': f = function(i, x) { return math.min(i, x); }; i = math.evaluate('Infinity'); break; case 'A': f = function(i, x) { return math.add(i, x); }; i = math.evaluate(0); break; case 'X': f = function(i, x) { return math.multiply(i, x); }; i = math.evaluate(1); } stack.push(stack.reduce(f, i)); break; case !p.match(/^(-?[0-9.]+(e-?[0-9.]+)?)$/): stack.push(math.evaluate(p)); break; default: throw `'${p}' unknown op`; } step++; if (debugConsole != null) { debugText = `step ${step}:[${p}] ${display(stack).join(' ')}${(applyAll ? '(F)' : '')}`; if (Object.keys(registers).length > 0) { debugText += `\t:reg{${((function() { var results; results = []; for (i in registers) { v = registers[i]; results.push(`${i}:${displayElement(v)}`); } return results; })()).join(' ')}}`; } debugConsole(debugText); } } return display(stack); }; module.exports = rpn;