@jbrowse/jexl 3.3.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/Expression.js +1 -2
  2. package/dist/Expression.js.map +1 -1
  3. package/dist/Jexl.d.ts +2 -2
  4. package/dist/Lexer.d.ts +10 -8
  5. package/dist/Lexer.js +46 -35
  6. package/dist/Lexer.js.map +1 -1
  7. package/dist/evaluator/compile.d.ts +6 -4
  8. package/dist/evaluator/compile.js +91 -55
  9. package/dist/evaluator/compile.js.map +1 -1
  10. package/dist/grammar.js +1 -1
  11. package/dist/parser/Parser.d.ts +2 -9
  12. package/dist/parser/Parser.js +2 -12
  13. package/dist/parser/Parser.js.map +1 -1
  14. package/dist/parser/handlers.d.ts +6 -3
  15. package/dist/parser/handlers.js +45 -28
  16. package/dist/parser/handlers.js.map +1 -1
  17. package/dist/parser/states.js +3 -5
  18. package/dist/parser/states.js.map +1 -1
  19. package/dist/types.d.ts +0 -3
  20. package/esm/Expression.js +1 -2
  21. package/esm/Expression.js.map +1 -1
  22. package/esm/Jexl.d.ts +2 -2
  23. package/esm/Lexer.d.ts +10 -8
  24. package/esm/Lexer.js +46 -35
  25. package/esm/Lexer.js.map +1 -1
  26. package/esm/evaluator/compile.d.ts +6 -4
  27. package/esm/evaluator/compile.js +91 -55
  28. package/esm/evaluator/compile.js.map +1 -1
  29. package/esm/grammar.js +1 -1
  30. package/esm/parser/Parser.d.ts +2 -9
  31. package/esm/parser/Parser.js +2 -12
  32. package/esm/parser/Parser.js.map +1 -1
  33. package/esm/parser/handlers.d.ts +6 -3
  34. package/esm/parser/handlers.js +45 -28
  35. package/esm/parser/handlers.js.map +1 -1
  36. package/esm/parser/states.js +3 -5
  37. package/esm/parser/states.js.map +1 -1
  38. package/esm/types.d.ts +0 -3
  39. package/package.json +2 -1
  40. package/src/Expression.ts +1 -2
  41. package/src/Jexl.ts +2 -2
  42. package/src/Lexer.ts +47 -36
  43. package/src/evaluator/compile.ts +108 -71
  44. package/src/grammar.ts +1 -1
  45. package/src/parser/Parser.ts +2 -13
  46. package/src/parser/handlers.ts +48 -31
  47. package/src/parser/states.ts +3 -5
  48. package/src/types.ts +0 -3
  49. package/dist/evaluator/Evaluator.d.ts +0 -37
  50. package/dist/evaluator/Evaluator.js +0 -49
  51. package/dist/evaluator/Evaluator.js.map +0 -1
  52. package/esm/evaluator/Evaluator.d.ts +0 -37
  53. package/esm/evaluator/Evaluator.js +0 -47
  54. package/esm/evaluator/Evaluator.js.map +0 -1
  55. package/src/evaluator/Evaluator.ts +0 -58
