@witchcraft/expressit 0.0.3 → 0.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.
Files changed (85) hide show
  1. package/README.md +3 -1
  2. package/dist/Lexer.d.ts +146 -0
  3. package/dist/Lexer.d.ts.map +1 -0
  4. package/dist/Lexer.js +960 -0
  5. package/dist/Parser.d.ts +140 -0
  6. package/dist/Parser.d.ts.map +1 -0
  7. package/dist/Parser.js +668 -0
  8. package/dist/ast/handlers.d.ts +3 -3
  9. package/dist/ast/handlers.d.ts.map +1 -1
  10. package/dist/examples/shortcutContextParser.d.ts +1 -1
  11. package/dist/examples/shortcutContextParser.js +1 -1
  12. package/dist/helpers/parser/extractPosition.d.ts +2 -6
  13. package/dist/helpers/parser/extractPosition.d.ts.map +1 -1
  14. package/dist/helpers/parser/extractPosition.js +3 -3
  15. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts +2 -3
  16. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts.map +1 -1
  17. package/dist/helpers/parser/getUnclosedRightParenCount.js +4 -4
  18. package/dist/index.d.ts +1 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3 -5
  21. package/dist/methods/autocomplete.d.ts.map +1 -1
  22. package/dist/methods/validate.js +1 -0
  23. package/dist/package.json.js +26 -39
  24. package/dist/types/ast.d.ts +1 -7
  25. package/dist/types/ast.d.ts.map +1 -1
  26. package/dist/types/errors.d.ts +5 -17
  27. package/dist/types/errors.d.ts.map +1 -1
  28. package/dist/types/errors.js +0 -1
  29. package/dist/types/parser.d.ts.map +1 -1
  30. package/dist/utils/getCursorInfo.d.ts +2 -2
  31. package/dist/utils/getCursorInfo.d.ts.map +1 -1
  32. package/dist/utils/getCursorInfo.js +1 -4
  33. package/dist/utils/getOppositeDelimiter.d.ts.map +1 -1
  34. package/dist/utils/prettyAst.js +1 -0
  35. package/package.json +24 -39
  36. package/src/Lexer.ts +704 -0
  37. package/src/Parser.ts +972 -0
  38. package/src/ast/builders/array.ts +1 -1
  39. package/src/ast/builders/condition.ts +1 -1
  40. package/src/ast/builders/expression.ts +1 -1
  41. package/src/ast/builders/group.ts +1 -1
  42. package/src/ast/builders/pos.ts +1 -1
  43. package/src/ast/builders/token.ts +1 -1
  44. package/src/ast/builders/type.ts +1 -1
  45. package/src/ast/builders/variable.ts +1 -1
  46. package/src/ast/classes/ConditionNode.ts +1 -1
  47. package/src/ast/classes/ErrorToken.ts +1 -1
  48. package/src/ast/classes/ValidToken.ts +2 -2
  49. package/src/ast/handlers.ts +6 -6
  50. package/src/examples/shortcutContextParser.ts +2 -2
  51. package/src/helpers/errors.ts +1 -1
  52. package/src/helpers/general/defaultConditionNormalizer.ts +1 -1
  53. package/src/helpers/parser/checkParserOpts.ts +10 -10
  54. package/src/helpers/parser/extractPosition.ts +4 -8
  55. package/src/helpers/parser/getUnclosedRightParenCount.ts +6 -6
  56. package/src/helpers/parser/parseParserOptions.ts +1 -1
  57. package/src/index.ts +1 -2
  58. package/src/methods/autocomplete.ts +4 -4
  59. package/src/methods/autoreplace.ts +1 -1
  60. package/src/methods/autosuggest.ts +1 -1
  61. package/src/methods/evaluate.ts +1 -1
  62. package/src/methods/normalize.ts +1 -1
  63. package/src/methods/validate.ts +1 -1
  64. package/src/types/ast.ts +1 -8
  65. package/src/types/errors.ts +12 -22
  66. package/src/types/parser.ts +0 -1
  67. package/src/utils/getCursorInfo.ts +4 -3
  68. package/src/utils/getOppositeDelimiter.ts +4 -1
  69. package/src/utils/prettyAst.ts +1 -1
  70. package/dist/grammar/ParserBase.d.ts +0 -51
  71. package/dist/grammar/ParserBase.d.ts.map +0 -1
  72. package/dist/grammar/ParserBase.js +0 -517
  73. package/dist/grammar/createTokens.d.ts +0 -56
  74. package/dist/grammar/createTokens.d.ts.map +0 -1
  75. package/dist/grammar/createTokens.js +0 -844
  76. package/dist/grammar/index.d.ts +0 -3
  77. package/dist/grammar/index.d.ts.map +0 -1
  78. package/dist/grammar/index.js +0 -6
  79. package/dist/parser.d.ts +0 -58
  80. package/dist/parser.d.ts.map +0 -1
  81. package/dist/parser.js +0 -137
  82. package/src/grammar/ParserBase.ts +0 -716
  83. package/src/grammar/createTokens.ts +0 -513
  84. package/src/grammar/index.ts +0 -4
  85. package/src/parser.ts +0 -184
