@sap/cds-compiler 6.3.6 → 6.4.2
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/CHANGELOG.md +48 -0
- package/LICENSE +32 -0
- package/README.md +14 -2
- package/bin/cdsse.js +0 -3
- package/doc/CHANGELOG_BETA.md +1 -1
- package/doc/CHANGELOG_DEPRECATED.md +1 -1
- package/lib/base/message-registry.js +7 -0
- package/lib/base/messages.js +1 -1
- package/lib/base/model.js +2 -0
- package/lib/compiler/assert-consistency.js +1 -0
- package/lib/compiler/checks.js +37 -26
- package/lib/compiler/define.js +1 -1
- package/lib/compiler/extend.js +39 -50
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/lsp-api.js +1 -1
- package/lib/compiler/populate.js +2 -2
- package/lib/compiler/propagator.js +29 -6
- package/lib/compiler/resolve.js +13 -3
- package/lib/compiler/shared.js +31 -25
- package/lib/compiler/tweak-assocs.js +86 -28
- package/lib/compiler/xpr-rewrite.js +70 -38
- package/lib/edm/annotations/edmJson.js +206 -37
- package/lib/edm/csn2edm.js +13 -0
- package/lib/edm/edmUtils.js +2 -2
- package/lib/gen/BaseParser.js +106 -72
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +1500 -1509
- package/lib/json/to-csn.js +8 -5
- package/lib/language/genericAntlrParser.js +0 -0
- package/lib/main.js +19 -16
- package/lib/model/csnRefs.js +589 -521
- package/lib/model/csnUtils.js +8 -5
- package/lib/model/enrichCsn.js +1 -0
- package/lib/parsers/AstBuildingParser.js +72 -27
- package/lib/render/toCdl.js +2 -1
- package/lib/render/toHdbcds.js +6 -3
- package/lib/render/toSql.js +5 -0
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/assertUnique.js +4 -1
- package/lib/transform/db/cdsPersistence.js +17 -18
- package/lib/transform/db/expansion.js +179 -3
- package/lib/transform/db/flattening.js +16 -5
- package/lib/transform/db/rewriteCalculatedElements.js +79 -283
- package/lib/transform/effective/main.js +8 -1
- package/lib/transform/forOdata.js +1 -1
- package/lib/transform/forRelationalDB.js +21 -80
- package/lib/transform/localized.js +65 -110
- package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +89 -63
- package/lib/transform/transformUtils.js +23 -21
- package/lib/transform/translateAssocsToJoins.js +7 -5
- package/lib/transform/tupleExpansion.js +16 -3
- package/package.json +1 -1
- package/doc/DeprecatedOptions_v2.md +0 -150
- package/doc/NameResolution.md +0 -837
- package/lib/transform/parseExpr.js +0 -415
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
|
-
'use strict';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* parseExpr() accepts any JSON object and tries to convert a token stream expression
|
|
7
|
-
* array into an AST like expression with CDL operator precedence.
|
|
8
|
-
*
|
|
9
|
-
* The following operators are supported:
|
|
10
|
-
*
|
|
11
|
-
* Unary: +/-
|
|
12
|
-
* Multiplication/Division: '*', '/'
|
|
13
|
-
* Addition/Subtraction: '+', '-'
|
|
14
|
-
* Concatenation: '||'
|
|
15
|
-
* Relational: '=', '<>', '>', '>=', '<', '<=', '==', '!=', 'like', 'in', 'exists', 'between and'
|
|
16
|
-
* Unary: 'is [not] null', 'not'
|
|
17
|
-
* Conditional: 'case [when then]+ [else]? end', 'and', 'or'
|
|
18
|
-
*
|
|
19
|
-
* stand-alone token: 'new'
|
|
20
|
-
*
|
|
21
|
-
* This is not an optimized LL(1) parser but a token 'sniffer'. A stream is
|
|
22
|
-
* cracked up in sub streams and passed down to the next higher function.
|
|
23
|
-
*
|
|
24
|
-
* Complex aggregates like case/when/else/end and between are parsed first to pass down the
|
|
25
|
-
* resulting sub expressions and avoiding 'and' ambiguities.
|
|
26
|
-
*
|
|
27
|
-
* Sub expressions are grouped as arrays, the final AST is an array of nested arrays.
|
|
28
|
-
* Alternatively, an object like AST can be produced by setting argument 'array' to false.
|
|
29
|
-
*
|
|
30
|
-
* This parser intentionally does no error handling. If a clause is malformed, it is accepted as is.
|
|
31
|
-
*
|
|
32
|
-
* @param {any} xpr A JSON object.
|
|
33
|
-
* @param {Object} state Object
|
|
34
|
-
* anno: Don't eliminate arrays with single entry in expressions (TODO?) as they are collections
|
|
35
|
-
* array: Bias AST representation.
|
|
36
|
-
* nary: return n-ary or binary tree
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
function parseExpr(xpr, state = { array: true, nary: false }) {
|
|
40
|
-
state.anno = 0;
|
|
41
|
-
// Notes:
|
|
42
|
-
// - Variables `s` and `e` are used as index variables into `xpr`s for start and end.
|
|
43
|
-
// - xpr's are our CSN expressions, see <https://cap.cloud.sap/docs/cds/cxn>
|
|
44
|
-
|
|
45
|
-
return parseExprInt(xpr, state);
|
|
46
|
-
|
|
47
|
-
function parseExprInt(xpr, state) {
|
|
48
|
-
return conditionOR(...CaseWhen(Cast(xpr, state)), state);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function Cast(xpr, state) {
|
|
52
|
-
if (xpr != null && !state.array) {
|
|
53
|
-
if (Array.isArray(xpr))
|
|
54
|
-
return xpr.map(x => Cast(x, state));
|
|
55
|
-
if (typeof xpr === 'object') {
|
|
56
|
-
const castKeys = Object.keys(xpr).filter(k => k !== 'cast');
|
|
57
|
-
if (xpr.cast != null && castKeys.length === 1)
|
|
58
|
-
return { cast: [ xpr.cast, { [castKeys[0]]: xpr[castKeys[0]] } ] };
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
for (const n in xpr) {
|
|
62
|
-
// xpr could be an array with polluted prototype
|
|
63
|
-
if (Object.hasOwnProperty.call(xpr, n))
|
|
64
|
-
xpr[n] = Cast(xpr[n], state);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return xpr;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function CaseWhen(xpr) {
|
|
72
|
-
if (Array.isArray(xpr))
|
|
73
|
-
recurseIntoCases();
|
|
74
|
-
|
|
75
|
-
return [ xpr, 0, Array.isArray(xpr) ? xpr.length : 1 ];
|
|
76
|
-
|
|
77
|
-
function recurseIntoCases(casePos = -1, lvl = -1) {
|
|
78
|
-
for (let c = casePos + 1; c < xpr.length; c++) {
|
|
79
|
-
if (xpr[c] === 'case')
|
|
80
|
-
recurseIntoCases(c, lvl + 1);
|
|
81
|
-
}
|
|
82
|
-
if (lvl > -1) {
|
|
83
|
-
let endPos = casePos;
|
|
84
|
-
while (xpr[endPos] !== 'end' && endPos < xpr.length)
|
|
85
|
-
endPos++;
|
|
86
|
-
if (xpr[endPos] === 'end') {
|
|
87
|
-
const caseTree = rewriteCaseBlock(casePos, endPos);
|
|
88
|
-
if (casePos === 0 && endPos === xpr.length - 1)
|
|
89
|
-
xpr = caseTree;
|
|
90
|
-
else
|
|
91
|
-
xpr.splice(casePos, endPos - casePos + 1, caseTree);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* @param {number} casePos
|
|
98
|
-
* @param {number} endPos
|
|
99
|
-
* @return {Array|object}
|
|
100
|
-
*/
|
|
101
|
-
function rewriteCaseBlock(casePos, endPos) {
|
|
102
|
-
const caseTree = state.array ? [ 'case' ] : { case: [] };
|
|
103
|
-
|
|
104
|
-
let elsePos = endPos;
|
|
105
|
-
let whenPos = casePos;
|
|
106
|
-
|
|
107
|
-
while (xpr[elsePos] !== 'else' && elsePos > casePos)
|
|
108
|
-
elsePos--;
|
|
109
|
-
let elseCond;
|
|
110
|
-
if (xpr[elsePos] === 'else') {
|
|
111
|
-
elseCond = xpr.slice(elsePos + 1, endPos);
|
|
112
|
-
endPos = elsePos;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
while (xpr[whenPos] !== 'when' && whenPos < endPos)
|
|
116
|
-
whenPos++;
|
|
117
|
-
if (xpr[whenPos] === 'when' && whenPos - (casePos + 1) >= 1) {
|
|
118
|
-
const caseExpr = xpr.slice(casePos + 1, whenPos);
|
|
119
|
-
if (state.array)
|
|
120
|
-
caseTree.push(caseExpr);
|
|
121
|
-
else
|
|
122
|
-
caseTree.case.push(caseExpr.length === 1 ? caseExpr[0] : caseExpr);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
while (xpr[whenPos] === 'when') {
|
|
126
|
-
const when = { when: [] };
|
|
127
|
-
if (state.array)
|
|
128
|
-
caseTree.push('when');
|
|
129
|
-
else
|
|
130
|
-
caseTree.case.push(when);
|
|
131
|
-
|
|
132
|
-
let thenPos = whenPos + 1;
|
|
133
|
-
while (xpr[thenPos] !== 'then' && thenPos < endPos)
|
|
134
|
-
thenPos++;
|
|
135
|
-
if (xpr[thenPos] === 'then') {
|
|
136
|
-
const whenExpr = xpr.slice(whenPos + 1, thenPos);
|
|
137
|
-
if (state.array)
|
|
138
|
-
caseTree.push(whenExpr);
|
|
139
|
-
else
|
|
140
|
-
when.when.push(whenExpr.length === 1 ? whenExpr[0] : whenExpr);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
whenPos = thenPos + 1;
|
|
144
|
-
while (xpr[whenPos] !== 'when' && whenPos < endPos)
|
|
145
|
-
whenPos++;
|
|
146
|
-
if (xpr[whenPos] === 'when' || whenPos === endPos) {
|
|
147
|
-
const then = xpr.slice(thenPos + 1, whenPos);
|
|
148
|
-
if (state.array)
|
|
149
|
-
caseTree.push('then', then);
|
|
150
|
-
else
|
|
151
|
-
when.when.push(then.length === 1 ? then[0] : then);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (elseCond) {
|
|
155
|
-
if (state.array)
|
|
156
|
-
caseTree.push('else', elseCond);
|
|
157
|
-
else
|
|
158
|
-
caseTree.case.push(elseCond.length === 1 ? elseCond[0] : elseCond);
|
|
159
|
-
}
|
|
160
|
-
if (state.array)
|
|
161
|
-
caseTree.push('end');
|
|
162
|
-
return caseTree;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function conditionOR(xpr, s, e, state) {
|
|
167
|
-
return binaryExpr(xpr, [ 'or' ], conditionAnd, s, e, state);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function conditionAnd(xpr, s, e, state) {
|
|
171
|
-
return binaryExpr(xpr, (xpr, s, e) => {
|
|
172
|
-
let a = s - 1;
|
|
173
|
-
let b;
|
|
174
|
-
do {
|
|
175
|
-
b = false;
|
|
176
|
-
for (a++; xpr[a] !== 'and' && a < e; a++) {
|
|
177
|
-
if (xpr[a] === 'between')
|
|
178
|
-
b = true;
|
|
179
|
-
}
|
|
180
|
-
} while (b && a < e);
|
|
181
|
-
|
|
182
|
-
if (!b && a < e)
|
|
183
|
-
return [ 1, a ];
|
|
184
|
-
return [ 1, -1 ];
|
|
185
|
-
}, conditionTerm, s, e, state);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function conditionTerm(xpr, s, e, state) {
|
|
189
|
-
if (Array.isArray(xpr)) {
|
|
190
|
-
if (xpr.length >= 3 && xpr[s + 1] === 'is') {
|
|
191
|
-
const isnull = conditionOR(xpr[s], 0, 0, state);
|
|
192
|
-
if (xpr[s + 2] === 'null')
|
|
193
|
-
return state.array ? [ isnull, 'is', 'null' ] : { isNull: isnull };
|
|
194
|
-
else if (xpr[s + 2] === 'not' && xpr[s + 3] === 'null')
|
|
195
|
-
return state.array ? [ isnull, 'is', 'not', 'null' ] : { isNotNull: isnull };
|
|
196
|
-
}
|
|
197
|
-
if (xpr[s] === 'not') {
|
|
198
|
-
const not = conditionTerm(xpr, s + 1, e, state);
|
|
199
|
-
return state.array ? [ 'not', not ] : { not };
|
|
200
|
-
}
|
|
201
|
-
if (xpr[s] === 'exists') {
|
|
202
|
-
const exists = conditionTerm(xpr, s + 1, e, state);
|
|
203
|
-
return state.array ? [ 'exists', exists ] : { exists };
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return compareTerm(xpr, s, e, state);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function compareTerm(xpr, s, e, state) {
|
|
210
|
-
if (Array.isArray(xpr)) {
|
|
211
|
-
let i = s;
|
|
212
|
-
let not = false;
|
|
213
|
-
let between;
|
|
214
|
-
while (i < e && xpr[i] !== 'between')
|
|
215
|
-
i++;
|
|
216
|
-
const b = i < e ? i : -1;
|
|
217
|
-
while (i < e && xpr[i] !== 'and')
|
|
218
|
-
i++;
|
|
219
|
-
const a = i < e ? i : -1;
|
|
220
|
-
if (b >= 0) {
|
|
221
|
-
const token = [ 'between' ];
|
|
222
|
-
not = (xpr[b - 1] === 'not');
|
|
223
|
-
if (not)
|
|
224
|
-
token.splice(0, 0, 'not');
|
|
225
|
-
const expr = expression(xpr, s, not ? b - 1 : b, state);
|
|
226
|
-
between = state.array
|
|
227
|
-
? [ expr, ...token ]
|
|
228
|
-
: { between: [ expr ] };
|
|
229
|
-
if (a >= 0) {
|
|
230
|
-
const lower = expression(xpr, b + 1, a, state);
|
|
231
|
-
const upper = expression(xpr, a + 1, e, state);
|
|
232
|
-
if (state.array)
|
|
233
|
-
between.push(lower, 'and', upper);
|
|
234
|
-
else
|
|
235
|
-
between.between.push(lower, upper);
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
const unspec = expression(xpr, b + 1, e, state);
|
|
239
|
-
if (state.array)
|
|
240
|
-
between.push(unspec);
|
|
241
|
-
else
|
|
242
|
-
between.between.push(unspec);
|
|
243
|
-
}
|
|
244
|
-
if (not && !state.array)
|
|
245
|
-
between = { not: between };
|
|
246
|
-
|
|
247
|
-
return between;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return binaryExpr(xpr, (xpr, s, e) => {
|
|
251
|
-
const token = [ '=', '<>', '>', '>=', '<', '<=', '==', '!=', 'like', 'in' ];
|
|
252
|
-
while (s < e && !token.includes(xpr[s]))
|
|
253
|
-
s++;
|
|
254
|
-
if (s < e) {
|
|
255
|
-
if (xpr[s - 1] === 'not' && (xpr[s] === 'in' || xpr[s] === 'like'))
|
|
256
|
-
return [ 2, s - 1 ];
|
|
257
|
-
return [ 1, s ];
|
|
258
|
-
}
|
|
259
|
-
return [ 1, -1 ];
|
|
260
|
-
}, expression, s, e, state);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function expression(xpr, s, e, state) {
|
|
264
|
-
return binaryExpr(xpr, [ '||' ], exprAddSub, s, e, state);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function exprAddSub(xpr, s, e, state) {
|
|
268
|
-
return binaryExpr(xpr, (xpr, s, e) => {
|
|
269
|
-
const skips = [ '+', '-', '*', '/' ];
|
|
270
|
-
let found = false;
|
|
271
|
-
let p = s;
|
|
272
|
-
while (!found && p < e) {
|
|
273
|
-
found = ((xpr[p] === '+' || xpr[p] === '-') && p > s && !skips.includes(xpr[p - 1]) && p < e);
|
|
274
|
-
if (!found)
|
|
275
|
-
p++;
|
|
276
|
-
}
|
|
277
|
-
if (found)
|
|
278
|
-
return [ 1, p ];
|
|
279
|
-
return [ 1, -1 ];
|
|
280
|
-
}, exprMulDiv, s, e, state);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function exprMulDiv(xpr, s, e, state) {
|
|
284
|
-
return binaryExpr(xpr, [ '*', '/' ], (state.array ? unary : dot), s, e, state);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function dot(xpr, s, e, state) {
|
|
288
|
-
return binaryExpr(xpr, [ '.' ], unary, s, e, state);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function unary(xpr, s, e, state) {
|
|
292
|
-
if (Array.isArray(xpr)) {
|
|
293
|
-
if (xpr[s] === '+' || xpr[s] === '-' || (!state.array && xpr[s] === 'new')) {
|
|
294
|
-
if (state.array)
|
|
295
|
-
return [ xpr[s], unary(xpr, s + 1, e, state) ];
|
|
296
|
-
return { [xpr[s]]: unary(xpr, s + 1, e, state) };
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return terminal(xpr, s, e, state);
|
|
300
|
-
}
|
|
301
|
-
function terminal(xpr, s, e, state) {
|
|
302
|
-
const csnarray = [
|
|
303
|
-
'ref', 'args', 'columns', 'keys', 'expand', 'inline',
|
|
304
|
-
'requires', 'extensions', 'includes', 'excluding',
|
|
305
|
-
];
|
|
306
|
-
const xprarray = [
|
|
307
|
-
'xpr', 'on', 'where', 'orderBy', 'groupBy', 'having',
|
|
308
|
-
];
|
|
309
|
-
|
|
310
|
-
if (Array.isArray(xpr) && xpr.length > 0) {
|
|
311
|
-
if (e - s <= 1 && state.anno === 0 && typeof xpr[e - 1] !== 'string')
|
|
312
|
-
return parseExprInt(xpr[e - 1], state);
|
|
313
|
-
return xpr.slice(s, e).map(ix => parseExprInt(ix, state));
|
|
314
|
-
}
|
|
315
|
-
if (typeof xpr === 'object') {
|
|
316
|
-
// if(xpr?.func && funkyfuncs.includes(xpr?.func))
|
|
317
|
-
// return xpr;
|
|
318
|
-
for (const n in xpr) {
|
|
319
|
-
// xpr could be an array with polluted prototype
|
|
320
|
-
if (!Object.hasOwnProperty.call(xpr, n))
|
|
321
|
-
continue;
|
|
322
|
-
const x = xpr[n];
|
|
323
|
-
const isAnno = n[0] === '@' && isSimpleAnnoValue(x);
|
|
324
|
-
if (isAnno)
|
|
325
|
-
state.anno++;
|
|
326
|
-
if (Array.isArray(x)) {
|
|
327
|
-
if (csnarray.includes(n) || state.anno !== 0)
|
|
328
|
-
xpr[n] = x.map(ix => parseExprInt(ix, state));
|
|
329
|
-
else if (xprarray.includes(n) && x.length === 1)
|
|
330
|
-
xpr[n] = x.map(ix => parseExprInt(ix, state));
|
|
331
|
-
else
|
|
332
|
-
xpr[n] = parseExprInt(x, state);
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
xpr[n] = parseExprInt(x, state);
|
|
336
|
-
}
|
|
337
|
-
if (isAnno)
|
|
338
|
-
state.anno--;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return xpr;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function binaryExpr(xpr, token, next, s, e, state) {
|
|
345
|
-
const naryExpr = [];
|
|
346
|
-
let not = false;
|
|
347
|
-
if (Array.isArray(xpr)) {
|
|
348
|
-
let [ tl, p ] = findToken(s, e);
|
|
349
|
-
if (p >= 0) {
|
|
350
|
-
let lhs = next(xpr, s, p, state);
|
|
351
|
-
naryExpr.push(lhs);
|
|
352
|
-
let op = xpr.slice(p, p + tl);
|
|
353
|
-
s = p + tl;
|
|
354
|
-
[ tl, p ] = findToken(s, e);
|
|
355
|
-
while (p >= 0) {
|
|
356
|
-
const rhs = next(xpr, s, p, state);
|
|
357
|
-
naryExpr.push(...op, rhs);
|
|
358
|
-
if (state.array) {
|
|
359
|
-
lhs = [ lhs, ...op, rhs ];
|
|
360
|
-
}
|
|
361
|
-
else {
|
|
362
|
-
not = op.length > 1 && op[0] === 'not';
|
|
363
|
-
if (not)
|
|
364
|
-
op = op.slice(1);
|
|
365
|
-
lhs = (not
|
|
366
|
-
? { not: { [op.join('')]: [ lhs, rhs ] } }
|
|
367
|
-
: { [op.join('')]: [ lhs, rhs ] });
|
|
368
|
-
}
|
|
369
|
-
op = xpr.slice(p, p + tl);
|
|
370
|
-
s = p + tl;
|
|
371
|
-
[ tl, p ] = findToken(s, e);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
let rhs = next(xpr, s, e, state);
|
|
375
|
-
if (Array.isArray(rhs) && rhs.length === 0)
|
|
376
|
-
rhs = undefined;
|
|
377
|
-
naryExpr.push(...op, rhs);
|
|
378
|
-
|
|
379
|
-
if (state.array)
|
|
380
|
-
return (state.nary ? naryExpr : [ lhs, ...op, rhs ]);
|
|
381
|
-
|
|
382
|
-
not = op.length > 1 && op[0] === 'not';
|
|
383
|
-
if (not)
|
|
384
|
-
op = op.slice(1);
|
|
385
|
-
return (not
|
|
386
|
-
? { not: { [op.join('')]: [ lhs, rhs ] } }
|
|
387
|
-
: { [op.join('')]: [ lhs, rhs ] });
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return next(xpr, s, e, state);
|
|
391
|
-
|
|
392
|
-
function findToken(s, e) {
|
|
393
|
-
if (typeof token === 'function')
|
|
394
|
-
return token(xpr, s, e);
|
|
395
|
-
|
|
396
|
-
while (s < e && !token.includes(xpr[s]))
|
|
397
|
-
s++;
|
|
398
|
-
if (s < e)
|
|
399
|
-
return [ 1, s ];
|
|
400
|
-
|
|
401
|
-
return [ 1, -1 ];
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function isSimpleAnnoValue(val) {
|
|
407
|
-
// Expressions as annotation values always have a `=` and another property.
|
|
408
|
-
// TODO: There must be at least one known expression property, otherwise
|
|
409
|
-
// it could be `type: 'unchecked'`.
|
|
410
|
-
return !val?.['='] || Object.keys(val) < 2;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
module.exports = {
|
|
414
|
-
parseExpr,
|
|
415
|
-
};
|