From e2c61896ca6219be0378f56d178a57ba9221426c Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Wed, 22 Apr 2015 17:01:10 +0430 Subject: [PATCH] feat: support negation sign (-) bump version to 1.1.0 --- dist/index.js | 17 ++++++++++- dist/tests/basic.js | 73 --------------------------------------------- dist/tests/solve.js | 14 +++++++++ equation.js | 17 ++++++++++- equation.min.js | 2 +- lib/index.js | 17 ++++++++++- package.json | 2 +- tests/solve.js | 14 +++++++++ 8 files changed, 78 insertions(+), 78 deletions(-) delete mode 100644 dist/tests/basic.js diff --git a/dist/index.js b/dist/index.js index d772cb6..7ef7dc9 100644 --- a/dist/index.js +++ b/dist/index.js @@ -154,10 +154,12 @@ var parseExpression = function parseExpression(expression) { // Create an array of separated numbers & operators while (stream.next()) { - var cur = stream.current(); + var cur = stream.current(), + past = stack.length - 1; if (cur === ' ') { continue; } + // it's probably a function with a length more than one if (!_.isNumber(cur) && !_operators2['default'][cur] && cur !== '.') { record += cur; @@ -167,6 +169,19 @@ var parseExpression = function parseExpression(expression) { } else if (_.isNumber(stack[stack.length - 1]) && (_.isNumber(cur) || cur === '.')) { stack[stack.length - 1] += cur; + } else if (stack[past] === '-') { + var beforeSign = stack[stack.length - 2]; + + if (_operators2['default'][beforeSign]) { + stack[past] += cur; + } else if (beforeSign === ')') { + stack[past] = '+'; + stack.push('-' + cur); + } else if (_.isNumber(beforeSign)) { + stack.push(cur); + } else { + stack[past] += cur; + } } else { stack.push(cur); } diff --git a/dist/tests/basic.js b/dist/tests/basic.js deleted file mode 100644 index 6495dc3..0000000 --- a/dist/tests/basic.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }; - -var _expect = require('chai'); - -var _M = require('../index.js'); - -var _M2 = _interopRequireWildcard(_M); - -describe('Basic math operators', function () { - it('should work for add +', function () { - _expect.expect(_M2['default'].solve('2+2')).to.equal(4); - }); - - it('should work for minus -', function () { - _expect.expect(_M2['default'].solve('15-3')).to.equal(12); - }); - - it('should work for divison /', function () { - _expect.expect(_M2['default'].solve('20/2')).to.equal(10); - }); - - it('should work for multiplication *', function () { - _expect.expect(_M2['default'].solve('6*3')).to.equal(18); - }); - - it('should work for power ^', function () { - _expect.expect(_M2['default'].solve('5^2')).to.equal(25); - }); - - it('should work for multi-digit numbers', function () { - _expect.expect(_M2['default'].solve('12+15')).to.equal(27); - }); -}); - -describe('Precedence', function () { - it('Test case 1', function () { - _expect.expect(_M2['default'].solve('2+(2+1)*(1+1)^2')).to.equal(14); - }); - - it('Test case 2', function () { - _expect.expect(_M2['default'].solve('2+5*4/2-2')).to.equal(10); - }); - - it('Test case 3', function () { - _expect.expect(_M2['default'].solve('2+(5*4/2)-2')).to.equal(10); - }); - - it('Test case 4', function () { - _expect.expect(_M2['default'].solve('(2+2)^2+(5+1)*4+(2+(4/2)/2)')).to.equal(16 + 24 + 3); - }); -}); - -describe('Functions', function () { - it('should work for with parantheses', function () { - _expect.expect(_M2['default'].solve('lg(4) * 5')).to.equal(10); - }); - - it('should work for without parantheses', function () { - _expect.expect(_M2['default'].solve('lg4 * 5')).to.equal(10); - }); -}); - -describe('Constats', function () { - it('should work for constant values', function () { - _expect.expect(_M2['default'].solve('sin(PI/2)')).to.equal(1); - }); - - it('should work for functions as constants', function () { - _expect.expect(_M2['default'].solve('RAND')).to.not.equal(_M2['default'].solve('RAND')); - }); -}); \ No newline at end of file diff --git a/dist/tests/solve.js b/dist/tests/solve.js index 2e1f5a7..b573531 100644 --- a/dist/tests/solve.js +++ b/dist/tests/solve.js @@ -34,6 +34,20 @@ describe('Basic math operators', function () { }); }); +describe('Negative Numbers', function () { + it('should work for negative numbers after operators', function () { + _expect.expect(_M2['default'].solve('2 + -5')).to.equal(-3); + }); + + it('should work for negative numbers after groups', function () { + _expect.expect(_M2['default'].solve('1 + (2 - 5) - 2')).to.equal(-4); + }); + + it('should work for expressions starting with negative numbers', function () { + _expect.expect(_M2['default'].solve('-2 + 1')).to.equal(-1); + }); +}); + describe('Precedence', function () { it('Test case 1', function () { _expect.expect(_M2['default'].solve('2+(2+1)*(1+1)^2')).to.equal(14); diff --git a/equation.js b/equation.js index fe93f70..ceab195 100644 --- a/equation.js +++ b/equation.js @@ -331,10 +331,12 @@ var parseExpression = function parseExpression(expression) { // Create an array of separated numbers & operators while (stream.next()) { - var cur = stream.current(); + var cur = stream.current(), + past = stack.length - 1; if (cur === ' ') { continue; } + // it's probably a function with a length more than one if (!_.isNumber(cur) && !_operators2['default'][cur] && cur !== '.') { record += cur; @@ -344,6 +346,19 @@ var parseExpression = function parseExpression(expression) { } else if (_.isNumber(stack[stack.length - 1]) && (_.isNumber(cur) || cur === '.')) { stack[stack.length - 1] += cur; + } else if (stack[past] === '-') { + var beforeSign = stack[stack.length - 2]; + + if (_operators2['default'][beforeSign]) { + stack[past] += cur; + } else if (beforeSign === ')') { + stack[past] = '+'; + stack.push('-' + cur); + } else if (_.isNumber(beforeSign)) { + stack.push(cur); + } else { + stack[past] += cur; + } } else { stack.push(cur); } diff --git a/equation.min.js b/equation.min.js index 4b635e5..5a02af2 100644 --- a/equation.min.js +++ b/equation.min.js @@ -1 +1 @@ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Equation=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gd;++d)c=c[c.length-1];return c};c.dive=g;var h=function(a){function b(b,c){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a,b){var c=void 0===arguments[2]?0:arguments[2];if(2>b)return{arr:a,index:c};var d=a.reduce(function(a,d,e){if(Array.isArray(d)){var f=h(d,b-1,e),g=f.arr,i=f.index,j=a.concat(g);return c=i,j}return a},[]);return{arr:d,index:c}});c.deep=h;var i=function(a){function b(b,c,d){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a,b,c){var d=[];if(!b.some(Array.isArray))return a[b[0]]=c,c;var e=!0,f=!1,g=void 0;try{for(var h,j=b[Symbol.iterator]();!(e=(h=j.next()).done);e=!0){var k=h.value;d.push(i(a,k,c))}}catch(l){f=!0,g=l}finally{try{!e&&j["return"]&&j["return"]()}finally{if(f)throw g}}return d});c.diveTo=i;var j=function(a){function b(b){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a){return Array.isArray(a)&&a.some(Array.isArray)?a.reduce(function(a,b){return a.concat(j(b))},[]):a});c.flatten=j;var k=function(a){return a.toString().replace(/\W/g,"")};c.removeSymbols=k},{}],3:[function(a,b,c){"use strict";var d=function(a){return a&&a.__esModule?a:{"default":a}},e=function(a,b){if(Array.isArray(a))return a;if(Symbol.iterator in Object(a)){var c=[],d=!0,e=!1,f=void 0;try{for(var g,h=a[Symbol.iterator]();!(d=(g=h.next()).done)&&(c.push(g.value),!b||c.length!==b);d=!0);}catch(i){e=!0,f=i}finally{try{!d&&h["return"]&&h["return"]()}finally{if(e)throw f}}return c}throw new TypeError("Invalid attempt to destructure non-iterable instance")},f=function(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);be;e++)d[e]=arguments[e];return a=a.replace(/[a-z]*/g,function(a){var b=c.indexOf(a);return b>-1?d[b]||0:a}),o.solve(a)}},registerOperator:function(a,b){j["default"][a]=b},registerConstant:function(a,b){l["default"][a]=b}},p=function(a){function b(b){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a){return a.some(Array.isArray)?(a=a.map(function(a){return Array.isArray(a)?p(a):a}),p(a)):x(a)}),q=Object.keys(j["default"]).map(function(a){return j["default"][a].precedence}),r=Math.max.apply(Math,f(q)),s=Math.min.apply(Math,f(q)),t=function(a){for(var b=new h["default"](a),c=[],d="";b.next();){var e=b.current();" "!==e&&(n.isNumber(e)||j["default"][e]||"."===e?d.length?(c.push(d,e),d=""):n.isNumber(c[c.length-1])&&(n.isNumber(e)||"."===e)?c[c.length-1]+=e:c.push(e):d+=e)}return d.length&&c.push(d),u(c)},u=function(a){var b=0;return a.reduce(function(a,c){return c.indexOf("(")>-1?(c.length>1?n.dive(a,b).push(c.replace("(",""),[]):n.dive(a,b).push([]),b++):")"===c?b--:n.dive(a,b).push(c),a},[])},v=function(a){var b="string"==typeof a?j["default"][a]:a;if(!b)return null;var c=b.format.split("1"),d=c[0].length,e=c[1].length;return{left:d,right:e}},w=function(a){function b(b){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a){var b=!0,c=!1,d=void 0;try{for(var f,g=a.entries()[Symbol.iterator]();!(b=(f=g.next()).done);b=!0){var h=e(f.value,2),i=h[0],k=h[1];Array.isArray(k)&&a.splice(i,1,w(k))}}catch(l){c=!0,d=l}finally{try{!b&&g["return"]&&g["return"]()}finally{if(c)throw d}}for(var m=s;r>=m;m++)for(var i=0;iu;u++)t=[t];i-=q}}return a}),x=function(a){var b,c=y(a);if(!c)return a[0];var d=v(c),e=d.left,g=a.slice(0,e),h=a.slice(e+1);return(b=j["default"][c]).fn.apply(b,f(g).concat(f(h)))},y=function(a){var b=!0,c=!1,d=void 0;try{for(var e,f=a[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;if("string"==typeof g)return g}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return null},z=function(a){return a.replace(/[A-Z]*/g,function(a){var b=l["default"][a];return b?"function"==typeof b?b():b:a})};c["default"]=o,b.exports=c["default"]},{"./constants":1,"./helpers":2,"./operators":4,"./readstream":5}],4:[function(a,b,c){"use strict";Object.defineProperty(c,"__esModule",{value:!0}),c["default"]={"^":{fn:function(a,b){return Math.pow(a,b)},format:"010",precedence:0},"*":{fn:function(a,b){return a*b},format:"010",precedence:1},"/":{fn:function(a,b){return a/b},format:"010",precedence:1},"%":{fn:function(a,b){return a%b},format:"010",precedence:1},"\\":{fn:function(a,b){return Math.floor(a/b)},format:"010",precedence:1},"+":{fn:function(a,b){return a+b},format:"010",precedence:2},"-":{fn:function(a,b){return a-b},format:"010",precedence:2},"!":{fn:function(a){for(var b=1,c=0;a>c;++c)b*=c;return b},format:"01",precedence:2},log:{fn:Math.log,format:"10",precedence:-1},ln:{fn:Math.log,format:"10",precedence:-1},lg:{fn:function(a){return Math.log(a)/Math.log(2)},format:"10",precedence:-1},sin:{fn:Math.sin,format:"10",precedence:-1},cos:{fn:Math.cos,format:"10",precedence:-1},tan:{fn:Math.tan,format:"10",precedence:-1},cot:{fn:Math.cot,format:"10",precedence:-1}},b.exports=c["default"]},{}],5:[function(a,b,c){"use strict";Object.defineProperty(c,"__esModule",{value:!0}),c["default"]=function(a){var b=0,c=[];return{next:function(){return c.push(a[b]),b>=a.length?null:a[b++]},current:function(){return a[b-1]},index:function(){return b-1},to:function(c){var d="",e=b+c;for(b=b;e>b;++b)d+=[a[b]];return d},drain:function(){return c.splice(0,c.length)},replace:function(a){function b(b,c,d){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(c,d,e){var f=a.split("");f.splice(c,d,e),a=f.join(""),b-=d-c}),go:function(a){b+=a},all:function(){return a}}},b.exports=c["default"]},{}]},{},[3])(3)}); \ No newline at end of file +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Equation=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gd;++d)c=c[c.length-1];return c};c.dive=g;var h=function(a){function b(b,c){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a,b){var c=void 0===arguments[2]?0:arguments[2];if(2>b)return{arr:a,index:c};var d=a.reduce(function(a,d,e){if(Array.isArray(d)){var f=h(d,b-1,e),g=f.arr,i=f.index,j=a.concat(g);return c=i,j}return a},[]);return{arr:d,index:c}});c.deep=h;var i=function(a){function b(b,c,d){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a,b,c){var d=[];if(!b.some(Array.isArray))return a[b[0]]=c,c;var e=!0,f=!1,g=void 0;try{for(var h,j=b[Symbol.iterator]();!(e=(h=j.next()).done);e=!0){var k=h.value;d.push(i(a,k,c))}}catch(l){f=!0,g=l}finally{try{!e&&j["return"]&&j["return"]()}finally{if(f)throw g}}return d});c.diveTo=i;var j=function(a){function b(b){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a){return Array.isArray(a)&&a.some(Array.isArray)?a.reduce(function(a,b){return a.concat(j(b))},[]):a});c.flatten=j;var k=function(a){return a.toString().replace(/\W/g,"")};c.removeSymbols=k},{}],3:[function(a,b,c){"use strict";var d=function(a){return a&&a.__esModule?a:{"default":a}},e=function(a,b){if(Array.isArray(a))return a;if(Symbol.iterator in Object(a)){var c=[],d=!0,e=!1,f=void 0;try{for(var g,h=a[Symbol.iterator]();!(d=(g=h.next()).done)&&(c.push(g.value),!b||c.length!==b);d=!0);}catch(i){e=!0,f=i}finally{try{!d&&h["return"]&&h["return"]()}finally{if(e)throw f}}return c}throw new TypeError("Invalid attempt to destructure non-iterable instance")},f=function(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);be;e++)d[e]=arguments[e];return a=a.replace(/[a-z]*/g,function(a){var b=c.indexOf(a);return b>-1?d[b]||0:a}),o.solve(a)}},registerOperator:function(a,b){j["default"][a]=b},registerConstant:function(a,b){l["default"][a]=b}},p=function(a){function b(b){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a){return a.some(Array.isArray)?(a=a.map(function(a){return Array.isArray(a)?p(a):a}),p(a)):x(a)}),q=Object.keys(j["default"]).map(function(a){return j["default"][a].precedence}),r=Math.max.apply(Math,f(q)),s=Math.min.apply(Math,f(q)),t=function(a){for(var b=new h["default"](a),c=[],d="";b.next();){var e=b.current(),f=c.length-1;if(" "!==e)if(n.isNumber(e)||j["default"][e]||"."===e)if(d.length)c.push(d,e),d="";else if(n.isNumber(c[c.length-1])&&(n.isNumber(e)||"."===e))c[c.length-1]+=e;else if("-"===c[f]){var g=c[c.length-2];j["default"][g]?c[f]+=e:")"===g?(c[f]="+",c.push("-"+e)):n.isNumber(g)?c.push(e):c[f]+=e}else c.push(e);else d+=e}return d.length&&c.push(d),u(c)},u=function(a){var b=0;return a.reduce(function(a,c){return c.indexOf("(")>-1?(c.length>1?n.dive(a,b).push(c.replace("(",""),[]):n.dive(a,b).push([]),b++):")"===c?b--:n.dive(a,b).push(c),a},[])},v=function(a){var b="string"==typeof a?j["default"][a]:a;if(!b)return null;var c=b.format.split("1"),d=c[0].length,e=c[1].length;return{left:d,right:e}},w=function(a){function b(b){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(a){var b=!0,c=!1,d=void 0;try{for(var f,g=a.entries()[Symbol.iterator]();!(b=(f=g.next()).done);b=!0){var h=e(f.value,2),i=h[0],k=h[1];Array.isArray(k)&&a.splice(i,1,w(k))}}catch(l){c=!0,d=l}finally{try{!b&&g["return"]&&g["return"]()}finally{if(c)throw d}}for(var m=s;r>=m;m++)for(var i=0;iu;u++)t=[t];i-=q}}return a}),x=function(a){var b,c=y(a);if(!c)return a[0];var d=v(c),e=d.left,g=a.slice(0,e),h=a.slice(e+1);return(b=j["default"][c]).fn.apply(b,f(g).concat(f(h)))},y=function(a){var b=!0,c=!1,d=void 0;try{for(var e,f=a[Symbol.iterator]();!(b=(e=f.next()).done);b=!0){var g=e.value;if("string"==typeof g)return g}}catch(h){c=!0,d=h}finally{try{!b&&f["return"]&&f["return"]()}finally{if(c)throw d}}return null},z=function(a){return a.replace(/[A-Z]*/g,function(a){var b=l["default"][a];return b?"function"==typeof b?b():b:a})};c["default"]=o,b.exports=c["default"]},{"./constants":1,"./helpers":2,"./operators":4,"./readstream":5}],4:[function(a,b,c){"use strict";Object.defineProperty(c,"__esModule",{value:!0}),c["default"]={"^":{fn:function(a,b){return Math.pow(a,b)},format:"010",precedence:0},"*":{fn:function(a,b){return a*b},format:"010",precedence:1},"/":{fn:function(a,b){return a/b},format:"010",precedence:1},"%":{fn:function(a,b){return a%b},format:"010",precedence:1},"\\":{fn:function(a,b){return Math.floor(a/b)},format:"010",precedence:1},"+":{fn:function(a,b){return a+b},format:"010",precedence:2},"-":{fn:function(a,b){return a-b},format:"010",precedence:2},"!":{fn:function(a){for(var b=1,c=0;a>c;++c)b*=c;return b},format:"01",precedence:2},log:{fn:Math.log,format:"10",precedence:-1},ln:{fn:Math.log,format:"10",precedence:-1},lg:{fn:function(a){return Math.log(a)/Math.log(2)},format:"10",precedence:-1},sin:{fn:Math.sin,format:"10",precedence:-1},cos:{fn:Math.cos,format:"10",precedence:-1},tan:{fn:Math.tan,format:"10",precedence:-1},cot:{fn:Math.cot,format:"10",precedence:-1}},b.exports=c["default"]},{}],5:[function(a,b,c){"use strict";Object.defineProperty(c,"__esModule",{value:!0}),c["default"]=function(a){var b=0,c=[];return{next:function(){return c.push(a[b]),b>=a.length?null:a[b++]},current:function(){return a[b-1]},index:function(){return b-1},to:function(c){var d="",e=b+c;for(b=b;e>b;++b)d+=[a[b]];return d},drain:function(){return c.splice(0,c.length)},replace:function(a){function b(b,c,d){return a.apply(this,arguments)}return b.toString=function(){return a.toString()},b}(function(c,d,e){var f=a.split("");f.splice(c,d,e),a=f.join(""),b-=d-c}),go:function(a){b+=a},all:function(){return a}}},b.exports=c["default"]},{}]},{},[3])(3)}); \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 282f750..b95aaa4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -118,10 +118,12 @@ const parseExpression = expression => { // Create an array of separated numbers & operators while (stream.next()) { - const cur = stream.current(); + const cur = stream.current(), + past = stack.length - 1; if (cur === ' ') { continue; } + // it's probably a function with a length more than one if (!_.isNumber(cur) && !operators[cur] && cur !== '.') { record += cur; @@ -132,6 +134,19 @@ const parseExpression = expression => { (_.isNumber(cur) || cur === '.')) { stack[stack.length - 1] += cur; + } else if (stack[past] === '-') { + const beforeSign = stack[stack.length - 2]; + + if (operators[beforeSign]) { + stack[past] += cur; + } else if (beforeSign === ')') { + stack[past] = '+'; + stack.push(`-${cur}`); + } else if (_.isNumber(beforeSign)) { + stack.push(cur); + } else { + stack[past] += cur; + } } else { stack.push(cur); } diff --git a/package.json b/package.json index 63992b5..047d457 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "equations", - "version": "1.0.1", + "version": "1.1.0", "description": "", "main": "dist/index.js", "directories": { diff --git a/tests/solve.js b/tests/solve.js index 75599aa..89eef22 100644 --- a/tests/solve.js +++ b/tests/solve.js @@ -27,6 +27,20 @@ describe('Basic math operators', () => { }); }); +describe('Negative Numbers', () => { + it('should work for negative numbers after operators', () => { + expect(M.solve('2 + -5')).to.equal(-3); + }); + + it('should work for negative numbers after groups', () => { + expect(M.solve('1 + (2 - 5) - 2')).to.equal(-4); + }); + + it('should work for expressions starting with negative numbers', () => { + expect(M.solve('-2 + 1')).to.equal(-1); + }); +}); + describe('Precedence', () => { it('Test case 1', () => { expect(M.solve('2+(2+1)*(1+1)^2')).to.equal(14);