expr-eval icon indicating copy to clipboard operation
expr-eval copied to clipboard

problem with equation: `length * width`

Open shanebdavis opened this issue 10 months ago • 3 comments

Parse Problem

Repro:

// fails with '*'
(new require('expr-eval').Parser).parse("length * width")

// fails with '/'
(new require('expr-eval').Parser).parse("length / width")

Throws error:

Uncaught Error: unexpected TOP: *
    at ParserState.parseAtom (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1076:13)
    at ParserState.parseMemberExpression (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1305:10)
    at ParserState.parseFunctionCall (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1277:12)
    at ParserState.parsePostfixExpression (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1260:10)
    at ParserState.parseExponential (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1252:10)
    at ParserState.parseFactor (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1247:12)
    at ParserState.parseFactor (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1244:12)
    at ParserState.parseTerm (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1215:10)
    at ParserState.parseAddSub (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1204:10)

But if you change the things just a little, it works:

// change the name to 'lengthh': works
(new require('expr-eval').Parser).parse("lengthh * width")

// change the order: works
(new require('expr-eval').Parser).parse("width * length")

// change the operator to '+': works
(new require('expr-eval').Parser).parse("length + width")

Eval Problem

On further testing, I also found that even if the equations parse, if the variable name "length" is used, it evaluates incorrectly:

> (new require('expr-eval').Parser).parse("width * length").evaluate({width: 5, length: 7})
NaN

> (new require('expr-eval').Parser).parse("length + width").evaluate({width: 5, length: 7})
1

But, if you don't use the variable name length it works:

> (new require('expr-eval').Parser).parse("len + width").evaluate({width: 5, len: 7})
12

Versions

  • expr-eval: 2.0.2
  • node: v22.12.0
  • MacOS: 15.3.2 (24D81)

shanebdavis avatar Apr 02 '25 09:04 shanebdavis

Hi @shanebdavis, I think this is expected - length is a utility function in expr eval so using the string "length" in a formula would mean using the function length(x), not the variable with name length. https://www.npmjs.com/package/expr-eval#unary-operators

Justinette2175 avatar Apr 02 '25 13:04 Justinette2175

Ah, I didn't realize "parentheses are optional" for functions. You are probably right that's what's happening.

I find the overall behavior still a little weird. How did width * length parse? If length is a unary operator, that should also be a parse error, no? And length + width -- I guess that is the same as length(+width) but shouldn't that be a type error? width is a number and has no length?

In any case, My application needs to work with all kinds of measurements and length is going to be a very common variable name. So shouldn't I be able to disable that operator?

Shouldn't this disable all operators except for multiply? It doesn't seem to work:

const {Parser} = require('expr-eval');
const parser = new Parser({operators: {multiply: true}});
parser.parse("length * width");

Uncaught Error: unexpected TOP: *
    at ParserState.parseAtom (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1076:13)
    at ParserState.parseMemberExpression (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1305:10)
    at ParserState.parseFunctionCall (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1277:12)
    at ParserState.parsePostfixExpression (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1260:10)
    at ParserState.parseExponential (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1252:10)
    at ParserState.parseFactor (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1247:12)
    at ParserState.parseFactor (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1244:12)
    at ParserState.parseTerm (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1215:10)
    at ParserState.parseAddSub (/Users/shanebdavis/dev/kaiizen/thd/node_modules/expr-eval/dist/bundle.js:1204:10)

Is length just a reserved word I can't use for variables at all?

shanebdavis avatar Apr 02 '25 13:04 shanebdavis

Is there a way to make the parentheses not optional for word-based functions? I don't see an option for it. It would disable the word-based unary operators, so for example "length * width" would look for a variable 'length' whereas "length(a)" would call the function to get the length of the array.

toxikman avatar Oct 19 '25 23:10 toxikman