@@ -32,7 +32,7 @@ const tokenHandlers: Record<
32
32
  /**
33
33
  * The Parser is a state machine that converts tokens from the {@link Lexer}
34
34
  * into an Abstract Syntax Tree (AST), capable of being evaluated in any
35
- * context by the {@link Evaluator}. The Parser expects that all tokens
35
+ * context by {@link compileAst}. The Parser expects that all tokens
36
36
  * provided to it are legal and typed properly according to the grammar, but
37
37
  * accepts that the tokens may still be in an invalid order or in some other
38
38
  * unparsable configuration that requires it to throw an Error.
@@ -52,13 +52,11 @@ class Parser {
52
52
  _state: string
53
53
  _tree: AstNode | null
54
54
  _exprStr: string
55
- _relative: boolean
56
55
  _stopMap: Record<string, string>
57
56
  _cursor?: AstNode | null
58
57
  _subParser?: Parser
59
58
  _parentStop?: boolean
60
59
  _nextIdentEncapsulate?: boolean
61
- _nextIdentRelative?: boolean
62
60
  _curObjKey?: string
63
61
  _sequenceExpressions?: AstNode[]
64
62
 
@@ -73,7 +71,6 @@ class Parser {
73
71
  this._state = 'expectOperand'
74
72
  this._tree = null
75
73
  this._exprStr = prefix || ''
76
- this._relative = false
77
74
  this._stopMap = stopMap || {}
78
75
  }
79
76
 
@@ -143,7 +140,7 @@ class Parser {
143
140
  /**
144
141
  * Marks this Parser instance as completed and retrieves the full AST.
145
142
  * @returns {{}|null} a full expression tree, ready for evaluation by the
146
- * {@link Evaluator#eval} function, or null if no tokens were passed to
143
+ * {@link compileAst} function, or null if no tokens were passed to
147
144
  * the parser before complete was called
148
145
  * @throws {Error} if the parser is not in a state where it's legal to end
149
146
  * the expression, indicating that the expression is incomplete
@@ -179,14 +176,6 @@ class Parser {
179
176
  return this._cursor ? this._tree : null
180
177
  }
181
178
 
182
- /**
183
- * Indicates whether the expression tree contains a relative path identifier.
184
- * @returns {boolean} true if a relative identifier exists false otherwise.
185
- */
186
- isRelative() {
187
- return this._relative
188
- }
189
-
190
179
  /**
191
180
  * Ends a subexpression by completing the subParser and passing its result
192
181
  * to the subHandler configured in the current state.
@@ -64,7 +64,7 @@ export function arrayVal(this: Parser, ast: AstNode | null) {
64
64
  export function binaryOp(this: Parser, token: Token) {
65
65
  if (token.value === '=') {
66
66
  // `from` marks a member access such as `a.b`; only a bare name can be
67
- // assigned to, since the Evaluator writes straight into the context
67
+ // assigned to, since the compiled closure writes straight into the context
68
68
  if (
69
69
  this._cursor?.type !== 'Identifier' ||
70
70
  (this._cursor as Identifier).from
@@ -90,9 +90,15 @@ export function binaryOp(this: Parser, token: Token) {
90
90
  if (!parentExpr.operator) {
91
91
  break
92
92
  }
93
- if (
94
- precedenceOf(this._grammar.elements[parentExpr.operator]) < precedence
95
- ) {
93
+ // a prefix operator binds tighter than any binary one, so `-x ^ 2` groups
94
+ // as `(-x) ^ 2` — the same way `-2 ^ 2` already does, since the Lexer folds
95
+ // that sign into the literal. Looking `-` up in the grammar finds its
96
+ // binary precedence instead, which is lower than `^`'s and gave `-(x ^ 2)`
97
+ const parentPrecedence =
98
+ parent.type === 'UnaryExpression'
99
+ ? Infinity
100
+ : precedenceOf(this._grammar.elements[parentExpr.operator])
101
+ if (parentPrecedence < precedence) {
96
102
  break
97
103
  }
98
104
  this._cursor = parent
@@ -115,18 +121,20 @@ export function binaryOp(this: Parser, token: Token) {
115
121
  */
