Hawkeye
Hawkeye

Reputation: 377

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?

Upvotes: 1

Views: 42

Answers (2)

AJ_
AJ_

Reputation: 3987

Your main problem is that you have an infinite loop which is here

        if (exAS !== null) {
            alg.addSubtr(solve);
        }

This is a useless check for two reasons. One because as you notcie exAS is defined in addSubtr. So every time you call this function you are resetting the value.
Your other problems are you are create variables with the same names, and relying off of static variables/ void functions. If pm me i cant help you workout the correct way to structure this this function and all the other functions .

Upvotes: 0

VLAZ
VLAZ

Reputation: 29086

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.

Upvotes: 1

Related Questions