@jbrowse/jexl 3.0.2 → 3.2.0

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 (76) hide show
  1. package/README.md +26 -2
  2. package/dist/Expression.d.ts +19 -7
  3. package/dist/Expression.js +32 -11
  4. package/dist/Expression.js.map +1 -1
  5. package/dist/Jexl.d.ts +13 -12
  6. package/dist/Jexl.js +31 -30
  7. package/dist/Jexl.js.map +1 -1
  8. package/dist/Lexer.d.ts +9 -9
  9. package/dist/Lexer.js +61 -24
  10. package/dist/Lexer.js.map +1 -1
  11. package/dist/evaluator/Evaluator.d.ts +20 -34
  12. package/dist/evaluator/Evaluator.js +19 -64
  13. package/dist/evaluator/Evaluator.js.map +1 -1
  14. package/dist/evaluator/compile.d.ts +27 -0
  15. package/dist/evaluator/compile.js +279 -0
  16. package/dist/evaluator/compile.js.map +1 -0
  17. package/dist/grammar.d.ts +29 -9
  18. package/dist/grammar.js +23 -7
  19. package/dist/grammar.js.map +1 -1
  20. package/dist/parser/Parser.d.ts +7 -8
  21. package/dist/parser/Parser.js +46 -14
  22. package/dist/parser/Parser.js.map +1 -1
  23. package/dist/parser/handlers.d.ts +8 -8
  24. package/dist/parser/handlers.js +84 -51
  25. package/dist/parser/handlers.js.map +1 -1
  26. package/dist/parser/states.d.ts +2 -2
  27. package/dist/parser/states.js +19 -40
  28. package/dist/parser/states.js.map +1 -1
  29. package/dist/types.d.ts +18 -7
  30. package/esm/Expression.d.ts +19 -7
  31. package/esm/Expression.js +32 -11
  32. package/esm/Expression.js.map +1 -1
  33. package/esm/Jexl.d.ts +13 -12
  34. package/esm/Jexl.js +31 -30
  35. package/esm/Jexl.js.map +1 -1
  36. package/esm/Lexer.d.ts +9 -9
  37. package/esm/Lexer.js +61 -24
  38. package/esm/Lexer.js.map +1 -1
  39. package/esm/evaluator/Evaluator.d.ts +20 -34
  40. package/esm/evaluator/Evaluator.js +19 -31
  41. package/esm/evaluator/Evaluator.js.map +1 -1
  42. package/esm/evaluator/compile.d.ts +27 -0
  43. package/esm/evaluator/compile.js +276 -0
  44. package/esm/evaluator/compile.js.map +1 -0
  45. package/esm/grammar.d.ts +29 -9
  46. package/esm/grammar.js +22 -7
  47. package/esm/grammar.js.map +1 -1
  48. package/esm/parser/Parser.d.ts +7 -8
  49. package/esm/parser/Parser.js +46 -14
  50. package/esm/parser/Parser.js.map +1 -1
  51. package/esm/parser/handlers.d.ts +8 -8
  52. package/esm/parser/handlers.js +81 -50
  53. package/esm/parser/handlers.js.map +1 -1
  54. package/esm/parser/states.d.ts +2 -2
  55. package/esm/parser/states.js +19 -40
  56. package/esm/parser/states.js.map +1 -1
  57. package/esm/types.d.ts +18 -7
  58. package/package.json +25 -28
  59. package/src/Expression.ts +31 -17
  60. package/src/Jexl.ts +59 -21
  61. package/src/Lexer.ts +63 -33
  62. package/src/evaluator/Evaluator.ts +27 -44
  63. package/src/evaluator/compile.ts +317 -0
  64. package/src/grammar.ts +69 -21
  65. package/src/parser/Parser.ts +50 -28
  66. package/src/parser/handlers.ts +122 -76
  67. package/src/parser/states.ts +22 -42
  68. package/src/types.ts +22 -7
  69. package/CHANGELOG.md +0 -249
  70. package/dist/evaluator/handlers.d.ts +0 -112
  71. package/dist/evaluator/handlers.js +0 -208
  72. package/dist/evaluator/handlers.js.map +0 -1
  73. package/esm/evaluator/handlers.d.ts +0 -112
  74. package/esm/evaluator/handlers.js +0 -194
  75. package/esm/evaluator/handlers.js.map +0 -1
  76. package/src/evaluator/handlers.ts +0 -212
