parseman 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 (60) hide show
  1. package/README.md +510 -0
  2. package/dist/combinators/choice.d.ts +15 -0
  3. package/dist/combinators/choice.d.ts.map +1 -0
  4. package/dist/combinators/first-set.d.ts +8 -0
  5. package/dist/combinators/first-set.d.ts.map +1 -0
  6. package/dist/combinators/grammar.d.ts +8 -0
  7. package/dist/combinators/grammar.d.ts.map +1 -0
  8. package/dist/combinators/guard.d.ts +15 -0
  9. package/dist/combinators/guard.d.ts.map +1 -0
  10. package/dist/combinators/lazy.d.ts +14 -0
  11. package/dist/combinators/lazy.d.ts.map +1 -0
  12. package/dist/combinators/literal.d.ts +6 -0
  13. package/dist/combinators/literal.d.ts.map +1 -0
  14. package/dist/combinators/map.d.ts +8 -0
  15. package/dist/combinators/map.d.ts.map +1 -0
  16. package/dist/combinators/not.d.ts +13 -0
  17. package/dist/combinators/not.d.ts.map +1 -0
  18. package/dist/combinators/parser.d.ts +25 -0
  19. package/dist/combinators/parser.d.ts.map +1 -0
  20. package/dist/combinators/recover.d.ts +20 -0
  21. package/dist/combinators/recover.d.ts.map +1 -0
  22. package/dist/combinators/ref.d.ts +18 -0
  23. package/dist/combinators/ref.d.ts.map +1 -0
  24. package/dist/combinators/regex.d.ts +3 -0
  25. package/dist/combinators/regex.d.ts.map +1 -0
  26. package/dist/combinators/repeat.d.ts +6 -0
  27. package/dist/combinators/repeat.d.ts.map +1 -0
  28. package/dist/combinators/scanTo.d.ts +30 -0
  29. package/dist/combinators/scanTo.d.ts.map +1 -0
  30. package/dist/combinators/sequence.d.ts +7 -0
  31. package/dist/combinators/sequence.d.ts.map +1 -0
  32. package/dist/combinators/withCtx.d.ts +13 -0
  33. package/dist/combinators/withCtx.d.ts.map +1 -0
  34. package/dist/compiler/codegen.d.ts +23 -0
  35. package/dist/compiler/codegen.d.ts.map +1 -0
  36. package/dist/compiler/line-index.d.ts +16 -0
  37. package/dist/compiler/line-index.d.ts.map +1 -0
  38. package/dist/cst/grammar.d.ts +84 -0
  39. package/dist/cst/grammar.d.ts.map +1 -0
  40. package/dist/cst/incremental.d.ts +34 -0
  41. package/dist/cst/incremental.d.ts.map +1 -0
  42. package/dist/cst/types.d.ts +74 -0
  43. package/dist/cst/types.d.ts.map +1 -0
  44. package/dist/index.cjs +1795 -0
  45. package/dist/index.cjs.map +7 -0
  46. package/dist/index.d.ts +26 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +1762 -0
  49. package/dist/index.js.map +7 -0
  50. package/dist/plugin/evaluator.d.ts +15 -0
  51. package/dist/plugin/evaluator.d.ts.map +1 -0
  52. package/dist/plugin/index.cjs +1473 -0
  53. package/dist/plugin/index.cjs.map +7 -0
  54. package/dist/plugin/index.d.ts +12 -0
  55. package/dist/plugin/index.d.ts.map +1 -0
  56. package/dist/plugin/index.js +1442 -0
  57. package/dist/plugin/index.js.map +7 -0
  58. package/dist/types.d.ts +201 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/package.json +67 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1795 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Parser: () => Parser,
