Fparse
A JavaScript Formula Parser
Install / Use
/learn @bylexus/FparseREADME
fparser
A JavaScript Formula Parser
fparser provides a Formula class that parses strings containing mathematical formulas (e.g. x*sin(PI*x/2)) into an evaluationable object.
One can then provide values for all unknown variables / functions and evaluate a numeric value from the formula.
For an example application, see https://fparser.alexi.ch/.
- Features
- Breaking Changes in v4.0
- Usage
- More options
- Pre-defined functions
- Changelog
- Contributors
- TODOs, Whishlist
- License
Features
Parses a mathematical formula from a string. Known expressions:
- Numbers in the form [-]digits[.digits], e.g. "-133.2945"
- Numbers in scientific notation: e.g. "1.23e5", "1.5E-10", "-2.5e+3"
- simple operators: '+','-','*','/', '^' expanded in correct order
- logical operators: '<','<=','>','>=', '=', '!=', which evaluate to 1 or 0. Useful for implementing conditional logic
- parentheses '(', ')' for grouping (e.g. "5*(3+2)")
- all JavaScript Math object functions (e.g. "sin(3.14)")
- all JavaScript Math constants like PI, E
- the use of own functions
- the use of variables (like 'x', 'myVar')
- the use of named variables with optional brackets (like '2*myVar' or '2*[myVar]')
- the use of strings as function arguments (like 'concat("Size: ", 2, " mm")')
- the use of strings as variables (like 'concat("Size: ", 2, " ", [unit])')
- the use of path named variables and functions (like '2*[myVar.property.innerProperty]')
- memoization: store already evaluated results for faster re-calcs
- use it in Web pages, as ES6 module or as NodeJS module
- Example:<br /> <code>-1*(sin(2^x)/(PI*x))*cos(x)</code>
Breaking Changes in v4.0
Version 4.0 introduces significant improvements to the parser architecture, but includes some breaking changes. If you're upgrading from v3.x, please review these changes:
Syntax Changes
Implicit multiplication is no longer supported. You must now use explicit * operators:
| Old Syntax (v3.x) | New Syntax (v4.0) | Status |
|-------------------|-------------------|--------|
| 2x | 2*x | ❌ No longer supported |
| 2xy | 2*x*y | ❌ No longer supported |
| -3x | -3*x | ❌ No longer supported |
| 3x^2 | 3*x^2 | ❌ No longer supported |
| [myVar] | myVar or [myVar] | ✅ Both work (brackets optional) |
| PI*x | PI*x | ✅ Still works |
Migration: Update all formulas to use explicit multiplication operators (*).
Semantic Changes
Power operator (^) is now right-associative (following mathematical convention):
| Expression | Old Behavior (v3.x) | New Behavior (v4.0) |
|------------|---------------------|---------------------|
| 2^3^2 | Left-associative: (2^3)^2 = 64 | Right-associative: 2^(3^2) = 512 |
| 2^2^3 | (2^2)^3 = 64 | 2^(2^3) = 256 |
If you have formulas with chained power operators and need the old behavior, add explicit parentheses: (2^3)^2.
Removed Public Methods
The following internal methods are no longer available as they were only used by the old parser:
isOperator(char)- Only used internally by old state machine parserisOperatorExpr(expr)- Only used internally by old state machine parsersplitFunctionParams(str)- Parser now handles function arguments directly
Benefits
These changes enable a cleaner, more maintainable parser with better error messages and easier extensibility. Multi-character variables no longer require brackets, making formulas more readable.
Usage
Include as ES module directly in your web page:
<!-- Within a web page: Load the fparser library: -->
<script type="module">
import Formula from "dist/fparser.js";
const f = new Formula('x+3');
</script>
Use CommonJS / global syntax for non-module environments:
<script src="dist/fparser.umd.cjs"></script>
<script>
const f = new Formula('x+3');
</script>
Install it from npmjs.org:
# Install it using npm:
$ npm install --save fparser
Then use as ES6 module (recommended):
import Formula from 'fparser';
or use it as UMD module:
const Formula = require('fparser');
... and finally use it:
// 1. Create a Formula object instance by passing a formula string:
const fObj = new Formula('2^x');
// 2. evaluate the formula, delivering a value object for each unknown entity:
let result = fObj.evaluate({ x: 3 }); // result = 8
// or deliver multiple value objects to return multiple results:
let results = fObj.evaluate([{ x: 2 }, { x: 4 }, { x: 8 }]); // results = [4,16,256]
// You can also directly evaluate a value if you only need a one-shot result:
let result = Formula.calc('2^x', { x: 3 }); // result = 8
let results = Formula.calc('2^x', [{ x: 2 }, { x: 4 }, { x: 8 }]); // results = [4,16,256]
// Scientific notation is supported for large or small numbers:
let result = Formula.calc('1.5e3 + 2.5e-2'); // result = 1500.025
let result = Formula.calc('6.022e23 * x', { x: 2 }); // result = 1.2044e24 (Avogadro's number * 2)
More options
Using multiple variables
const fObj = new Formula('a*x^2 + b*x + c');
// Just pass a value object containing a value for each unknown variable:
let result = fObj.evaluate({ a: 2, b: -1, c: 3, x: 3 }); // result = 18
Using named variables
You can use multi-character variable names. Brackets are optional but still supported for backwards compatibility:
const fObj = new Formula('2*var1 + sin(var2+PI)');
// Just pass a value object containing a value for each named variable:
let result = fObj.evaluate({ var1: 5, var2: 0.7 });
// Brackets are still supported if you prefer:
const fObj2 = new Formula('2*[var1] + sin([var2]+PI)');
let result2 = fObj2.evaluate({ var1: 5, var2: 0.7 });
Note: Since v4.0, operators must be explicit. Single-char variable shortcuts like 2x (meaning 2*x) are no longer supported. See Breaking Changes in v4.0 for more details.
Using named object path variables
Named variables in brackets can also describe an object property path:
const fObj = new Formula('2*[var1.propertyA] + 3*[var2.propertyB.propertyC]');
// Just pass a value object containing a value for each named variable:
let result = fObj.evaluate({ var1: { propertyA: 3 }, var2: { propertyB: { propertyC: 9 } } });
This even works for array values: Instead of the property name, use a 0-based index in an array:
// var2.propertyB is an array, so we can use an index for the 3rd entry of propertyB:
const fObj = new Formula('2*[var1.propertyA] + 3*[var2.propertyB.2]');
let result = fObj.evaluate({ var1: { propertyA: 3 }, var2: { propertyB: [2, 4, 6] } });
Using user-defined functions
const fObj = new Formula('sin(inverse(x))');
//Define the function(s) on the Formula object, then use it multiple times:
fObj.inverse = (value) => 1/value;
let results = fObj.evaluate([{ x: 1 }, { x: 2 }, { x: 3 }]);
// Or pass it in the value object, and OVERRIDE an existing function:
let result = fObj.evaluate({
x: 2/Math.PI,
inverse: (value) => (-1*value)
});
If the function is defined in the value object AND on the formula object, the Value object has precedence
Functions also support the object path syntax:
// in an evaluate() value object:
const fObj = new Formula('sin(lib.inverse([lib.x]))');
const res = fObj.evaluate({
lib: { inverse: (value) => 1 / value, x: Math.PI }
});
// or set it on the Formula instance:
const fObj2 = new Formula('sin(lib.inverse(x))');
fObj2.lib = { inverse: (value) => 1 / value };
const res2 = fObj2.evaluate({ x: Math.PI });
You can also pass objects as function arguments:
const fObj = new Formula('distance(p1, p2)');
fObj.distance = (point1, point2) =>
Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
let result = fObj.evaluate({
p1: { x: 1, y: 3 },
p2: { x: 4, y: 7 }
}); // result = 5
Using strings
You can also pass strings as values or variable values (not only numbers): It is then in your responsibility to provide a function that can make sense of the string:
E.g. you can create a function that concats 2 values:
const fObj = new Formula('concat([var1], "Bar")');
let result = fObj.evaluate({ var1: 'Foo', concat: (s1, s2) => s1 + s2 });
Here, the result of the evaluation is again a string.
Of course you can use strings to make decisions: Here, we provide a function longer that
returns the length of the longe
