Hawkeye - 1 year ago 49

Javascript Question

Why am I getting a

`RangeError: Maximum call stack exceeded`

My Code:

`var alg = {`

calc: function(eq, solveFor) {

var out;

var sideOne = eq.substring(0, eq.indexOf('='))

var sideTwo = eq.substring(eq.indexOf('=') + 1)

if (sideOne === solveFor) {

alg.simplify(sideTwo);

}

if (sideTwo === solveFor) {

alg.simplify(sideOne);

}

},

simplify: function(eq) {

str = $.trim(eq);

if (str == undefined) {

console.error('Error: null string')

} else {

var charMatch = /^[\d\*\/\+\-\^\(\) ]+$/

if (charMatch.exec(str) === null) {

console.error('Error: Invalid char/expression')

} else {

alg.parMath('not');

alg.expRoot(solve);

alg.multDiv(solve);

alg.addSubtr(solve);

}

}

},

fromPar: function(par) {

alg.parMath(par);

alg.expRoot(solve);

alg.multDiv(solve);

alg.addSubtr(solve);

},

parMath: function(source) {

var reP = /\(([\d\*\/\+\-\^\(\) ]+)\)/

var exP = reP.exec(str)

if (source === 'par') {

str = str.replace(exP[0], solve)

}

if (exP !== null) {

use = 'par'

solve = exP[1]

} else {

use = 'not'

solve = str;

}

},

expRoot: function() {

var fracCon = /(\d+)\/(\d+)/

var reER = /(\d+)(\^)(\d+(\/\d)?)(?!\/)/

var exER = reER.exec(solve)

if (exER !== null) {

var exFC = fracCon.exec(exER[3])

if (exFC !== null) {

var rep = Math.pow(parseFloat(exER[1]),(parseFloat(exFC[1]) / parseFloat(exFC[2])))

} else {

var rep = Math.pow(parseFloat(exER[1]),parseFloat(exER[3]))

}

solve = solve.replace(exER[0], rep)

if (reER.exec(solve) !== null) {

alg.expRoot();

}

}

},

multDiv: function() {

var reMD = /(\d+(?:\.\d+)?) *([\*|\/]) *(\d+(?:\.\d+)?)/

var exMD = reMD.exec(solve);

if (exMD !== null) {

if (exMD[2] === "*") {

var rep = parseFloat(exMD[1]) * parseFloat(exMD[3]);

var rep = Math.round(rep * 1000000) / 1000000;

} else {

var rep = parseFloat(exMD[1]) / parseFloat(exMD[3]);

var rep = Math.round(rep * 1000000) / 1000000;

}

if (use !== 'par') {

solve = solve.replace(exMD[0], rep);

}

if (reMD.exec(solve) !== null) {

alg.multDiv();

}

}

},

addSubtr: function() {

var reAS = /(\d+(?:\.\d+)?) *([\+|\-]) *(\d+(?:\.\d+)?)/

var exAS = reAS.exec(solve); //Getting RangeError here

if (exAS !== null) {

if (exAS[2] === "+") {

var rep = parseFloat(exAS[1]) + parseFloat(exAS[3])

var rep = Math.round(rep * 1000000) / 1000000

} else {

var rep = parseFloat(exAS[1]) - parseFloat(exAS[3])

var rep = Math.round(rep * 1000000) / 1000000

}

if (use !== 'par') {

str = str.replace(exAS[0], rep)

}

if (exAS !== null) {

alg.addSubtr(solve);

} else {

if (use == 'not') {

out = solve;

} else {

alg.fromPar('par')

}

}

} else {

if (use == 'not') {

out = solve;

} else {

alg.fromPar('par')

}

}

}

};

console.log(alg.calc('x=(1+1)', "x"));

`<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>`

I'm getting the error at the start of

`addSubtr`

Answer Source

The problem is that your code goes into an infinite loop. Here is the relevant part of the logic

```
addSubtr: function() {
/* ommitted */
var exAS = reAS.exec(solve); //Getting RangeError here
if (exAS !== null) {
/* ommitted - logic here*/
if (exAS !== null) {
alg.addSubtr(solve);
/* ommitted */
}
}
}
```

- You get the value for
`exAS`

by parsing`solve`

through a regex. - If this returns a non-null value you've gotten a match
- With that hen you go inside the
`if`

condition and do some logic - Still inside there, there is another
`if`

statement that checks if the regex matched anything. Now, by definition, this would be true - it can be easily seen with a lot of code removed - the same condition is checked for twice. There is nothing that would change the the outcome between the two`if`

s. - Since the conditional check passes you recursively call the same function again with the same input.

Because the input is the same, the logic will work the same so steps 1-5 are executed again and the function is called again.

This causes infinite recursion. Well, in reality there is a limit and that's the stack size for JavaScript, which is why you are getting the error. It's a bit misleading, since it's the regex that runs over the call stack size, not the recursive call to `addSubtr`

, else it would have been a bit more clear what is going on.

For how to fix it - you need to restructure the logic so you don't get into infinite loops. I am not sure exactly what is the best way for your case but I'd suggest working it out yourself - it would be a useful exercise regardless. Here are some pointers

In point `4.`

I made, I mentioned that there was an essentially useless check. I assume that it is supposed to be useful.
- You may have intended the inner `if`

to be outside of the outer one. As it stands now, the two are equivalent so the inner `if`

can just be removed.

- maybe the condition of the inner `if`

is incorrect - it could be that you only sometimes want to do the recursive call, not every time.
- perhaps there was supposed to be something that changes either `exAS`

or `solve`

or both. Thus either the condition would (potentially) yield a different result the second time it's checked, or the function would produce a different result when called recursively (which would make the recursive call useful) or both.