34
+ annotateSpan: () => annotateSpan,
35
+ balanced: () => balanced,
36
+ buildLineIndex: () => buildLineIndex,
37
+ choice: () => choice,
38
+ compile: () => compile,
39
+ guard: () => guard,
40
+ isParseError: () => isParseError,
41
+ literal: () => literal,
42
+ many: () => many,
43
+ not: () => not,
44
+ offsetToLineCol: () => offsetToLineCol,
45
+ oneOrMore: () => oneOrMore,
46
+ optional: () => optional,
47
+ parse: () => parse,
48
+ parser: () => parser,
49
+ recover: () => recover,
50
+ ref: () => ref,
51
+ regex: () => regex,
52
+ scanTo: () => scanTo,
53
+ sepBy: () => sepBy,
54
+ sequence: () => sequence,
55
+ skip: () => skip,
56
+ transform: () => transform,
57
+ trivia: () => trivia,
58
+ withCtx: () => withCtx
59
+ });
60
+ module.exports = __toCommonJS(index_exports);
61
+
62
+ // src/combinators/first-set.ts
63
+ function union(a, b) {
64
+ if (a.kind === "any" || b.kind === "any") return { kind: "any" };
65
+ if (a.kind === "empty") return b;
66
+ if (b.kind === "empty") return a;
67
+ return { kind: "ranges", ranges: mergeRanges([...a.ranges, ...b.ranges]) };
68
+ }
69
+ function intersects(a, b) {
70
+ if (a.kind === "any" || b.kind === "any") return true;
71
+ if (a.kind === "empty" || b.kind === "empty") return false;
72
+ for (const ra of a.ranges) {
73
+ for (const rb of b.ranges) {
74
+ if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
75
+ }
76
+ }
77
+ return false;
78
+ }
79
+ function fromChar(code) {
80
+ return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
81
+ }
82
+ function fromRange(lo, hi) {
83
+ return { kind: "ranges", ranges: [{ lo, hi }] };
84
+ }
85
+ function any() {
86
+ return { kind: "any" };
87
+ }
88
+ function empty() {
89
+ return { kind: "empty" };
90
+ }
91
+ function mergeRanges(ranges) {
92
+ if (ranges.length === 0) return [];
93
+ const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
94
+ const out = [{ lo: sorted[0].lo, hi: sorted[0].hi }];
95
+ for (let i = 1; i < sorted.length; i++) {
96
+ const top = out[out.length - 1];
97
+ const cur = sorted[i];
98
+ if (cur.lo <= top.hi + 1) {
99
+ if (cur.hi > top.hi) top.hi = cur.hi;
100
+ } else {
101
+ out.push({ lo: cur.lo, hi: cur.hi });
102
+ }
103
+ }
104
+ return out;
105
+ }
106
+
107
+ // src/combinators/literal.ts
108
+ var _collatorCache = null;
109
+ function collator() {
110
+ if (_collatorCache === null) {
111
+ _collatorCache = new Intl.Collator(void 0, { sensitivity: "accent" });
112
+ }
113
+ return _collatorCache;
114
+ }
115
+ function literal(value, opts = {}) {
116
+ const caseInsensitive = opts.caseInsensitive ?? false;
117
+ const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
118
+ const meta = {
119
+ firstSet,
120
+ canMatchNewline: value.includes("\n"),
121
+ isTrivia: false
122
+ };
123
+ if (caseInsensitive) {
124
+ const upper = value.toUpperCase();
125
+ const lower = value.toLowerCase();
126
+ const firstUpper = upper.codePointAt(0);
127
+ const firstLower = lower.codePointAt(0);
128
+ meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? { kind: "ranges", ranges: [
129
+ { lo: Math.min(firstLower, firstUpper), hi: Math.max(firstLower, firstUpper) }
130
+ ] } : firstSet;
131
+ }
132
+ return {
133
+ _tag: "literal",
134
+ _meta: meta,
135
+ _def: { tag: "literal", value, caseInsensitive },
136
+ parse(input, pos, _ctx) {
137
+ const end = pos + value.length;
138
+ if (end > input.length) {
139
+ return { ok: false, expected: [JSON.stringify(value)], span: { start: pos, end: pos } };
140
+ }
141
+ const slice = input.slice(pos, end);
142
+ const matched = caseInsensitive ? collator().compare(slice, value) === 0 : slice === value;
143
+ if (matched) {
144
+ const span = { start: pos, end };
145
+ const leaf = { _tag: "leaf", value: slice, span };
146
+ if (_ctx._cstLeaves) _ctx._cstLeaves.push(leaf);
147
+ if (_ctx._cstRawChildren) _ctx._cstRawChildren.push(leaf);
148
+ return { ok: true, value: slice, span };
149
+ }
150
+ return { ok: false, expected: [JSON.stringify(value)], span: { start: pos, end: pos } };
151
+ }
152
+ };
153
+ }
154
+
155
+ // src/combinators/regex.ts
156
+ var import_regexp_tree = __toESM(require("regexp-tree"), 1);
157
+ function firstSetFromRegex(pattern) {
158
+ try {
159
+ const ast = import_regexp_tree.default.parse(`/${pattern}/`);
160
+ return extractFirstSet(ast.body);
161
+ } catch {
162
+ return { firstSet: any(), canMatchNewline: true };
163
+ }
164
+ }
165
+ function canBeEmpty(node) {
166
+ if (!node) return true;
167
+ switch (node.type) {
168
+ case "Repetition": {
169
+ const q = node.quantifier;
170
+ return q.kind === "*" || q.kind === "?" || q.kind === "Range" && (q.from ?? 1) === 0;
171
+ }
172
+ case "Alternative": {
173
+ const exprs = node.expressions;
174
+ return !exprs || exprs.length === 0 || exprs.every((e) => canBeEmpty(e));
175
+ }
176
+ case "Group":
177
+ return canBeEmpty(node.expression);
178
+ case "Disjunction":
179
+ return canBeEmpty(node.left) || canBeEmpty(node.right);
180
+ default:
181
+ return false;
182
+ }
183
+ }
184
+ function extractFirstSet(node) {
185
+ if (!node) return { firstSet: empty(), canMatchNewline: false };
186
+ switch (node.type) {
187
+ case "Disjunction": {
188
+ const left = extractFirstSet(node.left);
189
+ const right = extractFirstSet(node.right);
190
+ return {
191
+ firstSet: union(left.firstSet, right.firstSet),
192
+ canMatchNewline: left.canMatchNewline || right.canMatchNewline
193
+ };
194
+ }
195
+ case "Alternative": {
196
+ const exprs = node.expressions;
197
+ if (!exprs || exprs.length === 0) return { firstSet: empty(), canMatchNewline: false };
198
+ let fs = empty();
199
+ let canNL = false;
200
+ for (const expr of exprs) {
201
+ const r = extractFirstSet(expr);
202
+ fs = union(fs, r.firstSet);
203
+ canNL = canNL || r.canMatchNewline;
204
+ if (!canBeEmpty(expr)) break;
205
+ }
206
+ return { firstSet: fs, canMatchNewline: canNL };
207
+ }
208
+ case "Char": {
209
+ const kind = node.kind;
210
+ if (kind === "simple") {
211
+ const code = node.codePoint ?? node.value.codePointAt(0) ?? 0;
212
+ return { firstSet: fromRange(code, code), canMatchNewline: code === 10 };
213
+ }
214
+ if (kind === "meta") {
215
+ const val = node.value;
216
+ if (val === ".") return { firstSet: any(), canMatchNewline: false };
217
+ if (val === "d") return { firstSet: fromRange(48, 57), canMatchNewline: false };
218
+ if (val === "D") return { firstSet: any(), canMatchNewline: true };
219
+ if (val === "w") return {
220
+ firstSet: union(
221
+ union(fromRange(48, 57), fromRange(65, 90)),
222
+ union(fromRange(97, 122), fromRange(95, 95))
223
+ ),
224
+ canMatchNewline: false
225
+ };
226
+ if (val === "s") return { firstSet: fromRange(9, 13), canMatchNewline: true };
227
+ if (val === "n") return { firstSet: fromRange(10, 10), canMatchNewline: true };
228
+ }
229
+ return { firstSet: any(), canMatchNewline: true };
230
+ }
231
+ case "CharacterClass": {
232
+ const expressions = node.expressions;
233
+ let fs = empty();
234
+ let canNL = false;
235
+ for (const expr of expressions) {
236
+ if (expr.type === "ClassRange") {
237
+ const from = expr.from.codePoint;
238
+ const to = expr.to.codePoint;
239
+ fs = union(fs, fromRange(from, to));
240
+ if (from <= 10 && 10 <= to) canNL = true;
241
+ } else if (expr.type === "Char") {
242
+ const r = extractFirstSet(expr);
243
+ fs = union(fs, r.firstSet);
244
+ canNL = canNL || r.canMatchNewline;
245
+ }
246
+ }
247
+ if (node.negative) return { firstSet: any(), canMatchNewline: true };
248
+ return { firstSet: fs, canMatchNewline: canNL };
249
+ }
250
+ case "Repetition": {
251
+ return extractFirstSet(node.expression);
252
+ }
253
+ case "Group": {
254
+ return extractFirstSet(node.expression);
255
+ }
256
+ default:
257
+ return { firstSet: any(), canMatchNewline: true };
258
+ }
259
+ }
260
+ function optimizeRegex(source, flags) {
261
+ try {
262
+ const result = import_regexp_tree.default.optimize(`/${source}/${flags}`);
263
+ const str = result.toString();
264
+ const lastSlash = str.lastIndexOf("/");
265
+ return str.slice(1, lastSlash);
266
+ } catch {
267
+ return source;
268
+ }
269
+ }
270
+ function regex(pattern, flags = "") {
271
+ const source = typeof pattern === "string" ? pattern : pattern.source;
272
+ const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
273
+ const optimizedSource = optimizeRegex(source, resolvedFlags);
274
+ const anchored = new RegExp(optimizedSource, "y" + resolvedFlags.replace(/[gy]/g, ""));
275
+ const { firstSet, canMatchNewline } = firstSetFromRegex(source);
276
+ const meta = { firstSet, canMatchNewline, isTrivia: false };
277
+ return {
278
+ _tag: "regex",
279
+ _meta: meta,
280
+ _def: { tag: "regex", source, flags: resolvedFlags, optimizedSource },
281
+ parse(input, pos, ctx) {
282
+ anchored.lastIndex = pos;
283
+ const m = anchored.exec(input);
284
+ if (m === null) {
285
+ return { ok: false, expected: [`/${source}/`], span: { start: pos, end: pos } };
286
+ }
287
+ const span = { start: pos, end: pos + m[0].length };
288
+ const leaf = { _tag: "leaf", value: m[0], span };
289
+ if (ctx._cstLeaves) ctx._cstLeaves.push(leaf);
290
+ if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
291
+ return { ok: true, value: m[0], span };
292
+ }
293
+ };
294
+ }
295
+
296
+ // src/combinators/sequence.ts
297
+ function sequence(...parsers) {
298
+ const meta = {
299
+ firstSet: parsers[0]?._meta.firstSet ?? empty(),
300
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
301
+ isTrivia: false
302
+ };
303
+ return {
304
+ _tag: "sequence",
305
+ _meta: meta,
306
+ _def: { tag: "sequence", parsers },
307
+ parse(input, pos, ctx) {
308
+ const values = [];
309
+ let cur = pos;
310
+ for (let i = 0; i < parsers.length; i++) {
311
+ if (ctx.trivia && i > 0) {
312
+ const tr = ctx.trivia.parse(input, cur, { trivia: ctx.trivia, trackLines: ctx.trackLines, user: ctx.user });
313
+ if (tr.ok) {
314
+ if (ctx._cstRawChildren && tr.span.end > tr.span.start)
315
+ ctx._cstRawChildren.push({ _tag: "trivia", value: input.slice(tr.span.start, tr.span.end), span: tr.span });
316
+ cur = tr.span.end;
317
+ }
318
+ }
319
+ const result = parsers[i].parse(input, cur, ctx);
320
+ if (!result.ok) return result;
321
+ values.push(result.value);
322
+ cur = result.span.end;
323
+ }
324
+ return {
325
+ ok: true,
326
+ value: values,
327
+ span: { start: pos, end: cur }
328
+ };
329
+ }
330
+ };
331
+ }
332
+
333
+ // src/combinators/choice.ts
334
+ function choice(...args) {
335
+ const parsers = args.map((a) => "gate" in a ? a.parser : a);
336
+ const gates = args.map((a) => "gate" in a ? a.gate : null);
337
+ const hasGates = gates.some((g) => g !== null);
338
+ const disjoint = !hasGates && areDisjoint(parsers.map((p) => p._meta.firstSet));
339
+ let combined = { kind: "empty" };
340
+ for (const p of parsers) combined = union(combined, p._meta.firstSet);
341
+ const meta = {
342
+ firstSet: combined,
343
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
344
+ isTrivia: false,
345
+ disjoint
346
+ };
347
+ const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
348
+ const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
349
+ let greedyRe = null;
350
+ let greedyLitMap = null;
351
+ let sortedParsers = null;
352
+ if (strategy?.tag === "greedyClassify") {
353
+ const regexDef = getCoreRegexDef(parsers[strategy.superIndex]);
354
+ const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
355
+ greedyRe = new RegExp(regexDef.source, flags);
356
+ greedyLitMap = /* @__PURE__ */ new Map();
357
+ for (let i = 0; i < parsers.length; i++) {
358
+ if (i === strategy.superIndex) continue;
359
+ const litVal = getCoreLiteralValue(parsers[i]);
360
+ if (litVal !== null) greedyLitMap.set(litVal, i);
361
+ }
362
+ } else if (strategy?.tag === "literalsLongestFirst") {
363
+ sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
364
+ }
365
+ return {
366
+ _tag: "choice",
367
+ _meta: meta,
368
+ _def: {
369
+ tag: "choice",
370
+ parsers,
371
+ gates,
372
+ disjoint,
373
+ strategy: strategy ?? { tag: "firstMatch" },
374
+ autoNot
375
+ },
376
+ parse(input, pos, ctx) {
377
+ const expected = [];
378
+ if (disjoint && pos < input.length) {
379
+ const code = input.codePointAt(pos);
380
+ for (const parser2 of parsers) {
381
+ if (inFirstSet(code, parser2._meta.firstSet)) {
382
+ const result = parser2.parse(input, pos, ctx);
383
+ if (result.ok) return result;
384
+ expected.push(...result.expected);
385
+ return { ok: false, expected, span: { start: pos, end: pos } };
386
+ }
387
+ }
388
+ return {
389
+ ok: false,
390
+ expected: parsers.flatMap((p) => {
391
+ const r = p.parse(input, pos, ctx);
392
+ return r.ok ? [] : r.expected;
393
+ }),
394
+ span: { start: pos, end: pos }
395
+ };
396
+ }
397
+ if (strategy?.tag === "greedyClassify") {
398
+ const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
399
+ if (!superResult.ok) return superResult;
400
+ const end = superResult.span.end;
401
+ const litIdx = greedyLitMap.get(input.slice(pos, end));
402
+ if (litIdx !== void 0) {
403
+ const litVal = getCoreLiteralValue(parsers[litIdx]);
404
+ const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
405
+ return { ok: true, value, span: { start: pos, end } };
406
+ }
407
+ return superResult;
408
+ }
409
+ if (strategy?.tag === "literalsLongestFirst") {
410
+ for (const p of sortedParsers) {
411
+ const r = p.parse(input, pos, ctx);
412
+ if (r.ok) return r;
413
+ expected.push(...r.expected);
414
+ }
415
+ return { ok: false, expected, span: { start: pos, end: pos } };
416
+ }
417
+ for (let i = 0; i < parsers.length; i++) {
418
+ if (gates[i] && !gates[i](ctx.user)) continue;
419
+ const result = parsers[i].parse(input, pos, ctx);
420
+ if (!result.ok) {
421
+ expected.push(...result.expected);
422
+ continue;
423
+ }
424
+ const checks = autoNot[i];
425
+ if (checks && autoNotFires(input, result.span.end, checks)) continue;
426
+ return result;
427
+ }
428
+ return { ok: false, expected, span: { start: pos, end: pos } };
429
+ }
430
+ };
431
+ }
432
+ function detectStrategy(parsers) {
433
+ const regexIndices = [];
434
+ const literalIndices = [];
435
+ for (let i = 0; i < parsers.length; i++) {
436
+ if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
437
+ else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
438
+ }
439
+ if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
440
+ const superIndex = regexIndices[0];
441
+ const regexDef = getCoreRegexDef(parsers[superIndex]);
442
+ const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
443
+ const re = new RegExp(regexDef.source, flags);
444
+ const allSubsumed = literalIndices.every((i) => {
445
+ const litVal = getCoreLiteralValue(parsers[i]);
446
+ re.lastIndex = 0;
447
+ const m = re.exec(litVal);
448
+ return m !== null && m[0] === litVal;
449
+ });
450
+ if (allSubsumed) return { tag: "greedyClassify", superIndex };
451
+ }
452
+ if (parsers.length === literalIndices.length) {
453
+ const sortedIndices = [...literalIndices].sort(
454
+ (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
455
+ );
456
+ return { tag: "literalsLongestFirst", sortedIndices };
457
+ }
458
+ return { tag: "firstMatch" };
459
+ }
460
+ function computeAutoNot(parsers) {
461
+ return parsers.map((p, i) => {
462
+ const litVal = getCoreLiteralValue(p);
463
+ if (litVal === null) return null;
464
+ const checks = [];
465
+ for (let j = i + 1; j < parsers.length; j++) {
466
+ const other = parsers[j];
467
+ const otherLit = getCoreLiteralValue(other);
468
+ if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
469
+ checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
470
+ continue;
471
+ }
472
+ const regexDef = getCoreRegexDef(other);
473
+ if (regexDef !== null) {
474
+ const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
475
+ if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
476
+ }
477
+ }
478
+ return checks.length > 0 ? checks : null;
479
+ });
480
+ }
481
+ function autoNotFires(input, end, checks) {
482
+ for (const check of checks) {
483
+ if (check.kind === "firstSet") {
484
+ const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
485
+ if (inFirstSet(code, check.set)) return true;
486
+ } else {
487
+ if (input.startsWith(check.value, end)) return true;
488
+ }
489
+ }
490
+ return false;
491
+ }
492
+ function getCoreLiteralValue(p) {
493
+ const def = p._def;
494
+ if (def.tag === "literal" && !def.caseInsensitive) return def.value;
495
+ if (def.tag === "transform") return getCoreLiteralValue(def.parser);
496
+ return null;
497
+ }
498
+ function getCoreRegexDef(p) {
499
+ const def = p._def;
500
+ if (def.tag === "regex") return { source: def.source, flags: def.flags };
501
+ if (def.tag === "transform") return getCoreRegexDef(def.parser);
502
+ return null;
503
+ }
504
+ function applyTransforms(p, value, span) {
505
+ const def = p._def;
506
+ if (def.tag === "transform") {
507
+ const inner = applyTransforms(def.parser, value, span);
508
+ return def.fn(inner, span);
509
+ }
510
+ return value;
511
+ }
512
+ function continuationFirstSet(lit, source, flags) {
513
+ const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
514
+ re.lastIndex = 0;
515
+ const base = re.exec(lit);
516
+ if (!base || base[0] !== lit) return null;
517
+ const contCodes = [];
518
+ for (let code = 1; code < 128; code++) {
519
+ re.lastIndex = 0;
520
+ const m = re.exec(lit + String.fromCharCode(code));
521
+ if (m && m[0].length > lit.length) contCodes.push(code);
522
+ }
523
+ if (contCodes.length === 0) return null;
524
+ return codesToFirstSet(contCodes);
525
+ }
526
+ function codesToFirstSet(codes) {
527
+ codes.sort((a, b) => a - b);
528
+ const ranges = [];
529
+ let lo = codes[0], hi = codes[0];
530
+ for (let i = 1; i < codes.length; i++) {
531
+ if (codes[i] === hi + 1) {
532
+ hi = codes[i];
533
+ } else {
534
+ ranges.push({ lo, hi });
535
+ lo = hi = codes[i];
536
+ }
537
+ }
538
+ ranges.push({ lo, hi });
539
+ return { kind: "ranges", ranges };
540
+ }
541
+ function inFirstSet(code, fs) {
542
+ if (fs.kind === "any") return true;
543
+ if (fs.kind === "empty") return false;
544
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
545
+ return false;
546
+ }
547
+ function areDisjoint(sets) {
548
+ if (sets.some((s) => s.kind === "any")) return false;
549
+ for (let i = 0; i < sets.length; i++)
550
+ for (let j = i + 1; j < sets.length; j++)
551
+ if (intersects(sets[i], sets[j])) return false;
552
+ return true;
553
+ }
554
+
555
+ // src/combinators/repeat.ts
556
+ function many(parser2) {
557
+ const meta = {
558
+ firstSet: parser2._meta.firstSet,
559
+ canMatchNewline: parser2._meta.canMatchNewline,
560
+ isTrivia: false
561
+ };
562
+ return {
563
+ _tag: "many",
564
+ _meta: meta,
565
+ _def: { tag: "many", parser: parser2, min: 0 },
566
+ parse(input, pos, ctx) {
567
+ const values = [];
568
+ let cur = pos;
569
+ while (cur < input.length) {
570
+ const result = parser2.parse(input, cur, ctx);
571
+ if (!result.ok) break;
572
+ if (result.span.end === cur) break;
573
+ values.push(result.value);
574
+ cur = result.span.end;
575
+ }
576
+ return { ok: true, value: values, span: { start: pos, end: cur } };
577
+ }
578
+ };
579
+ }
580
+ function oneOrMore(parser2) {
581
+ const meta = {
582
+ firstSet: parser2._meta.firstSet,
583
+ canMatchNewline: parser2._meta.canMatchNewline,
584
+ isTrivia: false
585
+ };
586
+ return {
587
+ _tag: "oneOrMore",
588
+ _meta: meta,
589
+ _def: { tag: "oneOrMore", parser: parser2, min: 1 },
590
+ parse(input, pos, ctx) {
591
+ const first = parser2.parse(input, pos, ctx);
592
+ if (!first.ok) return first;
593
+ const values = [first.value];
594
+ let cur = first.span.end;
595
+ while (cur < input.length) {
596
+ const result = parser2.parse(input, cur, ctx);
597
+ if (!result.ok) break;
598
+ if (result.span.end === cur) break;
599
+ values.push(result.value);
600
+ cur = result.span.end;
601
+ }
602
+ return { ok: true, value: values, span: { start: pos, end: cur } };
603
+ }
604
+ };
605
+ }
606
+ function optional(parser2) {
607
+ const meta = {
608
+ firstSet: parser2._meta.firstSet,
609
+ canMatchNewline: parser2._meta.canMatchNewline,
610
+ isTrivia: false
611
+ };
612
+ return {
613
+ _tag: "optional",
614
+ _meta: meta,
615
+ _def: { tag: "optional", parser: parser2 },
616
+ parse(input, pos, ctx) {
617
+ const result = parser2.parse(input, pos, ctx);
618
+ if (result.ok) return result;
619
+ return { ok: true, value: null, span: { start: pos, end: pos } };
620
+ }
621
+ };
622
+ }
623
+ function sepBy(parser2, separator) {
624
+ const meta = {
625
+ firstSet: parser2._meta.firstSet,
626
+ canMatchNewline: parser2._meta.canMatchNewline || separator._meta.canMatchNewline,
627
+ isTrivia: false
628
+ };
629
+ return {
630
+ _tag: "sepBy",
631
+ _meta: meta,
632
+ _def: { tag: "sepBy", parser: parser2, separator },
633
+ parse(input, pos, ctx) {
634
+ const first = parser2.parse(input, pos, ctx);
635
+ if (!first.ok) return { ok: true, value: [], span: { start: pos, end: pos } };
636
+ const values = [first.value];
637
+ let cur = first.span.end;
638
+ while (cur < input.length) {
639
+ let sepPos = cur;
640
+ if (ctx.trivia) {
641
+ const triviaCtx = { trivia: ctx.trivia, trackLines: ctx.trackLines, user: ctx.user };
642
+ const tr = ctx.trivia.parse(input, sepPos, triviaCtx);
643
+ if (tr.ok) {
644
+ if (ctx._cstRawChildren && tr.span.end > tr.span.start) ctx._cstRawChildren.push({ _tag: "trivia", value: input.slice(tr.span.start, tr.span.end), span: tr.span });
645
+ sepPos = tr.span.end;
646
+ }
647
+ }
648
+ const sep = separator.parse(input, sepPos, ctx);
649
+ if (!sep.ok) break;
650
+ let nextPos = sep.span.end;
651
+ if (ctx.trivia) {
652
+ const triviaCtx = { trivia: ctx.trivia, trackLines: ctx.trackLines, user: ctx.user };
653
+ const tr = ctx.trivia.parse(input, nextPos, triviaCtx);
654
+ if (tr.ok) {
655
+ if (ctx._cstRawChildren && tr.span.end > tr.span.start) ctx._cstRawChildren.push({ _tag: "trivia", value: input.slice(tr.span.start, tr.span.end), span: tr.span });
656
+ nextPos = tr.span.end;
657
+ }
658
+ }
659
+ const next = parser2.parse(input, nextPos, ctx);
660
+ if (!next.ok) break;
661
+ values.push(next.value);
662
+ cur = next.span.end;
663
+ }
664
+ return { ok: true, value: values, span: { start: pos, end: cur } };
665
+ }
666
+ };
667
+ }
668
+
669
+ // src/combinators/ref.ts
670
+ function ref() {
671
+ let resolved = null;
672
+ const meta = {
673
+ firstSet: any(),
674
+ canMatchNewline: true,
675
+ isTrivia: false
676
+ };
677
+ const slot = {
678
+ _tag: "lazy",
679
+ _meta: meta,
680
+ _def: {
681
+ tag: "lazy",
682
+ thunk: () => {
683
+ if (!resolved) throw new Error("ref<T>() used before .define() was called");
684
+ return resolved;
685
+ }
686
+ },
687
+ parse(input, pos, ctx) {
688
+ if (!resolved) throw new Error("ref<T>() used before .define() was called");
689
+ return resolved.parse(input, pos, ctx);
690
+ },
691
+ define(p) {
692
+ if (resolved) throw new Error("ref<T>() already defined");
693
+ resolved = p;
694
+ }
695
+ };
696
+ return slot;
697
+ }
698
+
699
+ // src/combinators/parser.ts
700
+ function parser(factory) {
701
+ const cache = {};
702
+ const proxy = new Proxy(cache, {
703
+ get(target, key) {
704
+ if (typeof key !== "string") return void 0;
705
+ const record = target;
706
+ if (!(key in record)) {
707
+ record[key] = ref();
708
+ }
709
+ return record[key];
710
+ }
711
+ });
712
+ const definitions = factory(proxy);
713
+ for (const key of Object.keys(definitions)) {
714
+ const placeholder = cache[key];
715
+ const parser2 = definitions[key];
716
+ if (placeholder !== void 0 && typeof placeholder.define === "function") {
717
+ ;
718
+ placeholder.define(parser2);
719
+ placeholder._meta.firstSet = parser2._meta.firstSet;
720
+ placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
721
+ } else {
722
+ ;
723
+ cache[key] = parser2;
724
+ }
725
+ }
726
+ return cache;
727
+ }
728
+
729
+ // src/combinators/not.ts
730
+ function not(parser2) {
731
+ const meta = {
732
+ firstSet: any(),
733
+ // we don't know what NOT matches
734
+ canMatchNewline: false,
735
+ isTrivia: false
736
+ };
737
+ return {
738
+ _tag: "unknown",
739
+ _meta: meta,
740
+ _def: { tag: "unknown" },
741
+ parse(input, pos, ctx) {
742
+ const result = parser2.parse(input, pos, ctx);
743
+ if (result.ok) {
744
+ return { ok: false, expected: [`not(${parser2._tag})`], span: { start: pos, end: pos } };
745
+ }
746
+ return { ok: true, value: null, span: { start: pos, end: pos } };
747
+ }
748
+ };
749
+ }
750
+
751
+ // src/combinators/map.ts
752
+ function transform(parser2, fn) {
753
+ return {
754
+ _tag: "transform",
755
+ _meta: parser2._meta,
756
+ _def: { tag: "transform", parser: parser2, fn },
757
+ parse(input, pos, ctx) {
758
+ const result = parser2.parse(input, pos, ctx);
759
+ if (!result.ok) return result;
760
+ return { ...result, value: fn(result.value, result.span) };
761
+ }
762
+ };
763
+ }
764
+ function skip(main, skipped) {
765
+ return {
766
+ _tag: "skip",
767
+ _meta: main._meta,
768
+ _def: { tag: "skip", main, skipped },
769
+ parse(input, pos, ctx) {
770
+ const result = main.parse(input, pos, ctx);
771
+ if (!result.ok) return result;
772
+ const s = skipped.parse(input, result.span.end, ctx);
773
+ if (!s.ok) return result;
774
+ return { ...result, span: { start: result.span.start, end: s.span.end } };
775
+ }
776
+ };
777
+ }
778
+ function trivia(parser2) {
779
+ return {
780
+ _tag: parser2._tag,
781
+ _meta: { ...parser2._meta, isTrivia: true },
782
+ _def: { tag: "trivia", parser: parser2 },
783
+ parse: parser2.parse.bind(parser2)
784
+ };
785
+ }
786
+
787
+ // src/compiler/line-index.ts
788
+ function buildLineIndex(input) {
789
+ const lineStarts = [0];
790
+ for (let i = 0; i < input.length; i++) {
791
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
792
+ }
793
+ return { lineStarts };
794
+ }
795
+ function offsetToLineCol(index, offset) {
796
+ const { lineStarts } = index;
797
+ let lo = 0;
798
+ let hi = lineStarts.length - 1;
799
+ while (lo < hi) {
800
+ const mid = lo + hi + 1 >> 1;
801
+ if (lineStarts[mid] <= offset) lo = mid;
802
+ else hi = mid - 1;
803
+ }
804
+ return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
805
+ }
806
+ function annotateSpan(span, index) {
807
+ const s = offsetToLineCol(index, span.start);
808
+ const e = offsetToLineCol(index, span.end);
809
+ return {
810
+ ...span,
811
+ startLine: s.line,
812
+ startColumn: s.col,
813
+ endLine: e.line,
814
+ endColumn: e.col
815
+ };
816
+ }
817
+
818
+ // src/combinators/grammar.ts
819
+ function parse(parser2, input, opts = {}) {
820
+ const trackLines = opts.trackLines ?? false;
821
+ const ctx = opts.trivia !== void 0 ? { trivia: opts.trivia, trackLines } : { trackLines };
822
+ const result = parser2.parse(input, 0, ctx);
823
+ if (trackLines) {
824
+ const idx = buildLineIndex(input);
825
+ return { ...result, span: annotateSpan(result.span, idx) };
826
+ }
827
+ return result;
828
+ }
829
+
830
+ // src/compiler/codegen.ts
831
+ function v(ctx, prefix = "_v") {
832
+ return `${prefix}${ctx.vars++}`;
833
+ }
834
+ function ind(ctx) {
835
+ return " ".repeat(ctx.indent);
836
+ }
837
+ function failStmt(ctx, expected, posExpr) {
838
+ return `${ind(ctx)}return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
839
+ }
840
+ function firstSetCond(codeVar, fs) {
841
+ if (fs.kind === "any") return "true";
842
+ if (fs.kind === "empty") return "false";
843
+ return fs.ranges.map(
844
+ (r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
845
+ ).join(" || ");
846
+ }
847
+ function asIIFE(stmts, valueVar, endVar, startPos, indent) {
848
+ return [
849
+ `(() => {`,
850
+ ...stmts,
851
+ `${indent} return { ok: true, value: ${valueVar}, span: { start: ${startPos}, end: ${endVar} } }`,
852
+ `${indent}})()`
853
+ ].join("\n");
854
+ }
855
+ function emitLit(def, ctx, pos) {
856
+ const { value, caseInsensitive } = def;
857
+ const len = value.length;
858
+ const vv = v(ctx);
859
+ const expectedStr = JSON.stringify(JSON.stringify(value));
860
+ const stmts = [];
861
+ if (caseInsensitive) {
862
+ ctx.needsCollator = true;
863
+ stmts.push(
864
+ `${ind(ctx)}if (${pos} + ${len} > input.length) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
865
+ `${ind(ctx)}const ${vv}_s = input.slice(${pos}, ${pos} + ${len})`,
866
+ `${ind(ctx)}if (_collator.compare(${vv}_s, ${JSON.stringify(value)}) !== 0) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
867
+ `${ind(ctx)}const ${vv} = ${vv}_s`
868
+ );
869
+ } else if (len === 0) {
870
+ stmts.push(`${ind(ctx)}const ${vv} = ''`);
871
+ } else if (len === 1) {
872
+ const code = value.codePointAt(0);
873
+ stmts.push(
874
+ `${ind(ctx)}if (${pos} >= input.length || input.charCodeAt(${pos}) !== ${code}) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
875
+ `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
876
+ );
877
+ } else if (len <= 4) {
878
+ const checks = Array.from(
879
+ { length: len },
880
+ (_, i) => `input.charCodeAt(${pos}${i > 0 ? ` + ${i}` : ""}) !== ${value.codePointAt(i)}`
881
+ ).join(" || ");
882
+ stmts.push(
883
+ `${ind(ctx)}if (${pos} + ${len} > input.length || ${checks}) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
884
+ `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
885
+ );
886
+ } else {
887
+ stmts.push(
888
+ `${ind(ctx)}if (!input.startsWith(${JSON.stringify(value)}, ${pos})) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
889
+ `${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
890
+ );
891
+ }
892
+ return { stmts, valueVar: vv, endVar: len === 0 ? pos : `${pos} + ${len}` };
893
+ }
894
+ function emitRegex(def, ctx, pos) {
895
+ const flags = "y" + def.flags.replace(/[gy]/g, "");
896
+ const rName = `_re${ctx.regexDecls.length}`;
897
+ ctx.regexDecls.push(`const ${rName} = /${def.optimizedSource}/${flags}`);
898
+ const mv = v(ctx, "_m");
899
+ const vv = v(ctx);
900
+ const expectedStr = JSON.stringify(`/${def.source}/`);
901
+ const stmts = [
902
+ `${ind(ctx)}${rName}.lastIndex = ${pos}`,
903
+ `${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
904
+ `${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
905
+ `${ind(ctx)}const ${vv} = ${mv}[0]`
906
+ ];
907
+ return { stmts, valueVar: vv, endVar: `${pos} + ${vv}.length` };
908
+ }
909
+ function ensureTriviaFn(ctx) {
910
+ const trivia2 = ctx.activeTrivia;
911
+ if (!ctx.namedParsers.has(trivia2)) {
912
+ const fnName = `_pf${ctx.namedParsers.size}`;
913
+ ctx.namedParsers.set(trivia2, fnName);
914
+ const savedIndent = ctx.indent;
915
+ ctx.indent = 1;
916
+ const r = emit(trivia2, ctx, "_pos");
917
+ ctx.indent = savedIndent;
918
+ ctx.namedFnDecls.push([
919
+ `function ${fnName}(input, _pos, _ctx) {`,
920
+ ...r.stmts,
921
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
922
+ `}`
923
+ ].join("\n"));
924
+ }
925
+ return ctx.namedParsers.get(trivia2);
926
+ }
927
+ function emitSeq(def, ctx, pos) {
928
+ const startV = v(ctx, "_start");
929
+ const curV = v(ctx, "_cur");
930
+ const stmts = [
931
+ `${ind(ctx)}const ${startV} = ${pos}`,
932
+ `${ind(ctx)}let ${curV} = ${pos}`
933
+ ];
934
+ const valueVars = [];
935
+ for (let i = 0; i < def.parsers.length; i++) {
936
+ if (i > 0 && ctx.activeTrivia) {
937
+ const trivFn = ensureTriviaFn(ctx);
938
+ const tmp = v(ctx, "_trv");
939
+ stmts.push(
940
+ `${ind(ctx)}const ${tmp} = ${trivFn}(input, ${curV}, _ctx)`,
941
+ `${ind(ctx)}if (${tmp}.ok) ${curV} = ${tmp}.span.end`
942
+ );
943
+ }
944
+ const r = emit(def.parsers[i], ctx, curV);
945
+ stmts.push(...r.stmts, `${ind(ctx)}${curV} = ${r.endVar}`);
946
+ valueVars.push(r.valueVar);
947
+ }
948
+ const arrV = v(ctx, "_arr");
949
+ stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
950
+ return { stmts, valueVar: arrV, endVar: curV };
951
+ }
952
+ function emitChoice(def, ctx, pos) {
953
+ const allExpected = JSON.stringify(
954
+ def.parsers.map((p) => {
955
+ const d = p._def;
956
+ if (d.tag === "literal") return JSON.stringify(d.value);
957
+ if (d.tag === "regex") return `/${d.source}/`;
958
+ return p._tag;
959
+ })
960
+ );
961
+ if (def.disjoint) {
962
+ const codeV = v(ctx, "_code");
963
+ const valV = v(ctx, "_chv");
964
+ const endV = v(ctx, "_che");
965
+ const stmts = [
966
+ `${ind(ctx)}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
967
+ `${ind(ctx)}let ${valV}, ${endV} = ${pos}`
968
+ ];
969
+ let first = true;
970
+ for (const p of def.parsers) {
971
+ const cond = firstSetCond(codeV, p._meta.firstSet);
972
+ const kw = first ? "if" : "else if";
973
+ first = false;
974
+ stmts.push(`${ind(ctx)}${kw} (${cond}) {`);
975
+ ctx.indent++;
976
+ const r = emit(p, ctx, pos);
977
+ stmts.push(...r.stmts);
978
+ stmts.push(`${ind(ctx)}${valV} = ${r.valueVar}; ${endV} = ${r.endVar}`);
979
+ ctx.indent--;
980
+ stmts.push(`${ind(ctx)}}`);
981
+ }
982
+ stmts.push(
983
+ `${ind(ctx)}else return { ok: false, expected: ${allExpected}, span: { start: ${pos}, end: ${pos} } }`
984
+ );
985
+ return { stmts, valueVar: valV, endVar: endV };
986
+ }
987
+ return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
988
+ }
989
+ function emitGreedyClassify(def, superIndex, allExpected, ctx, pos) {
990
+ const superParser = def.parsers[superIndex];
991
+ const regexDef = getCoreRegexDef(superParser);
992
+ const reIdx = ctx.regexDecls.length;
993
+ const reVar = `_re${reIdx}`;
994
+ const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
995
+ ctx.regexDecls.push(`const ${reVar} = /${regexDef.source}/${cleanFlags}`);
996
+ const matchV = v(ctx, "_gm");
997
+ const wordV = v(ctx, "_gw");
998
+ const endV = v(ctx, "_ge");
999
+ const stmts = [
1000
+ `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
1001
+ `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
1002
+ `${ind(ctx)}if (${matchV} === null) return { ok: false, expected: ${allExpected}, span: { start: ${pos}, end: ${pos} } }`,
1003
+ `${ind(ctx)}const ${wordV} = ${matchV}[0]`,
1004
+ `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`
1005
+ ];
1006
+ for (let i = 0; i < def.parsers.length; i++) {
1007
+ if (i === superIndex) continue;
1008
+ const p = def.parsers[i];
1009
+ const litVal = getCoreLiteralValue(p);
1010
+ if (litVal === null) continue;
1011
+ stmts.push(`${ind(ctx)}if (${wordV} === ${JSON.stringify(litVal)}) {`);
1012
+ ctx.indent++;
1013
+ const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
1014
+ stmts.push(...tR.stmts);
1015
+ stmts.push(`${ind(ctx)}return { ok: true, value: ${tR.valueVar}, span: { start: ${pos}, end: ${endV} } }`);
1016
+ ctx.indent--;
1017
+ stmts.push(`${ind(ctx)}}`);
1018
+ }
1019
+ const rR = emitTransformChain(superParser, wordV, endV, pos, ctx);
1020
+ stmts.push(...rR.stmts);
1021
+ return { stmts, valueVar: rR.valueVar, endVar: endV };
1022
+ }
1023
+ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
1024
+ const valV = v(ctx, "_llv");
1025
+ const endV = v(ctx, "_lle");
1026
+ const stmts = [`${ind(ctx)}let ${valV}, ${endV} = ${pos}`];
1027
+ let first = true;
1028
+ for (const idx of sortedIndices) {
1029
+ const p = def.parsers[idx];
1030
+ const litVal = getCoreLiteralValue(p);
1031
+ const litLen = litVal.length;
1032
+ const litCond = emitLiteralCondition(litVal, pos);
1033
+ const kw = first ? "if" : "else if";
1034
+ first = false;
1035
+ stmts.push(`${ind(ctx)}${kw} (${litCond}) {`);
1036
+ ctx.indent++;
1037
+ const tR = emitTransformChain(p, JSON.stringify(litVal), `${pos} + ${litLen}`, pos, ctx);
1038
+ stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}; ${endV} = ${pos} + ${litLen}`);
1039
+ ctx.indent--;
1040
+ stmts.push(`${ind(ctx)}}`);
1041
+ }
1042
+ stmts.push(`${ind(ctx)}else return { ok: false, expected: ${allExpected}, span: { start: ${pos}, end: ${pos} } }`);
1043
+ return { stmts, valueVar: valV, endVar: endV };
1044
+ }
1045
+ function emitFirstMatch(def, allExpected, ctx, pos) {
1046
+ const resV = v(ctx, "_cr");
1047
+ const stmts = [`${ind(ctx)}let ${resV}`];
1048
+ for (let i = 0; i < def.parsers.length; i++) {
1049
+ const p = def.parsers[i];
1050
+ const gate = def.gates[i];
1051
+ const autoNot = def.autoNot[i];
1052
+ const savedIndent = ctx.indent;
1053
+ ctx.indent = 0;
1054
+ const r = emit(p, ctx, pos);
1055
+ ctx.indent = savedIndent;
1056
+ const iife = asIIFE(r.stmts, r.valueVar, r.endVar, pos, ind(ctx));
1057
+ let gateCond = null;
1058
+ if (gate) {
1059
+ const gateIdx = ctx.mapFns.length;
1060
+ ctx.mapFns.push(gate);
1061
+ gateCond = `_mf[${gateIdx}](_ctx.user)`;
1062
+ }
1063
+ const skipCond = gateCond ? `!${resV}?.ok && ${gateCond}` : `!${resV}?.ok`;
1064
+ if (autoNot && autoNot.length > 0) {
1065
+ const tmp = v(ctx, "_ct");
1066
+ const anCode = v(ctx, "_anc");
1067
+ const rejectCond = autoNot.map(
1068
+ (check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${tmp}.span.end)`
1069
+ ).join(" || ");
1070
+ stmts.push(
1071
+ `${ind(ctx)}if (${skipCond}) { const ${tmp} = (() => { try { return ${iife} } catch {} })(); if (${tmp}?.ok) { const ${anCode} = ${tmp}.span.end < input.length ? input.charCodeAt(${tmp}.span.end) : -1; if (!(${rejectCond})) ${resV} = ${tmp} } }`
1072
+ );
1073
+ } else {
1074
+ stmts.push(`${ind(ctx)}if (${skipCond}) { try { ${resV} = ${iife} } catch {} }`);
1075
+ }
1076
+ }
1077
+ stmts.push(
1078
+ `${ind(ctx)}if (!${resV}?.ok) return { ok: false, expected: ${allExpected}, span: { start: ${pos}, end: ${pos} } }`
1079
+ );
1080
+ return { stmts, valueVar: `${resV}.value`, endVar: `${resV}.span.end` };
1081
+ }
1082
+ function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
1083
+ if (strategy.tag === "greedyClassify")
1084
+ return emitGreedyClassify(def, strategy.superIndex, allExpected, ctx, pos);
1085
+ if (strategy.tag === "literalsLongestFirst")
1086
+ return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
1087
+ return emitFirstMatch(def, allExpected, ctx, pos);
1088
+ }
1089
+ function emitTransformChain(p, baseValue, endV, startPos, ctx) {
1090
+ const def = p._def;
1091
+ if (def.tag === "transform") {
1092
+ const innerR = emitTransformChain(def.parser, baseValue, endV, startPos, ctx);
1093
+ const fnIdx = ctx.mapFns.length;
1094
+ ctx.mapFns.push(def.fn);
1095
+ const vv = v(ctx);
1096
+ return {
1097
+ stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = _mf[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
1098
+ valueVar: vv,
1099
+ endVar: endV
1100
+ };
1101
+ }
1102
+ return { stmts: [], valueVar: baseValue, endVar: endV };
1103
+ }
1104
+ function emitLiteralCondition(litVal, pos) {
1105
+ const len = litVal.length;
1106
+ if (len === 0) return "true";
1107
+ if (len > 4) return `input.startsWith(${JSON.stringify(litVal)}, ${pos})`;
1108
+ const checks = [`${pos} + ${len} <= input.length`];
1109
+ for (let i = 0; i < len; i++) {
1110
+ const code = litVal.codePointAt(i);
1111
+ checks.push(`input.charCodeAt(${pos}${i > 0 ? ` + ${i}` : ""}) === ${code}`);
1112
+ }
1113
+ return checks.join(" && ");
1114
+ }
1115
+ function emitMany(def, ctx, pos) {
1116
+ const arrV = v(ctx, "_arr");
1117
+ const curV = v(ctx, "_cur");
1118
+ const stmts = [
1119
+ `${ind(ctx)}const ${arrV} = []`,
1120
+ `${ind(ctx)}let ${curV} = ${pos}`
1121
+ ];
1122
+ const emitInnerIIFE = () => {
1123
+ const savedIndent = ctx.indent;
1124
+ ctx.indent = 0;
1125
+ const r = emit(def.parser, ctx, curV);
1126
+ ctx.indent = savedIndent;
1127
+ return asIIFE(r.stmts, r.valueVar, r.endVar, curV, ind(ctx) + " ");
1128
+ };
1129
+ if (def.min === 1) {
1130
+ const firstR = emit(def.parser, ctx, curV);
1131
+ stmts.push(...firstR.stmts);
1132
+ stmts.push(
1133
+ `${ind(ctx)}${arrV}.push(${firstR.valueVar})`,
1134
+ `${ind(ctx)}${curV} = ${firstR.endVar}`
1135
+ );
1136
+ }
1137
+ stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
1138
+ ctx.indent++;
1139
+ stmts.push(
1140
+ `${ind(ctx)}const _iter = (() => { try { return ${emitInnerIIFE()} } catch { return null } })()`,
1141
+ `${ind(ctx)}if (!_iter?.ok || _iter.span.end === ${curV}) break`,
1142
+ `${ind(ctx)}${arrV}.push(_iter.value)`,
1143
+ `${ind(ctx)}${curV} = _iter.span.end`
1144
+ );
1145
+ ctx.indent--;
1146
+ stmts.push(`${ind(ctx)}}`);
1147
+ return { stmts, valueVar: arrV, endVar: curV };
1148
+ }
1149
+ function emitOptional(def, ctx, pos) {
1150
+ const valV = v(ctx, "_opt");
1151
+ const endV = v(ctx, "_opte");
1152
+ const savedIndent = ctx.indent;
1153
+ ctx.indent = 0;
1154
+ const r = emit(def.parser, ctx, pos);
1155
+ ctx.indent = savedIndent;
1156
+ const iife = asIIFE(r.stmts, r.valueVar, r.endVar, pos, ind(ctx));
1157
+ const resV = v(ctx, "_optr");
1158
+ const stmts = [
1159
+ `${ind(ctx)}const ${resV} = (() => { try { return ${iife} } catch { return null } })()`,
1160
+ `${ind(ctx)}const ${valV} = ${resV}?.ok ? ${resV}.value : null`,
1161
+ `${ind(ctx)}const ${endV} = ${resV}?.ok ? ${resV}.span.end : ${pos}`
1162
+ ];
1163
+ return { stmts, valueVar: valV, endVar: endV };
1164
+ }
1165
+ function emitSepBy(_p, def, ctx, pos) {
1166
+ const arrV = v(ctx, "_arr");
1167
+ const curV = v(ctx, "_cur");
1168
+ const iife = (inner, posExpr) => {
1169
+ const saved = ctx.indent;
1170
+ ctx.indent = 0;
1171
+ const r = emit(inner, ctx, posExpr);
1172
+ ctx.indent = saved;
1173
+ return asIIFE(r.stmts, r.valueVar, r.endVar, posExpr, ind(ctx));
1174
+ };
1175
+ const firstR_saved = ctx.indent;
1176
+ ctx.indent = 0;
1177
+ const firstR = emit(def.parser, ctx, pos);
1178
+ ctx.indent = firstR_saved;
1179
+ const firstV = v(ctx, "_sb0");
1180
+ const sepV = v(ctx, "_sbs");
1181
+ const nextV = v(ctx, "_sbn");
1182
+ const stmts = [
1183
+ `${ind(ctx)}const ${arrV} = []`,
1184
+ `${ind(ctx)}let ${curV} = ${pos}`,
1185
+ `${ind(ctx)}const ${firstV} = (() => { try { return ${asIIFE(firstR.stmts, firstR.valueVar, firstR.endVar, pos, ind(ctx))} } catch { return null } })()`,
1186
+ `${ind(ctx)}if (${firstV}?.ok) {`
1187
+ ];
1188
+ ctx.indent++;
1189
+ stmts.push(
1190
+ `${ind(ctx)}${arrV}.push(${firstV}.value)`,
1191
+ `${ind(ctx)}${curV} = ${firstV}.span.end`,
1192
+ `${ind(ctx)}while (${curV} < input.length) {`
1193
+ );
1194
+ ctx.indent++;
1195
+ stmts.push(
1196
+ `${ind(ctx)}const ${sepV} = (() => { try { return ${iife(def.separator, curV)} } catch { return null } })()`,
1197
+ `${ind(ctx)}if (!${sepV}?.ok) break`,
1198
+ `${ind(ctx)}const ${nextV} = (() => { try { return ${iife(def.parser, `${sepV}.span.end`)} } catch { return null } })()`,
1199
+ `${ind(ctx)}if (!${nextV}?.ok) break`,
1200
+ `${ind(ctx)}${arrV}.push(${nextV}.value)`,
1201
+ `${ind(ctx)}${curV} = ${nextV}.span.end`
1202
+ );
1203
+ ctx.indent--;
1204
+ stmts.push(`${ind(ctx)}}`);
1205
+ ctx.indent--;
1206
+ stmts.push(`${ind(ctx)}}`);
1207
+ return { stmts, valueVar: arrV, endVar: curV };
1208
+ }
1209
+ function emitScanTo(def, ctx, pos) {
1210
+ const safeIIFE = (inner, posExpr) => {
1211
+ const saved = ctx.indent;
1212
+ ctx.indent = 0;
1213
+ const r = emit(inner, ctx, posExpr);
1214
+ ctx.indent = saved;
1215
+ return `(() => { try { return ${asIIFE(r.stmts, r.valueVar, r.endVar, posExpr, ind(ctx))} } catch { return null } })()`;
1216
+ };
1217
+ const curV = v(ctx, "_stcur");
1218
+ const foundV = v(ctx, "_stfnd");
1219
+ const stmts = [
1220
+ `${ind(ctx)}let ${curV} = ${pos}`,
1221
+ `${ind(ctx)}let ${foundV} = false`,
1222
+ `${ind(ctx)}while (${curV} < input.length) {`
1223
+ ];
1224
+ ctx.indent++;
1225
+ const sentV = v(ctx, "_sts");
1226
+ stmts.push(
1227
+ `${ind(ctx)}const ${sentV} = ${safeIIFE(def.sentinel, curV)}`,
1228
+ `${ind(ctx)}if (${sentV}?.ok) { ${foundV} = true; break }`
1229
+ );
1230
+ if (def.skip.length > 0) {
1231
+ const advV = v(ctx, "_stadv");
1232
+ stmts.push(`${ind(ctx)}let ${advV} = false`);
1233
+ for (const skipper of def.skip) {
1234
+ const skV = v(ctx, "_sk");
1235
+ stmts.push(
1236
+ `${ind(ctx)}if (!${advV}) { const ${skV} = ${safeIIFE(skipper, curV)}; if (${skV}?.ok && ${skV}.span.end > ${curV}) { ${curV} = ${skV}.span.end; ${advV} = true } }`
1237
+ );
1238
+ }
1239
+ stmts.push(`${ind(ctx)}if (!${advV}) ${curV}++`);
1240
+ } else {
1241
+ stmts.push(`${ind(ctx)}${curV}++`);
1242
+ }
1243
+ ctx.indent--;
1244
+ stmts.push(`${ind(ctx)}}`);
1245
+ if (!def.orEOF) {
1246
+ const sentDef = def.sentinel._def;
1247
+ const expectedStr = sentDef.tag === "literal" ? JSON.stringify([JSON.stringify(sentDef.value)]) : `["sentinel"]`;
1248
+ stmts.push(
1249
+ `${ind(ctx)}if (!${foundV}) return { ok: false, expected: ${expectedStr}, span: { start: ${pos}, end: ${curV} } }`
1250
+ );
1251
+ }
1252
+ const valV = v(ctx);
1253
+ stmts.push(`${ind(ctx)}const ${valV} = input.slice(${pos}, ${curV})`);
1254
+ return { stmts, valueVar: valV, endVar: curV };
1255
+ }
1256
+ function emitRuntimeFallback(parser2, ctx, pos) {
1257
+ const idx = ctx.runtimeParsers.length;
1258
+ ctx.runtimeParsers.push(parser2);
1259
+ const rv = v(ctx, "_rt");
1260
+ const vv = v(ctx, "_rtv");
1261
+ const ev = v(ctx, "_rte");
1262
+ const stmts = [
1263
+ `${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
1264
+ `${ind(ctx)}if (!${rv}.ok) return ${rv}`,
1265
+ `${ind(ctx)}const ${vv} = ${rv}.value`,
1266
+ `${ind(ctx)}const ${ev} = ${rv}.span.end`
1267
+ ];
1268
+ return { stmts, valueVar: vv, endVar: ev };
1269
+ }
1270
+ function emitLazy(p, def, ctx, pos) {
1271
+ if (!ctx.namedParsers.has(p)) {
1272
+ const fnName2 = `_pf${ctx.namedParsers.size}`;
1273
+ ctx.namedParsers.set(p, fnName2);
1274
+ let resolved;
1275
+ try {
1276
+ resolved = def.thunk();
1277
+ } catch {
1278
+ ctx.namedParsers.delete(p);
1279
+ return emitRuntimeFallback(p, ctx, pos);
1280
+ }
1281
+ const savedIndent = ctx.indent;
1282
+ ctx.indent = 1;
1283
+ const r = emit(resolved, ctx, "_pos");
1284
+ ctx.indent = savedIndent;
1285
+ ctx.namedFnDecls.push([
1286
+ `function ${fnName2}(input, _pos, _ctx) {`,
1287
+ ...r.stmts,
1288
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
1289
+ `}`
1290
+ ].join("\n"));
1291
+ }
1292
+ const fnName = ctx.namedParsers.get(p);
1293
+ const rv = v(ctx, "_pfr");
1294
+ const vv = v(ctx, "_pfv");
1295
+ const ev = v(ctx, "_pfe");
1296
+ return {
1297
+ stmts: [
1298
+ `${ind(ctx)}const ${rv} = ${fnName}(input, ${pos}, _ctx)`,
1299
+ `${ind(ctx)}if (!${rv}.ok) return ${rv}`,
1300
+ `${ind(ctx)}const ${vv} = ${rv}.value`,
1301
+ `${ind(ctx)}const ${ev} = ${rv}.span.end`
1302
+ ],
1303
+ valueVar: vv,
1304
+ endVar: ev
1305
+ };
1306
+ }
1307
+ function emit(p, ctx, pos) {
1308
+ const def = p._def;
1309
+ switch (def.tag) {
1310
+ case "literal":
1311
+ return emitLit(def, ctx, pos);
1312
+ case "regex":
1313
+ return emitRegex(def, ctx, pos);
1314
+ case "sequence":
1315
+ return emitSeq(def, ctx, pos);
1316
+ case "choice":
1317
+ return emitChoice(def, ctx, pos);
1318
+ case "many":
1319
+ case "oneOrMore":
1320
+ return emitMany(def, ctx, pos);
1321
+ case "optional":
1322
+ return emitOptional(def, ctx, pos);
1323
+ case "sepBy":
1324
+ return emitSepBy(p, def, ctx, pos);
1325
+ case "transform": {
1326
+ const inner = emit(def.parser, ctx, pos);
1327
+ const fnIdx = ctx.mapFns.length;
1328
+ ctx.mapFns.push(def.fn);
1329
+ const mv = v(ctx, "_mapped");
1330
+ return {
1331
+ stmts: [
1332
+ ...inner.stmts,
1333
+ `${ind(ctx)}const ${mv} = _mf[${fnIdx}](${inner.valueVar}, { start: ${pos}, end: ${inner.endVar} })`
1334
+ ],
1335
+ valueVar: mv,
1336
+ endVar: inner.endVar
1337
+ };
1338
+ }
1339
+ case "skip": {
1340
+ const mainR = emit(def.main, ctx, pos);
1341
+ const skipR = emit(def.skipped, ctx, mainR.endVar);
1342
+ const endV = v(ctx, "_skipe");
1343
+ return {
1344
+ stmts: [
1345
+ ...mainR.stmts,
1346
+ // try skipped; if fails, keep main end
1347
+ `${ind(ctx)}let ${endV} = ${mainR.endVar}`,
1348
+ `${ind(ctx)}try {`,
1349
+ ...skipR.stmts.map((s) => " " + s),
1350
+ `${ind(ctx)} ${endV} = ${skipR.endVar}`,
1351
+ `${ind(ctx)}} catch {}`
1352
+ ],
1353
+ valueVar: mainR.valueVar,
1354
+ endVar: endV
1355
+ };
1356
+ }
1357
+ case "lazy":
1358
+ return emitLazy(p, def, ctx, pos);
1359
+ case "trivia":
1360
+ return emit(def.parser, ctx, pos);
1361
+ case "grammar": {
1362
+ const savedTrivia = ctx.activeTrivia;
1363
+ if (def.triviaParser) ctx.activeTrivia = def.triviaParser;
1364
+ const r = emit(def.parser, ctx, pos);
1365
+ if (savedTrivia === void 0) delete ctx.activeTrivia;
1366
+ else ctx.activeTrivia = savedTrivia;
1367
+ return r;
1368
+ }
1369
+ case "scanTo":
1370
+ return emitScanTo(def, ctx, pos);
1371
+ case "guard": {
1372
+ const fnIdx = ctx.mapFns.length;
1373
+ ctx.mapFns.push(def.predicate);
1374
+ const vv = v(ctx);
1375
+ return {
1376
+ stmts: [
1377
+ `${ind(ctx)}if (!_mf[${fnIdx}](_ctx.user)) ${failStmt({ ...ctx, indent: 0 }, '"gate"', pos).trim()}`,
1378
+ `${ind(ctx)}const ${vv} = null`
1379
+ ],
1380
+ valueVar: vv,
1381
+ endVar: pos
1382
+ };
1383
+ }
1384
+ case "withCtx": {
1385
+ const evIdx = ctx.mapFns.length;
1386
+ const extra = def.extra;
1387
+ ctx.mapFns.push((() => extra));
1388
+ const innerParser = def.parser;
1389
+ if (!ctx.namedParsers.has(innerParser)) {
1390
+ const fnName = `_wcf${ctx.namedParsers.size}`;
1391
+ ctx.namedParsers.set(innerParser, fnName);
1392
+ const savedIndent = ctx.indent;
1393
+ ctx.indent = 1;
1394
+ const innerR = emit(innerParser, ctx, "_pos");
1395
+ ctx.indent = savedIndent;
1396
+ ctx.namedFnDecls.push([
1397
+ `function ${fnName}(input, _pos, _ctx) {`,
1398
+ ...innerR.stmts,
1399
+ ` return { ok: true, value: ${innerR.valueVar}, span: { start: _pos, end: ${innerR.endVar} } }`,
1400
+ `}`
1401
+ ].join("\n"));
1402
+ }
1403
+ const fn = ctx.namedParsers.get(innerParser);
1404
+ const rv = v(ctx, "_wcr");
1405
+ const vv = v(ctx);
1406
+ const ev = v(ctx, "_wce");
1407
+ return {
1408
+ stmts: [
1409
+ `${ind(ctx)}const ${rv} = ${fn}(input, ${pos}, { ..._ctx, user: _mf[${evIdx}]() })`,
1410
+ `${ind(ctx)}if (!${rv}.ok) return ${rv}`,
1411
+ `${ind(ctx)}const ${vv} = ${rv}.value`,
1412
+ `${ind(ctx)}const ${ev} = ${rv}.span.end`
1413
+ ],
1414
+ valueVar: vv,
1415
+ endVar: ev
1416
+ };
1417
+ }
1418
+ default:
1419
+ return emitRuntimeFallback(p, ctx, pos);
1420
+ }
1421
+ }
1422
+ function compile(parser2) {
1423
+ const ctx = {
1424
+ vars: 0,
1425
+ indent: 1,
1426
+ regexDecls: [],
1427
+ mapFns: [],
1428
+ runtimeParsers: [],
1429
+ needsCollator: false,
1430
+ namedParsers: /* @__PURE__ */ new Map(),
1431
+ namedFnDecls: []
1432
+ };
1433
+ const r = emit(parser2, ctx, "_pos");
1434
+ const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
1435
+ ` : "";
1436
+ const source = [
1437
+ ...ctx.regexDecls,
1438
+ "",
1439
+ ...ctx.namedFnDecls,
1440
+ `${collatorDecl}function _parse(input, _pos, _rp, _mf, _ctx) {`,
1441
+ ` let pos = _pos`,
1442
+ ...r.stmts,
1443
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
1444
+ `}`
1445
+ ].join("\n");
1446
+ const fn = new Function("input", "_pos", "_rp", "_mf", "_ctx", [
1447
+ ...ctx.regexDecls,
1448
+ collatorDecl,
1449
+ ...ctx.namedFnDecls,
1450
+ `let pos = _pos`,
1451
+ ...r.stmts,
1452
+ `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
1453
+ ].join("\n"));
1454
+ const defaultCtx = { trackLines: false };
1455
+ const canInline = ctx.runtimeParsers.length === 0 && ctx.mapFns.length === 0;
1456
+ const inlineExpression = canInline ? buildInlineExpression(ctx, r, collatorDecl) : null;
1457
+ return {
1458
+ source,
1459
+ inlineExpression,
1460
+ parse(input, pos = 0) {
1461
+ return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, defaultCtx);
1462
+ }
1463
+ };
1464
+ }
1465
+ function buildInlineExpression(ctx, r, collatorDecl) {
1466
+ const bodyLines = [
1467
+ ` let pos = _pos`,
1468
+ ...r.stmts.map((s) => ` ${s}`),
1469
+ ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
1470
+ ];
1471
+ const innerFn = [
1472
+ `function(input, _pos, _ctx) {`,
1473
+ ...bodyLines,
1474
+ `}`
1475
+ ].join("\n");
1476
+ const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0;
1477
+ if (!needsWrapper) {
1478
+ return innerFn;
1479
+ }
1480
+ return [
1481
+ `/* @__PURE__ */ (() => {`,
1482
+ ...ctx.regexDecls.map((d) => ` ${d}`),
1483
+ collatorDecl ? ` ${collatorDecl.trim()}` : "",
1484
+ ...ctx.namedFnDecls.flatMap((f) => f.split("\n").map((l) => ` ${l}`)),
1485
+ ` return ${innerFn}`,
1486
+ `})()`
1487
+ ].filter(Boolean).join("\n");
1488
+ }
1489
+
1490
+ // src/combinators/guard.ts
1491
+ function guard(predicate) {
1492
+ const meta = {
1493
+ firstSet: { kind: "any" },
1494
+ canMatchNewline: false,
1495
+ isTrivia: false
1496
+ };
1497
+ return {
1498
+ _tag: "guard",
1499
+ _meta: meta,
1500
+ _def: { tag: "guard", predicate },
1501
+ parse(_input, pos, ctx) {
1502
+ if (predicate(ctx.user))
1503
+ return { ok: true, value: null, span: { start: pos, end: pos } };
1504
+ return { ok: false, expected: ["guard"], span: { start: pos, end: pos } };
1505
+ }
1506
+ };
1507
+ }
1508
+
1509
+ // src/combinators/withCtx.ts
1510
+ function withCtx(extra, parser2) {
1511
+ const meta = {
1512
+ firstSet: parser2._meta.firstSet,
1513
+ canMatchNewline: parser2._meta.canMatchNewline,
1514
+ isTrivia: false
1515
+ };
1516
+ return {
1517
+ _tag: "withCtx",
1518
+ _meta: meta,
1519
+ _def: { tag: "withCtx", extra, parser: parser2 },
1520
+ parse(input, pos, ctx) {
1521
+ return parser2.parse(input, pos, { ...ctx, user: extra });
1522
+ }
1523
+ };
1524
+ }
1525
+
1526
+ // src/combinators/recover.ts
1527
+ function recover(parser2, sentinel) {
1528
+ const meta = {
1529
+ firstSet: { kind: "any" },
1530
+ canMatchNewline: true,
1531
+ isTrivia: false
1532
+ };
1533
+ return {
1534
+ _tag: "recover",
1535
+ _meta: meta,
1536
+ _def: { tag: "recover", parser: parser2, sentinel },
1537
+ parse(input, pos, ctx) {
1538
+ const result = parser2.parse(input, pos, ctx);
1539
+ if (result.ok) return result;
1540
+ let scanPos = pos;
1541
+ while (scanPos < input.length) {
1542
+ if (sentinel.parse(input, scanPos, ctx).ok) break;
1543
+ scanPos++;
1544
+ }
1545
+ const error = {
1546
+ _tag: "parseError",
1547
+ span: { start: pos, end: scanPos },
1548
+ expected: result.expected
1549
+ };
1550
+ return { ok: true, value: error, span: { start: pos, end: scanPos } };
1551
+ }
1552
+ };
1553
+ }
1554
+ function isParseError(value) {
1555
+ return typeof value === "object" && value !== null && value._tag === "parseError";
1556
+ }
1557
+
1558
+ // src/combinators/scanTo.ts
1559
+ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
1560
+ const meta = {
1561
+ firstSet: any(),
1562
+ canMatchNewline: true,
1563
+ isTrivia: false
1564
+ };
1565
+ return {
1566
+ _tag: "scanTo",
1567
+ _meta: meta,
1568
+ _def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
1569
+ parse(input, pos, ctx) {
1570
+ let cur = pos;
1571
+ while (cur < input.length) {
1572
+ const s = sentinel.parse(input, cur, ctx);
1573
+ if (s.ok) {
1574
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
1575
+ }
1576
+ let advanced = false;
1577
+ for (const skipper of skip2) {
1578
+ const r = skipper.parse(input, cur, ctx);
1579
+ if (r.ok && r.span.end > cur) {
1580
+ cur = r.span.end;
1581
+ advanced = true;
1582
+ break;
1583
+ }
1584
+ }
1585
+ if (!advanced) cur++;
1586
+ }
1587
+ if (orEOF) {
1588
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
1589
+ }
1590
+ const sentDef = sentinel._def;
1591
+ const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
1592
+ return { ok: false, expected, span: { start: pos, end: cur } };
1593
+ }
1594
+ };
1595
+ }
1596
+ function balanced(open, close, options = {}) {
1597
+ const inner = scanTo(literal(close), options);
1598
+ return transform(
1599
+ sequence(literal(open), inner, literal(close)),
1600
+ ([o, content, c]) => o + content + c
1601
+ );
1602
+ }
1603
+
1604
+ // src/cst/incremental.ts
1605
+ function isNode(x) {
1606
+ return typeof x === "object" && x !== null && x._tag === "node";
1607
+ }
1608
+ function findContaining(node, pos, path = []) {
1609
+ for (let i = 0; i < node.children.length; i++) {
1610
+ const child = node.children[i];
1611
+ if (!isNode(child)) continue;
1612
+ if (child.span.start <= pos && pos < child.span.end) {
1613
+ return findContaining(child, pos, [...path, i]) ?? { node: child, path: [...path, i] };
1614
+ }
1615
+ }
1616
+ return null;
1617
+ }
1618
+ function ancestorsAt(root, path) {
1619
+ const ancestors = [root];
1620
+ let cur = root;
1621
+ for (const idx of path.slice(0, -1)) {
1622
+ const child = cur.children[idx];
1623
+ if (!child || !isNode(child)) break;
1624
+ ancestors.push(child);
1625
+ cur = child;
1626
+ }
1627
+ return ancestors;
1628
+ }
1629
+ function replaceAtPath(grammar, root, path, newNode) {
1630
+ if (path.length === 0) return newNode;
1631
+ const [idx, ...rest] = path;
1632
+ const newChildren = [...root.children];
1633
+ newChildren[idx] = rest.length === 0 ? newNode : replaceAtPath(grammar, root.children[idx], rest, newNode);
1634
+ return grammar.rebuild(root, newChildren);
1635
+ }
1636
+ var ParseDocImpl = class _ParseDocImpl {
1637
+ _parser;
1638
+ _ruleName;
1639
+ tree;
1640
+ errors;
1641
+ input;
1642
+ constructor(parser2, ruleName, tree, errors, input) {
1643
+ this._parser = parser2;
1644
+ this._ruleName = ruleName;
1645
+ this.tree = tree;
1646
+ this.errors = errors;
1647
+ this.input = input;
1648
+ }
1649
+ edit(changeStart, oldChangeEnd, newText) {
1650
+ const newInput = this.input.slice(0, changeStart) + newText + this.input.slice(oldChangeEnd);
1651
+ if (!this.tree) return makeParseDoc(this._parser, this._ruleName, newInput);
1652
+ const delta = newText.length - (oldChangeEnd - changeStart);
1653
+ const found = findContaining(this.tree, changeStart);
1654
+ if (!found) return makeParseDoc(this._parser, this._ruleName, newInput);
1655
+ const ancestors = ancestorsAt(this.tree, found.path);
1656
+ const candidates = [found];
1657
+ const pathCopy = [...found.path];
1658
+ for (let i = ancestors.length - 2; i >= 0; i--) {
1659
+ pathCopy.pop();
1660
+ candidates.push({ node: ancestors[i + 1], path: [...pathCopy] });
1661
+ }
1662
+ for (const candidate of candidates) {
1663
+ const { node, path } = candidate;
1664
+ const expectedEnd = node.span.end + delta;
1665
+ const parser2 = this._parser.rule(node.type);
1666
+ const ctx = { trackLines: false, user: node.savedContext };
1667
+ const r = parser2.parse(newInput, node.span.start, ctx);
1668
+ if (!r.ok) continue;
1669
+ if (r.span.end === expectedEnd) {
1670
+ const newTree = replaceAtPath(this._parser, this.tree, path, r.value);
1671
+ return new _ParseDocImpl(this._parser, this._ruleName, newTree, [], newInput);
1672
+ }
1673
+ }
1674
+ return makeParseDoc(this._parser, this._ruleName, newInput);
1675
+ }
1676
+ };
1677
+ function makeParseDoc(parser2, ruleName, input) {
1678
+ const ctx = { trackLines: false };
1679
+ const r = parser2.rule(ruleName).parse(input, 0, ctx);
1680
+ if (r.ok) {
1681
+ return new ParseDocImpl(parser2, ruleName, r.value, [], input);
1682
+ }
1683
+ return new ParseDocImpl(parser2, ruleName, null, [{ ok: false, expected: r.expected, span: r.span }], input);
1684
+ }
1685
+
1686
+ // src/cst/grammar.ts
1687
+ var Parser = class {
1688
+ _built = false;
1689
+ _build() {
1690
+ if (this._built) return;
1691
+ this._built = true;
1692
+ const keys = Object.keys(this).filter((k) => !k.startsWith("_"));
1693
+ const slots = /* @__PURE__ */ new Map();
1694
+ const g = {};
1695
+ for (const key of keys) {
1696
+ const val = this[key];
1697
+ if (isCombinator(val)) {
1698
+ const isRule = /^[A-Z]/.test(key);
1699
+ const final = isRule ? this._makeNodeParser(key, val) : val;
1700
+ g[key] = final;
1701
+ Object.defineProperty(this, key, { value: final, writable: false, configurable: false });
1702
+ } else if (typeof val === "function") {
1703
+ const slot = ref();
1704
+ slots.set(key, slot);
1705
+ g[key] = slot;
1706
+ }
1707
+ }
1708
+ for (const [key, slot] of slots) {
1709
+ const thunk = this[key];
1710
+ const inner = thunk(g);
1711
+ const isRule = /^[A-Z]/.test(key);
1712
+ const final = isRule ? this._makeNodeParser(key, inner) : inner;
1713
+ slot.define(final);
1714
+ slot._meta.firstSet = final._meta.firstSet;
1715
+ slot._meta.canMatchNewline = final._meta.canMatchNewline;
1716
+ Object.defineProperty(this, key, { value: final, writable: false, configurable: false });
1717
+ }
1718
+ }
1719
+ /**
1720
+ * Override to produce a custom AST node instead of a plain CSTNode.
1721
+ * The returned object must satisfy NodeLike for IncrementalParser to work.
1722
+ *
1723
+ * `rawChildren` is `children` plus any trivia tokens (whitespace/comments)
1724
+ * consumed between terms, in parse order. Use it to inspect trivia when the
1725
+ * grammar is whitespace-sensitive (e.g. CSS descendant vs adjacent combinators).
1726
+ * The default implementation ignores `rawChildren`.
1727
+ */
1728
+ buildNode(type, span, children, savedContext, _rawChildren) {
1729
+ return { _tag: "node", type, span, children, savedContext };
1730
+ }
1731
+ /** Wrap an inner combinator so it produces a CSTNode on each match. */
1732
+ _makeNodeParser(type, inner) {
1733
+ const self = this;
1734
+ const meta = {
1735
+ firstSet: inner._meta.firstSet,
1736
+ canMatchNewline: inner._meta.canMatchNewline,
1737
+ isTrivia: false
1738
+ };
1739
+ return {
1740
+ _tag: "cstNode",
1741
+ _meta: meta,
1742
+ _def: { tag: "unknown" },
1743
+ parse(input, pos, ctx) {
1744
+ const savedContext = ctx.user !== void 0 ? Object.assign({}, ctx.user) : void 0;
1745
+ const children = [];
1746
+ const rawChildren = [];
1747
+ const innerCtx = {
1748
+ ...ctx,
1749
+ _cstChildren: children,
1750
+ _cstLeaves: children,
1751
+ _cstRawChildren: rawChildren
1752
+ };
1753
+ const r = inner.parse(input, pos, innerCtx);
1754
+ if (!r.ok) return r;
1755
+ const node = self.buildNode(type, r.span, children, savedContext, rawChildren);
1756
+ if (ctx._cstChildren) ctx._cstChildren.push(node);
1757
+ if (ctx._cstRawChildren) ctx._cstRawChildren.push(node);
1758
+ return { ok: true, value: node, span: r.span };
1759
+ }
1760
+ };
1761
+ }
1762
+ /** Reconstruct a node with a new children array (used by IncrementalParser). */
1763
+ rebuild(node, newChildren) {
1764
+ return this.buildNode(node.type, node.span, newChildren, node.savedContext, []);
1765
+ }
1766
+ /**
1767
+ * Parse input starting from a named rule, returning a ParseDoc.
1768
+ * The doc carries the tree, any parse errors, and an edit() method
1769
+ * for incremental re-parsing on subsequent changes.
1770
+ *
1771
+ * const doc = css.parse('Stylesheet', src)
1772
+ * doc.tree // the CST root, or null on failure
1773
+ * doc.errors // ParseFail[], empty on success
1774
+ *
1775
+ * // In an editor — just keep calling edit():
1776
+ * const doc2 = doc.edit(newSrc, changeStart, changeEnd)
1777
+ */
1778
+ parse(ruleName, input) {
1779
+ return makeParseDoc(this, ruleName, input);
1780
+ }
1781
+ /**
1782
+ * Get the compiled Combinator for a named rule.
1783
+ * Triggers lazy initialization on first call.
1784
+ */
1785
+ rule(name) {
1786
+ this._build();
1787
+ const p = this[name];
1788
+ if (!p) throw new Error(`No rule '${String(name)}' on this parser`);
1789
+ return p;
1790
+ }
1791
+ };
1792
+ function isCombinator(val) {
1793
+ return val !== null && typeof val === "object" && "_tag" in val;
1794
+ }
1795
+ //# sourceMappingURL=index.cjs.map