@@ -1,716 +0,0 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
-
3
- import { isArray } from "@alanscodelog/utils/isArray"
4
- import { unreachable } from "@alanscodelog/utils/unreachable"
5
- import { EmbeddedActionsParser, EOF, type IToken, tokenMatcher } from "chevrotain"
6
-
7
- import type { createTokens } from "./createTokens.js"
8
-
9
- import { pos } from "../ast/builders/pos.js"
10
- import { ArrayNode } from "../ast/classes/ArrayNode.js"
11
- import { ConditionNode } from "../ast/classes/ConditionNode.js"
12
- import { ErrorToken } from "../ast/classes/ErrorToken.js"
13
- import type { ExpressionNode } from "../ast/classes/ExpressionNode.js"
14
- import type { GroupNode } from "../ast/classes/GroupNode.js"
15
- import type { ValidToken } from "../ast/classes/ValidToken.js"
16
- import { VariableNode } from "../ast/classes/VariableNode.js"
17
- import * as handle from "../ast/handlers.js"
18
- import { extractPosition } from "../helpers/parser/extractPosition.js"
19
- import { Parser } from "../parser.js"
20
- import { type AnyToken, type ParserResults, type Position, TOKEN_TYPE, type TokenQuoteTypes } from "../types/ast.js"
21
- import type { FullParserOptions } from "../types/parser.js"
22
-
23
-
24
- function processToken<TDefined extends boolean = boolean>(token: IToken, shift: number): [TDefined extends true ? string : string | undefined, Position] {
25
- let val: string | undefined = token.image
26
- if (token.isInsertedInRecovery) val = undefined
27
- return [val as any, extractPosition(token, shift)]
28
- }
29
- export class ParserBase<T extends {} = {}> extends EmbeddedActionsParser {
30
- rawInput!: string
31
-
32
- private subParser?: Parser
33
-
34
- private subParser2?: Parser
35
-
36
- constructor(opts: FullParserOptions<T>, t: ReturnType<typeof createTokens>["tokens"], { customOpAlsoNegation, expandedSepAlsoCustom }: ReturnType<typeof createTokens>["info"]) {
37
- super(t, {
38
- recoveryEnabled: true,
39
- // skipValidations: true
40
- })
41
-
42
- // eslint-disable-next-line @typescript-eslint/no-this-alias
43
- const $ = this
44
-
45
- $.RULE("main", () => {
46
- const res = $.SUBRULE($.boolOr)
47
- $.CONSUME(EOF)
48
-
49
- return $.ACTION(() => {
50
- if (res === undefined) {
51
- const error = handle.token.value(undefined, { start: 0, end: 0 })
52
- return error
53
- }
54
- return res
55
- })
56
- })
57
- $.RULE("boolOr", () => {
58
- const pairs: any[][] = []
59
-
60
- const DEF = (): void => {
61
- const exp = $.SUBRULE2($.boolAnd)
62
- const extras: any[] = []
63
-
64
- let next = $.LA(1)
65
- $.OPTION1({
66
- GATE: () => opts.onMissingBooleanOperator === "or" &&
67
- (
68
- tokenMatcher(next, t.VALUE) ||
69
- tokenMatcher(next, t.QUOTE_ANY) ||
70
- tokenMatcher(next, t.PAREN_L) ||
71
- tokenMatcher(next, t.EXP_PROP_OP) ||
72
- tokenMatcher(next, t.REGEX_START) ||
73
- tokenMatcher(next, t.CUSTOM_PROP_OP)
74
- ),
75
- DEF: () => {
76
- let dummyOp
77
- const cond = $.SUBRULE3($.condition)
78
- $.ACTION(() => {
79
- // the operator is missing between the previous token and this exp
80
- const prev = $.LA(-1)
81
- const start = prev.endOffset! + 1
82
- dummyOp = handle.operator.or("", pos({ start }, { fill: true }))
83
- })
84
-
85
- extras.push([dummyOp, cond])
86
- },
87
- })
88
-
89
- next = $.LA(1)
90
- pairs.push([exp, tokenMatcher(next, t.OPERATOR_OR) ? handle.operator.or(...processToken<true>(next, $.shift)) : undefined])
91
- for (const extra of extras) {
92
- pairs[pairs.length - 1].splice(1, 1, extra[0])
93
- pairs.push([extra[1]])
94
- }
95
- }
96
-
97
- $.MANY_SEP({ SEP: t.OPERATOR_OR, DEF })
98
-
99
-
100
- $.OPTION({
101
- // many sep sometimes fails to recover when it technically could
102
- GATE: () => pairs.length === 0 && tokenMatcher($.LA(1), t.OPERATOR_OR),
103
- DEF: () => {
104
- $.MANY(() => {
105
- const next = $.CONSUME(t.OPERATOR_OR)
106
- pairs.push([undefined, handle.operator.or(...processToken<true>(next, $.shift))])
107
- while (tokenMatcher($.LA(1), t.VALUE) || tokenMatcher($.LA(1), t.QUOTE_ANY) || tokenMatcher($.LA(1), t.PAREN_L)) {
108
- pairs.push([$.SUBRULE3($.condition)])
109
- }
110
- })
111
- },
112
- })
113
-
114
- return $.ACTION(() => {
115
- let res = pairs[pairs.length - 1][0]
116
- for (let i = pairs.length - 1; i > 0; i--) {
117
- const before = pairs[i - 1]
118
- if (res === undefined && before === undefined) return undefined
119
- res = handle.expression(before[0], before[1], res)
120
- }
121
- return res
122
- })
123
- })
124
- $.RULE("boolAnd", () => {
125
- const pairs: any[][] = []
126
-
127
- const DEF = (): void => {
128
- const exp = $.SUBRULE2($.condition)
129
- const extras: any[][] = []
130
-
131
- let next = $.LA(1)
132
- $.OPTION1({
133
- GATE: () => ["error", "and"].includes(opts.onMissingBooleanOperator) &&
134
- (
135
- tokenMatcher(next, t.VALUE) ||
136
- tokenMatcher(next, t.QUOTE_ANY) ||
137
- tokenMatcher(next, t.PAREN_L) ||
138
- tokenMatcher(next, t.EXP_PROP_OP) ||
139
- tokenMatcher(next, t.REGEX_START) ||
140
- tokenMatcher(next, t.CUSTOM_PROP_OP)
141
- ),
142
- DEF: () => {
143
- $.MANY2(() => {
144
- let dummyOp
145
- const cond = $.SUBRULE3($.condition)
146
- $.ACTION(() => {
147
- if (opts.onMissingBooleanOperator === "and") {
148
- // the operator is missing between the previous token and this exp
149
- const prev = $.LA(-1)
150
- const start = prev.endOffset! + 1
151
- dummyOp = handle.operator.and("", pos({ start }, { fill: true }))
152
- }
153
- })
154
-
155
- extras.push([dummyOp, cond])
156
- })
157
- },
158
- })
159
-
160
- next = $.LA(1)
161
- pairs.push([exp, tokenMatcher(next, t.OPERATOR_AND) ? handle.operator.and(...processToken<true>(next, $.shift)) : undefined])
162
- for (const extra of extras) {
163
- pairs[pairs.length - 1].splice(1, 1, extra[0])
164
- pairs.push([extra[1]])
165
- }
166
- }
167
-
168
- $.MANY_SEP({ SEP: t.OPERATOR_AND, DEF })
169
-
170
-
171
- $.OPTION({
172
- GATE: () => pairs.length === 0 && tokenMatcher($.LA(1), t.OPERATOR_AND),
173
- DEF: () => {
174
- $.MANY(() => {
175
- const next = $.CONSUME(t.OPERATOR_AND)
176
- pairs.push([undefined, handle.operator.and(...processToken<true>(next, $.shift))])
177
- while (tokenMatcher($.LA(1), t.VALUE) || tokenMatcher($.LA(1), t.QUOTE_ANY) || tokenMatcher($.LA(1), t.PAREN_L)) {
178
- pairs.push([$.SUBRULE3($.condition)])
179
- }
180
- })
181
- },
182
- })
183
-
184
- return $.ACTION(() => {
185
- if (pairs.length === 0) return undefined // handle situations like `a ||` where b is missing
186
- let res = pairs[pairs.length - 1][0]
187
- for (let i = pairs.length - 1; i > 0; i--) {
188
- const before = pairs[i - 1]
189
- res = handle.expression(before[0], before[1], res)
190
- }
191
- return res
192
- })
193
- })
194
-
195
- $.RULE("condition", () => {
196
- const not = $.OPTION(() => $.SUBRULE($.not))
197
-
198
- const property = $.OPTION2({
199
- GATE: () => (
200
- tokenMatcher($.LA(1), t.EXP_PROP_OP) ||
201
- tokenMatcher($.LA(1), t.CUSTOM_PROP_OP) ||
202
- tokenMatcher($.LA(2), t.EXP_PROP_OP) ||
203
- tokenMatcher($.LA(2), t.CUSTOM_PROP_OP) ||
204
- (
205
- customOpAlsoNegation &&
206
- (
207
- tokenMatcher($.LA(2), t.SYM_NOT) ||
208
- (tokenMatcher($.LA(0), t.SYM_NOT) && tokenMatcher($.LA(1), t.SYM_NOT))
209
- )
210
- )
211
- ),
212
- DEF: () => $.SUBRULE($.property),
213
- }) as ReturnType<typeof $["property"]> | undefined
214
- const propVal = $.ACTION(() => property?.prop?.value === undefined
215
- ? undefined
216
- : property.prop.value instanceof ErrorToken
217
- ? ""
218
- : property.prop.value.value)
219
-
220
- const propOpVal = $.ACTION(() => property?.rest.propertyOperator === undefined
221
- ? undefined
222
- : property.rest.propertyOperator instanceof ErrorToken
223
- ? ""
224
- : property.rest.propertyOperator.value)
225
-
226
- const isExpanded = $.ACTION(() => (property?.rest.sepL ?? property?.rest.sepR) !== undefined)
227
- const convertRegexValues = $.ACTION(() =>
228
- typeof opts.regexValues === "function" && !opts.regexValues(propVal, propOpVal, isExpanded))
229
-
230
- const convertArrayValues = $.ACTION(() =>
231
- typeof opts.arrayValues === "function" && !opts.arrayValues(propVal, propOpVal, isExpanded))
232
-
233
-
234
- let value: ReturnType<typeof $["plainGroup"]> |
235
- ReturnType<typeof $["plainBracketGroup"]> |
236
- ReturnType<typeof $["variable"]> |
237
- undefined = $.OR2([
238
- {
239
- GATE: () => opts.prefixableGroups && property === undefined &&
240
- $.LA(1).tokenType !== t.PAREN_L && // moves to parsing group below
241
- (
242
- (
243
- tokenMatcher($.LA(1), t.VALUE) &&
244
- (
245
- tokenMatcher($.LA(2), t.PAREN_L) || // a(
246
- (tokenMatcher($.LA(2), t.QUOTE_ANY) && tokenMatcher($.LA(3), t.PAREN_L)) // a"(
247
- )
248
- ) ||
249
- (
250
- tokenMatcher($.LA(1), t.QUOTE_ANY) &&
251
- (
252
- tokenMatcher($.LA(2), t.PAREN_L) || // "(
253
- (tokenMatcher($.LA(2), t.VALUE) &&
254
- (
255
- tokenMatcher($.LA(3), t.PAREN_L) || // "a(
256
- (tokenMatcher($.LA(3), t.QUOTE_ANY) && tokenMatcher($.LA(4), t.PAREN_L)) // "a"(
257
- )
258
- )
259
- )
260
- )
261
-
262
- )
263
- ,
264
- ALT: () => $.SUBRULE<any, any>($.variable, { ARGS: [{ unprefixed: true }]}), // un-prefixed
265
- },
266
- {
267
- GATE: () => $.LA(1).tokenType !== t.PAREN_L,
268
- ALT: () => $.SUBRULE2($.variable),
269
- },
270
- {
271
- GATE: () => $.LA(1).tokenType === t.PAREN_L,
272
- ALT: () => $.SUBRULE2<any, any>($.plainGroup, { ARGS: [{ onlyValues: property !== undefined, convertRegexValues, convertArrayValues }]}),
273
- },
274
- {
275
- GATE: () => $.LA(1).tokenType === t.BRACKET_L,
276
- ALT: () => $.SUBRULE2<any, any>($.plainBracketGroup, { ARGS: [{ convertArrayValues }]}),
277
- },
278
- {
279
- GATE: () => not !== undefined || property !== undefined || $.LA(1).tokenType === EOF,
280
- ALT: () => undefined,
281
- },
282
- ])
283
-
284
- let group = $.OPTION3({
285
- GATE: () => !(value instanceof ArrayNode) && !isArray(value) && (!value || opts.prefixableGroups) && $.LA(1).tokenType === t.PAREN_L, // is not already plain group
286
- DEF: () => $.SUBRULE3<any, any>($.plainGroup, { ARGS: [{ onlyValues: property !== undefined, convertRegexValues, convertArrayValues }]}),
287
- })
288
-
289
-
290
- return $.ACTION(() => {
291
- if (isArray(value)) {
292
- group = value
293
- value = undefined
294
- }
295
-
296
- if (convertRegexValues && value instanceof VariableNode && value.quote?.left.type === TOKEN_TYPE.REGEX) {
297
- value = handle.variable(undefined, undefined, handle.token.value(
298
- (value.quote?.left?.value ?? "") + (value.value.value ?? "") + (value.quote?.right?.value ?? ""),
299
- pos(value)
300
- ), undefined) as ReturnType<this["variable"]>
301
- }
302
- if (group) {
303
- if (property) {
304
- // @ts-expect-error group is spreadable
305
- return handle.condition(not, property?.prop, property?.rest, handle.group(undefined, undefined, ...group))
306
- }
307
- if (value) {
308
- // @ts-expect-error group is spreadable
309
- return handle.group(undefined, handle.condition(not, undefined, undefined, value), ...group)
310
- }
311
- // @ts-expect-error group is spreadable
312
- return handle.group(not, value, ...group)
313
- }
314
- if ([not, property, value].every(_ => _ === undefined)) return undefined
315
- return handle.condition(not, property?.prop, property?.rest, value)
316
- })
317
- })
318
-
319
- $.RULE("property", () => {
320
- const prop: any = $.OPTION3(() => $.SUBRULE<any, any>($.variable, { ARGS: [{ unprefixed: true }]}))
321
-
322
- const rest = $.OR([
323
- {
324
- ALT: () => {
325
- let sepL: any = $.CONSUME(t.EXP_PROP_OP)
326
- sepL &&= handle.token.sep(...processToken(sepL, $.shift))
327
-
328
- let op: any = $.OPTION4(() => $.CONSUME2(t.VALUE_UNQUOTED))
329
- op &&= handle.token.value(...processToken(op, $.shift))
330
-
331
- let sepR: any = $.OPTION5(() => $.CONSUME2(t.EXP_PROP_OP))
332
- sepR &&= handle.token.sep(...processToken(sepR, $.shift))
333
- if (expandedSepAlsoCustom && op === undefined && sepR === undefined) {
334
- op = sepL
335
- op.type = TOKEN_TYPE.OP_CUSTOM
336
- sepL = undefined
337
- }
338
- return { sepL, sepR, propertyOperator: op }
339
- },
340
- },
341
- {
342
- ALT: () => {
343
- let op: any = $.CONSUME(t.CUSTOM_PROP_OP)
344
- if (!op.isInsertedInRecovery) op = handle.token.custom(...processToken(op, $.shift))
345
- return { propertyOperator: op }
346
- },
347
- },
348
- {
349
- GATE: () => customOpAlsoNegation,
350
- ALT: () => {
351
- let op: any = $.CONSUME2(t.SYM_NOT)
352
- if (!op.isInsertedInRecovery) op = handle.token.custom(...processToken(op, $.shift))
353
- return { propertyOperator: op }
354
- },
355
- },
356
- ])
357
-
358
- return { prop, rest }
359
- })
360
- $.RULE("plainGroup", (
361
- { onlyValues = false, convertRegexValues = false, convertArrayValues = false }:
362
- { onlyValues?: boolean, convertRegexValues?: boolean, convertArrayValues?: boolean } = {}) => {
363
- const parenL = $.SUBRULE1($.parenL)
364
- let parenLeftCount = 0
365
- let start: undefined | number
366
- let end: undefined | number
367
- const condition = $.OPTION1({
368
- GATE: () => !onlyValues,
369
- DEF: () => $.SUBRULE1($.boolOr),
370
- })
371
-
372
- // bypasses self analysis (which goes into an infinite loop for some reason...)
373
- // see subParser hack below for why
374
- if (onlyValues && $.LA(1).tokenType !== EOF) {
375
- while (
376
- !tokenMatcher($.LA(1), EOF) &&
377
- (!tokenMatcher($.LA(1), t.PAREN_R) || parenLeftCount !== 0)
378
- ) {
379
- const token = $.CONSUME(t.ANY)
380
-
381
- start ??= extractPosition(token, this.shift).start
382
- if (tokenMatcher(token, t.PAREN_L)) {
383
- parenLeftCount++
384
- }
385
- if (tokenMatcher(token, t.PAREN_R)) {
386
- parenLeftCount--
387
- }
388
- }
389
- }
390
-
391
- if (start !== undefined) {
392
- end ??= extractPosition($.LA(0), this.shift).end
393
- }
394
-
395
- const parenR = $.OPTION2(() => $.SUBRULE1($.parenR))
396
- return $.ACTION(() => {
397
- if (start !== undefined) {
398
- /**
399
- * This is a bit of a hack to ignore forbidden expressions in groups when used as values (it would make no sense to do something like `prop:op(prop:op(...)))` or `prop:op:(prefix(...))`).
400
- *
401
- * Doing this from the tokenizer is very complicated because it would require keeping track of a lot of state since we need to know when a group follows something that even looks like a property/operator.
402
- *
403
- * This way we just consume all input until the correct next matching paren (or EOF) and re-parse it with a restricted version of the parser.
404
- *
405
- * Performance wise this should not be a problem since at most we add the time of one initialization per Parser/ParserBase class instance and only on demand. After that the parser is re-used when needed for any future parse calls. Additionally it only needs to be called once for the outer group used in a property value (i.e. `prop:OP:((()))` will only cause a single "sub parse").
406
- */
407
- const subInput = this.rawInput.slice(start, end)
408
-
409
- if (this.subParser === undefined) {
410
- this.subParser = new Parser({
411
- ...opts,
412
- customPropertyOperators: [],
413
- expandedPropertySeparator: undefined,
414
- regexValues: convertRegexValues,
415
- arrayValues: convertArrayValues,
416
- })
417
- }
418
- // @ts-expect-error extra param
419
- const parsed = this.subParser.parse(" ".repeat(start) + subInput, { unsealed: true })
420
- return [parenL, parsed, parenR]
421
- }
422
- // return parsed
423
- return [parenL, condition, parenR]
424
- })
425
- })
426
- $.RULE("plainBracketGroup", (
427
- { convertArrayValues = false }:
428
- { convertArrayValues?: boolean } = {}
429
- ) => {
430
- const bracketL = $.SUBRULE1($.bracketL)
431
- const start = bracketL.start
432
- const values: any[] = []
433
- $.MANY({
434
- GATE: () => !convertArrayValues,
435
- DEF: () => values.push($.SUBRULE<any, any>($.variable, { ARGS: [{ unprefixed: false, bracketVal: true }]})),
436
- })
437
- // bypasses self analysis (which goes into an infinite loop for some reason...)
438
- // see subParser hack below for why
439
- if (convertArrayValues && $.LA(1).tokenType !== EOF) {
440
- while (
441
- !tokenMatcher($.LA(1), EOF) &&
442
- !tokenMatcher($.LA(1), t.BRACKET_R)
443
- ) {
444
- $.CONSUME(t.ANY)
445
- }
446
- }
447
- const bracketR = $.OPTION2(() => $.SUBRULE1($.bracketR))
448
- const end = bracketR?.end
449
-
450
- return $.ACTION(() => {
451
- if (!convertArrayValues) return handle.array(bracketL, values, bracketR)
452
- /**
453
- * Similar problem as with regex values above.
454
- */
455
- const subInput = this.rawInput.slice(start, end)
456
-
457
- if (this.subParser2 === undefined) {
458
- this.subParser2 = new Parser({
459
- ...opts,
460
- customPropertyOperators: [],
461
- expandedPropertySeparator: undefined,
462
- arrayValues: false,
463
- })
464
- }
465
- // @ts-expect-error extra param
466
- const parsed = this.subParser2.parse(" ".repeat(start) + subInput, { unsealed: true })
467
-
468
- if (parsed instanceof ConditionNode) {
469
- return parsed.value
470
- }
471
- return parsed
472
- })
473
- })
474
-
475
- $.RULE("not", () => {
476
- const op = $.CONSUME(t.OPERATOR_NOT)
477
- return $.ACTION(() => handle.operator.not(...processToken<true>(op, $.shift)))
478
- })
479
-
480
- $.RULE("variable", (
481
- { unprefixed = false, bracketVal = false }:
482
- { unprefixed?: boolean, bracketVal?: boolean } = {}
483
- ) => {
484
- let prefix: any = $.OPTION({
485
- GATE: () => !unprefixed && opts.prefixableStrings !== undefined &&
486
- tokenMatcher($.LA(2), t.QUOTE_ANY) &&
487
- tokenMatcher($.LA(4), $.LA(2).tokenType) &&
488
- opts.prefixableStrings.includes($.LA(1).image),
489
- DEF: () => $.SUBRULE7<any, any>($.valueUnquoted, { ARGS: [{ bracketVal, onlyToken: true }]}),
490
- })
491
-
492
-
493
- prefix &&= handle.token.value(...processToken(prefix, $.shift))
494
-
495
- const ARGS = [{ bracketVal }]
496
- const val = $.OR([
497
- {
498
- ALT: () => {
499
- const quoteL = $.SUBRULE($.quoteDouble)
500
- const value = $.OPTION1(() => $.OR1([
501
- { ALT: () => $.SUBRULE<any, any>($.valueUnquoted, { ARGS }) },
502
- { ALT: () => $.SUBRULE($.valueNotDouble) },
503
- ]))
504
- const quoteR = $.SUBRULE2($.quoteDouble)
505
- return $.ACTION(() => handle.variable(prefix, quoteL, value, quoteR))
506
- },
507
- },
508
- {
509
- ALT: () => {
510
- const quoteL = $.SUBRULE($.quoteSingle)
511
- const value = $.OPTION2(() => $.OR2([
512
- { ALT: () => $.SUBRULE2<any, any>($.valueUnquoted, { ARGS }) },
513
- { ALT: () => $.SUBRULE($.valueNotSingle) },
514
- ]))
515
- const quoteR = $.SUBRULE2($.quoteSingle)
516
- return $.ACTION(() => handle.variable(prefix, quoteL, value, quoteR))
517
- },
518
- },
519
- {
520
- ALT: () => {
521
- const quoteL = $.SUBRULE($.quoteBacktick)
522
- const value = $.OPTION3(() => $.OR3([
523
- { ALT: () => $.SUBRULE3<any, any>($.valueUnquoted, { ARGS }) },
524
- { ALT: () => $.SUBRULE($.valueNotBacktick) },
525
- ]))
526
- const quoteR = $.SUBRULE2($.quoteBacktick)
527
- return $.ACTION(() => handle.variable(prefix, quoteL, value, quoteR))
528
- },
529
- },
530
- {
531
- ALT: () => {
532
- const quoteL = $.SUBRULE($.regexAny) as ValidToken<TOKEN_TYPE.REGEX> // the start can never match flags
533
- // unlike other values, regexes will swallow all input if incorrect
534
- const value = $.OPTION4(() => $.SUBRULE5($.valueRegex))
535
- const quoteR = $.OPTION5(() => $.SUBRULE5($.regexAny))
536
- return $.ACTION(() => {
537
- const args = isArray(quoteR) ? quoteR : [quoteR] as [typeof quoteR]
538
- return handle.variable(undefined, quoteL, value, args[0], args[1])
539
- })
540
- },
541
- },
542
- { // error
543
- ALT: () => {
544
- const value = $.SUBRULE4<any, any>($.valueUnquoted, { ARGS })
545
- const quoteR = $.SUBRULE4($.valueDelimAny)
546
- return $.ACTION(() => handle.variable(undefined, undefined, value, quoteR))
547
- },
548
- },
549
- { // error
550
- ALT: () => {
551
- const quoteL = $.SUBRULE5($.valueDelimAny)
552
- const value = $.OPTION6(() => $.SUBRULE5<any, any>($.valueUnquoted, { ARGS }))
553
- return $.ACTION(() => handle.variable(undefined, quoteL, value, undefined))
554
- },
555
- },
556
- {
557
- ALT: () => {
558
- const value = $.SUBRULE6<any, any>($.valueUnquoted, { ARGS })
559
- return $.ACTION(() => handle.variable(undefined, undefined, value, undefined))
560
- },
561
- },
562
- ])
563
- return val
564
- })
565
-
566
- $.RULE("valueDelimAny", () => {
567
- const value = $.CONSUME(t.QUOTE_ANY)
568
- return $.ACTION(() => {
569
- const type = value.image === `"`
570
- ? "double"
571
- : value.image === "'"
572
- ? "single"
573
- : value.image === "\\"
574
- ? "regex"
575
- : value.image === "`"
576
- ? "tick"
577
- : unreachable()
578
- return handle.delimiter[type](...processToken(value, $.shift))
579
- })
580
- })
581
- $.RULE("regexAny", () => {
582
- const value = $.CONSUME(t.REGEX_ANY)
583
- return $.ACTION(() => {
584
- if (value.image.length > 1) {
585
- // cheat a bit to extract the flags
586
- const delim = {
587
- image: "/",
588
- startOffset: value.startOffset,
589
- endOffset: value.startOffset,
590
- }
591
- const flags = {
592
- image: value.image.slice(1),
593
- startOffset: value.startOffset + 1,
594
- endOffset: value.endOffset,
595
- }
596
- return [
597
- handle.delimiter.regex(...processToken(delim as IToken, $.shift)),
598
- handle.token.value(...processToken(flags as IToken, $.shift)),
599
- ]
600
- }
601
- return handle.delimiter.regex(...processToken(value, $.shift))
602
- })
603
- })
604
- $.RULE("valueRegex", () => {
605
- const value = $.CONSUME(t.VALUE_REGEX)
606
- return $.ACTION(() => handle.token.value(...processToken(value, $.shift)))
607
- })
608
- $.RULE("quoteSingle", () => {
609
- const value = $.CONSUME(t.QUOTE_SINGLE)
610
- return $.ACTION(() => handle.delimiter.single(...processToken(value, $.shift)))
611
- })
612
- $.RULE("quoteDouble", () => {
613
- const value = $.CONSUME(t.QUOTE_DOUBLE)
614
- return $.ACTION(() => handle.delimiter.double(...processToken(value, $.shift)))
615
- })
616
- $.RULE("quoteBacktick", () => {
617
- const value = $.CONSUME(t.QUOTE_BACKTICK)
618
- return $.ACTION(() => handle.delimiter.tick(...processToken(value, $.shift)))
619
- })
620
- $.RULE("valueNotSingle", () => {
621
- const value = $.CONSUME(t.VALUE_FOR_SINGLE)
622
- return $.ACTION(() => handle.token.value(...processToken(value, $.shift)))
623
- })
624
- $.RULE("valueNotDouble", () => {
625
- const value = $.CONSUME(t.VALUE_FOR_DOUBLE)
626
- return $.ACTION(() => handle.token.value(...processToken(value, $.shift)))
627
- })
628
- $.RULE("valueNotBacktick", () => {
629
- const value = $.CONSUME(t.VALUE_FOR_BACKTICK)
630
- return $.ACTION(() => handle.token.value(...processToken(value, $.shift)))
631
- })
632
- $.RULE("valueUnquoted", (
633
- { bracketVal = false, onlyToken = false }:
634
- { bracketVal?: boolean, onlyToken?: boolean } = {}
635
- ) => {
636
- const value: any = $.OR([
637
- {
638
- GATE: () => !bracketVal,
639
- ALT: () => $.CONSUME(t.VALUE_UNQUOTED),
640
- },
641
- {
642
- GATE: () => bracketVal,
643
- ALT: () => $.CONSUME(t.BRACKET_VALUE_UNQUOTED),
644
- },
645
- ])
646
- return $.ACTION(() => onlyToken ? value : handle.token.value(...processToken(value, $.shift)))
647
- })
648
- $.RULE("parenL", () => {
649
- const value = $.CONSUME(t.PAREN_L)
650
-
651
- return $.ACTION(() => {
652
- // magic, see parse
653
- const loc = extractPosition(value, $.shift)
654
- return $.shift === 0 || loc.start > 0
655
- ? handle.delimiter.parenL(value.isInsertedInRecovery ? undefined : value.image, loc)
656
- : undefined
657
- })
658
- })
659
- $.RULE("parenR", () => {
660
- const value: any = $.CONSUME(t.PAREN_R)
661
- return $.ACTION(() => handle.delimiter.parenR(...processToken(value, $.shift)))
662
- })
663
- $.RULE("bracketL", () => {
664
- const value = $.CONSUME(t.BRACKET_L)
665
-
666
- return $.ACTION(() => {
667
- // magic, see parse
668
- const loc = extractPosition(value, $.shift)
669
- return $.shift === 0 || loc.start > 0
670
- ? handle.delimiter.bracketL(value.isInsertedInRecovery ? undefined : value.image, loc)
671
- : undefined
672
- })
673
- })
674
- $.RULE("bracketR", () => {
675
- const value: any = $.CONSUME(t.BRACKET_R)
676
- return $.ACTION(() => handle.delimiter.bracketR(...processToken(value, $.shift)))
677
- })
678
- this.performSelfAnalysis()
679
- }
680
- }
681
- export interface ParserBase {
682
- shift: number
683
- main: () => ParserResults
684
- anySym: () => IToken
685
- boolOr: () => ExpressionNode
686
- boolAnd: () => ExpressionNode
687
- condition: () => ConditionNode | GroupNode
688
- // the arguments to add a property to a condition node
689
- property: () => {
690
- prop?: VariableNode
691
- rest: {
692
- sepL?: ValidToken<TOKEN_TYPE.OP_EXPANDED_SEP>
693
- sepR?: ValidToken<TOKEN_TYPE.OP_EXPANDED_SEP>
694
- propertyOperator?: ConditionNode["propertyOperator"]
695
- }
696
- }
697
- // not an actual group node but the arguments to create one
698
- plainGroup: () => [ValidToken<TOKEN_TYPE.PARENL>, GroupNode["expression"], ValidToken<TOKEN_TYPE.PARENR> | undefined]
699
- plainBracketGroup: () => ArrayNode
700
- not: () => ValidToken<TOKEN_TYPE.NOT> // is always valid since it's optional
701
- variable: () => VariableNode
702
- valueDelimAny: () => AnyToken<TokenQuoteTypes>
703
- quoteSingle: () => AnyToken<TOKEN_TYPE.SINGLEQUOTE>
704
- quoteDouble: () => AnyToken<TOKEN_TYPE.DOUBLEQUOTE>
705
- quoteBacktick: () => AnyToken<TOKEN_TYPE.BACKTICK>
706
- regexAny: () => AnyToken<TOKEN_TYPE.REGEX> | [AnyToken<TOKEN_TYPE.REGEX>, ValidToken<TOKEN_TYPE.VALUE>]
707
- valueNotSingle: () => AnyToken<TOKEN_TYPE.VALUE>
708
- valueNotDouble: () => AnyToken<TOKEN_TYPE.VALUE>
709
- valueNotBacktick: () => AnyToken<TOKEN_TYPE.VALUE>
710
- valueUnquoted: () => AnyToken<TOKEN_TYPE.VALUE>
711
- valueRegex: () => AnyToken<TOKEN_TYPE.VALUE>
712
- parenL: () => ValidToken<TOKEN_TYPE.PARENL> // always valid, see getUnclosedRightParenCount for magic
713
- parenR: () => ValidToken<TOKEN_TYPE.PARENR> | undefined
714
- bracketL: () => ValidToken<TOKEN_TYPE.BRACKETL> // always valid, see getUnclosedRightParenCount for magic
715
- bracketR: () => ValidToken<TOKEN_TYPE.BRACKETR> | undefined
716
- }