@@ -1,16 +1,17 @@
1
- import type { AstNode } from '../types.ts';
2
- interface Grammar {
3
- elements: Record<string, any>;
4
- [key: string]: any;
5
- }
1
+ import type { Grammar } from '../grammar.ts';
2
+ import type { AstNode, JexlValue } from '../types.ts';
6
3
  /**
7
- * The Evaluator takes a Jexl expression tree as generated by the
8
- * {@link Parser} and calculates its value within a given context. The
9
- * collection of transforms, context, and a relative context to be used as the
10
- * root for relative identifiers, are all specific to an Evaluator instance.
11
- * When any of these things change, a new instance is required. However, a
12
- * single instance can be used to simultaneously evaluate many different
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
13
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
+ *
14
15
  * @param {{}} grammar A grammar object against which to evaluate the expression
15
16
  * tree
16
17
  * @param {{}} [context] A map of variable keys to their values. This will be
@@ -20,32 +21,17 @@ interface Grammar {
20
21
  */
21
22
  declare class Evaluator {
22
23
  _grammar: Grammar;
23
- _context: any;
24
- _relContext: any;
25
- constructor(grammar: Grammar, context?: any, relativeContext?: any);
24
+ _context: Record<string, JexlValue>;
25
+ _relContext: Record<string, JexlValue>;
26
+ constructor(grammar: Grammar, context?: Record<string, JexlValue>, relativeContext?: Record<string, JexlValue>);
26
27
  /**
27
- * Evaluates an expression tree within the configured context.
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.
28
32
  * @param {{}} ast An expression tree object
29
33
  * @returns {*} the resulting value of the expression.
30
34
  */
31
- eval(ast: AstNode): any;
32
- /**
33
- * Evaluates each expression within an array, and delivers the response as an
34
- * array with the resulting values at the same indexes as their originating
35
- * expressions.
36
- * @param {Array<string>} arr An array of expression strings to be evaluated
37
- * @returns {Array<{}>} the result array
38
- */
39
- evalArray(arr: AstNode[]): any[];
40
- /**
41
- * Evaluates each expression within a map, and delivers the response as a map
42
- * with the same keys, but with the evaluated result for each as their value.
43
- * @param {{}} map A map of expression names to expression trees to be
44
- * evaluated
45
- * @returns {{}} the result map.
46
- */
47
- evalMap(map: Record<string, AstNode>): {
48
- [k: string]: any;
49
- };
35
+ eval(ast: AstNode): JexlValue;
50
36
  }
51
37
  export default Evaluator;
@@ -2,15 +2,19 @@
2
2
  * Jexl
3
3
  * Copyright 2020 Tom Shawver
4
4
  */
5
- import * as handlers from "./handlers.js";
5
+ import { compileAst } from "./compile.js";
6
6
  /**
7
- * The Evaluator takes a Jexl expression tree as generated by the
8
- * {@link Parser} and calculates its value within a given context. The
9
- * collection of transforms, context, and a relative context to be used as the
10
- * root for relative identifiers, are all specific to an Evaluator instance.
11
- * When any of these things change, a new instance is required. However, a
12
- * single instance can be used to simultaneously evaluate many different
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
13
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
+ *
14
18
  * @param {{}} grammar A grammar object against which to evaluate the expression
15
19
  * tree
16
20
  * @param {{}} [context] A map of variable keys to their values. This will be
@@ -19,40 +23,24 @@ import * as handlers from "./handlers.js";
19
23
  * to resolve the value of a relative identifier.
20
24
  */
21
25
  class Evaluator {
26
+ _grammar;
27
+ _context;
28
+ _relContext;
22
29
  constructor(grammar, context, relativeContext) {
23
30
  this._grammar = grammar;
24
31
  this._context = context || {};
25
32
  this._relContext = relativeContext || this._context;
26
33
  }
27
34
  /**
28
- * Evaluates an expression tree within the configured context.
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.
29
39
  * @param {{}} ast An expression tree object
30
40
  * @returns {*} the resulting value of the expression.
31
41
  */
32
42
  eval(ast) {
33
- return handlers[ast.type].call(this, ast);
34
- }
35
- /**
36
- * Evaluates each expression within an array, and delivers the response as an
37
- * array with the resulting values at the same indexes as their originating
38
- * expressions.
39
- * @param {Array<string>} arr An array of expression strings to be evaluated
40
- * @returns {Array<{}>} the result array
41
- */
42
- evalArray(arr) {
43
- return arr.map((elem) => this.eval(elem));
44
- }
45
- /**
46
- * Evaluates each expression within a map, and delivers the response as a map
47
- * with the same keys, but with the evaluated result for each as their value.
48
- * @param {{}} map A map of expression names to expression trees to be
49
- * evaluated
50
- * @returns {{}} the result map.
51
- */
52
- evalMap(map) {
53
- const entries = Object.entries(map);
54
- const vals = entries.map(([_, ast]) => this.eval(ast));
55
- return Object.fromEntries(entries.map(([key], idx) => [key, vals[idx]]));
43
+ return compileAst(ast, this._grammar)(this);
56
44
  }
57
45
  }