116
122
  export function dot(this: Parser) {
117
123
  const cursor = this._cursor
118
- // the dot continues an identifier chain unless the cursor is an operator
119
- // still waiting on its right-hand side, in which case it opens a relative
120
- // path instead — as in the leading dot of `list[.price > 5]`
121
- this._nextIdentEncapsulate =
122
- !!cursor &&
123
- cursor.type !== 'UnaryExpression' &&
124
- (cursor.type !== 'BinaryExpression' || !!cursor.right)
125
-
126
- this._nextIdentRelative = !this._nextIdentEncapsulate
127
- if (this._nextIdentRelative) {
128
- this._relative = true
124
+ // a dot continues an identifier chain. With nothing to continue — no cursor,
125
+ // or an operator still waiting on its right-hand side — it would instead open
126
+ // a relative path, the leading dot of `list[.price > 5]`. This fork removed
127
+ // array filtering expressions, which are the only construct that gives a
128
+ // relative path a root to resolve against, so it is rejected here rather than
129
+ // parsed into a tree that can only fail once it is evaluated.
130
+ if (
131
+ !cursor ||
132
+ cursor.type === 'UnaryExpression' ||
133
+ (cursor.type === 'BinaryExpression' && !cursor.right)
134
+ ) {
135
+ throw new Error(`Relative paths are not supported: ${this._exprStr}`)
129
136
  }
137
+ this._nextIdentEncapsulate = true
130
138
  }
131
139
 
132
140
  /**
@@ -138,7 +146,6 @@ export function filter(this: Parser, ast: AstNode | null) {
138
146
  const node: FilterExpression = {
139
147
  type: 'FilterExpression',
140
148
  expr: ast!,
141
- relative: this._subParser!.isRelative(),
142
149
  subject: this._cursor!
143
150
  }
144
151
  this._placeBeforeCursor(node)
@@ -162,12 +169,11 @@ export function functionCall(this: Parser) {
162
169
  // there is nothing to look up in the function pool
163
170
  throw new Error(`Functions must be called by name: ${this._exprStr}`)
164
171
  }
165
- const { from } = cursor as Identifier
172
+ const { from, value } = cursor as Identifier
166
173
  const node: FunctionCall = {
167
174
  type: 'FunctionCall',
168
- name: (cursor as Identifier).value,
169
- args: from ? [from] : [],
170
- pool: 'functions'
175
+ name: value,
176
+ args: from ? [from] : []
171
177
  }
172
178
  this._placeBeforeCursor(node)
173
179
  }
@@ -186,10 +192,6 @@ export function identifier(this: Parser, token: Token) {
186
192
  this._placeBeforeCursor(node)
187
193
  this._nextIdentEncapsulate = false
188
194
  } else {
189
- if (this._nextIdentRelative) {
190
- node.relative = true
191
- this._nextIdentRelative = false
192
- }
193
195
  this._placeAtCursor(node)
194
196
  }
195
197
  }
@@ -274,7 +276,7 @@ export function objStart(this: Parser) {
274
276
  export function objVal(this: Parser, ast: AstNode | null) {
275
277
  // defined rather than assigned so that the key "__proto__" becomes an
276
278
  // ordinary entry of the node's key map instead of re-pointing its prototype,
277
- // which dropped the entry before the Evaluator ever saw it
279
+ // which dropped the entry before it could be compiled
278
280
  Object.defineProperty(
279
281
  (this._cursor as ObjectLiteral).value,
280
282
  this._curObjKey!,
@@ -313,17 +315,32 @@ export function ternaryMid(this: Parser, ast: AstNode | null) {
313
315
  }
314
316
 
315
317
  /**
316
- * Handles the start of a new ternary expression by encapsulating the entire
317
- * AST in a ConditionalExpression node, and using the existing tree as the
318
- * test element.
318
+ * Handles the start of a new ternary expression by encapsulating the tree so
319
+ * far in a ConditionalExpression node, and using it as the test element.
320
+ *
321
+ * Every operator binds tighter than the conditional and so belongs in the test
322
+ * — except `=`, which binds looser. `x = a ? b : c` therefore assigns the
323
+ * conditional rather than testing the assignment, which had stored `a` in `x`.
319
324
  */
320
325
  export function ternaryStart(this: Parser) {
326
+ let assignment: AstNode | undefined
327
+ let test = this._tree!
328
+ while (test.type === 'AssignmentExpression' && test.right) {
329
+ assignment = test
330
+ test = test.right
331
+ }
332
+
321
333
  const node: ConditionalExpression = {
322
334
  type: 'ConditionalExpression',
323
- test: this._tree!
335
+ test
336
+ }
337
+ if (assignment) {
338
+ assignment.right = node
339
+ this._setParent(node, assignment)
340
+ } else {
341
+ this._tree = node
324
342
  }
325
- this._tree = node
326
- this._cursor = this._tree
343
+ this._cursor = node
327
344
  }
328
345
 
329
346
  /**
@@ -97,10 +97,6 @@ export const states: States = {
97
97
  colon: { toState: 'objVal' }
98
98
  }
99
99
  },
100
- postArgs: {
101
- tokenTypes: afterOperand,
102
- completable: true
103
- },
104
100
  identifier: {
105
101
  tokenTypes: {
106
102
  ...afterOperand,
@@ -131,7 +127,9 @@ export const states: States = {
131
127
  subHandler: h.argVal,
132
128
  endStates: {
133
129
  comma: 'argVal',
134
- closeParen: 'postArgs'
130
+ // a call's result is an ordinary operand: it can be operated on or
131
+ // drilled into, but not called again, since only a name can be called
132
+ closeParen: 'expectBinOp'
135
133
  }
136
134
  },
137
135
  objVal: {
package/src/types.ts CHANGED
@@ -38,7 +38,6 @@ export interface Identifier extends AstNode {
38
38
  type: 'Identifier'
39
39
  value: string
40
40
  from?: AstNode
41
- relative?: boolean
42
41
  }
43
42
 
44
43
  export interface BinaryExpression extends AstNode {
@@ -77,13 +76,11 @@ export interface FunctionCall extends AstNode {
77
76
  type: 'FunctionCall'
78
77
  name: string
79
78
  args: AstNode[]
80
- pool: 'functions'
81
79
  }
82
80
 
83
81
  export interface FilterExpression extends AstNode {
84
82
  type: 'FilterExpression'
85
83
  expr: AstNode
86
- relative: boolean
87
84
  subject: AstNode
88
85
  }
89
86
 
@@ -1,37 +0,0 @@
1
- import type { Grammar } from '../grammar.ts';
2
- import type { AstNode, JexlValue } from '../types.ts';
3
- /**
4
- * The Evaluator carries everything an expression is evaluated against: the
5
- * grammar, the context, and a relative context to be used as the root for
6
- * relative identifiers. When any of these change, a new instance is required.
7
- * However, a single instance can be used to evaluate many different
8
- * expressions, and does not have to be reinstantiated for each.
9
- *
10
- * The work of evaluation itself lives in {@link compileAst}, which lowers a
11
- * tree to closures. Prefer compiling once and reusing the result — that is what
12
- * {@link Expression} does — over calling {@link #eval}, which compiles the tree
13
- * it is given every time.
14
- *
15
- * @param {{}} grammar A grammar object against which to evaluate the expression
16
- * tree
17
- * @param {{}} [context] A map of variable keys to their values. This will be
18
- * accessed to resolve the value of each non-relative identifier.
19
- * @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
20
- * to resolve the value of a relative identifier.
21
- */
22
- declare class Evaluator {
23
- _grammar: Grammar;
24
- _context: Record<string, JexlValue>;
25
- _relContext: Record<string, JexlValue>;
26
- constructor(grammar: Grammar, context?: Record<string, JexlValue>, relativeContext?: Record<string, JexlValue>);
27
- /**
28
- * Compiles and evaluates an expression tree within the configured context.
29
- * Convenient for a one-shot evaluation; for repeated evaluation of the same
30
- * tree, hold onto the closure from {@link compileAst} instead so the tree is
31
- * only lowered once.
32
- * @param {{}} ast An expression tree object
33
- * @returns {*} the resulting value of the expression.
34
- */
35
- eval(ast: AstNode): JexlValue;
36
- }
37
- export default Evaluator;
@@ -1,49 +0,0 @@
1
- "use strict";
2
- /*
3
- * Jexl
4
- * Copyright 2020 Tom Shawver
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const compile_ts_1 = require("./compile.js");
8
- /**
9
- * The Evaluator carries everything an expression is evaluated against: the
10
- * grammar, the context, and a relative context to be used as the root for
11
- * relative identifiers. When any of these change, a new instance is required.
12
- * However, a single instance can be used to evaluate many different
13
- * expressions, and does not have to be reinstantiated for each.
14
- *
15
- * The work of evaluation itself lives in {@link compileAst}, which lowers a
16
- * tree to closures. Prefer compiling once and reusing the result — that is what
17
- * {@link Expression} does — over calling {@link #eval}, which compiles the tree
18
- * it is given every time.
19
- *
20
- * @param {{}} grammar A grammar object against which to evaluate the expression
21
- * tree
22
- * @param {{}} [context] A map of variable keys to their values. This will be
23
- * accessed to resolve the value of each non-relative identifier.
24
- * @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
25
- * to resolve the value of a relative identifier.
26
- */
27
- class Evaluator {
28
- _grammar;
29
- _context;
30
- _relContext;
31
- constructor(grammar, context, relativeContext) {
32
- this._grammar = grammar;
33
- this._context = context || {};
34
- this._relContext = relativeContext || this._context;
35
- }
36
- /**
37
- * Compiles and evaluates an expression tree within the configured context.
38
- * Convenient for a one-shot evaluation; for repeated evaluation of the same
39
- * tree, hold onto the closure from {@link compileAst} instead so the tree is
40
- * only lowered once.
41
- * @param {{}} ast An expression tree object
42
- * @returns {*} the resulting value of the expression.
43
- */
44
- eval(ast) {
45
- return (0, compile_ts_1.compileAst)(ast, this._grammar)(this);
46
- }
47
- }
48
- exports.default = Evaluator;
49
- //# sourceMappingURL=Evaluator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAEH,6CAAyC;AAKzC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,SAAS;IACb,QAAQ,CAAS;IACjB,QAAQ,CAA2B;IACnC,WAAW,CAA2B;IAEtC,YACE,OAAgB,EAChB,OAAmC,EACnC,eAA2C;QAE3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAA;QAC7B,IAAI,CAAC,WAAW,GAAG,eAAe,IAAI,IAAI,CAAC,QAAQ,CAAA;IACrD,CAAC;IAED;;;;;;;OAOG;IACH,IAAI,CAAC,GAAY;QACf,OAAO,IAAA,uBAAU,EAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAA;IAC7C,CAAC;CACF;AAED,kBAAe,SAAS,CAAA"}
@@ -1,37 +0,0 @@
1
- import type { Grammar } from '../grammar.ts';
2
- import type { AstNode, JexlValue } from '../types.ts';
3
- /**
4
- * The Evaluator carries everything an expression is evaluated against: the
5
- * grammar, the context, and a relative context to be used as the root for
6
- * relative identifiers. When any of these change, a new instance is required.
7
- * However, a single instance can be used to evaluate many different
8
- * expressions, and does not have to be reinstantiated for each.
9
- *
10
- * The work of evaluation itself lives in {@link compileAst}, which lowers a
11
- * tree to closures. Prefer compiling once and reusing the result — that is what
12
- * {@link Expression} does — over calling {@link #eval}, which compiles the tree
13
- * it is given every time.
14
- *
15
- * @param {{}} grammar A grammar object against which to evaluate the expression
16
- * tree
17
- * @param {{}} [context] A map of variable keys to their values. This will be
18
- * accessed to resolve the value of each non-relative identifier.
19
- * @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
20
- * to resolve the value of a relative identifier.
21
- */
22
- declare class Evaluator {
23
- _grammar: Grammar;
24
- _context: Record<string, JexlValue>;
25
- _relContext: Record<string, JexlValue>;
26
- constructor(grammar: Grammar, context?: Record<string, JexlValue>, relativeContext?: Record<string, JexlValue>);
27
- /**
28
- * Compiles and evaluates an expression tree within the configured context.
29
- * Convenient for a one-shot evaluation; for repeated evaluation of the same
30
- * tree, hold onto the closure from {@link compileAst} instead so the tree is
31
- * only lowered once.
32
- * @param {{}} ast An expression tree object
33
- * @returns {*} the resulting value of the expression.
34
- */
35
- eval(ast: AstNode): JexlValue;
36
- }
37
- export default Evaluator;
@@ -1,47 +0,0 @@
1
- /*
2
- * Jexl
3
- * Copyright 2020 Tom Shawver
4
- */
5
- import { compileAst } from "./compile.js";
6
- /**
7
- * The Evaluator carries everything an expression is evaluated against: the
8
- * grammar, the context, and a relative context to be used as the root for
9
- * relative identifiers. When any of these change, a new instance is required.
10
- * However, a single instance can be used to evaluate many different
11
- * expressions, and does not have to be reinstantiated for each.
12
- *
13
- * The work of evaluation itself lives in {@link compileAst}, which lowers a
14
- * tree to closures. Prefer compiling once and reusing the result — that is what
15
- * {@link Expression} does — over calling {@link #eval}, which compiles the tree
16
- * it is given every time.
17
- *
18
- * @param {{}} grammar A grammar object against which to evaluate the expression
19
- * tree
20
- * @param {{}} [context] A map of variable keys to their values. This will be
21
- * accessed to resolve the value of each non-relative identifier.
22
- * @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
23
- * to resolve the value of a relative identifier.
24
- */
25
- class Evaluator {
26
- _grammar;
27
- _context;
28
- _relContext;
29
- constructor(grammar, context, relativeContext) {
30
- this._grammar = grammar;
31
- this._context = context || {};
32
- this._relContext = relativeContext || this._context;
33
- }
34
- /**
35
- * Compiles and evaluates an expression tree within the configured context.
36
- * Convenient for a one-shot evaluation; for repeated evaluation of the same
37
- * tree, hold onto the closure from {@link compileAst} instead so the tree is
38
- * only lowered once.
39
- * @param {{}} ast An expression tree object
40
- * @returns {*} the resulting value of the expression.
41
- */
42
- eval(ast) {
43
- return compileAst(ast, this._grammar)(this);
44
- }
45
- }
46
- export default Evaluator;
47
- //# sourceMappingURL=Evaluator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAKzC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,SAAS;IACb,QAAQ,CAAS;IACjB,QAAQ,CAA2B;IACnC,WAAW,CAA2B;IAEtC,YACE,OAAgB,EAChB,OAAmC,EACnC,eAA2C;QAE3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAA;QAC7B,IAAI,CAAC,WAAW,GAAG,eAAe,IAAI,IAAI,CAAC,QAAQ,CAAA;IACrD,CAAC;IAED;;;;;;;OAOG;IACH,IAAI,CAAC,GAAY;QACf,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAA;IAC7C,CAAC;CACF;AAED,eAAe,SAAS,CAAA"}
@@ -1,58 +0,0 @@
1
- /*
2
- * Jexl
3
- * Copyright 2020 Tom Shawver
4
- */
5
-
6
- import { compileAst } from './compile.ts'
7
-
8
- import type { Grammar } from '../grammar.ts'
9
- import type { AstNode, JexlValue } from '../types.ts'
10
-
11
- /**
12
- * The Evaluator carries everything an expression is evaluated against: the
13
- * grammar, the context, and a relative context to be used as the root for
14
- * relative identifiers. When any of these change, a new instance is required.
15
- * However, a single instance can be used to evaluate many different
16
- * expressions, and does not have to be reinstantiated for each.
17
- *
18
- * The work of evaluation itself lives in {@link compileAst}, which lowers a
19
- * tree to closures. Prefer compiling once and reusing the result — that is what
20
- * {@link Expression} does — over calling {@link #eval}, which compiles the tree
21
- * it is given every time.
22
- *
23
- * @param {{}} grammar A grammar object against which to evaluate the expression
24
- * tree
25
- * @param {{}} [context] A map of variable keys to their values. This will be
26
- * accessed to resolve the value of each non-relative identifier.
27
- * @param {{}|Array<{}|Array>} [relativeContext] A map or array to be accessed
28
- * to resolve the value of a relative identifier.
29
- */
30
- class Evaluator {
31
- _grammar: Grammar
32
- _context: Record<string, JexlValue>
33
- _relContext: Record<string, JexlValue>
34
-
35
- constructor(
36
- grammar: Grammar,
37
- context?: Record<string, JexlValue>,
38
- relativeContext?: Record<string, JexlValue>
39
- ) {
40
- this._grammar = grammar
41
- this._context = context || {}
42
- this._relContext = relativeContext || this._context
43
- }
44
-
45
- /**
46
- * Compiles and evaluates an expression tree within the configured context.
47
- * Convenient for a one-shot evaluation; for repeated evaluation of the same
48
- * tree, hold onto the closure from {@link compileAst} instead so the tree is
49
- * only lowered once.
50
- * @param {{}} ast An expression tree object
51
- * @returns {*} the resulting value of the expression.
52
- */
53
- eval(ast: AstNode): JexlValue {
54
- return compileAst(ast, this._grammar)(this)
55
- }
56
- }
57
-
58
- export default Evaluator