@jbrowse/jexl 3.0.2 → 3.1.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.
- package/README.md +11 -2
- package/dist/Expression.d.ts +16 -6
- package/dist/Expression.js +34 -8
- package/dist/Expression.js.map +1 -1
- package/dist/Jexl.d.ts +13 -12
- package/dist/Jexl.js +31 -30
- package/dist/Jexl.js.map +1 -1
- package/dist/Lexer.d.ts +9 -8
- package/dist/Lexer.js +58 -18
- package/dist/Lexer.js.map +1 -1
- package/dist/evaluator/Evaluator.d.ts +20 -34
- package/dist/evaluator/Evaluator.js +19 -64
- package/dist/evaluator/Evaluator.js.map +1 -1
- package/dist/evaluator/compile.d.ts +27 -0
- package/dist/evaluator/compile.js +261 -0
- package/dist/evaluator/compile.js.map +1 -0
- package/dist/grammar.d.ts +29 -9
- package/dist/grammar.js +19 -3
- package/dist/grammar.js.map +1 -1
- package/dist/parser/Parser.d.ts +5 -7
- package/dist/parser/Parser.js +17 -2
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/handlers.d.ts +0 -6
- package/dist/parser/handlers.js +54 -46
- package/dist/parser/handlers.js.map +1 -1
- package/dist/parser/states.d.ts +2 -2
- package/dist/parser/states.js +0 -20
- package/dist/parser/states.js.map +1 -1
- package/dist/types.d.ts +18 -7
- package/esm/Expression.d.ts +16 -6
- package/esm/Expression.js +34 -8
- package/esm/Expression.js.map +1 -1
- package/esm/Jexl.d.ts +13 -12
- package/esm/Jexl.js +31 -30
- package/esm/Jexl.js.map +1 -1
- package/esm/Lexer.d.ts +9 -8
- package/esm/Lexer.js +58 -18
- package/esm/Lexer.js.map +1 -1
- package/esm/evaluator/Evaluator.d.ts +20 -34
- package/esm/evaluator/Evaluator.js +19 -31
- package/esm/evaluator/Evaluator.js.map +1 -1
- package/esm/evaluator/compile.d.ts +27 -0
- package/esm/evaluator/compile.js +258 -0
- package/esm/evaluator/compile.js.map +1 -0
- package/esm/grammar.d.ts +29 -9
- package/esm/grammar.js +18 -3
- package/esm/grammar.js.map +1 -1
- package/esm/parser/Parser.d.ts +5 -7
- package/esm/parser/Parser.js +17 -2
- package/esm/parser/Parser.js.map +1 -1
- package/esm/parser/handlers.d.ts +0 -6
- package/esm/parser/handlers.js +54 -45
- package/esm/parser/handlers.js.map +1 -1
- package/esm/parser/states.d.ts +2 -2
- package/esm/parser/states.js +0 -20
- package/esm/parser/states.js.map +1 -1
- package/esm/types.d.ts +18 -7
- package/package.json +25 -28
- package/src/Expression.ts +33 -13
- package/src/Jexl.ts +59 -21
- package/src/Lexer.ts +60 -27
- package/src/evaluator/Evaluator.ts +27 -44
- package/src/evaluator/compile.ts +310 -0
- package/src/grammar.ts +66 -17
- package/src/parser/Parser.ts +24 -20
- package/src/parser/handlers.ts +96 -73
- package/src/parser/states.ts +2 -22
- package/src/types.ts +22 -7
- package/CHANGELOG.md +0 -249
- package/dist/evaluator/handlers.d.ts +0 -112
- package/dist/evaluator/handlers.js +0 -208
- package/dist/evaluator/handlers.js.map +0 -1
- package/esm/evaluator/handlers.d.ts +0 -112
- package/esm/evaluator/handlers.js +0 -194
- package/esm/evaluator/handlers.js.map +0 -1
- package/src/evaluator/handlers.ts +0 -212
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Jexl
|
|
3
|
-
* Copyright 2020 Tom Shawver
|
|
4
|
-
*/
|
|
5
|
-
const poolNames = {
|
|
6
|
-
functions: 'Jexl Function'
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Evaluates an ArrayLiteral by returning its value, with each element
|
|
10
|
-
* independently run through the evaluator.
|
|
11
|
-
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
12
|
-
* ObjectLiteral as the top node
|
|
13
|
-
* @returns {[]} an array of evaluated values.
|
|
14
|
-
* @private
|
|
15
|
-
*/
|
|
16
|
-
export function ArrayLiteral(ast) {
|
|
17
|
-
return this.evalArray(ast.value);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Evaluates a BinaryExpression node by running the Grammar's evaluator for
|
|
21
|
-
* the given operator. Note that binary expressions support two types of
|
|
22
|
-
* evaluators: `eval` is called with the left and right operands pre-evaluated.
|
|
23
|
-
* `evalOnDemand`, if it exists, will be called with the left and right operands
|
|
24
|
-
* each individually wrapped in an object with an "eval" function that returns
|
|
25
|
-
* the resulting value. This allows the binary expression to evaluate the
|
|
26
|
-
* operands conditionally.
|
|
27
|
-
* @param {{type: 'BinaryExpression', operator: <string>, left: {},
|
|
28
|
-
* right: {}}} ast An expression tree with a BinaryExpression as the top
|
|
29
|
-
* node
|
|
30
|
-
* @returns {*} the value of the BinaryExpression.
|
|
31
|
-
* @private
|
|
32
|
-
*/
|
|
33
|
-
export function BinaryExpression(ast) {
|
|
34
|
-
const grammarOp = this._grammar.elements[ast.operator];
|
|
35
|
-
if (grammarOp.evalOnDemand) {
|
|
36
|
-
const wrap = (subAst) => ({ eval: () => this.eval(subAst) });
|
|
37
|
-
return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right));
|
|
38
|
-
}
|
|
39
|
-
const left = this.eval(ast.left);
|
|
40
|
-
const right = this.eval(ast.right);
|
|
41
|
-
return grammarOp.eval(left, right);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Evaluates a ConditionalExpression node by first evaluating its test branch,
|
|
45
|
-
* and returning the consequent branch if the test is truthy, or the alternate
|
|
46
|
-
* branch if it is not. If there is no consequent branch, the test result will
|
|
47
|
-
* be used instead.
|
|
48
|
-
* @param {{type: 'ConditionalExpression', test: {}, consequent: {},
|
|
49
|
-
* alternate: {}}} ast An expression tree with a ConditionalExpression as
|
|
50
|
-
* the top node
|
|
51
|
-
* @private
|
|
52
|
-
*/
|
|
53
|
-
export function ConditionalExpression(ast) {
|
|
54
|
-
const res = this.eval(ast.test);
|
|
55
|
-
if (res) {
|
|
56
|
-
return ast.consequent ? this.eval(ast.consequent) : res;
|
|
57
|
-
}
|
|
58
|
-
return this.eval(ast.alternate);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Evaluates a FilterExpression by applying bracket notation for array/object access.
|
|
62
|
-
* Note: Relative filtering (with leading dot) is not supported.
|
|
63
|
-
* @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
|
|
64
|
-
* subject: {}}} ast An expression tree with a FilterExpression as the top
|
|
65
|
-
* node
|
|
66
|
-
* @returns {*} the value at the specified index/property.
|
|
67
|
-
* @private
|
|
68
|
-
*/
|
|
69
|
-
export function FilterExpression(ast) {
|
|
70
|
-
const subject = this.eval(ast.subject);
|
|
71
|
-
if (ast.relative) {
|
|
72
|
-
throw new Error('Relative filter expressions are not supported');
|
|
73
|
-
}
|
|
74
|
-
const index = this.eval(ast.expr);
|
|
75
|
-
return subject?.[index];
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Evaluates an Identifier by either stemming from the evaluated 'from'
|
|
79
|
-
* expression tree or accessing the context provided when this Evaluator was
|
|
80
|
-
* constructed.
|
|
81
|
-
* @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
|
|
82
|
-
* tree with an Identifier as the top node
|
|
83
|
-
* @returns {*} the identifier's value.
|
|
84
|
-
* @private
|
|
85
|
-
*/
|
|
86
|
-
export function Identifier(ast) {
|
|
87
|
-
if (!ast.from) {
|
|
88
|
-
const contextSource = ast.relative ? this._relContext : this._context;
|
|
89
|
-
return contextSource[ast.value];
|
|
90
|
-
}
|
|
91
|
-
const context = this.eval(ast.from);
|
|
92
|
-
if (context == null) {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
const ctx = Array.isArray(context) ? context[0] : context;
|
|
96
|
-
return ctx?.[ast.value];
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Evaluates a Literal by returning its value property.
|
|
100
|
-
* @param {{type: 'Literal', value: <string|number|boolean>}} ast An expression
|
|
101
|
-
* tree with a Literal as its only node
|
|
102
|
-
* @returns {string|number|boolean} The value of the Literal node
|
|
103
|
-
* @private
|
|
104
|
-
*/
|
|
105
|
-
export function Literal(ast) {
|
|
106
|
-
return ast.value;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Evaluates a TemplateLiteral by evaluating each interpolated expression
|
|
110
|
-
* and concatenating all parts into a final string.
|
|
111
|
-
* @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
|
|
112
|
-
* tree with a TemplateLiteral as the top node
|
|
113
|
-
* @returns {string} the final interpolated string
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
export function TemplateLiteral(ast) {
|
|
117
|
-
const values = ast.parts.map((part) => {
|
|
118
|
-
if (part.type === 'static') {
|
|
119
|
-
return part.value;
|
|
120
|
-
}
|
|
121
|
-
const result = this.eval(part.value);
|
|
122
|
-
if (result == null) {
|
|
123
|
-
return '';
|
|
124
|
-
}
|
|
125
|
-
return String(result);
|
|
126
|
-
});
|
|
127
|
-
return values.join('');
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Evaluates an ObjectLiteral by returning its value, with each key
|
|
131
|
-
* independently run through the evaluator.
|
|
132
|
-
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
133
|
-
* ObjectLiteral as the top node
|
|
134
|
-
* @returns {{}} a map of evaluated values.
|
|
135
|
-
* @private
|
|
136
|
-
*/
|
|
137
|
-
export function ObjectLiteral(ast) {
|
|
138
|
-
return this.evalMap(ast.value);
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Evaluates a FunctionCall node by applying the supplied arguments to a
|
|
142
|
-
* function defined in one of the grammar's function pools.
|
|
143
|
-
* @param {{type: 'FunctionCall', name: <string>}} ast An
|
|
144
|
-
* expression tree with a FunctionCall as the top node
|
|
145
|
-
* @returns {*} the value of the function call.
|
|
146
|
-
* @private
|
|
147
|
-
*/
|
|
148
|
-
export function FunctionCall(ast) {
|
|
149
|
-
const poolName = poolNames[ast.pool];
|
|
150
|
-
if (!poolName) {
|
|
151
|
-
throw new Error(`Corrupt AST: Pool '${ast.pool}' not found`);
|
|
152
|
-
}
|
|
153
|
-
const pool = this._grammar[ast.pool];
|
|
154
|
-
const func = pool?.[ast.name];
|
|
155
|
-
if (!func) {
|
|
156
|
-
throw new Error(`${poolName} ${ast.name} is not defined.`);
|
|
157
|
-
}
|
|
158
|
-
const args = this.evalArray(ast.args || []);
|
|
159
|
-
return func(...args);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Evaluates a Unary expression by passing the right side through the
|
|
163
|
-
* operator's eval function.
|
|
164
|
-
* @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
|
|
165
|
-
* expression tree with a UnaryExpression as the top node
|
|
166
|
-
* @returns {*} the value of the UnaryExpression.
|
|
167
|
-
* @constructor
|
|
168
|
-
*/
|
|
169
|
-
export function UnaryExpression(ast) {
|
|
170
|
-
const right = this.eval(ast.right);
|
|
171
|
-
return this._grammar.elements[ast.operator].eval(right);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Evaluates a SequenceExpression by evaluating each expression in order
|
|
175
|
-
* and returning the value of the last expression.
|
|
176
|
-
*/
|
|
177
|
-
export function SequenceExpression(ast) {
|
|
178
|
-
let lastValue;
|
|
179
|
-
for (const expr of ast.expressions) {
|
|
180
|
-
lastValue = this.eval(expr);
|
|
181
|
-
}
|
|
182
|
-
return lastValue;
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Evaluates an AssignmentExpression by evaluating the right side
|
|
186
|
-
* and assigning it to the variable name on the left side.
|
|
187
|
-
*/
|
|
188
|
-
export function AssignmentExpression(ast) {
|
|
189
|
-
const value = this.eval(ast.right);
|
|
190
|
-
const varName = ast.left.value;
|
|
191
|
-
this._context[varName] = value;
|
|
192
|
-
return value;
|
|
193
|
-
}
|
|
194
|
-
//# sourceMappingURL=handlers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/evaluator/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Jexl
|
|
3
|
-
* Copyright 2020 Tom Shawver
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { AstNode } from '../types.ts'
|
|
7
|
-
import type Evaluator from './Evaluator.ts'
|
|
8
|
-
|
|
9
|
-
const poolNames: Record<string, string> = {
|
|
10
|
-
functions: 'Jexl Function'
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Evaluates an ArrayLiteral by returning its value, with each element
|
|
15
|
-
* independently run through the evaluator.
|
|
16
|
-
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
17
|
-
* ObjectLiteral as the top node
|
|
18
|
-
* @returns {[]} an array of evaluated values.
|
|
19
|
-
* @private
|
|
20
|
-
*/
|
|
21
|
-
export function ArrayLiteral(this: Evaluator, ast: any) {
|
|
22
|
-
return this.evalArray(ast.value)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Evaluates a BinaryExpression node by running the Grammar's evaluator for
|
|
27
|
-
* the given operator. Note that binary expressions support two types of
|
|
28
|
-
* evaluators: `eval` is called with the left and right operands pre-evaluated.
|
|
29
|
-
* `evalOnDemand`, if it exists, will be called with the left and right operands
|
|
30
|
-
* each individually wrapped in an object with an "eval" function that returns
|
|
31
|
-
* the resulting value. This allows the binary expression to evaluate the
|
|
32
|
-
* operands conditionally.
|
|
33
|
-
* @param {{type: 'BinaryExpression', operator: <string>, left: {},
|
|
34
|
-
* right: {}}} ast An expression tree with a BinaryExpression as the top
|
|
35
|
-
* node
|
|
36
|
-
* @returns {*} the value of the BinaryExpression.
|
|
37
|
-
* @private
|
|
38
|
-
*/
|
|
39
|
-
export function BinaryExpression(this: Evaluator, ast: any) {
|
|
40
|
-
const grammarOp = this._grammar.elements[ast.operator]
|
|
41
|
-
if (grammarOp.evalOnDemand) {
|
|
42
|
-
const wrap = (subAst: AstNode) => ({ eval: () => this.eval(subAst) })
|
|
43
|
-
return grammarOp.evalOnDemand(wrap(ast.left), wrap(ast.right))
|
|
44
|
-
}
|
|
45
|
-
const left = this.eval(ast.left)
|
|
46
|
-
const right = this.eval(ast.right)
|
|
47
|
-
return grammarOp.eval(left, right)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Evaluates a ConditionalExpression node by first evaluating its test branch,
|
|
52
|
-
* and returning the consequent branch if the test is truthy, or the alternate
|
|
53
|
-
* branch if it is not. If there is no consequent branch, the test result will
|
|
54
|
-
* be used instead.
|
|
55
|
-
* @param {{type: 'ConditionalExpression', test: {}, consequent: {},
|
|
56
|
-
* alternate: {}}} ast An expression tree with a ConditionalExpression as
|
|
57
|
-
* the top node
|
|
58
|
-
* @private
|
|
59
|
-
*/
|
|
60
|
-
export function ConditionalExpression(this: Evaluator, ast: any) {
|
|
61
|
-
const res = this.eval(ast.test)
|
|
62
|
-
if (res) {
|
|
63
|
-
return ast.consequent ? this.eval(ast.consequent) : res
|
|
64
|
-
}
|
|
65
|
-
return this.eval(ast.alternate)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Evaluates a FilterExpression by applying bracket notation for array/object access.
|
|
70
|
-
* Note: Relative filtering (with leading dot) is not supported.
|
|
71
|
-
* @param {{type: 'FilterExpression', relative: <boolean>, expr: {},
|
|
72
|
-
* subject: {}}} ast An expression tree with a FilterExpression as the top
|
|
73
|
-
* node
|
|
74
|
-
* @returns {*} the value at the specified index/property.
|
|
75
|
-
* @private
|
|
76
|
-
*/
|
|
77
|
-
export function FilterExpression(this: Evaluator, ast: any) {
|
|
78
|
-
const subject = this.eval(ast.subject)
|
|
79
|
-
if (ast.relative) {
|
|
80
|
-
throw new Error('Relative filter expressions are not supported')
|
|
81
|
-
}
|
|
82
|
-
const index = this.eval(ast.expr)
|
|
83
|
-
return subject?.[index]
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Evaluates an Identifier by either stemming from the evaluated 'from'
|
|
88
|
-
* expression tree or accessing the context provided when this Evaluator was
|
|
89
|
-
* constructed.
|
|
90
|
-
* @param {{type: 'Identifier', value: <string>, [from]: {}}} ast An expression
|
|
91
|
-
* tree with an Identifier as the top node
|
|
92
|
-
* @returns {*} the identifier's value.
|
|
93
|
-
* @private
|
|
94
|
-
*/
|
|
95
|
-
export function Identifier(this: Evaluator, ast: any) {
|
|
96
|
-
if (!ast.from) {
|
|
97
|
-
const contextSource = ast.relative ? this._relContext : this._context
|
|
98
|
-
return contextSource[ast.value]
|
|
99
|
-
}
|
|
100
|
-
const context = this.eval(ast.from)
|
|
101
|
-
if (context == null) {
|
|
102
|
-
return undefined
|
|
103
|
-
}
|
|
104
|
-
const ctx = Array.isArray(context) ? context[0] : context
|
|
105
|
-
return ctx?.[ast.value]
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Evaluates a Literal by returning its value property.
|
|
110
|
-
* @param {{type: 'Literal', value: <string|number|boolean>}} ast An expression
|
|
111
|
-
* tree with a Literal as its only node
|
|
112
|
-
* @returns {string|number|boolean} The value of the Literal node
|
|
113
|
-
* @private
|
|
114
|
-
*/
|
|
115
|
-
export function Literal(this: Evaluator, ast: any) {
|
|
116
|
-
return ast.value
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Evaluates a TemplateLiteral by evaluating each interpolated expression
|
|
121
|
-
* and concatenating all parts into a final string.
|
|
122
|
-
* @param {{type: 'TemplateLiteral', parts: Array<{}>}} ast An expression
|
|
123
|
-
* tree with a TemplateLiteral as the top node
|
|
124
|
-
* @returns {string} the final interpolated string
|
|
125
|
-
* @private
|
|
126
|
-
*/
|
|
127
|
-
export function TemplateLiteral(this: Evaluator, ast: any) {
|
|
128
|
-
const values = ast.parts.map((part: any) => {
|
|
129
|
-
if (part.type === 'static') {
|
|
130
|
-
return part.value
|
|
131
|
-
}
|
|
132
|
-
const result = this.eval(part.value)
|
|
133
|
-
if (result == null) {
|
|
134
|
-
return ''
|
|
135
|
-
}
|
|
136
|
-
return String(result)
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
return values.join('')
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Evaluates an ObjectLiteral by returning its value, with each key
|
|
144
|
-
* independently run through the evaluator.
|
|
145
|
-
* @param {{type: 'ObjectLiteral', value: <{}>}} ast An expression tree with an
|
|
146
|
-
* ObjectLiteral as the top node
|
|
147
|
-
* @returns {{}} a map of evaluated values.
|
|
148
|
-
* @private
|
|
149
|
-
*/
|
|
150
|
-
export function ObjectLiteral(this: Evaluator, ast: any) {
|
|
151
|
-
return this.evalMap(ast.value)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Evaluates a FunctionCall node by applying the supplied arguments to a
|
|
156
|
-
* function defined in one of the grammar's function pools.
|
|
157
|
-
* @param {{type: 'FunctionCall', name: <string>}} ast An
|
|
158
|
-
* expression tree with a FunctionCall as the top node
|
|
159
|
-
* @returns {*} the value of the function call.
|
|
160
|
-
* @private
|
|
161
|
-
*/
|
|
162
|
-
export function FunctionCall(this: Evaluator, ast: any) {
|
|
163
|
-
const poolName = poolNames[ast.pool]
|
|
164
|
-
if (!poolName) {
|
|
165
|
-
throw new Error(`Corrupt AST: Pool '${ast.pool}' not found`)
|
|
166
|
-
}
|
|
167
|
-
const pool = (this._grammar as any)[ast.pool]
|
|
168
|
-
const func = pool?.[ast.name]
|
|
169
|
-
if (!func) {
|
|
170
|
-
throw new Error(`${poolName} ${ast.name} is not defined.`)
|
|
171
|
-
}
|
|
172
|
-
const args = this.evalArray(ast.args || [])
|
|
173
|
-
return func(...args)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Evaluates a Unary expression by passing the right side through the
|
|
178
|
-
* operator's eval function.
|
|
179
|
-
* @param {{type: 'UnaryExpression', operator: <string>, right: {}}} ast An
|
|
180
|
-
* expression tree with a UnaryExpression as the top node
|
|
181
|
-
* @returns {*} the value of the UnaryExpression.
|
|
182
|
-
* @constructor
|
|
183
|
-
*/
|
|
184
|
-
export function UnaryExpression(this: Evaluator, ast: any) {
|
|
185
|
-
const right = this.eval(ast.right)
|
|
186
|
-
return this._grammar.elements[ast.operator].eval(right)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Evaluates a SequenceExpression by evaluating each expression in order
|
|
191
|
-
* and returning the value of the last expression.
|
|
192
|
-
*/
|
|
193
|
-
export function SequenceExpression(this: Evaluator, ast: any) {
|
|
194
|
-
let lastValue: any
|
|
195
|
-
|
|
196
|
-
for (const expr of ast.expressions) {
|
|
197
|
-
lastValue = this.eval(expr)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return lastValue
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Evaluates an AssignmentExpression by evaluating the right side
|
|
205
|
-
* and assigning it to the variable name on the left side.
|
|
206
|
-
*/
|
|
207
|
-
export function AssignmentExpression(this: Evaluator, ast: any) {
|
|
208
|
-
const value = this.eval(ast.right)
|
|
209
|
-
const varName = ast.left.value
|
|
210
|
-
this._context[varName] = value
|
|
211
|
-
return value
|
|
212
|
-
}
|