TomFrost / Jexl

Javascript Expression Language: Powerful context-based expression parser and evaluator
MIT License
559 stars 90 forks source link

Scientific number notation: 1e2, 2.1e-3 etc #114

Open dy opened 2 years ago

dy commented 2 years ago

Is there any plan to support scientific number notation?

Other not supported things:

2 + .3  // unexpected literal
1 * +2 // unexpected unary
a(b)(c) // calling results of functions
TomFrost commented 2 years ago

Hi Dmitri! There are no official plans for scientific notation, but this is very easy to add by using the addBinaryOp function. You can define a new binary operator called e, set to (arg1, arg2) => arg1 * Math.pow(10, arg2), and viola! Now you can use 8.14e5 in your expressions :)

As for your other notes: 2 + .3 // unexpected literal - This is because, in Jexl, a leading dot indicates a local identifier. I could see a case for making that functionality dependent upon whether the first character after the dot is a number, but that would be a breaking change. For now, Jexl expects you to do 2 + 0.3.

1 * +2 // unexpected unary - The plus sign isn't a unary operator in Jexl. You can add unary operators as well, but Jexl currently has a limitation where you can't reuse a binary operator symbol as a unary operator, or vice versa. This is planned to be fixed. For a workaround, you can define another symbol to serve the same purpose with addUnaryOp.

a(b)(c) // calling results of functions - Jexl does not allow functions to return callable functions. This is a safety feature that's unlikely to be changed, I'm afraid. All callable functions have to be explicitly registered with addFunction, and no functions can be generated or called dynamically. This prevents a number of severe security exploits.

dy commented 2 years ago

While here, I have a suggestion. It's a bit unclear from readme how to use the module or how to just parse an expression, I had to check the source. Adding imports would be valuable:

import {Jexl} from 'jexl.js'
let jexl = new Jexl

...
await const res = jexl.eval('assoc[.first == "Lana"].last', context)
console.log(res) // Output: Kane
...
dy commented 2 years ago

(arg1, arg2) => arg1 * Math.pow(10, arg2)

That can be done simpler as

(a,b) => parseFloat(a+'e'+b)