Hawkeye Hawkeye - 2 months ago 11
Javascript Question

Function worked, now RangeError

Why am I getting a

RangeError: Maximum call stack exceeded
error? I am trying to parse through text to find math and solve it. It was working until I started to implement parenthesis'. I have tried to find the error but I just can't figure it out.

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
function (marked by a comment). Can anyone help me find how to fix the error?

Answer

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 */
        }
    }
}
  1. You get the value for exAS by parsing solve through a regex.
  2. If this returns a non-null value you've gotten a match
  3. With that hen you go inside the if condition and do some logic
  4. 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 ifs.
  5. 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.