58
46
  export default Evaluator;
@@ -1 +1 @@
1
- {"version":3,"file":"Evaluator.js","sourceRoot":"","sources":["../../src/evaluator/Evaluator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AASzC;;;;;;;;;;;;;;GAcG;AACH,MAAM,SAAS;IAKb,YAAY,OAAgB,EAAE,OAAa,EAAE,eAAqB;QAChE,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;;;;OAIG;IACH,IAAI,CAAC,GAAY;QACf,OAAQ,QAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACpD,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,GAAc;QACtB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACpD,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAA4B;QAClC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACnC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QACtD,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1E,CAAC;CACF;AAED,eAAe,SAAS,CAAA"}
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"}
@@ -0,0 +1,27 @@
1
+ import type { Grammar } from '../grammar.ts';
2
+ import type { AstNode, JexlValue } from '../types.ts';
3
+ import type Evaluator from './Evaluator.ts';
4
+ /**
5
+ * An AST node lowered to a closure. Calling it with an Evaluator (which carries
6
+ * the context and grammar) produces the node's value.
7
+ */
8
+ export type CompiledNode = (ev: Evaluator) => JexlValue;
9
+ /**
10
+ * Lowers an expression tree into a tree of closures, resolving each node's type
11
+ * and its operator's implementation once, at compile time, rather than
12
+ * re-dispatching on `node.type` for every node on every evaluation. An
13
+ * expression compiled once and evaluated per-item — the usual shape for
14
+ * per-feature config callbacks — pays the dispatch cost once instead of N
15
+ * times.
16
+ *
17
+ * Operators are bound here, so a grammar change after compilation requires
18
+ * recompiling, which is what {@link Expression#compile} already documents.
19
+ * Functions are looked up per call, since they are commonly registered after
20
+ * an expression has been compiled.
21
+ *
22
+ * @param {{}} ast An expression tree, as produced by the Parser
23
+ * @param {{}} grammar The grammar to resolve operators against
24
+ * @returns {function} a closure returning the expression's value
25
+ * @throws {Error} if the tree contains an unrecognized node type
26
+ */
27
+ export declare function compileAst(ast: AstNode, grammar: Grammar): CompiledNode;
@@ -0,0 +1,276 @@
1
+ /*
2
+ * Jexl
3
+ * Copyright 2020 Tom Shawver
4
+ */
5
+ /**
6
+ * Writes a key that a plain assignment would mishandle. Storing to
7
+ * "__proto__" invokes the prototype setter rather than creating a property, so
8
+ * an object literal or assignment using that key silently lost its value (and
9
+ * re-pointed the target's prototype). Defining the property instead matches
10
+ * what `JSON.parse('{"__proto__":1}')` produces: an ordinary own property.
11
+ */
12
+ function defineOwn(target, key, value) {
13
+ Object.defineProperty(target, key, {
14
+ value,
15
+ writable: true,
16
+ enumerable: true,
17
+ configurable: true
18
+ });
19
+ }
20
+ function assignOwn(target, key, value) {
21
+ target[key] = value;
22
+ }
23
+ /** Renders an interpolated value for a template literal. */
24
+ function stringify(value) {
25
+ if (value == null) {
26
+ return '';
27
+ }
28
+ if (typeof value === 'string' ||
29
+ typeof value === 'number' ||
30
+ typeof value === 'boolean') {
31
+ return String(value);
32
+ }
33
+ return JSON.stringify(value);
34
+ }
35
+ /**
36
+ * Lowers an expression tree into a tree of closures, resolving each node's type
37
+ * and its operator's implementation once, at compile time, rather than
38
+ * re-dispatching on `node.type` for every node on every evaluation. An
39
+ * expression compiled once and evaluated per-item — the usual shape for
40
+ * per-feature config callbacks — pays the dispatch cost once instead of N
41
+ * times.
42
+ *
43
+ * Operators are bound here, so a grammar change after compilation requires
44
+ * recompiling, which is what {@link Expression#compile} already documents.
45
+ * Functions are looked up per call, since they are commonly registered after
46
+ * an expression has been compiled.
47
+ *
48
+ * @param {{}} ast An expression tree, as produced by the Parser
49
+ * @param {{}} grammar The grammar to resolve operators against
50
+ * @returns {function} a closure returning the expression's value
51
+ * @throws {Error} if the tree contains an unrecognized node type
52
+ */
53
+ export function compileAst(ast, grammar) {
54
+ // AstNode types its `type` as a plain string so the Parser can build the tree
55
+ // loosely; narrowing to the union once, here, lets every case below see its
56
+ // own node type instead of repeating the same cast in each branch
57
+ const node = ast;
58
+ switch (node.type) {
59
+ case 'Literal': {
60
+ const { value } = node;
61
+ return () => value;
62
+ }
63
+ case 'Identifier': {
64
+ const name = node.value;
65
+ if (!node.from) {
66
+ return node.relative
67
+ ? (ev) => ev._relContext[name]
68
+ : (ev) => ev._context[name];
69
+ }
70
+ const from = compileAst(node.from, grammar);
71
+ return (ev) => {
72
+ const context = from(ev);
73
+ if (context == null) {
74
+ return undefined;
75
+ }
76
+ // an identifier chained off an array reads through its first element
77
+ const ctx = Array.isArray(context) ? context[0] : context;
78
+ return ctx == null
79
+ ? undefined
80
+ : ctx[name];
81
+ };
82
+ }
83
+ case 'BinaryExpression': {
84
+ const op = grammar.elements[node.operator];
85
+ if (op?.type !== 'binaryOp') {
86
+ // matches the tree-walking behaviour: an unknown operator yields
87
+ // undefined without evaluating either operand
88
+ return () => undefined;
89
+ }
90
+ const left = compileAst(node.left, grammar);
91
+ const right = compileAst(node.right, grammar);
92
+ const { evalOnDemand } = op;
93
+ if (evalOnDemand) {
94
+ // operands stay unevaluated behind an `eval` thunk, so operators such
95
+ // as && and || can short-circuit
96
+ return (ev) => evalOnDemand({ eval: () => left(ev) }, { eval: () => right(ev) });
97
+ }
98
+ const fn = op.eval;
99
+ if (!fn) {
100
+ return (ev) => {
101
+ left(ev);
102
+ right(ev);
103
+ return undefined;
104
+ };
105
+ }
106
+ return (ev) => fn(left(ev), right(ev));
107
+ }
108
+ case 'UnaryExpression': {
109
+ const right = compileAst(node.right, grammar);
110
+ const elem = grammar.elements[node.operator];
111
+ const fn = elem?.type === 'unaryOp'
112
+ ? elem.eval
113
+ : elem?.type === 'binaryOp'
114
+ ? elem.unaryEval
115
+ : undefined;
116
+ if (!fn) {
117
+ // the operand is still evaluated for an unknown operator, as before
118
+ return (ev) => {
119
+ right(ev);
120
+ return undefined;
121
+ };
122
+ }
123
+ return (ev) => fn(right(ev));
124
+ }
125
+ case 'ConditionalExpression': {
126
+ const test = compileAst(node.test, grammar);
127
+ const consequent = node.consequent
128
+ ? compileAst(node.consequent, grammar)
129
+ : undefined;
130
+ const alternate = node.alternate
131
+ ? compileAst(node.alternate, grammar)
132
+ : undefined;
133
+ return (ev) => {
134
+ const res = test(ev);
135
+ if (res) {
136
+ // an omitted consequent ("a ?: b") yields the test result
137
+ return consequent ? consequent(ev) : res;
138
+ }
139
+ return alternate ? alternate(ev) : undefined;
140
+ };
141
+ }
142
+ case 'FilterExpression': {
143
+ if (node.relative) {
144
+ // thrown on evaluation rather than compilation, as before
145
+ return () => {
146
+ throw new Error('Relative filter expressions are not supported');
147
+ };
148
+ }
149
+ const subject = compileAst(node.subject, grammar);
150
+ const index = compileAst(node.expr, grammar);
151
+ return (ev) => {
152
+ const subjectVal = subject(ev);
153
+ const indexVal = index(ev);
154
+ if (subjectVal == null) {
155
+ return undefined;
156
+ }
157
+ return typeof indexVal === 'string' || typeof indexVal === 'number'
158
+ ? subjectVal[indexVal]
159
+ : undefined;
160
+ };
161
+ }
162
+ case 'ArrayLiteral': {
163
+ const items = node.value.map((item) => compileAst(item, grammar));
164
+ const len = items.length;
165
+ return (ev) => {
166
+ const out = new Array(len);
167
+ for (let i = 0; i < len; i++) {
168
+ out[i] = items[i](ev);
169
+ }
170
+ return out;
171
+ };
172
+ }
173
+ case 'ObjectLiteral': {
174
+ const entries = Object.entries(node.value);
175
+ const keys = entries.map(([key]) => key);
176
+ const values = entries.map(([, value]) => compileAst(value, grammar));
177
+ const len = keys.length;
178
+ // resolved once, here, so the common case keeps its plain store
179
+ const store = keys.includes('__proto__') ? defineOwn : assignOwn;
180
+ return (ev) => {
181
+ const out = {};
182
+ for (let i = 0; i < len; i++) {
183
+ store(out, keys[i], values[i](ev));
184
+ }
185
+ return out;
186
+ };
187
+ }
188
+ case 'TemplateLiteral': {
189
+ // every part renders to a string, so these are narrower than CompiledNode
190
+ const parts = node.parts.map((part) => {
191
+ if (part.type === 'static') {
192
+ const { value } = part;
193
+ return () => value;
194
+ }
195
+ const expr = compileAst(part.value, grammar);
196
+ return (ev) => stringify(expr(ev));
197
+ });
198
+ return (ev) => {
199
+ let out = '';
200
+ for (const part of parts) {
201
+ out += part(ev);
202
+ }
203
+ return out;
204
+ };
205
+ }
206
+ case 'FunctionCall': {
207
+ const { name } = node;
208
+ const args = node.args.map((arg) => compileAst(arg, grammar));
209
+ // hasOwn, so that inherited Object.prototype members such as `toString`
210
+ // and `constructor` aren't callable as Jexl functions. Resolved per call
211
+ // rather than baked in, since functions are routinely registered after
212
+ // an expression has been compiled.
213
+ const lookup = (ev) => {
214
+ const { functions } = ev._grammar;
215
+ if (!Object.hasOwn(functions, name)) {
216
+ throw new Error(`Jexl Function ${name} is not defined.`);
217
+ }
218
+ return functions[name];
219
+ };
220
+ // the small arities are spelled out so an ordinary call allocates no
221
+ // argument array and needs no spread
222
+ switch (args.length) {
223
+ case 0: {
224
+ return (ev) => lookup(ev)();
225
+ }
226
+ case 1: {
227
+ const [a0] = args;
228
+ return (ev) => lookup(ev)(a0(ev));
229
+ }
230
+ case 2: {
231
+ const [a0, a1] = args;
232
+ return (ev) => lookup(ev)(a0(ev), a1(ev));
233
+ }
234
+ case 3: {
235
+ const [a0, a1, a2] = args;
236
+ return (ev) => lookup(ev)(a0(ev), a1(ev), a2(ev));
237
+ }
238
+ default: {
239
+ const len = args.length;
240
+ return (ev) => {
241
+ const vals = new Array(len);
242
+ for (let i = 0; i < len; i++) {
243
+ vals[i] = args[i](ev);
244
+ }
245
+ return lookup(ev)(...vals);
246
+ };
247
+ }
248
+ }
249
+ }
250
+ case 'SequenceExpression': {
251
+ const exprs = node.expressions.map((expr) => compileAst(expr, grammar));
252
+ const len = exprs.length;
253
+ return (ev) => {
254
+ let last;
255
+ for (let i = 0; i < len; i++) {
256
+ last = exprs[i](ev);
257
+ }
258
+ return last;
259
+ };
260
+ }
261
+ case 'AssignmentExpression': {
262
+ const name = node.left.value;
263
+ const right = compileAst(node.right, grammar);
264
+ const store = name === '__proto__' ? defineOwn : assignOwn;
265
+ return (ev) => {
266
+ const value = right(ev);
267
+ store(ev._context, name, value);
268
+ return value;
269
+ };
270
+ }
271
+ default: {
272
+ throw new Error(`Corrupt AST: unknown node type '${ast.type}'`);
273
+ }
274
+ }
275
+ }
276
+ //# sourceMappingURL=compile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/evaluator/compile.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;;;;;GAMG;AACH,SAAS,SAAS,CAChB,MAAiC,EACjC,GAAW,EACX,KAAgB;IAEhB,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE;QACjC,KAAK;QACL,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,IAAI;KACnB,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,SAAS,CAChB,MAAiC,EACjC,GAAW,EACX,KAAgB;IAEhB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AACrB,CAAC;AAED,4DAA4D;AAC5D,SAAS,SAAS,CAAC,KAAgB;IACjC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,SAAS,EAC1B,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,OAAgB;IACvD,8EAA8E;IAC9E,4EAA4E;IAC5E,kEAAkE;IAClE,MAAM,IAAI,GAAG,GAAmB,CAAA;IAChC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;YACtB,OAAO,GAAG,EAAE,CAAC,KAAK,CAAA;QACpB,CAAC;QAED,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAA;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC,QAAQ;oBAClB,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC;oBAC9B,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YAC/B,CAAC;YACD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC3C,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;gBACxB,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACpB,OAAO,SAAS,CAAA;gBAClB,CAAC;gBACD,qEAAqE;gBACrE,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;gBACzD,OAAO,GAAG,IAAI,IAAI;oBAChB,CAAC,CAAC,SAAS;oBACX,CAAC,CAAE,GAAiC,CAAC,IAAI,CAAC,CAAA;YAC9C,CAAC,CAAA;QACH,CAAC;QAED,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC1C,IAAI,EAAE,EAAE,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC5B,iEAAiE;gBACjE,8CAA8C;gBAC9C,OAAO,GAAG,EAAE,CAAC,SAAS,CAAA;YACxB,CAAC;YACD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAM,EAAE,OAAO,CAAC,CAAA;YAC9C,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,CAAA;YAC3B,IAAI,YAAY,EAAE,CAAC;gBACjB,sEAAsE;gBACtE,iCAAiC;gBACjC,OAAO,CAAC,EAAE,EAAE,EAAE,CACZ,YAAY,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;YACrE,CAAC;YACD,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAA;YAClB,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,OAAO,CAAC,EAAE,EAAE,EAAE;oBACZ,IAAI,CAAC,EAAE,CAAC,CAAA;oBACR,KAAK,CAAC,EAAE,CAAC,CAAA;oBACT,OAAO,SAAS,CAAA;gBAClB,CAAC,CAAA;YACH,CAAC;YACD,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;QACxC,CAAC;QAED,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAM,EAAE,OAAO,CAAC,CAAA;YAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC5C,MAAM,EAAE,GACN,IAAI,EAAE,IAAI,KAAK,SAAS;gBACtB,CAAC,CAAC,IAAI,CAAC,IAAI;gBACX,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,UAAU;oBACzB,CAAC,CAAC,IAAI,CAAC,SAAS;oBAChB,CAAC,CAAC,SAAS,CAAA;YACjB,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,oEAAoE;gBACpE,OAAO,CAAC,EAAE,EAAE,EAAE;oBACZ,KAAK,CAAC,EAAE,CAAC,CAAA;oBACT,OAAO,SAAS,CAAA;gBAClB,CAAC,CAAA;YACH,CAAC;YACD,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;QAC9B,CAAC;QAED,KAAK,uBAAuB,CAAC,CAAC,CAAC;YAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU;gBAChC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;gBACtC,CAAC,CAAC,SAAS,CAAA;YACb,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS;gBAC9B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;gBACrC,CAAC,CAAC,SAAS,CAAA;YACb,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;gBACpB,IAAI,GAAG,EAAE,CAAC;oBACR,0DAA0D;oBAC1D,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;gBAC1C,CAAC;gBACD,OAAO,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC9C,CAAC,CAAA;QACH,CAAC;QAED,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,0DAA0D;gBAC1D,OAAO,GAAG,EAAE;oBACV,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;gBAClE,CAAC,CAAA;YACH,CAAC;YACD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YACjD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC5C,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,MAAM,UAAU,GAAG,OAAO,CAAC,EAAE,CAAC,CAAA;gBAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC,CAAA;gBAC1B,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;oBACvB,OAAO,SAAS,CAAA;gBAClB,CAAC;gBACD,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;oBACjE,CAAC,CAAE,UAAiD,CAAC,QAAQ,CAAC;oBAC9D,CAAC,CAAC,SAAS,CAAA;YACf,CAAC,CAAA;QACH,CAAC;QAED,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;YACjE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAA;YACxB,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,MAAM,GAAG,GAAgB,IAAI,KAAK,CAAC,GAAG,CAAC,CAAA;gBACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7B,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAA;gBACxB,CAAC;gBACD,OAAO,GAAG,CAAA;YACZ,CAAC,CAAA;QACH,CAAC;QAED,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAA;YACxC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;YACrE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAA;YACvB,gEAAgE;YAChE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;YAChE,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,MAAM,GAAG,GAA8B,EAAE,CAAA;gBACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7B,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAA;gBACtC,CAAC;gBACD,OAAO,GAAG,CAAA;YACZ,CAAC,CAAA;QACH,CAAC;QAED,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,0EAA0E;YAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAA+B,EAAE;gBACjE,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;oBACtB,OAAO,GAAG,EAAE,CAAC,KAAK,CAAA;gBACpB,CAAC;gBACD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;gBAC5C,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;YACpC,CAAC,CAAC,CAAA;YACF,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,IAAI,GAAG,GAAG,EAAE,CAAA;gBACZ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAA;gBACjB,CAAC;gBACD,OAAO,GAAG,CAAA;YACZ,CAAC,CAAA;QACH,CAAC;QAED,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;YACrB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;YAC7D,wEAAwE;YACxE,yEAAyE;YACzE,uEAAuE;YACvE,mCAAmC;YACnC,MAAM,MAAM,GAAG,CAAC,EAAa,EAAE,EAAE;gBAC/B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAA;gBACjC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC;oBACpC,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,kBAAkB,CAAC,CAAA;gBAC1D,CAAC;gBACD,OAAO,SAAS,CAAC,IAAI,CAAE,CAAA;YACzB,CAAC,CAAA;YACD,qEAAqE;YACrE,qCAAqC;YACrC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;gBACpB,KAAK,CAAC,CAAC,CAAC,CAAC;oBACP,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;gBAC7B,CAAC;gBACD,KAAK,CAAC,CAAC,CAAC,CAAC;oBACP,MAAM,CAAC,EAAE,CAAC,GAAG,IAAsB,CAAA;oBACnC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;gBACnC,CAAC;gBACD,KAAK,CAAC,CAAC,CAAC,CAAC;oBACP,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAoC,CAAA;oBACrD,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;gBAC3C,CAAC;gBACD,KAAK,CAAC,CAAC,CAAC,CAAC;oBACP,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAIpB,CAAA;oBACD,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;gBACnD,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAA;oBACvB,OAAO,CAAC,EAAE,EAAE,EAAE;wBACZ,MAAM,IAAI,GAAgB,IAAI,KAAK,CAAC,GAAG,CAAC,CAAA;wBACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;4BAC7B,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAA;wBACxB,CAAC;wBACD,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;oBAC5B,CAAC,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,KAAK,oBAAoB,CAAC,CAAC,CAAC;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;YACvE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAA;YACxB,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,IAAI,IAAe,CAAA;gBACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7B,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAA;gBACtB,CAAC;gBACD,OAAO,IAAI,CAAA;YACb,CAAC,CAAA;QACH,CAAC;QAED,KAAK,sBAAsB,CAAC,CAAC,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA;YAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAM,EAAE,OAAO,CAAC,CAAA;YAC9C,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;YAC1D,OAAO,CAAC,EAAE,EAAE,EAAE;gBACZ,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,CAAA;gBACvB,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;gBAC/B,OAAO,KAAK,CAAA;YACd,CAAC,CAAA;QACH,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;AACH,CAAC"}
package/esm/grammar.d.ts CHANGED
@@ -1,24 +1,44 @@
1
+ import type { JexlValue } from './types.ts';
2
+ export type BinaryOpEval = (left: JexlValue, right: JexlValue) => JexlValue;
3
+ export type BinaryOpEvalOnDemand = (left: {
4
+ eval: () => JexlValue;
5
+ }, right: {
6
+ eval: () => JexlValue;
7
+ }) => JexlValue;
1
8
  export interface BinaryOp {
2
9
  type: 'binaryOp';
3
10
  precedence: number;
4
- eval?: (left: any, right: any) => any;
5
- evalOnDemand?: (left: {
6
- eval: () => any;
7
- }, right: {
8
- eval: () => any;
9
- }) => any;
11
+ eval?: BinaryOpEval;
12
+ evalOnDemand?: BinaryOpEvalOnDemand;
13
+ /**
14
+ * Evaluator for the operator's prefix form, if it has one. The Lexer emits a
15
+ * unaryOp token when such an operator appears where an operand is expected,
16
+ * which is how `-x` is distinguished from `a - x`.
17
+ */
18
+ unaryEval?: (right: JexlValue) => JexlValue;
10
19
  }
11
20
  export interface UnaryOp {
12
21
  type: 'unaryOp';
13
22
  precedence: number;
14
- eval: (right: any) => any;
23
+ eval: (right: JexlValue) => JexlValue;
15
24
  }
25
+ /**
26
+ * The punctuation elements of the grammar. Unlike operators these carry no
27
+ * behavior of their own; the Parser's state machine gives them meaning. The
28
+ * type is a literal union rather than `string` so that `GrammarElement` is a
29
+ * discriminated union, letting operator properties be accessed without casts.
30
+ */
16
31
  export interface SimpleElement {
17
- type: string;
32
+ type: 'dot' | 'openBracket' | 'closeBracket' | 'openCurl' | 'closeCurl' | 'colon' | 'comma' | 'openParen' | 'closeParen' | 'question' | 'semicolon';
18
33
  }
19
34
  export type GrammarElement = BinaryOp | UnaryOp | SimpleElement;
20
35
  export interface Grammar {
21
36
  elements: Record<string, GrammarElement>;
22
- functions: Record<string, (...args: any[]) => any>;
37
+ functions: Record<string, (...args: JexlValue[]) => JexlValue>;
23
38
  }
39
+ /**
40
+ * Returns the binding power of a grammar element, or 0 for elements that
41
+ * aren't operators and therefore don't participate in precedence.
42
+ */
43
+ export declare function precedenceOf(elem: GrammarElement | undefined): number;
24
44
  export declare const getGrammar: () => Grammar;
package/esm/grammar.js CHANGED
@@ -2,6 +2,15 @@
2
2
  * Jexl
3
3
  * Copyright 2020 Tom Shawver
4
4
  */
5
+ /**
6
+ * Returns the binding power of a grammar element, or 0 for elements that
7
+ * aren't operators and therefore don't participate in precedence.
8
+ */
9
+ export function precedenceOf(elem) {
10
+ return elem && (elem.type === 'binaryOp' || elem.type === 'unaryOp')
11
+ ? elem.precedence
12
+ : 0;
13
+ }
5
14
  export const getGrammar = () => ({
6
15
  /**
7
16
  * A map of all expression elements to their properties. Note that changes
@@ -28,7 +37,8 @@ export const getGrammar = () => ({
28
37
  '-': {
29
38
  type: 'binaryOp',
30
39
  precedence: 30,
31
- eval: (left, right) => left - right
40
+ eval: (left, right) => left - right,
41
+ unaryEval: (right) => -right
32
42
  },
33
43
  '*': {
34
44
  type: 'binaryOp',
@@ -53,7 +63,7 @@ export const getGrammar = () => ({
53
63
  '^': {
54
64
  type: 'binaryOp',
55
65
  precedence: 50,
56
- eval: (left, right) => Math.pow(left, right)
66
+ eval: (left, right) => left ** right
57
67
  },
58
68
  '==': {
59
69
  type: 'binaryOp',
@@ -112,12 +122,17 @@ export const getGrammar = () => ({
112
122
  precedence: 20,
113
123
  eval: (left, right) => {
114
124
  if (typeof right === 'string') {
115
- return right.includes(left);
116
- }
117
- if (Array.isArray(right)) {
118
- return right.includes(left);
125
+ // only a primitive has a meaningful substring form. An absent or
126
+ // structured left operand is not "in" a string, and must not be
127
+ // coerced to '' — every string contains the empty string, so that
128
+ // made `feature.missingAttr in "someString"` true for every feature.
129
+ return typeof left === 'string' ||
130
+ typeof left === 'number' ||
131
+ typeof left === 'boolean'
132
+ ? right.includes(String(left))
133
+ : false;
119
134
  }
120
- return false;
135
+ return Array.isArray(right) ? right.includes(left) : false;
121
136
  }
122
137
  },
123
138
  '!': {
@@ -1 +1 @@
1
- {"version":3,"file":"grammar.js","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grammar.js","sourceRoot":"","sources":["../src/grammar.ts"],"names":[],"mappings":"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"}