Skip to content

Commit

Permalink
Fix #660: Implement a way to customize handling undefined symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
josdejong committed Nov 19, 2020
1 parent e1dce7b commit d4bb295
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 2 deletions.
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Implemented units `kilogramforce` (`kgf`). Thanks @rnd-debug.
- Fix #2026: Implement a new option `fractionsLimit` for function `simplify`,
defaulting to `Infinity`.
- Fix #660: Implement a way to customize handling undefined symbols.


# 2020-11-09, version 8.0.1
Expand Down
19 changes: 19 additions & 0 deletions docs/expressions/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,22 @@ math.parse.isAlpha = function (c, cPrev, cNext) {
const result = math.evaluate('\u260Efoo', {'\u260Efoo': 42}) // returns 42
console.log(result)
```


## Customize handling of undefined symbols

When evaluating an expression which contains undefined symbols, an error will be thrown:

```js
math.evaluate('foo + 42') // throws "Error: Undefined symbol foo"
```

In some cases, you may want to resolve the undefined symbol instead of throwing an error. You could for example return `0` instead, or resolve the undefined symbol by looking it up somewhere. This is possible by overriding the method `handleUndefinedSymbol` on the prototype of `SymbolNode`:

```js
math.SymbolNode.prototype.handleUndefinedSymbol = function (name) {
return 0
}

math.evaluate('foo + 42') // returns 42
```
5 changes: 3 additions & 2 deletions src/expression/node/SymbolNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,14 @@ export const createSymbolNode = /* #__PURE__ */ factory(name, dependencies, ({ m
}
} else {
const isUnit = isValuelessUnit(name)
const handleUndefinedSymbol = SymbolNode.prototype.handleUndefinedSymbol

return function (scope, args, context) {
return name in scope
? getSafeProperty(scope, name)
: isUnit
? new Unit(null, name)
: undef(name)
: handleUndefinedSymbol(name)
}
}
}
Expand All @@ -107,7 +108,7 @@ export const createSymbolNode = /* #__PURE__ */ factory(name, dependencies, ({ m
* Throws an error 'Undefined symbol {name}'
* @param {string} name
*/
function undef (name) {
SymbolNode.prototype.handleUndefinedSymbol = function (name) {
throw new Error('Undefined symbol ' + name)
}

Expand Down
12 changes: 12 additions & 0 deletions test/unit-tests/expression/node/SymbolNode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ describe('SymbolNode', function () {
assert.strictEqual(expr2.evaluate(scope2), math.sqrt)
})

it('should allow customizing the behavior for undefined symbols', function () {
const original = SymbolNode.prototype.handleUndefinedSymbol

const foo = new SymbolNode('foo')
assert.throws(() => foo.evaluate(), /Undefined symbol foo/)

SymbolNode.prototype.handleUndefinedSymbol = () => 0
assert.strictEqual(foo.evaluate(), 0)

SymbolNode.prototype.handleUndefinedSymbol = original
})

it('should filter a SymbolNode', function () {
const n = new SymbolNode('x')
assert.deepStrictEqual(n.filter(function (node) { return node instanceof SymbolNode }), [n])
Expand Down

0 comments on commit d4bb295

Please sign in to comment.