parseman 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -126
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/completions.d.ts +17 -0
- package/dist/combinators/completions.d.ts.map +1 -0
- package/dist/combinators/grammar.d.ts +20 -4
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/guard.d.ts +2 -2
- package/dist/combinators/guard.d.ts.map +1 -1
- package/dist/combinators/keywords.d.ts +22 -0
- package/dist/combinators/keywords.d.ts.map +1 -0
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +24 -0
- package/dist/combinators/node.d.ts.map +1 -0
- package/dist/combinators/parser.d.ts +7 -7
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/probe.d.ts +13 -0
- package/dist/combinators/probe.d.ts.map +1 -0
- package/dist/combinators/recover.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +33 -0
- package/dist/combinators/trivia-skip.d.ts.map +1 -0
- package/dist/combinators/withCtx.d.ts +1 -1
- package/dist/compiler/codegen.d.ts +13 -4
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/cst/grammar.d.ts +33 -2
- package/dist/cst/grammar.d.ts.map +1 -1
- package/dist/cst/incremental.d.ts +4 -2
- package/dist/cst/incremental.d.ts.map +1 -1
- package/dist/cst/trivia-index.d.ts +50 -0
- package/dist/cst/trivia-index.d.ts.map +1 -0
- package/dist/cst/types.d.ts +7 -7
- package/dist/cst/types.d.ts.map +1 -1
- package/dist/functional/doc.d.ts +53 -0
- package/dist/functional/doc.d.ts.map +1 -0
- package/dist/index.cjs +953 -221
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6519 -226
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +26 -6
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +1164 -215
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +5 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1164 -215
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +51 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/plugin/index.js
CHANGED
|
@@ -48,6 +48,51 @@ function mergeRanges(ranges) {
|
|
|
48
48
|
return out;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// src/combinators/ref.ts
|
|
52
|
+
function ref() {
|
|
53
|
+
let resolved = null;
|
|
54
|
+
const meta = {
|
|
55
|
+
firstSet: any(),
|
|
56
|
+
canMatchNewline: true,
|
|
57
|
+
isTrivia: false
|
|
58
|
+
};
|
|
59
|
+
const slot = {
|
|
60
|
+
_tag: "lazy",
|
|
61
|
+
_meta: meta,
|
|
62
|
+
_def: {
|
|
63
|
+
tag: "lazy",
|
|
64
|
+
thunk: () => {
|
|
65
|
+
if (!resolved) throw new Error("ref<T>() used before .define() was called");
|
|
66
|
+
return resolved;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
parse(input, pos, ctx) {
|
|
70
|
+
if (!resolved) throw new Error("ref<T>() used before .define() was called");
|
|
71
|
+
return resolved.parse(input, pos, ctx);
|
|
72
|
+
},
|
|
73
|
+
define(p) {
|
|
74
|
+
if (resolved) throw new Error("ref<T>() already defined");
|
|
75
|
+
resolved = p;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
return slot;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/combinators/probe.ts
|
|
82
|
+
function failAt(ctx, expected, pos) {
|
|
83
|
+
const r = { ok: false, expected, span: { start: pos, end: pos } };
|
|
84
|
+
const probe = ctx._probe;
|
|
85
|
+
if (probe !== void 0 && pos <= probe.offset) {
|
|
86
|
+
const best = probe.best;
|
|
87
|
+
if (best === null || pos > best.span.start) {
|
|
88
|
+
probe.best = r;
|
|
89
|
+
} else if (pos === best.span.start) {
|
|
90
|
+
probe.best = { ...best, expected: [...best.expected, ...expected] };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return r;
|
|
94
|
+
}
|
|
95
|
+
|
|
51
96
|
// src/combinators/literal.ts
|
|
52
97
|
var _collatorCache = null;
|
|
53
98
|
function collator() {
|
|
@@ -77,21 +122,21 @@ function literal(value, opts = {}) {
|
|
|
77
122
|
_tag: "literal",
|
|
78
123
|
_meta: meta,
|
|
79
124
|
_def: { tag: "literal", value, caseInsensitive },
|
|
80
|
-
parse(input, pos,
|
|
125
|
+
parse(input, pos, ctx) {
|
|
81
126
|
const end = pos + value.length;
|
|
82
127
|
if (end > input.length) {
|
|
83
|
-
return
|
|
128
|
+
return failAt(ctx, [JSON.stringify(value)], pos);
|
|
84
129
|
}
|
|
85
130
|
const slice = input.slice(pos, end);
|
|
86
131
|
const matched = caseInsensitive ? collator().compare(slice, value) === 0 : slice === value;
|
|
87
132
|
if (matched) {
|
|
88
133
|
const span = { start: pos, end };
|
|
89
134
|
const leaf = { _tag: "leaf", value: slice, span };
|
|
90
|
-
if (
|
|
91
|
-
if (
|
|
135
|
+
if (ctx._cstLeaves) ctx._cstLeaves.push(leaf);
|
|
136
|
+
if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
|
|
92
137
|
return { ok: true, value: slice, span };
|
|
93
138
|
}
|
|
94
|
-
return
|
|
139
|
+
return failAt(ctx, [JSON.stringify(value)], pos);
|
|
95
140
|
}
|
|
96
141
|
};
|
|
97
142
|
}
|
|
@@ -106,38 +151,38 @@ function firstSetFromRegex(pattern) {
|
|
|
106
151
|
return { firstSet: any(), canMatchNewline: true };
|
|
107
152
|
}
|
|
108
153
|
}
|
|
109
|
-
function canBeEmpty(
|
|
110
|
-
if (!
|
|
111
|
-
switch (
|
|
154
|
+
function canBeEmpty(node2) {
|
|
155
|
+
if (!node2) return true;
|
|
156
|
+
switch (node2.type) {
|
|
112
157
|
case "Repetition": {
|
|
113
|
-
const q =
|
|
158
|
+
const q = node2.quantifier;
|
|
114
159
|
return q.kind === "*" || q.kind === "?" || q.kind === "Range" && (q.from ?? 1) === 0;
|
|
115
160
|
}
|
|
116
161
|
case "Alternative": {
|
|
117
|
-
const exprs =
|
|
162
|
+
const exprs = node2.expressions;
|
|
118
163
|
return !exprs || exprs.length === 0 || exprs.every((e) => canBeEmpty(e));
|
|
119
164
|
}
|
|
120
165
|
case "Group":
|
|
121
|
-
return canBeEmpty(
|
|
166
|
+
return canBeEmpty(node2.expression);
|
|
122
167
|
case "Disjunction":
|
|
123
|
-
return canBeEmpty(
|
|
168
|
+
return canBeEmpty(node2.left) || canBeEmpty(node2.right);
|
|
124
169
|
default:
|
|
125
170
|
return false;
|
|
126
171
|
}
|
|
127
172
|
}
|
|
128
|
-
function extractFirstSet(
|
|
129
|
-
if (!
|
|
130
|
-
switch (
|
|
173
|
+
function extractFirstSet(node2) {
|
|
174
|
+
if (!node2) return { firstSet: empty(), canMatchNewline: false };
|
|
175
|
+
switch (node2.type) {
|
|
131
176
|
case "Disjunction": {
|
|
132
|
-
const left = extractFirstSet(
|
|
133
|
-
const right = extractFirstSet(
|
|
177
|
+
const left = extractFirstSet(node2.left);
|
|
178
|
+
const right = extractFirstSet(node2.right);
|
|
134
179
|
return {
|
|
135
180
|
firstSet: union(left.firstSet, right.firstSet),
|
|
136
181
|
canMatchNewline: left.canMatchNewline || right.canMatchNewline
|
|
137
182
|
};
|
|
138
183
|
}
|
|
139
184
|
case "Alternative": {
|
|
140
|
-
const exprs =
|
|
185
|
+
const exprs = node2.expressions;
|
|
141
186
|
if (!exprs || exprs.length === 0) return { firstSet: empty(), canMatchNewline: false };
|
|
142
187
|
let fs = empty();
|
|
143
188
|
let canNL = false;
|
|
@@ -150,13 +195,13 @@ function extractFirstSet(node) {
|
|
|
150
195
|
return { firstSet: fs, canMatchNewline: canNL };
|
|
151
196
|
}
|
|
152
197
|
case "Char": {
|
|
153
|
-
const kind =
|
|
198
|
+
const kind = node2.kind;
|
|
154
199
|
if (kind === "simple") {
|
|
155
|
-
const code =
|
|
200
|
+
const code = node2.codePoint ?? node2.value.codePointAt(0) ?? 0;
|
|
156
201
|
return { firstSet: fromRange(code, code), canMatchNewline: code === 10 };
|
|
157
202
|
}
|
|
158
203
|
if (kind === "meta") {
|
|
159
|
-
const val =
|
|
204
|
+
const val = node2.value;
|
|
160
205
|
if (val === ".") return { firstSet: any(), canMatchNewline: false };
|
|
161
206
|
if (val === "d") return { firstSet: fromRange(48, 57), canMatchNewline: false };
|
|
162
207
|
if (val === "D") return { firstSet: any(), canMatchNewline: true };
|
|
@@ -173,7 +218,7 @@ function extractFirstSet(node) {
|
|
|
173
218
|
return { firstSet: any(), canMatchNewline: true };
|
|
174
219
|
}
|
|
175
220
|
case "CharacterClass": {
|
|
176
|
-
const expressions =
|
|
221
|
+
const expressions = node2.expressions;
|
|
177
222
|
let fs = empty();
|
|
178
223
|
let canNL = false;
|
|
179
224
|
for (const expr of expressions) {
|
|
@@ -188,14 +233,14 @@ function extractFirstSet(node) {
|
|
|
188
233
|
canNL = canNL || r.canMatchNewline;
|
|
189
234
|
}
|
|
190
235
|
}
|
|
191
|
-
if (
|
|
236
|
+
if (node2.negative) return { firstSet: any(), canMatchNewline: true };
|
|
192
237
|
return { firstSet: fs, canMatchNewline: canNL };
|
|
193
238
|
}
|
|
194
239
|
case "Repetition": {
|
|
195
|
-
return extractFirstSet(
|
|
240
|
+
return extractFirstSet(node2.expression);
|
|
196
241
|
}
|
|
197
242
|
case "Group": {
|
|
198
|
-
return extractFirstSet(
|
|
243
|
+
return extractFirstSet(node2.expression);
|
|
199
244
|
}
|
|
200
245
|
default:
|
|
201
246
|
return { firstSet: any(), canMatchNewline: true };
|
|
@@ -226,7 +271,7 @@ function regex(pattern, flags = "") {
|
|
|
226
271
|
anchored.lastIndex = pos;
|
|
227
272
|
const m = anchored.exec(input);
|
|
228
273
|
if (m === null) {
|
|
229
|
-
return
|
|
274
|
+
return failAt(ctx, [`/${source}/`], pos);
|
|
230
275
|
}
|
|
231
276
|
const span = { start: pos, end: pos + m[0].length };
|
|
232
277
|
const leaf = { _tag: "leaf", value: m[0], span };
|
|
@@ -237,6 +282,55 @@ function regex(pattern, flags = "") {
|
|
|
237
282
|
};
|
|
238
283
|
}
|
|
239
284
|
|
|
285
|
+
// src/combinators/trivia-skip.ts
|
|
286
|
+
var NOOP_COMMIT = () => {
|
|
287
|
+
};
|
|
288
|
+
function scanTrivia(input, cur, ctx) {
|
|
289
|
+
const triviaP = ctx.trivia;
|
|
290
|
+
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
291
|
+
const log = ctx._triviaLog;
|
|
292
|
+
if (log !== void 0) {
|
|
293
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: false, state: ctx.state });
|
|
294
|
+
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
295
|
+
const end = tr2.span.end;
|
|
296
|
+
return {
|
|
297
|
+
end,
|
|
298
|
+
commit: () => {
|
|
299
|
+
log.push(cur, end);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
if (ctx.captureTrivia && ctx._cstRawChildren) {
|
|
304
|
+
const sink = [];
|
|
305
|
+
const tr2 = triviaP.parse(input, cur, {
|
|
306
|
+
trackLines: ctx.trackLines,
|
|
307
|
+
state: ctx.state,
|
|
308
|
+
_cstLeaves: sink
|
|
309
|
+
});
|
|
310
|
+
if (tr2.ok && tr2.span.end > cur) {
|
|
311
|
+
const out = ctx._cstRawChildren;
|
|
312
|
+
return {
|
|
313
|
+
end: tr2.span.end,
|
|
314
|
+
commit: () => {
|
|
315
|
+
for (const tok of sink) {
|
|
316
|
+
if (tok._tag === "leaf" && tok.span.end > tok.span.start) {
|
|
317
|
+
out.push({ _tag: "trivia", value: tok.value, span: tok.span });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return { end: cur, commit: NOOP_COMMIT };
|
|
324
|
+
}
|
|
325
|
+
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
326
|
+
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
327
|
+
}
|
|
328
|
+
function consumeTrivia(input, cur, ctx) {
|
|
329
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
330
|
+
scan.commit();
|
|
331
|
+
return scan.end;
|
|
332
|
+
}
|
|
333
|
+
|
|
240
334
|
// src/combinators/sequence.ts
|
|
241
335
|
function sequence(...parsers) {
|
|
242
336
|
const meta = {
|
|
@@ -253,12 +347,19 @@ function sequence(...parsers) {
|
|
|
253
347
|
let cur = pos;
|
|
254
348
|
for (let i = 0; i < parsers.length; i++) {
|
|
255
349
|
if (ctx.trivia && i > 0) {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
350
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
351
|
+
const raw = ctx._cstRawChildren;
|
|
352
|
+
const mark = raw ? raw.length : 0;
|
|
353
|
+
scan.commit();
|
|
354
|
+
const result2 = parsers[i].parse(input, scan.end, ctx);
|
|
355
|
+
if (!result2.ok) return result2;
|
|
356
|
+
if (result2.span.end > scan.end) {
|
|
357
|
+
cur = result2.span.end;
|
|
358
|
+
} else if (raw) {
|
|
359
|
+
raw.length = mark;
|
|
261
360
|
}
|
|
361
|
+
values.push(result2.value);
|
|
362
|
+
continue;
|
|
262
363
|
}
|
|
263
364
|
const result = parsers[i].parse(input, cur, ctx);
|
|
264
365
|
if (!result.ok) return result;
|
|
@@ -359,14 +460,22 @@ function choice(...args) {
|
|
|
359
460
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
360
461
|
}
|
|
361
462
|
for (let i = 0; i < parsers.length; i++) {
|
|
362
|
-
if (gates[i] && !gates[i](ctx.
|
|
463
|
+
if (gates[i] && !gates[i](ctx.state)) continue;
|
|
464
|
+
const leavesLen = ctx._cstLeaves?.length;
|
|
465
|
+
const rawLen = ctx._cstRawChildren?.length;
|
|
363
466
|
const result = parsers[i].parse(input, pos, ctx);
|
|
364
467
|
if (!result.ok) {
|
|
468
|
+
if (leavesLen !== void 0 && ctx._cstLeaves) ctx._cstLeaves.length = leavesLen;
|
|
469
|
+
if (rawLen !== void 0 && ctx._cstRawChildren) ctx._cstRawChildren.length = rawLen;
|
|
365
470
|
expected.push(...result.expected);
|
|
366
471
|
continue;
|
|
367
472
|
}
|
|
368
473
|
const checks = autoNot[i];
|
|
369
|
-
if (checks && autoNotFires(input, result.span.end, checks))
|
|
474
|
+
if (checks && autoNotFires(input, result.span.end, checks)) {
|
|
475
|
+
if (leavesLen !== void 0 && ctx._cstLeaves) ctx._cstLeaves.length = leavesLen;
|
|
476
|
+
if (rawLen !== void 0 && ctx._cstRawChildren) ctx._cstRawChildren.length = rawLen;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
370
479
|
return result;
|
|
371
480
|
}
|
|
372
481
|
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
@@ -497,6 +606,30 @@ function areDisjoint(sets) {
|
|
|
497
606
|
}
|
|
498
607
|
|
|
499
608
|
// src/combinators/repeat.ts
|
|
609
|
+
function repItem(parser2, input, cur, ctx) {
|
|
610
|
+
const raw = ctx._cstRawChildren;
|
|
611
|
+
const mark = raw ? raw.length : 0;
|
|
612
|
+
let pos = cur;
|
|
613
|
+
if (ctx.trivia) {
|
|
614
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
615
|
+
scan.commit();
|
|
616
|
+
pos = scan.end;
|
|
617
|
+
}
|
|
618
|
+
if (pos >= input.length) {
|
|
619
|
+
if (raw) raw.length = mark;
|
|
620
|
+
return "stop";
|
|
621
|
+
}
|
|
622
|
+
const result = parser2.parse(input, pos, ctx);
|
|
623
|
+
if (!result.ok) {
|
|
624
|
+
if (raw) raw.length = mark;
|
|
625
|
+
return { fail: result };
|
|
626
|
+
}
|
|
627
|
+
if (result.span.end === pos) {
|
|
628
|
+
if (raw) raw.length = mark;
|
|
629
|
+
return "stop";
|
|
630
|
+
}
|
|
631
|
+
return { value: result.value, end: result.span.end };
|
|
632
|
+
}
|
|
500
633
|
function many(parser2) {
|
|
501
634
|
const meta = {
|
|
502
635
|
firstSet: parser2._meta.firstSet,
|
|
@@ -511,11 +644,10 @@ function many(parser2) {
|
|
|
511
644
|
const values = [];
|
|
512
645
|
let cur = pos;
|
|
513
646
|
while (cur < input.length) {
|
|
514
|
-
const
|
|
515
|
-
if (
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
cur = result.span.end;
|
|
647
|
+
const item = repItem(parser2, input, cur, ctx);
|
|
648
|
+
if (item === "stop" || "fail" in item) break;
|
|
649
|
+
values.push(item.value);
|
|
650
|
+
cur = item.end;
|
|
519
651
|
}
|
|
520
652
|
return { ok: true, value: values, span: { start: pos, end: cur } };
|
|
521
653
|
}
|
|
@@ -537,11 +669,10 @@ function oneOrMore(parser2) {
|
|
|
537
669
|
const values = [first.value];
|
|
538
670
|
let cur = first.span.end;
|
|
539
671
|
while (cur < input.length) {
|
|
540
|
-
const
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
cur = result.span.end;
|
|
672
|
+
const item = repItem(parser2, input, cur, ctx);
|
|
673
|
+
if (item === "stop" || "fail" in item) break;
|
|
674
|
+
values.push(item.value);
|
|
675
|
+
cur = item.end;
|
|
545
676
|
}
|
|
546
677
|
return { ok: true, value: values, span: { start: pos, end: cur } };
|
|
547
678
|
}
|
|
@@ -580,26 +711,10 @@ function sepBy(parser2, separator) {
|
|
|
580
711
|
const values = [first.value];
|
|
581
712
|
let cur = first.span.end;
|
|
582
713
|
while (cur < input.length) {
|
|
583
|
-
|
|
584
|
-
if (ctx.trivia) {
|
|
585
|
-
const triviaCtx = { trivia: ctx.trivia, trackLines: ctx.trackLines, user: ctx.user };
|
|
586
|
-
const tr = ctx.trivia.parse(input, sepPos, triviaCtx);
|
|
587
|
-
if (tr.ok) {
|
|
588
|
-
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 });
|
|
589
|
-
sepPos = tr.span.end;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
714
|
+
const sepPos = ctx.trivia ? consumeTrivia(input, cur, ctx) : cur;
|
|
592
715
|
const sep = separator.parse(input, sepPos, ctx);
|
|
593
716
|
if (!sep.ok) break;
|
|
594
|
-
|
|
595
|
-
if (ctx.trivia) {
|
|
596
|
-
const triviaCtx = { trivia: ctx.trivia, trackLines: ctx.trackLines, user: ctx.user };
|
|
597
|
-
const tr = ctx.trivia.parse(input, nextPos, triviaCtx);
|
|
598
|
-
if (tr.ok) {
|
|
599
|
-
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 });
|
|
600
|
-
nextPos = tr.span.end;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
717
|
+
const nextPos = ctx.trivia ? consumeTrivia(input, sep.span.end, ctx) : sep.span.end;
|
|
603
718
|
const next = parser2.parse(input, nextPos, ctx);
|
|
604
719
|
if (!next.ok) break;
|
|
605
720
|
values.push(next.value);
|
|
@@ -610,6 +725,148 @@ function sepBy(parser2, separator) {
|
|
|
610
725
|
};
|
|
611
726
|
}
|
|
612
727
|
|
|
728
|
+
// src/combinators/not.ts
|
|
729
|
+
function not(parser2) {
|
|
730
|
+
const meta = {
|
|
731
|
+
firstSet: any(),
|
|
732
|
+
// we don't know what NOT matches
|
|
733
|
+
canMatchNewline: false,
|
|
734
|
+
isTrivia: false
|
|
735
|
+
};
|
|
736
|
+
return {
|
|
737
|
+
_tag: "not",
|
|
738
|
+
_meta: meta,
|
|
739
|
+
_def: { tag: "not", parser: parser2 },
|
|
740
|
+
parse(input, pos, ctx) {
|
|
741
|
+
const result = parser2.parse(input, pos, ctx);
|
|
742
|
+
if (result.ok) {
|
|
743
|
+
return { ok: false, expected: [`not(${parser2._tag})`], span: { start: pos, end: pos } };
|
|
744
|
+
}
|
|
745
|
+
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// src/combinators/node.ts
|
|
751
|
+
function node(type, parser2, build) {
|
|
752
|
+
const meta = {
|
|
753
|
+
firstSet: parser2._meta.firstSet,
|
|
754
|
+
canMatchNewline: parser2._meta.canMatchNewline,
|
|
755
|
+
isTrivia: false
|
|
756
|
+
};
|
|
757
|
+
return {
|
|
758
|
+
_tag: "node",
|
|
759
|
+
_meta: meta,
|
|
760
|
+
_def: { tag: "node", type, parser: parser2, build },
|
|
761
|
+
parse(input, pos, ctx) {
|
|
762
|
+
const children = [];
|
|
763
|
+
const rawChildren = [];
|
|
764
|
+
const innerCtx = {
|
|
765
|
+
...ctx,
|
|
766
|
+
// A node() always records the trivia between its terms — the library owns
|
|
767
|
+
// capture so grammar authors don't reconstruct it. (Matches the compiler.)
|
|
768
|
+
captureTrivia: true,
|
|
769
|
+
_cstChildren: children,
|
|
770
|
+
_cstLeaves: children,
|
|
771
|
+
_cstRawChildren: rawChildren
|
|
772
|
+
};
|
|
773
|
+
const r = parser2.parse(input, pos, innerCtx);
|
|
774
|
+
if (!r.ok) return r;
|
|
775
|
+
const built = build(children, rawChildren, r.span);
|
|
776
|
+
const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
|
|
777
|
+
if (ctx._cstChildren) ctx._cstChildren.push(built);
|
|
778
|
+
if (ctx._cstRawChildren) {
|
|
779
|
+
ctx._cstRawChildren.push(
|
|
780
|
+
isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span }
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
return { ok: true, value: built, span: r.span };
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// src/combinators/map.ts
|
|
789
|
+
function transform(parser2, fn) {
|
|
790
|
+
return {
|
|
791
|
+
_tag: "transform",
|
|
792
|
+
_meta: parser2._meta,
|
|
793
|
+
_def: { tag: "transform", parser: parser2, fn },
|
|
794
|
+
parse(input, pos, ctx) {
|
|
795
|
+
const result = parser2.parse(input, pos, ctx);
|
|
796
|
+
if (!result.ok) return result;
|
|
797
|
+
return { ...result, value: fn(result.value, result.span) };
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
function trivia(parser2) {
|
|
802
|
+
return {
|
|
803
|
+
_tag: parser2._tag,
|
|
804
|
+
_meta: { ...parser2._meta, isTrivia: true },
|
|
805
|
+
_def: { tag: "trivia", parser: parser2 },
|
|
806
|
+
parse: parser2.parse.bind(parser2)
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// src/compiler/line-index.ts
|
|
811
|
+
function buildLineIndex(input) {
|
|
812
|
+
const lineStarts = [0];
|
|
813
|
+
for (let i = 0; i < input.length; i++) {
|
|
814
|
+
if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
|
|
815
|
+
}
|
|
816
|
+
return { lineStarts };
|
|
817
|
+
}
|
|
818
|
+
function offsetToLineCol(index, offset) {
|
|
819
|
+
const { lineStarts } = index;
|
|
820
|
+
let lo = 0;
|
|
821
|
+
let hi = lineStarts.length - 1;
|
|
822
|
+
while (lo < hi) {
|
|
823
|
+
const mid = lo + hi + 1 >> 1;
|
|
824
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
825
|
+
else hi = mid - 1;
|
|
826
|
+
}
|
|
827
|
+
return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
|
|
828
|
+
}
|
|
829
|
+
function annotateSpan(span, index) {
|
|
830
|
+
const s = offsetToLineCol(index, span.start);
|
|
831
|
+
const e = offsetToLineCol(index, span.end);
|
|
832
|
+
return {
|
|
833
|
+
...span,
|
|
834
|
+
startLine: s.line,
|
|
835
|
+
startColumn: s.col,
|
|
836
|
+
endLine: e.line,
|
|
837
|
+
endColumn: e.col
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// src/combinators/grammar.ts
|
|
842
|
+
function parser(opts, root) {
|
|
843
|
+
return {
|
|
844
|
+
_tag: "grammar",
|
|
845
|
+
_meta: root._meta,
|
|
846
|
+
_def: {
|
|
847
|
+
tag: "grammar",
|
|
848
|
+
parser: root,
|
|
849
|
+
triviaParser: opts.trivia,
|
|
850
|
+
trackLines: opts.trackLines ?? false
|
|
851
|
+
},
|
|
852
|
+
parse(input, pos, _ctx) {
|
|
853
|
+
const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
|
|
854
|
+
const ctx = {
|
|
855
|
+
..._ctx,
|
|
856
|
+
trackLines,
|
|
857
|
+
...opts.trivia !== void 0 ? { trivia: opts.trivia } : {},
|
|
858
|
+
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {}
|
|
859
|
+
};
|
|
860
|
+
const result = root.parse(input, pos ?? 0, ctx);
|
|
861
|
+
if (trackLines) {
|
|
862
|
+
const idx = buildLineIndex(input);
|
|
863
|
+
return { ...result, span: annotateSpan(result.span, idx) };
|
|
864
|
+
}
|
|
865
|
+
return result;
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
|
|
613
870
|
// src/compiler/codegen.ts
|
|
614
871
|
function v(ctx, prefix = "_v") {
|
|
615
872
|
return `${prefix}${ctx.vars++}`;
|
|
@@ -617,9 +874,58 @@ function v(ctx, prefix = "_v") {
|
|
|
617
874
|
function ind(ctx) {
|
|
618
875
|
return " ".repeat(ctx.indent);
|
|
619
876
|
}
|
|
877
|
+
function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
|
|
878
|
+
if (!ctx.capturing) return [];
|
|
879
|
+
const i = ind(ctx);
|
|
880
|
+
if (ctx.capAsTrivia) {
|
|
881
|
+
return [`${i}if (_ctx._cstRawChildren) _ctx._cstRawChildren.push({ _tag: 'trivia', value: ${valExpr}, span: { start: ${startExpr}, end: ${endExpr} } })`];
|
|
882
|
+
}
|
|
883
|
+
const lf = v(ctx, "_lf");
|
|
884
|
+
return [
|
|
885
|
+
`${i}if (_ctx._cstLeaves) {`,
|
|
886
|
+
`${i} const ${lf} = { _tag: 'leaf', value: ${valExpr}, span: { start: ${startExpr}, end: ${endExpr} } }`,
|
|
887
|
+
`${i} _ctx._cstLeaves.push(${lf})`,
|
|
888
|
+
`${i} if (_ctx._cstRawChildren) _ctx._cstRawChildren.push(${lf})`,
|
|
889
|
+
`${i}}`
|
|
890
|
+
];
|
|
891
|
+
}
|
|
892
|
+
function ensureTriviaCaptureFn(ctx) {
|
|
893
|
+
const trivia2 = ctx.activeTrivia;
|
|
894
|
+
const existing = ctx.triviaCaptureNames.get(trivia2);
|
|
895
|
+
if (existing) return existing;
|
|
896
|
+
const fnName = `_tc${ctx.triviaCaptureNames.size}`;
|
|
897
|
+
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
898
|
+
const saved = { indent: ctx.indent, failLabel: ctx.failLabel, asTrivia: ctx.capAsTrivia, trivia: ctx.activeTrivia };
|
|
899
|
+
ctx.indent = 2;
|
|
900
|
+
ctx.failLabel = "_cap";
|
|
901
|
+
ctx.capAsTrivia = true;
|
|
902
|
+
delete ctx.activeTrivia;
|
|
903
|
+
const r = emit(trivia2, ctx, "_pos");
|
|
904
|
+
ctx.indent = saved.indent;
|
|
905
|
+
ctx.failLabel = saved.failLabel;
|
|
906
|
+
ctx.capAsTrivia = saved.asTrivia;
|
|
907
|
+
if (saved.trivia) ctx.activeTrivia = saved.trivia;
|
|
908
|
+
ctx.namedFnDecls.push([
|
|
909
|
+
`function ${fnName}(input, _pos, _ctx) {`,
|
|
910
|
+
` let _e = _pos`,
|
|
911
|
+
` _cap: {`,
|
|
912
|
+
...r.stmts,
|
|
913
|
+
` _e = ${r.endVar}`,
|
|
914
|
+
` }`,
|
|
915
|
+
` if (_ctx._triviaLog !== undefined && _e > _pos) _ctx._triviaLog.push(_pos, _e)`,
|
|
916
|
+
` return _e`,
|
|
917
|
+
`}`
|
|
918
|
+
].join("\n"));
|
|
919
|
+
return fnName;
|
|
920
|
+
}
|
|
620
921
|
function failStmt(ctx, expected, posExpr) {
|
|
922
|
+
if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
|
|
621
923
|
return `${ind(ctx)}return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
622
924
|
}
|
|
925
|
+
function failArr(ctx, expectedArr, posExpr) {
|
|
926
|
+
if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
|
|
927
|
+
return `${ind(ctx)}return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
|
|
928
|
+
}
|
|
623
929
|
function firstSetCond(codeVar, fs) {
|
|
624
930
|
if (fs.kind === "any") return "true";
|
|
625
931
|
if (fs.kind === "empty") return "false";
|
|
@@ -635,6 +941,30 @@ function asIIFE(stmts, valueVar, endVar, startPos, indent) {
|
|
|
635
941
|
`${indent}})()`
|
|
636
942
|
].join("\n");
|
|
637
943
|
}
|
|
944
|
+
function emitFallible(inner, ctx, pos) {
|
|
945
|
+
const lbl = v(ctx, "_lbl");
|
|
946
|
+
const okV = `${lbl}ok`;
|
|
947
|
+
const valV = `${lbl}v`;
|
|
948
|
+
const endV = `${lbl}e`;
|
|
949
|
+
const savedLabel = ctx.failLabel;
|
|
950
|
+
const savedIndent = ctx.indent;
|
|
951
|
+
ctx.failLabel = lbl;
|
|
952
|
+
ctx.indent = 0;
|
|
953
|
+
const r = emit(inner, ctx, pos);
|
|
954
|
+
ctx.failLabel = savedLabel;
|
|
955
|
+
ctx.indent = savedIndent;
|
|
956
|
+
const ind0 = ind(ctx);
|
|
957
|
+
const stmts = [
|
|
958
|
+
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
959
|
+
`${ind0}${lbl}: {`,
|
|
960
|
+
...r.stmts,
|
|
961
|
+
`${ind0} ${valV} = ${r.valueVar}`,
|
|
962
|
+
`${ind0} ${endV} = ${r.endVar}`,
|
|
963
|
+
`${ind0} ${okV} = true`,
|
|
964
|
+
`${ind0}}`
|
|
965
|
+
];
|
|
966
|
+
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
967
|
+
}
|
|
638
968
|
function emitLit(def, ctx, pos) {
|
|
639
969
|
const { value, caseInsensitive } = def;
|
|
640
970
|
const len = value.length;
|
|
@@ -672,12 +1002,19 @@ function emitLit(def, ctx, pos) {
|
|
|
672
1002
|
`${ind(ctx)}const ${vv} = ${JSON.stringify(value)}`
|
|
673
1003
|
);
|
|
674
1004
|
}
|
|
675
|
-
|
|
1005
|
+
const endVar = len === 0 ? pos : `${pos} + ${len}`;
|
|
1006
|
+
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
1007
|
+
return { stmts, valueVar: vv, endVar };
|
|
676
1008
|
}
|
|
677
1009
|
function emitRegex(def, ctx, pos) {
|
|
678
1010
|
const flags = "y" + def.flags.replace(/[gy]/g, "");
|
|
679
|
-
const
|
|
680
|
-
|
|
1011
|
+
const key = `${def.optimizedSource}/${flags}`;
|
|
1012
|
+
let rName = ctx.regexMap.get(key);
|
|
1013
|
+
if (rName === void 0) {
|
|
1014
|
+
rName = `_re${ctx.regexDecls.length}`;
|
|
1015
|
+
ctx.regexDecls.push(`const ${rName} = /${def.optimizedSource}/${flags}`);
|
|
1016
|
+
ctx.regexMap.set(key, rName);
|
|
1017
|
+
}
|
|
681
1018
|
const mv = v(ctx, "_m");
|
|
682
1019
|
const vv = v(ctx);
|
|
683
1020
|
const expectedStr = JSON.stringify(`/${def.source}/`);
|
|
@@ -687,7 +1024,9 @@ function emitRegex(def, ctx, pos) {
|
|
|
687
1024
|
`${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, expectedStr, pos).trim()}`,
|
|
688
1025
|
`${ind(ctx)}const ${vv} = ${mv}[0]`
|
|
689
1026
|
];
|
|
690
|
-
|
|
1027
|
+
const endVar = `${pos} + ${vv}.length`;
|
|
1028
|
+
stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
|
|
1029
|
+
return { stmts, valueVar: vv, endVar };
|
|
691
1030
|
}
|
|
692
1031
|
function ensureTriviaFn(ctx) {
|
|
693
1032
|
const trivia2 = ctx.activeTrivia;
|
|
@@ -695,9 +1034,15 @@ function ensureTriviaFn(ctx) {
|
|
|
695
1034
|
const fnName = `_pf${ctx.namedParsers.size}`;
|
|
696
1035
|
ctx.namedParsers.set(trivia2, fnName);
|
|
697
1036
|
const savedIndent = ctx.indent;
|
|
1037
|
+
const savedFailLabel = ctx.failLabel;
|
|
1038
|
+
const savedTrivia = ctx.activeTrivia;
|
|
698
1039
|
ctx.indent = 1;
|
|
1040
|
+
ctx.failLabel = void 0;
|
|
1041
|
+
delete ctx.activeTrivia;
|
|
699
1042
|
const r = emit(trivia2, ctx, "_pos");
|
|
700
1043
|
ctx.indent = savedIndent;
|
|
1044
|
+
ctx.failLabel = savedFailLabel;
|
|
1045
|
+
if (savedTrivia) ctx.activeTrivia = savedTrivia;
|
|
701
1046
|
ctx.namedFnDecls.push([
|
|
702
1047
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
703
1048
|
...r.stmts,
|
|
@@ -717,12 +1062,17 @@ function emitSeq(def, ctx, pos) {
|
|
|
717
1062
|
const valueVars = [];
|
|
718
1063
|
for (let i = 0; i < def.parsers.length; i++) {
|
|
719
1064
|
if (i > 0 && ctx.activeTrivia) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1065
|
+
if (ctx.capturing) {
|
|
1066
|
+
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1067
|
+
stmts.push(`${ind(ctx)}${curV} = ${capFn}(input, ${curV}, _ctx)`);
|
|
1068
|
+
} else {
|
|
1069
|
+
const trivFn = ensureTriviaFn(ctx);
|
|
1070
|
+
const tmp = v(ctx, "_trv");
|
|
1071
|
+
stmts.push(
|
|
1072
|
+
`${ind(ctx)}const ${tmp} = ${trivFn}(input, ${curV}, _ctx)`,
|
|
1073
|
+
`${ind(ctx)}if (${tmp}.ok) ${curV} = ${tmp}.span.end`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
726
1076
|
}
|
|
727
1077
|
const r = emit(def.parsers[i], ctx, curV);
|
|
728
1078
|
stmts.push(...r.stmts, `${ind(ctx)}${curV} = ${r.endVar}`);
|
|
@@ -762,9 +1112,7 @@ function emitChoice(def, ctx, pos) {
|
|
|
762
1112
|
ctx.indent--;
|
|
763
1113
|
stmts.push(`${ind(ctx)}}`);
|
|
764
1114
|
}
|
|
765
|
-
stmts.push(
|
|
766
|
-
`${ind(ctx)}else return { ok: false, expected: ${allExpected}, span: { start: ${pos}, end: ${pos} } }`
|
|
767
|
-
);
|
|
1115
|
+
stmts.push(`${ind(ctx)}else ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
|
|
768
1116
|
return { stmts, valueVar: valV, endVar: endV };
|
|
769
1117
|
}
|
|
770
1118
|
return emitNonDisjoint(def, def.strategy, allExpected, ctx, pos);
|
|
@@ -772,17 +1120,21 @@ function emitChoice(def, ctx, pos) {
|
|
|
772
1120
|
function emitGreedyClassify(def, superIndex, allExpected, ctx, pos) {
|
|
773
1121
|
const superParser = def.parsers[superIndex];
|
|
774
1122
|
const regexDef = getCoreRegexDef(superParser);
|
|
775
|
-
const reIdx = ctx.regexDecls.length;
|
|
776
|
-
const reVar = `_re${reIdx}`;
|
|
777
1123
|
const cleanFlags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
778
|
-
|
|
1124
|
+
const reKey = `${regexDef.source}/${cleanFlags}`;
|
|
1125
|
+
let reVar = ctx.regexMap.get(reKey);
|
|
1126
|
+
if (reVar === void 0) {
|
|
1127
|
+
reVar = `_re${ctx.regexDecls.length}`;
|
|
1128
|
+
ctx.regexDecls.push(`const ${reVar} = /${regexDef.source}/${cleanFlags}`);
|
|
1129
|
+
ctx.regexMap.set(reKey, reVar);
|
|
1130
|
+
}
|
|
779
1131
|
const matchV = v(ctx, "_gm");
|
|
780
1132
|
const wordV = v(ctx, "_gw");
|
|
781
1133
|
const endV = v(ctx, "_ge");
|
|
782
1134
|
const stmts = [
|
|
783
1135
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
784
1136
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
785
|
-
`${ind(ctx)}if (${matchV} === null)
|
|
1137
|
+
`${ind(ctx)}if (${matchV} === null) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`,
|
|
786
1138
|
`${ind(ctx)}const ${wordV} = ${matchV}[0]`,
|
|
787
1139
|
`${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`
|
|
788
1140
|
];
|
|
@@ -822,7 +1174,7 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
|
|
|
822
1174
|
ctx.indent--;
|
|
823
1175
|
stmts.push(`${ind(ctx)}}`);
|
|
824
1176
|
}
|
|
825
|
-
stmts.push(`${ind(ctx)}else
|
|
1177
|
+
stmts.push(`${ind(ctx)}else ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
|
|
826
1178
|
return { stmts, valueVar: valV, endVar: endV };
|
|
827
1179
|
}
|
|
828
1180
|
function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
@@ -833,40 +1185,60 @@ function emitFirstMatch(def, allExpected, ctx, pos) {
|
|
|
833
1185
|
const gate = def.gates[i];
|
|
834
1186
|
const autoNot = def.autoNot[i];
|
|
835
1187
|
const savedIndent = ctx.indent;
|
|
1188
|
+
const savedFailLabel = ctx.failLabel;
|
|
836
1189
|
ctx.indent = 0;
|
|
1190
|
+
ctx.failLabel = void 0;
|
|
837
1191
|
const r = emit(p, ctx, pos);
|
|
838
1192
|
ctx.indent = savedIndent;
|
|
1193
|
+
ctx.failLabel = savedFailLabel;
|
|
839
1194
|
const iife = asIIFE(r.stmts, r.valueVar, r.endVar, pos, ind(ctx));
|
|
840
1195
|
let gateCond = null;
|
|
841
1196
|
if (gate) {
|
|
842
1197
|
const gateIdx = ctx.mapFns.length;
|
|
843
1198
|
ctx.mapFns.push(gate);
|
|
844
|
-
gateCond = `_mf[${gateIdx}](_ctx.
|
|
1199
|
+
gateCond = `_mf[${gateIdx}](_ctx.state)`;
|
|
845
1200
|
}
|
|
846
1201
|
const skipCond = gateCond ? `!${resV}?.ok && ${gateCond}` : `!${resV}?.ok`;
|
|
1202
|
+
const markLeaves = ctx.capturing ? v(ctx, "_cml") : null;
|
|
1203
|
+
const markRaw = ctx.capturing ? v(ctx, "_cmr") : null;
|
|
1204
|
+
const rollback = markLeaves ? `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLeaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markRaw}` : "";
|
|
1205
|
+
const markStmts = markLeaves ? [
|
|
1206
|
+
`${ind(ctx)} const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
1207
|
+
`${ind(ctx)} const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`
|
|
1208
|
+
] : [];
|
|
1209
|
+
const rollbackStmt = rollback ? `${ind(ctx)} if (!${resV}?.ok) { ${rollback} }` : "";
|
|
847
1210
|
if (autoNot && autoNot.length > 0) {
|
|
848
1211
|
const tmp = v(ctx, "_ct");
|
|
849
1212
|
const anCode = v(ctx, "_anc");
|
|
850
1213
|
const rejectCond = autoNot.map(
|
|
851
1214
|
(check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${tmp}.span.end)`
|
|
852
1215
|
).join(" || ");
|
|
1216
|
+
stmts.push(`${ind(ctx)}if (${skipCond}) {`);
|
|
1217
|
+
stmts.push(...markStmts);
|
|
853
1218
|
stmts.push(
|
|
854
|
-
`${ind(ctx)}
|
|
1219
|
+
`${ind(ctx)} const ${tmp} = (() => { try { return ${iife} } catch {} })()`,
|
|
1220
|
+
`${ind(ctx)} if (${tmp}?.ok) { const ${anCode} = ${tmp}.span.end < input.length ? input.charCodeAt(${tmp}.span.end) : -1; if (!(${rejectCond})) ${resV} = ${tmp} }`
|
|
855
1221
|
);
|
|
1222
|
+
if (rollbackStmt) stmts.push(rollbackStmt);
|
|
1223
|
+
stmts.push(`${ind(ctx)}}`);
|
|
856
1224
|
} else {
|
|
857
|
-
stmts.push(`${ind(ctx)}if (${skipCond}) {
|
|
1225
|
+
stmts.push(`${ind(ctx)}if (${skipCond}) {`);
|
|
1226
|
+
stmts.push(...markStmts);
|
|
1227
|
+
stmts.push(`${ind(ctx)} try { ${resV} = ${iife} } catch {}`);
|
|
1228
|
+
if (rollbackStmt) stmts.push(rollbackStmt);
|
|
1229
|
+
stmts.push(`${ind(ctx)}}`);
|
|
858
1230
|
}
|
|
859
1231
|
}
|
|
860
|
-
stmts.push(
|
|
861
|
-
`${ind(ctx)}if (!${resV}?.ok) return { ok: false, expected: ${allExpected}, span: { start: ${pos}, end: ${pos} } }`
|
|
862
|
-
);
|
|
1232
|
+
stmts.push(`${ind(ctx)}if (!${resV}?.ok) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
|
|
863
1233
|
return { stmts, valueVar: `${resV}.value`, endVar: `${resV}.span.end` };
|
|
864
1234
|
}
|
|
865
1235
|
function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
866
|
-
if (
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1236
|
+
if (!ctx.capturing) {
|
|
1237
|
+
if (strategy.tag === "greedyClassify")
|
|
1238
|
+
return emitGreedyClassify(def, strategy.superIndex, allExpected, ctx, pos);
|
|
1239
|
+
if (strategy.tag === "literalsLongestFirst")
|
|
1240
|
+
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
1241
|
+
}
|
|
870
1242
|
return emitFirstMatch(def, allExpected, ctx, pos);
|
|
871
1243
|
}
|
|
872
1244
|
function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
@@ -875,6 +1247,7 @@ function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
|
875
1247
|
const innerR = emitTransformChain(def.parser, baseValue, endV, startPos, ctx);
|
|
876
1248
|
const fnIdx = ctx.mapFns.length;
|
|
877
1249
|
ctx.mapFns.push(def.fn);
|
|
1250
|
+
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
878
1251
|
const vv = v(ctx);
|
|
879
1252
|
return {
|
|
880
1253
|
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = _mf[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
|
|
@@ -902,13 +1275,6 @@ function emitMany(def, ctx, pos) {
|
|
|
902
1275
|
`${ind(ctx)}const ${arrV} = []`,
|
|
903
1276
|
`${ind(ctx)}let ${curV} = ${pos}`
|
|
904
1277
|
];
|
|
905
|
-
const emitInnerIIFE = () => {
|
|
906
|
-
const savedIndent = ctx.indent;
|
|
907
|
-
ctx.indent = 0;
|
|
908
|
-
const r = emit(def.parser, ctx, curV);
|
|
909
|
-
ctx.indent = savedIndent;
|
|
910
|
-
return asIIFE(r.stmts, r.valueVar, r.endVar, curV, ind(ctx) + " ");
|
|
911
|
-
};
|
|
912
1278
|
if (def.min === 1) {
|
|
913
1279
|
const firstR = emit(def.parser, ctx, curV);
|
|
914
1280
|
stmts.push(...firstR.stmts);
|
|
@@ -919,11 +1285,35 @@ function emitMany(def, ctx, pos) {
|
|
|
919
1285
|
}
|
|
920
1286
|
stmts.push(`${ind(ctx)}while (${curV} < input.length) {`);
|
|
921
1287
|
ctx.indent++;
|
|
1288
|
+
let itemPos = curV;
|
|
1289
|
+
let rollback = "";
|
|
1290
|
+
if (ctx.activeTrivia) {
|
|
1291
|
+
if (ctx.capturing) {
|
|
1292
|
+
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1293
|
+
const markV = v(ctx, "_mk");
|
|
1294
|
+
const npV = v(ctx, "_np");
|
|
1295
|
+
stmts.push(
|
|
1296
|
+
`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
|
|
1297
|
+
`${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx)`
|
|
1298
|
+
);
|
|
1299
|
+
itemPos = npV;
|
|
1300
|
+
rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; `;
|
|
1301
|
+
} else {
|
|
1302
|
+
const trivFn = ensureTriviaFn(ctx);
|
|
1303
|
+
const npV = v(ctx, "_np");
|
|
1304
|
+
stmts.push(
|
|
1305
|
+
`${ind(ctx)}let ${npV} = ${curV}`,
|
|
1306
|
+
`${ind(ctx)}{ const _trv = ${trivFn}(input, ${npV}, _ctx); if (_trv.ok) ${npV} = _trv.span.end }`
|
|
1307
|
+
);
|
|
1308
|
+
itemPos = npV;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos);
|
|
922
1312
|
stmts.push(
|
|
923
|
-
|
|
924
|
-
`${ind(ctx)}if (
|
|
925
|
-
`${ind(ctx)}${arrV}.push(
|
|
926
|
-
`${ind(ctx)}${curV} =
|
|
1313
|
+
...iterStmts,
|
|
1314
|
+
`${ind(ctx)}if (!${iterOk} || ${iterEnd} === ${curV}) { ${rollback}break }`,
|
|
1315
|
+
`${ind(ctx)}${arrV}.push(${iterVal})`,
|
|
1316
|
+
`${ind(ctx)}${curV} = ${iterEnd}`
|
|
927
1317
|
);
|
|
928
1318
|
ctx.indent--;
|
|
929
1319
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -932,56 +1322,80 @@ function emitMany(def, ctx, pos) {
|
|
|
932
1322
|
function emitOptional(def, ctx, pos) {
|
|
933
1323
|
const valV = v(ctx, "_opt");
|
|
934
1324
|
const endV = v(ctx, "_opte");
|
|
935
|
-
const
|
|
936
|
-
|
|
937
|
-
const r = emit(def.parser, ctx, pos);
|
|
938
|
-
ctx.indent = savedIndent;
|
|
939
|
-
const iife = asIIFE(r.stmts, r.valueVar, r.endVar, pos, ind(ctx));
|
|
940
|
-
const resV = v(ctx, "_optr");
|
|
1325
|
+
const { stmts: lblStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
1326
|
+
const ind0 = ind(ctx);
|
|
941
1327
|
const stmts = [
|
|
942
|
-
|
|
943
|
-
`${
|
|
944
|
-
`${
|
|
1328
|
+
...lblStmts,
|
|
1329
|
+
`${ind0}const ${valV} = ${okVar} ? ${valVar} : null`,
|
|
1330
|
+
`${ind0}const ${endV} = ${okVar} ? ${endVar} : ${pos}`
|
|
945
1331
|
];
|
|
946
1332
|
return { stmts, valueVar: valV, endVar: endV };
|
|
947
1333
|
}
|
|
948
1334
|
function emitSepBy(_p, def, ctx, pos) {
|
|
949
1335
|
const arrV = v(ctx, "_arr");
|
|
950
1336
|
const curV = v(ctx, "_cur");
|
|
951
|
-
const
|
|
952
|
-
const saved = ctx.indent;
|
|
953
|
-
ctx.indent = 0;
|
|
954
|
-
const r = emit(inner, ctx, posExpr);
|
|
955
|
-
ctx.indent = saved;
|
|
956
|
-
return asIIFE(r.stmts, r.valueVar, r.endVar, posExpr, ind(ctx));
|
|
957
|
-
};
|
|
958
|
-
const firstR_saved = ctx.indent;
|
|
959
|
-
ctx.indent = 0;
|
|
960
|
-
const firstR = emit(def.parser, ctx, pos);
|
|
961
|
-
ctx.indent = firstR_saved;
|
|
962
|
-
const firstV = v(ctx, "_sb0");
|
|
963
|
-
const sepV = v(ctx, "_sbs");
|
|
964
|
-
const nextV = v(ctx, "_sbn");
|
|
1337
|
+
const { stmts: firstStmts, okVar: firstOk, valVar: firstVal, endVar: firstEnd } = emitFallible(def.parser, ctx, pos);
|
|
965
1338
|
const stmts = [
|
|
966
1339
|
`${ind(ctx)}const ${arrV} = []`,
|
|
967
1340
|
`${ind(ctx)}let ${curV} = ${pos}`,
|
|
968
|
-
|
|
969
|
-
`${ind(ctx)}if (${
|
|
1341
|
+
...firstStmts,
|
|
1342
|
+
`${ind(ctx)}if (${firstOk}) {`
|
|
970
1343
|
];
|
|
971
1344
|
ctx.indent++;
|
|
972
1345
|
stmts.push(
|
|
973
|
-
`${ind(ctx)}${arrV}.push(${
|
|
974
|
-
`${ind(ctx)}${curV} = ${
|
|
1346
|
+
`${ind(ctx)}${arrV}.push(${firstVal})`,
|
|
1347
|
+
`${ind(ctx)}${curV} = ${firstEnd}`,
|
|
975
1348
|
`${ind(ctx)}while (${curV} < input.length) {`
|
|
976
1349
|
);
|
|
977
1350
|
ctx.indent++;
|
|
1351
|
+
let rollback = "";
|
|
1352
|
+
if (ctx.capturing) {
|
|
1353
|
+
const markV = v(ctx, "_mk");
|
|
1354
|
+
stmts.push(`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`);
|
|
1355
|
+
rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; `;
|
|
1356
|
+
}
|
|
1357
|
+
let sepAtPos = curV;
|
|
1358
|
+
if (ctx.activeTrivia) {
|
|
1359
|
+
if (ctx.capturing) {
|
|
1360
|
+
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1361
|
+
const spV = v(ctx, "_sp");
|
|
1362
|
+
stmts.push(`${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx)`);
|
|
1363
|
+
sepAtPos = spV;
|
|
1364
|
+
} else {
|
|
1365
|
+
const trivFn = ensureTriviaFn(ctx);
|
|
1366
|
+
const spV = v(ctx, "_sp");
|
|
1367
|
+
stmts.push(
|
|
1368
|
+
`${ind(ctx)}let ${spV} = ${curV}`,
|
|
1369
|
+
`${ind(ctx)}{ const _trv = ${trivFn}(input, ${spV}, _ctx); if (_trv.ok) ${spV} = _trv.span.end }`
|
|
1370
|
+
);
|
|
1371
|
+
sepAtPos = spV;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
|
|
1375
|
+
stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollback}break }`);
|
|
1376
|
+
let nextAtPos = sepEnd;
|
|
1377
|
+
if (ctx.activeTrivia) {
|
|
1378
|
+
if (ctx.capturing) {
|
|
1379
|
+
const capFn = ensureTriviaCaptureFn(ctx);
|
|
1380
|
+
const npV = v(ctx, "_np");
|
|
1381
|
+
stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx)`);
|
|
1382
|
+
nextAtPos = npV;
|
|
1383
|
+
} else {
|
|
1384
|
+
const trivFn = ensureTriviaFn(ctx);
|
|
1385
|
+
const npV = v(ctx, "_np");
|
|
1386
|
+
stmts.push(
|
|
1387
|
+
`${ind(ctx)}let ${npV} = ${sepEnd}`,
|
|
1388
|
+
`${ind(ctx)}{ const _trv = ${trivFn}(input, ${npV}, _ctx); if (_trv.ok) ${npV} = _trv.span.end }`
|
|
1389
|
+
);
|
|
1390
|
+
nextAtPos = npV;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, nextAtPos);
|
|
978
1394
|
stmts.push(
|
|
979
|
-
|
|
980
|
-
`${ind(ctx)}if (!${
|
|
981
|
-
`${ind(ctx)}
|
|
982
|
-
`${ind(ctx)}
|
|
983
|
-
`${ind(ctx)}${arrV}.push(${nextV}.value)`,
|
|
984
|
-
`${ind(ctx)}${curV} = ${nextV}.span.end`
|
|
1395
|
+
...nextStmts,
|
|
1396
|
+
`${ind(ctx)}if (!${nextOk}) { ${rollback}break }`,
|
|
1397
|
+
`${ind(ctx)}${arrV}.push(${nextVal})`,
|
|
1398
|
+
`${ind(ctx)}${curV} = ${nextEnd}`
|
|
985
1399
|
);
|
|
986
1400
|
ctx.indent--;
|
|
987
1401
|
stmts.push(`${ind(ctx)}}`);
|
|
@@ -990,13 +1404,6 @@ function emitSepBy(_p, def, ctx, pos) {
|
|
|
990
1404
|
return { stmts, valueVar: arrV, endVar: curV };
|
|
991
1405
|
}
|
|
992
1406
|
function emitScanTo(def, ctx, pos) {
|
|
993
|
-
const safeIIFE = (inner, posExpr) => {
|
|
994
|
-
const saved = ctx.indent;
|
|
995
|
-
ctx.indent = 0;
|
|
996
|
-
const r = emit(inner, ctx, posExpr);
|
|
997
|
-
ctx.indent = saved;
|
|
998
|
-
return `(() => { try { return ${asIIFE(r.stmts, r.valueVar, r.endVar, posExpr, ind(ctx))} } catch { return null } })()`;
|
|
999
|
-
};
|
|
1000
1407
|
const curV = v(ctx, "_stcur");
|
|
1001
1408
|
const foundV = v(ctx, "_stfnd");
|
|
1002
1409
|
const stmts = [
|
|
@@ -1005,18 +1412,19 @@ function emitScanTo(def, ctx, pos) {
|
|
|
1005
1412
|
`${ind(ctx)}while (${curV} < input.length) {`
|
|
1006
1413
|
];
|
|
1007
1414
|
ctx.indent++;
|
|
1008
|
-
const
|
|
1009
|
-
stmts.
|
|
1010
|
-
|
|
1011
|
-
`${ind(ctx)}if (${sentV}?.ok) { ${foundV} = true; break }`
|
|
1012
|
-
);
|
|
1415
|
+
const probeCtx = { ...ctx, capturing: false };
|
|
1416
|
+
const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, probeCtx, curV);
|
|
1417
|
+
stmts.push(...sentStmts, `${ind(ctx)}if (${sentOk}) { ${foundV} = true; break }`);
|
|
1013
1418
|
if (def.skip.length > 0) {
|
|
1014
1419
|
const advV = v(ctx, "_stadv");
|
|
1015
1420
|
stmts.push(`${ind(ctx)}let ${advV} = false`);
|
|
1016
1421
|
for (const skipper of def.skip) {
|
|
1017
|
-
const
|
|
1422
|
+
const { stmts: skStmts, okVar: skOk, endVar: skEnd } = emitFallible(skipper, probeCtx, curV);
|
|
1018
1423
|
stmts.push(
|
|
1019
|
-
`${ind(ctx)}if (!${advV}) {
|
|
1424
|
+
`${ind(ctx)}if (!${advV}) {`,
|
|
1425
|
+
...skStmts,
|
|
1426
|
+
`${ind(ctx)} if (${skOk} && ${skEnd} > ${curV}) { ${curV} = ${skEnd}; ${advV} = true }`,
|
|
1427
|
+
`${ind(ctx)}}`
|
|
1020
1428
|
);
|
|
1021
1429
|
}
|
|
1022
1430
|
stmts.push(`${ind(ctx)}if (!${advV}) ${curV}++`);
|
|
@@ -1028,14 +1436,54 @@ function emitScanTo(def, ctx, pos) {
|
|
|
1028
1436
|
if (!def.orEOF) {
|
|
1029
1437
|
const sentDef = def.sentinel._def;
|
|
1030
1438
|
const expectedStr = sentDef.tag === "literal" ? JSON.stringify([JSON.stringify(sentDef.value)]) : `["sentinel"]`;
|
|
1031
|
-
stmts.push(
|
|
1032
|
-
`${ind(ctx)}if (!${foundV}) return { ok: false, expected: ${expectedStr}, span: { start: ${pos}, end: ${curV} } }`
|
|
1033
|
-
);
|
|
1439
|
+
stmts.push(`${ind(ctx)}if (!${foundV}) ${failArr({ ...ctx, indent: 0 }, expectedStr, pos)}`);
|
|
1034
1440
|
}
|
|
1035
1441
|
const valV = v(ctx);
|
|
1036
1442
|
stmts.push(`${ind(ctx)}const ${valV} = input.slice(${pos}, ${curV})`);
|
|
1443
|
+
if (ctx.capturing) {
|
|
1444
|
+
const cap = emitLeafCapture(ctx, valV, pos, curV).map((s) => " " + s);
|
|
1445
|
+
stmts.push(`${ind(ctx)}if (${curV} > ${pos}) {`, ...cap, `${ind(ctx)}}`);
|
|
1446
|
+
}
|
|
1037
1447
|
return { stmts, valueVar: valV, endVar: curV };
|
|
1038
1448
|
}
|
|
1449
|
+
function emitNot(def, ctx, pos) {
|
|
1450
|
+
const { stmts, okVar } = emitFallible(def.parser, ctx, pos);
|
|
1451
|
+
return {
|
|
1452
|
+
stmts: [
|
|
1453
|
+
...stmts,
|
|
1454
|
+
`${ind(ctx)}if (${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"not"', pos).trim()}`
|
|
1455
|
+
],
|
|
1456
|
+
valueVar: "null",
|
|
1457
|
+
endVar: pos
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
function emitNode(def, ctx, pos) {
|
|
1461
|
+
const fnIdx = ctx.buildFns.length;
|
|
1462
|
+
ctx.buildFns.push(def.build);
|
|
1463
|
+
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
1464
|
+
const i = ind(ctx);
|
|
1465
|
+
const chV = v(ctx, "_ch");
|
|
1466
|
+
const rawV = v(ctx, "_raw");
|
|
1467
|
+
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st");
|
|
1468
|
+
const stmts = [
|
|
1469
|
+
`${i}const ${chV} = [], ${rawV} = []`,
|
|
1470
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia`,
|
|
1471
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true`
|
|
1472
|
+
];
|
|
1473
|
+
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
1474
|
+
stmts.push(...innerStmts);
|
|
1475
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}`);
|
|
1476
|
+
stmts.push(`${i}if (!${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"node"', pos).trim()}`);
|
|
1477
|
+
const ndV = v(ctx, "_nd");
|
|
1478
|
+
stmts.push(
|
|
1479
|
+
`${i}const ${ndV} = _build[${fnIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} })`,
|
|
1480
|
+
// Record into the caller's collectors (the node in children; the node, or a
|
|
1481
|
+
// spanned leaf if build collapsed to a non-node value, in rawChildren).
|
|
1482
|
+
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
1483
|
+
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && ${ndV}._tag === 'node') ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
1484
|
+
);
|
|
1485
|
+
return { stmts, valueVar: ndV, endVar };
|
|
1486
|
+
}
|
|
1039
1487
|
function emitRuntimeFallback(parser2, ctx, pos) {
|
|
1040
1488
|
const idx = ctx.runtimeParsers.length;
|
|
1041
1489
|
ctx.runtimeParsers.push(parser2);
|
|
@@ -1044,7 +1492,7 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
1044
1492
|
const ev = v(ctx, "_rte");
|
|
1045
1493
|
const stmts = [
|
|
1046
1494
|
`${ind(ctx)}const ${rv} = _rp[${idx}].parse(input, ${pos}, _ctx)`,
|
|
1047
|
-
`${ind(ctx)}if (!${rv}.ok)
|
|
1495
|
+
`${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"runtime"', pos).trim()}`,
|
|
1048
1496
|
`${ind(ctx)}const ${vv} = ${rv}.value`,
|
|
1049
1497
|
`${ind(ctx)}const ${ev} = ${rv}.span.end`
|
|
1050
1498
|
];
|
|
@@ -1062,9 +1510,12 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
1062
1510
|
return emitRuntimeFallback(p, ctx, pos);
|
|
1063
1511
|
}
|
|
1064
1512
|
const savedIndent = ctx.indent;
|
|
1513
|
+
const savedFailLabel = ctx.failLabel;
|
|
1065
1514
|
ctx.indent = 1;
|
|
1515
|
+
ctx.failLabel = void 0;
|
|
1066
1516
|
const r = emit(resolved, ctx, "_pos");
|
|
1067
1517
|
ctx.indent = savedIndent;
|
|
1518
|
+
ctx.failLabel = savedFailLabel;
|
|
1068
1519
|
ctx.namedFnDecls.push([
|
|
1069
1520
|
`function ${fnName2}(input, _pos, _ctx) {`,
|
|
1070
1521
|
...r.stmts,
|
|
@@ -1079,7 +1530,7 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
1079
1530
|
return {
|
|
1080
1531
|
stmts: [
|
|
1081
1532
|
`${ind(ctx)}const ${rv} = ${fnName}(input, ${pos}, _ctx)`,
|
|
1082
|
-
`${ind(ctx)}if (!${rv}.ok)
|
|
1533
|
+
`${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"parser"', pos).trim()}`,
|
|
1083
1534
|
`${ind(ctx)}const ${vv} = ${rv}.value`,
|
|
1084
1535
|
`${ind(ctx)}const ${ev} = ${rv}.span.end`
|
|
1085
1536
|
],
|
|
@@ -1087,6 +1538,33 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
1087
1538
|
endVar: ev
|
|
1088
1539
|
};
|
|
1089
1540
|
}
|
|
1541
|
+
function emitRecover(def, ctx, pos) {
|
|
1542
|
+
const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
1543
|
+
const ind0 = ind(ctx);
|
|
1544
|
+
const scanV = v(ctx, "_sc");
|
|
1545
|
+
const errV = v(ctx, "_err");
|
|
1546
|
+
const savedIndent = ctx.indent;
|
|
1547
|
+
ctx.indent += 2;
|
|
1548
|
+
const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, ctx, scanV);
|
|
1549
|
+
ctx.indent = savedIndent;
|
|
1550
|
+
const stmts = [
|
|
1551
|
+
...innerStmts,
|
|
1552
|
+
`${ind0}if (!${okVar}) {`,
|
|
1553
|
+
`${ind0} let ${scanV} = ${pos}`,
|
|
1554
|
+
`${ind0} while (${scanV} < input.length) {`,
|
|
1555
|
+
...sentStmts,
|
|
1556
|
+
`${ind0} if (${sentOk}) break`,
|
|
1557
|
+
`${ind0} ${scanV}++`,
|
|
1558
|
+
`${ind0} }`,
|
|
1559
|
+
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: [] }`,
|
|
1560
|
+
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
1561
|
+
`${ind0} ${valVar} = ${errV}`,
|
|
1562
|
+
`${ind0} ${endVar} = ${scanV}`,
|
|
1563
|
+
`${ind0} ${okVar} = true`,
|
|
1564
|
+
`${ind0}}`
|
|
1565
|
+
];
|
|
1566
|
+
return { stmts, valueVar: valVar, endVar };
|
|
1567
|
+
}
|
|
1090
1568
|
function emit(p, ctx, pos) {
|
|
1091
1569
|
const def = p._def;
|
|
1092
1570
|
switch (def.tag) {
|
|
@@ -1109,6 +1587,7 @@ function emit(p, ctx, pos) {
|
|
|
1109
1587
|
const inner = emit(def.parser, ctx, pos);
|
|
1110
1588
|
const fnIdx = ctx.mapFns.length;
|
|
1111
1589
|
ctx.mapFns.push(def.fn);
|
|
1590
|
+
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
1112
1591
|
const mv = v(ctx, "_mapped");
|
|
1113
1592
|
return {
|
|
1114
1593
|
stmts: [
|
|
@@ -1149,15 +1628,21 @@ function emit(p, ctx, pos) {
|
|
|
1149
1628
|
else ctx.activeTrivia = savedTrivia;
|
|
1150
1629
|
return r;
|
|
1151
1630
|
}
|
|
1631
|
+
case "not":
|
|
1632
|
+
return emitNot(def, ctx, pos);
|
|
1633
|
+
case "node":
|
|
1634
|
+
return emitNode(def, ctx, pos);
|
|
1152
1635
|
case "scanTo":
|
|
1153
1636
|
return emitScanTo(def, ctx, pos);
|
|
1637
|
+
case "recover":
|
|
1638
|
+
return emitRecover(def, ctx, pos);
|
|
1154
1639
|
case "guard": {
|
|
1155
1640
|
const fnIdx = ctx.mapFns.length;
|
|
1156
1641
|
ctx.mapFns.push(def.predicate);
|
|
1157
1642
|
const vv = v(ctx);
|
|
1158
1643
|
return {
|
|
1159
1644
|
stmts: [
|
|
1160
|
-
`${ind(ctx)}if (!_mf[${fnIdx}](_ctx.
|
|
1645
|
+
`${ind(ctx)}if (!_mf[${fnIdx}](_ctx.state)) ${failStmt({ ...ctx, indent: 0 }, '"gate"', pos).trim()}`,
|
|
1161
1646
|
`${ind(ctx)}const ${vv} = null`
|
|
1162
1647
|
],
|
|
1163
1648
|
valueVar: vv,
|
|
@@ -1173,9 +1658,12 @@ function emit(p, ctx, pos) {
|
|
|
1173
1658
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
1174
1659
|
ctx.namedParsers.set(innerParser, fnName);
|
|
1175
1660
|
const savedIndent = ctx.indent;
|
|
1661
|
+
const savedFailLabel = ctx.failLabel;
|
|
1176
1662
|
ctx.indent = 1;
|
|
1663
|
+
ctx.failLabel = void 0;
|
|
1177
1664
|
const innerR = emit(innerParser, ctx, "_pos");
|
|
1178
1665
|
ctx.indent = savedIndent;
|
|
1666
|
+
ctx.failLabel = savedFailLabel;
|
|
1179
1667
|
ctx.namedFnDecls.push([
|
|
1180
1668
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
1181
1669
|
...innerR.stmts,
|
|
@@ -1189,8 +1677,8 @@ function emit(p, ctx, pos) {
|
|
|
1189
1677
|
const ev = v(ctx, "_wce");
|
|
1190
1678
|
return {
|
|
1191
1679
|
stmts: [
|
|
1192
|
-
`${ind(ctx)}const ${rv} = ${fn}(input, ${pos}, { ..._ctx,
|
|
1193
|
-
`${ind(ctx)}if (!${rv}.ok)
|
|
1680
|
+
`${ind(ctx)}const ${rv} = ${fn}(input, ${pos}, { ..._ctx, state: _mf[${evIdx}]() })`,
|
|
1681
|
+
`${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"withCtx"', pos).trim()}`,
|
|
1194
1682
|
`${ind(ctx)}const ${vv} = ${rv}.value`,
|
|
1195
1683
|
`${ind(ctx)}const ${ev} = ${rv}.span.end`
|
|
1196
1684
|
],
|
|
@@ -1202,16 +1690,61 @@ function emit(p, ctx, pos) {
|
|
|
1202
1690
|
return emitRuntimeFallback(p, ctx, pos);
|
|
1203
1691
|
}
|
|
1204
1692
|
}
|
|
1205
|
-
function
|
|
1693
|
+
function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
1694
|
+
if (seen.has(p)) return false;
|
|
1695
|
+
seen.add(p);
|
|
1696
|
+
const d = p._def;
|
|
1697
|
+
switch (d.tag) {
|
|
1698
|
+
case "node":
|
|
1699
|
+
return true;
|
|
1700
|
+
case "lazy": {
|
|
1701
|
+
try {
|
|
1702
|
+
return hasNodeDef(d.thunk(), seen);
|
|
1703
|
+
} catch {
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
case "grammar":
|
|
1708
|
+
case "trivia":
|
|
1709
|
+
case "optional":
|
|
1710
|
+
case "many":
|
|
1711
|
+
case "oneOrMore":
|
|
1712
|
+
case "not":
|
|
1713
|
+
case "transform":
|
|
1714
|
+
return hasNodeDef(d.parser, seen);
|
|
1715
|
+
case "skip":
|
|
1716
|
+
return hasNodeDef(d.main, seen) || hasNodeDef(d.skipped, seen);
|
|
1717
|
+
case "sequence":
|
|
1718
|
+
case "choice":
|
|
1719
|
+
return d.parsers.some((x) => hasNodeDef(x, seen));
|
|
1720
|
+
case "sepBy":
|
|
1721
|
+
return hasNodeDef(d.parser, seen) || hasNodeDef(d.separator, seen);
|
|
1722
|
+
case "scanTo":
|
|
1723
|
+
return hasNodeDef(d.sentinel, seen) || d.skip.some((x) => hasNodeDef(x, seen));
|
|
1724
|
+
case "recover":
|
|
1725
|
+
return hasNodeDef(d.parser, seen) || hasNodeDef(d.sentinel, seen);
|
|
1726
|
+
case "withCtx":
|
|
1727
|
+
return hasNodeDef(d.parser, seen);
|
|
1728
|
+
default:
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
function compile(parser2, mapFnSources) {
|
|
1206
1733
|
const ctx = {
|
|
1207
1734
|
vars: 0,
|
|
1208
1735
|
indent: 1,
|
|
1209
1736
|
regexDecls: [],
|
|
1737
|
+
regexMap: /* @__PURE__ */ new Map(),
|
|
1210
1738
|
mapFns: [],
|
|
1739
|
+
mapFnSrcs: [],
|
|
1740
|
+
buildFns: [],
|
|
1741
|
+
buildSrcs: [],
|
|
1211
1742
|
runtimeParsers: [],
|
|
1212
1743
|
needsCollator: false,
|
|
1213
1744
|
namedParsers: /* @__PURE__ */ new Map(),
|
|
1214
|
-
|
|
1745
|
+
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
1746
|
+
namedFnDecls: [],
|
|
1747
|
+
capturing: hasNodeDef(parser2)
|
|
1215
1748
|
};
|
|
1216
1749
|
const r = emit(parser2, ctx, "_pos");
|
|
1217
1750
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
@@ -1220,13 +1753,13 @@ function compile(parser2) {
|
|
|
1220
1753
|
...ctx.regexDecls,
|
|
1221
1754
|
"",
|
|
1222
1755
|
...ctx.namedFnDecls,
|
|
1223
|
-
`${collatorDecl}function _parse(input, _pos, _rp, _mf, _ctx) {`,
|
|
1756
|
+
`${collatorDecl}function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
|
|
1224
1757
|
` let pos = _pos`,
|
|
1225
1758
|
...r.stmts,
|
|
1226
1759
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
1227
1760
|
`}`
|
|
1228
1761
|
].join("\n");
|
|
1229
|
-
const fn = new Function("input", "_pos", "_rp", "_mf", "_ctx", [
|
|
1762
|
+
const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
|
|
1230
1763
|
...ctx.regexDecls,
|
|
1231
1764
|
collatorDecl,
|
|
1232
1765
|
...ctx.namedFnDecls,
|
|
@@ -1235,17 +1768,27 @@ function compile(parser2) {
|
|
|
1235
1768
|
`return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
|
|
1236
1769
|
].join("\n"));
|
|
1237
1770
|
const defaultCtx = { trackLines: false };
|
|
1238
|
-
const
|
|
1239
|
-
const
|
|
1771
|
+
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
1772
|
+
const effectiveSources = mapFnSources ?? derivedSrcs;
|
|
1773
|
+
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
1774
|
+
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
1775
|
+
const mfCovered = ctx.mapFns.length === 0 || effectiveSources !== void 0 && effectiveSources.length === ctx.mapFns.length;
|
|
1776
|
+
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
1777
|
+
const inlineExpression = canInline ? buildInlineExpression(ctx, r, collatorDecl, effectiveSources, buildSources) : null;
|
|
1240
1778
|
return {
|
|
1241
1779
|
source,
|
|
1242
1780
|
inlineExpression,
|
|
1243
1781
|
parse(input, pos = 0) {
|
|
1244
|
-
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, defaultCtx);
|
|
1782
|
+
return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
|
|
1783
|
+
},
|
|
1784
|
+
parseWithErrors(input, pos = 0) {
|
|
1785
|
+
const errors = [];
|
|
1786
|
+
const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
|
|
1787
|
+
return { ...result, errors };
|
|
1245
1788
|
}
|
|
1246
1789
|
};
|
|
1247
1790
|
}
|
|
1248
|
-
function buildInlineExpression(ctx, r, collatorDecl) {
|
|
1791
|
+
function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
|
|
1249
1792
|
const bodyLines = [
|
|
1250
1793
|
` let pos = _pos`,
|
|
1251
1794
|
...r.stmts.map((s) => ` ${s}`),
|
|
@@ -1256,20 +1799,82 @@ function buildInlineExpression(ctx, r, collatorDecl) {
|
|
|
1256
1799
|
...bodyLines,
|
|
1257
1800
|
`}`
|
|
1258
1801
|
].join("\n");
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1802
|
+
const mfDecl = mapFnSources?.length ? ` const _mf = [${mapFnSources.join(", ")}]` : "";
|
|
1803
|
+
const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
|
|
1804
|
+
const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl;
|
|
1805
|
+
if (!needsWrapper) return innerFn;
|
|
1263
1806
|
return [
|
|
1264
1807
|
`/* @__PURE__ */ (() => {`,
|
|
1265
1808
|
...ctx.regexDecls.map((d) => ` ${d}`),
|
|
1266
1809
|
collatorDecl ? ` ${collatorDecl.trim()}` : "",
|
|
1810
|
+
mfDecl,
|
|
1811
|
+
buildDecl,
|
|
1267
1812
|
...ctx.namedFnDecls.flatMap((f) => f.split("\n").map((l) => ` ${l}`)),
|
|
1268
1813
|
` return ${innerFn}`,
|
|
1269
1814
|
`})()`
|
|
1270
1815
|
].filter(Boolean).join("\n");
|
|
1271
1816
|
}
|
|
1272
1817
|
|
|
1818
|
+
// src/combinators/scanTo.ts
|
|
1819
|
+
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
1820
|
+
const meta = {
|
|
1821
|
+
firstSet: any(),
|
|
1822
|
+
canMatchNewline: true,
|
|
1823
|
+
isTrivia: false
|
|
1824
|
+
};
|
|
1825
|
+
return {
|
|
1826
|
+
_tag: "scanTo",
|
|
1827
|
+
_meta: meta,
|
|
1828
|
+
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
1829
|
+
parse(input, pos, ctx) {
|
|
1830
|
+
let cur = pos;
|
|
1831
|
+
const probeCtx = { trackLines: ctx.trackLines, state: ctx.state };
|
|
1832
|
+
const emit2 = (end) => {
|
|
1833
|
+
if (end > pos && (ctx._cstLeaves || ctx._cstRawChildren)) {
|
|
1834
|
+
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
1835
|
+
if (ctx._cstLeaves) ctx._cstLeaves.push(leaf);
|
|
1836
|
+
if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
while (cur < input.length) {
|
|
1840
|
+
const s = sentinel.parse(input, cur, probeCtx);
|
|
1841
|
+
if (s.ok) {
|
|
1842
|
+
emit2(cur);
|
|
1843
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
1844
|
+
}
|
|
1845
|
+
let advanced = false;
|
|
1846
|
+
for (const skipper of skip2) {
|
|
1847
|
+
const r = skipper.parse(input, cur, probeCtx);
|
|
1848
|
+
if (r.ok && r.span.end > cur) {
|
|
1849
|
+
cur = r.span.end;
|
|
1850
|
+
advanced = true;
|
|
1851
|
+
break;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
if (!advanced) cur++;
|
|
1855
|
+
}
|
|
1856
|
+
if (orEOF) {
|
|
1857
|
+
emit2(cur);
|
|
1858
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
1859
|
+
}
|
|
1860
|
+
const sentDef = sentinel._def;
|
|
1861
|
+
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
1862
|
+
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
function balanced(open, close, options = {}) {
|
|
1867
|
+
const inner = scanTo(literal(close), options);
|
|
1868
|
+
const combi = transform(
|
|
1869
|
+
sequence(literal(open), inner, literal(close)),
|
|
1870
|
+
([o, content, c]) => o + content + c
|
|
1871
|
+
);
|
|
1872
|
+
if (combi._def.tag === "transform") {
|
|
1873
|
+
combi._def.fnSrc = "([o, content, c]) => o + content + c";
|
|
1874
|
+
}
|
|
1875
|
+
return combi;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1273
1878
|
// src/plugin/evaluator.ts
|
|
1274
1879
|
var SUPPORTED = {
|
|
1275
1880
|
literal: (...a) => literal(a[0], a[1]),
|
|
@@ -1279,19 +1884,144 @@ var SUPPORTED = {
|
|
|
1279
1884
|
many: (...a) => many(a[0]),
|
|
1280
1885
|
oneOrMore: (...a) => oneOrMore(a[0]),
|
|
1281
1886
|
optional: (...a) => optional(a[0]),
|
|
1282
|
-
sepBy: (...a) => sepBy(a[0], a[1])
|
|
1283
|
-
|
|
1887
|
+
sepBy: (...a) => sepBy(a[0], a[1]),
|
|
1888
|
+
trivia: (...a) => trivia(a[0])
|
|
1284
1889
|
};
|
|
1285
|
-
function
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1890
|
+
function isScopeEntry(v2) {
|
|
1891
|
+
return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
|
|
1892
|
+
}
|
|
1893
|
+
function isCombinator(v2) {
|
|
1894
|
+
return !!v2 && typeof v2 === "object" && "_def" in v2;
|
|
1895
|
+
}
|
|
1896
|
+
function scopeGet(scope, name, mfs) {
|
|
1897
|
+
const entry = scope.get(name);
|
|
1898
|
+
if (!entry) return null;
|
|
1899
|
+
if (isScopeEntry(entry)) {
|
|
1900
|
+
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
1901
|
+
return entry.combi;
|
|
1902
|
+
}
|
|
1903
|
+
if (isCombinator(entry)) return entry;
|
|
1904
|
+
return null;
|
|
1905
|
+
}
|
|
1906
|
+
function exprToCombi(node2, scope, code, mfs) {
|
|
1907
|
+
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
1908
|
+
if (node2.type !== "CallExpression") return null;
|
|
1909
|
+
const callee = node2.callee;
|
|
1289
1910
|
if (callee.type !== "Identifier") return null;
|
|
1911
|
+
if (callee.name === "transform" && code !== void 0 && mfs !== void 0) {
|
|
1912
|
+
const [parserArg, fnArg] = node2.arguments;
|
|
1913
|
+
if (!parserArg || !fnArg || parserArg.type === "SpreadElement" || fnArg.type === "SpreadElement") return null;
|
|
1914
|
+
const inner = anyValue(parserArg, scope, code, mfs);
|
|
1915
|
+
if (!isCombinator(inner)) return null;
|
|
1916
|
+
const fnSrc = code.slice(fnArg.start, fnArg.end);
|
|
1917
|
+
mfs.push(fnSrc);
|
|
1918
|
+
try {
|
|
1919
|
+
const combi = transform(inner, (v2) => v2);
|
|
1920
|
+
if (combi._def.tag === "transform") combi._def.fnSrc = fnSrc;
|
|
1921
|
+
return combi;
|
|
1922
|
+
} catch {
|
|
1923
|
+
return null;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
if (callee.name === "node" && code !== void 0) {
|
|
1927
|
+
const [typeArg, parserArg, buildArg] = node2.arguments;
|
|
1928
|
+
if (!typeArg || !parserArg || !buildArg || typeArg.type === "SpreadElement" || parserArg.type === "SpreadElement" || buildArg.type === "SpreadElement") return null;
|
|
1929
|
+
const typeVal = anyValue(typeArg, scope, code);
|
|
1930
|
+
if (typeof typeVal !== "string") return null;
|
|
1931
|
+
const inner = anyValue(parserArg, scope, code, mfs);
|
|
1932
|
+
if (!isCombinator(inner)) return null;
|
|
1933
|
+
const buildSrc = code.slice(buildArg.start, buildArg.end);
|
|
1934
|
+
try {
|
|
1935
|
+
const combi = node(typeVal, inner, () => null);
|
|
1936
|
+
if (combi._def.tag === "node") combi._def.buildSrc = buildSrc;
|
|
1937
|
+
return combi;
|
|
1938
|
+
} catch {
|
|
1939
|
+
return null;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
if (callee.name === "rules") return null;
|
|
1943
|
+
if (callee.name === "parser") {
|
|
1944
|
+
const [optsArg, rootArg] = node2.arguments;
|
|
1945
|
+
if (!optsArg || !rootArg || optsArg.type === "SpreadElement" || rootArg.type === "SpreadElement") return null;
|
|
1946
|
+
const opts = anyValue(optsArg, scope, code, []);
|
|
1947
|
+
if (!opts || typeof opts !== "object") return null;
|
|
1948
|
+
const root = anyValue(rootArg, scope, code, mfs);
|
|
1949
|
+
if (!isCombinator(root)) return null;
|
|
1950
|
+
try {
|
|
1951
|
+
return parser(opts, root);
|
|
1952
|
+
} catch {
|
|
1953
|
+
return null;
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
if (callee.name === "sepBy") {
|
|
1957
|
+
const [itemArg, sepArg] = node2.arguments;
|
|
1958
|
+
if (!itemArg || !sepArg || itemArg.type === "SpreadElement" || sepArg.type === "SpreadElement") return null;
|
|
1959
|
+
const itemMfs = [];
|
|
1960
|
+
const itemCombi = anyValue(itemArg, scope, code, itemMfs);
|
|
1961
|
+
if (!isCombinator(itemCombi)) return null;
|
|
1962
|
+
const sepMfs = [];
|
|
1963
|
+
const sepCombi = anyValue(sepArg, scope, code, sepMfs);
|
|
1964
|
+
if (!isCombinator(sepCombi)) return null;
|
|
1965
|
+
if (mfs) mfs.push(...itemMfs, ...sepMfs, ...itemMfs);
|
|
1966
|
+
try {
|
|
1967
|
+
return sepBy(itemCombi, sepCombi);
|
|
1968
|
+
} catch {
|
|
1969
|
+
return null;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
if (callee.name === "oneOrMore") {
|
|
1973
|
+
const [itemArg] = node2.arguments;
|
|
1974
|
+
if (!itemArg || itemArg.type === "SpreadElement") return null;
|
|
1975
|
+
const itemMfs = [];
|
|
1976
|
+
const itemCombi = anyValue(itemArg, scope, code, itemMfs);
|
|
1977
|
+
if (!isCombinator(itemCombi)) return null;
|
|
1978
|
+
if (mfs) mfs.push(...itemMfs, ...itemMfs);
|
|
1979
|
+
try {
|
|
1980
|
+
return oneOrMore(itemCombi);
|
|
1981
|
+
} catch {
|
|
1982
|
+
return null;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
if (callee.name === "not") {
|
|
1986
|
+
const [innerArg] = node2.arguments;
|
|
1987
|
+
if (!innerArg || innerArg.type === "SpreadElement") return null;
|
|
1988
|
+
const inner = anyValue(innerArg, scope, code, mfs);
|
|
1989
|
+
if (!isCombinator(inner)) return null;
|
|
1990
|
+
try {
|
|
1991
|
+
return not(inner);
|
|
1992
|
+
} catch {
|
|
1993
|
+
return null;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
if (callee.name === "balanced") {
|
|
1997
|
+
const [openArg, closeArg] = node2.arguments;
|
|
1998
|
+
if (!openArg || !closeArg || openArg.type === "SpreadElement" || closeArg.type === "SpreadElement") return null;
|
|
1999
|
+
const open = anyValue(openArg, scope, code, []);
|
|
2000
|
+
const close = anyValue(closeArg, scope, code, []);
|
|
2001
|
+
if (typeof open !== "string" || typeof close !== "string") return null;
|
|
2002
|
+
try {
|
|
2003
|
+
return balanced(open, close);
|
|
2004
|
+
} catch {
|
|
2005
|
+
return null;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
if (callee.name === "scanTo") {
|
|
2009
|
+
const [sentinelArg, optsArg] = node2.arguments;
|
|
2010
|
+
if (!sentinelArg || sentinelArg.type === "SpreadElement") return null;
|
|
2011
|
+
const sentinel = anyValue(sentinelArg, scope, code, []);
|
|
2012
|
+
if (!isCombinator(sentinel)) return null;
|
|
2013
|
+
const opts = optsArg && optsArg.type !== "SpreadElement" ? anyValue(optsArg, scope, code, []) : void 0;
|
|
2014
|
+
try {
|
|
2015
|
+
return scanTo(sentinel, opts);
|
|
2016
|
+
} catch {
|
|
2017
|
+
return null;
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
1290
2020
|
const factory = SUPPORTED[callee.name];
|
|
1291
2021
|
if (!factory) return null;
|
|
1292
|
-
const args =
|
|
2022
|
+
const args = node2.arguments.map((arg) => {
|
|
1293
2023
|
if (arg.type === "SpreadElement") return null;
|
|
1294
|
-
return
|
|
2024
|
+
return anyValue(arg, scope, code, mfs);
|
|
1295
2025
|
});
|
|
1296
2026
|
if (args.some((a) => a === null)) return null;
|
|
1297
2027
|
try {
|
|
@@ -1300,37 +2030,142 @@ function evaluateExpr(node, scope) {
|
|
|
1300
2030
|
return null;
|
|
1301
2031
|
}
|
|
1302
2032
|
}
|
|
1303
|
-
function
|
|
1304
|
-
if (
|
|
1305
|
-
if ("regex" in
|
|
1306
|
-
return new RegExp(
|
|
2033
|
+
function anyValue(node2, scope, code, mfs) {
|
|
2034
|
+
if (node2.type === "Literal") {
|
|
2035
|
+
if ("regex" in node2 && node2.regex !== null && node2.regex !== void 0) {
|
|
2036
|
+
return new RegExp(node2.regex.pattern, node2.regex.flags);
|
|
1307
2037
|
}
|
|
1308
|
-
return
|
|
2038
|
+
return node2.value;
|
|
1309
2039
|
}
|
|
1310
|
-
if (
|
|
2040
|
+
if (node2.type === "ArrayExpression") {
|
|
2041
|
+
const arr = node2;
|
|
2042
|
+
const out = [];
|
|
2043
|
+
for (const el of arr.elements) {
|
|
2044
|
+
if (el === null) {
|
|
2045
|
+
out.push(null);
|
|
2046
|
+
continue;
|
|
2047
|
+
}
|
|
2048
|
+
if (el.type === "SpreadElement") return null;
|
|
2049
|
+
out.push(anyValue(el, scope, code, mfs));
|
|
2050
|
+
}
|
|
2051
|
+
return out;
|
|
2052
|
+
}
|
|
2053
|
+
if (node2.type === "ObjectExpression") {
|
|
1311
2054
|
const obj = {};
|
|
1312
|
-
for (const prop of
|
|
2055
|
+
for (const prop of node2.properties) {
|
|
1313
2056
|
if (prop.type !== "Property") return null;
|
|
1314
2057
|
if (prop.computed) return null;
|
|
1315
2058
|
const key = prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" ? String(prop.key.value) : null;
|
|
1316
2059
|
if (key === null) return null;
|
|
1317
|
-
obj[key] =
|
|
2060
|
+
obj[key] = anyValue(prop.value, scope, code, mfs);
|
|
1318
2061
|
}
|
|
1319
2062
|
return obj;
|
|
1320
2063
|
}
|
|
1321
|
-
if (
|
|
1322
|
-
if (
|
|
1323
|
-
|
|
2064
|
+
if (node2.type === "Identifier") {
|
|
2065
|
+
if (node2.name === "undefined") return void 0;
|
|
2066
|
+
const entry = scope.get(node2.name) ?? null;
|
|
2067
|
+
if (isScopeEntry(entry)) {
|
|
2068
|
+
if (mfs && entry.mfSrcs.length > 0) mfs.push(...entry.mfSrcs);
|
|
2069
|
+
return entry.combi;
|
|
2070
|
+
}
|
|
2071
|
+
return entry;
|
|
1324
2072
|
}
|
|
1325
|
-
if (
|
|
2073
|
+
if (node2.type === "MemberExpression") {
|
|
2074
|
+
const mem = node2;
|
|
2075
|
+
const obj = anyValue(mem.object, scope, code, mfs);
|
|
2076
|
+
if (!obj || typeof obj !== "object") return null;
|
|
2077
|
+
if (node2.computed) {
|
|
2078
|
+
const key = anyValue(node2.property, scope, code, mfs);
|
|
2079
|
+
if (typeof key !== "string" && typeof key !== "number") return null;
|
|
2080
|
+
return obj[key] ?? null;
|
|
2081
|
+
}
|
|
2082
|
+
const propName = mem.property.name;
|
|
2083
|
+
if (!propName) return null;
|
|
2084
|
+
return obj[propName] ?? null;
|
|
2085
|
+
}
|
|
2086
|
+
if (node2.type === "CallExpression") return exprToCombi(node2, scope, code, mfs);
|
|
1326
2087
|
return null;
|
|
1327
2088
|
}
|
|
1328
|
-
function
|
|
1329
|
-
|
|
1330
|
-
|
|
2089
|
+
function evaluateExpr(node2, scope, code, mapFnSources) {
|
|
2090
|
+
return exprToCombi(node2, scope, code, mapFnSources);
|
|
2091
|
+
}
|
|
2092
|
+
function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
2093
|
+
if (factoryNode.type !== "ArrowFunctionExpression" && factoryNode.type !== "FunctionDeclaration" && factoryNode.type !== "FunctionExpression") return null;
|
|
2094
|
+
const factory = factoryNode;
|
|
2095
|
+
const params = factory.params;
|
|
2096
|
+
if (params.length !== 1) return null;
|
|
2097
|
+
const param = params[0];
|
|
2098
|
+
const proxyName = param.type === "Identifier" ? param.name ?? null : null;
|
|
2099
|
+
if (!proxyName) return null;
|
|
2100
|
+
const body = factory.body;
|
|
2101
|
+
if (!body) return null;
|
|
2102
|
+
const statements = [];
|
|
2103
|
+
let returnExpr = null;
|
|
2104
|
+
if (body.type === "BlockStatement") {
|
|
2105
|
+
const stmts = body.body;
|
|
2106
|
+
for (const stmt of stmts) {
|
|
2107
|
+
const s = stmt;
|
|
2108
|
+
if (s.type === "ReturnStatement") {
|
|
2109
|
+
returnExpr = s.argument ?? null;
|
|
2110
|
+
break;
|
|
2111
|
+
}
|
|
2112
|
+
if (s.type === "VariableDeclaration") {
|
|
2113
|
+
statements.push(s);
|
|
2114
|
+
} else {
|
|
2115
|
+
return null;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
} else {
|
|
2119
|
+
returnExpr = body;
|
|
2120
|
+
}
|
|
2121
|
+
if (!returnExpr) return null;
|
|
2122
|
+
const retObj = returnExpr.type === "ParenthesizedExpression" ? returnExpr.expression : returnExpr;
|
|
2123
|
+
if (retObj.type !== "ObjectExpression") return null;
|
|
2124
|
+
const ruleRefs = /* @__PURE__ */ new Map();
|
|
2125
|
+
for (const prop of retObj.properties) {
|
|
2126
|
+
if (prop.type !== "Property") return null;
|
|
2127
|
+
if (prop.computed) return null;
|
|
2128
|
+
const p = prop;
|
|
2129
|
+
const key = p.key.type === "Identifier" ? p.key.name : p.key.type === "Literal" ? String(p.key.value) : null;
|
|
2130
|
+
if (!key) return null;
|
|
2131
|
+
ruleRefs.set(key, ref());
|
|
2132
|
+
}
|
|
2133
|
+
const localScope = new Map(scope);
|
|
2134
|
+
localScope.set(proxyName, Object.fromEntries(ruleRefs));
|
|
2135
|
+
const bodyMfs = [];
|
|
2136
|
+
for (const stmt of statements) {
|
|
2137
|
+
for (const d of stmt.declarations) {
|
|
2138
|
+
const decl = d;
|
|
2139
|
+
if (!decl.init) return null;
|
|
2140
|
+
const id = decl.id;
|
|
2141
|
+
if (id.type !== "Identifier" && id.type !== "BindingIdentifier") return null;
|
|
2142
|
+
const name = id.name;
|
|
2143
|
+
const before = bodyMfs.length;
|
|
2144
|
+
const val = anyValue(decl.init, localScope, code, bodyMfs);
|
|
2145
|
+
if (val === null) return null;
|
|
2146
|
+
const thisDeclMfSrcs = bodyMfs.slice(before);
|
|
2147
|
+
if (isCombinator(val)) {
|
|
2148
|
+
localScope.set(name, { combi: val, mfSrcs: thisDeclMfSrcs });
|
|
2149
|
+
} else {
|
|
2150
|
+
localScope.set(name, val);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
for (const prop of retObj.properties) {
|
|
2155
|
+
const p = prop;
|
|
2156
|
+
const key = p.key.type === "Identifier" ? p.key.name : String(p.key.value);
|
|
2157
|
+
const val = anyValue(p.value, localScope, code, mapFnSources);
|
|
2158
|
+
if (!isCombinator(val)) return null;
|
|
2159
|
+
ruleRefs.get(key).define(val);
|
|
2160
|
+
}
|
|
2161
|
+
return ruleRefs;
|
|
2162
|
+
}
|
|
2163
|
+
function referencesAny(node2, names, scope) {
|
|
2164
|
+
if (node2.type === "Identifier") {
|
|
2165
|
+
return names.has(node2.name) || scope.has(node2.name);
|
|
1331
2166
|
}
|
|
1332
|
-
for (const key of Object.keys(
|
|
1333
|
-
const child =
|
|
2167
|
+
for (const key of Object.keys(node2)) {
|
|
2168
|
+
const child = node2[key];
|
|
1334
2169
|
if (!child || typeof child !== "object") continue;
|
|
1335
2170
|
if (Array.isArray(child)) {
|
|
1336
2171
|
if (child.some((c) => c && typeof c === "object" && "type" in c && referencesAny(c, names, scope))) return true;
|
|
@@ -1345,6 +2180,10 @@ function referencesAny(node, names, scope) {
|
|
|
1345
2180
|
var PARSEMAN_MODULE = "parseman";
|
|
1346
2181
|
var plugin_default = createUnplugin((opts = {}) => ({
|
|
1347
2182
|
name: "parseman",
|
|
2183
|
+
// Run BEFORE the bundler's TS/JS transform — otherwise esbuild (Vite) strips
|
|
2184
|
+
// the `with { type: 'macro' }` import attribute before we ever see it, and the
|
|
2185
|
+
// macro silently never fires.
|
|
2186
|
+
enforce: "pre",
|
|
1348
2187
|
transformInclude(id) {
|
|
1349
2188
|
return /\.[jt]sx?$/.test(id) && !id.includes("node_modules");
|
|
1350
2189
|
},
|
|
@@ -1352,7 +2191,15 @@ var plugin_default = createUnplugin((opts = {}) => ({
|
|
|
1352
2191
|
if (!code.includes("parseman")) return null;
|
|
1353
2192
|
if (!code.includes("macro")) return null;
|
|
1354
2193
|
const moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE, ...opts.moduleAliases ?? []]);
|
|
1355
|
-
|
|
2194
|
+
const result = transformMacro(code, id, moduleAliases);
|
|
2195
|
+
if (result?.warnings.length) {
|
|
2196
|
+
for (const w of result.warnings) {
|
|
2197
|
+
if (typeof this?.warn === "function") this.warn(`[parseman] ${w}`);
|
|
2198
|
+
else console.warn(`[parseman] ${w}`);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
if (!result) return null;
|
|
2202
|
+
return { code: result.code, map: result.map };
|
|
1356
2203
|
}
|
|
1357
2204
|
}));
|
|
1358
2205
|
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE])) {
|
|
@@ -1385,35 +2232,136 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
1385
2232
|
if (macroImports.length === 0) return null;
|
|
1386
2233
|
const scope = /* @__PURE__ */ new Map();
|
|
1387
2234
|
const replacements = [];
|
|
2235
|
+
const warnings = [];
|
|
1388
2236
|
let anyUnresolved = false;
|
|
2237
|
+
const lineOf = (pos) => {
|
|
2238
|
+
let line = 1;
|
|
2239
|
+
for (let i = 0; i < pos && i < code.length; i++) if (code.charCodeAt(i) === 10) line++;
|
|
2240
|
+
return line;
|
|
2241
|
+
};
|
|
2242
|
+
const warn = (pos, msg) => {
|
|
2243
|
+
anyUnresolved = true;
|
|
2244
|
+
warnings.push(`${id}:${lineOf(pos)} \u2014 ${msg} (running via the interpreter; add the plugin or simplify the declaration to compile it)`);
|
|
2245
|
+
};
|
|
2246
|
+
const compileRulesFactory = (init, label) => {
|
|
2247
|
+
const args = init.arguments;
|
|
2248
|
+
const factoryArg = args[0];
|
|
2249
|
+
if (!factoryArg) {
|
|
2250
|
+
warn(init.start, `${label}: rules() needs a factory argument`);
|
|
2251
|
+
return null;
|
|
2252
|
+
}
|
|
2253
|
+
const ruleMap = evaluateParserFactory(factoryArg, scope, code, []);
|
|
2254
|
+
if (!ruleMap) {
|
|
2255
|
+
warn(init.start, `${label}: rules(...) factory isn't statically evaluable`);
|
|
2256
|
+
return null;
|
|
2257
|
+
}
|
|
2258
|
+
const entries = [];
|
|
2259
|
+
for (const [ruleKey, rule] of ruleMap) {
|
|
2260
|
+
const compiled = compile(rule);
|
|
2261
|
+
if (compiled.inlineExpression === null) {
|
|
2262
|
+
warn(init.start, `${label}: rule "${ruleKey}" couldn't be inlined`);
|
|
2263
|
+
return null;
|
|
2264
|
+
}
|
|
2265
|
+
entries.push([ruleKey, compiled.inlineExpression]);
|
|
2266
|
+
}
|
|
2267
|
+
return { entries, ruleMap };
|
|
2268
|
+
};
|
|
2269
|
+
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
1389
2270
|
for (const stmt of body) {
|
|
1390
|
-
|
|
1391
|
-
|
|
2271
|
+
let vd = null;
|
|
2272
|
+
let stmtStart = stmt.start;
|
|
2273
|
+
let stmtEnd = stmt.end;
|
|
2274
|
+
let exportPrefix = "";
|
|
2275
|
+
if (stmt.type === "VariableDeclaration") {
|
|
2276
|
+
vd = stmt;
|
|
2277
|
+
} else if (stmt.type === "ExportNamedDeclaration") {
|
|
2278
|
+
const expStmt = stmt;
|
|
2279
|
+
if (expStmt.declaration?.type === "VariableDeclaration") {
|
|
2280
|
+
vd = expStmt.declaration;
|
|
2281
|
+
exportPrefix = "export ";
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
if (!vd) continue;
|
|
2285
|
+
for (const decl of vd.declarations) {
|
|
1392
2286
|
const d = decl;
|
|
1393
2287
|
if (!d.init) continue;
|
|
1394
|
-
if (d.id.type !== "Identifier") continue;
|
|
1395
|
-
const varName = d.id.name;
|
|
1396
2288
|
const init = d.init;
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
2289
|
+
const kind = vd.kind ?? "const";
|
|
2290
|
+
if (d.id.type === "Identifier") {
|
|
2291
|
+
const varName = d.id.name;
|
|
2292
|
+
if (!referencesAny(init, allNames, scope)) continue;
|
|
2293
|
+
if (isRulesCall(init)) {
|
|
2294
|
+
const compiledRules = compileRulesFactory(init, varName);
|
|
2295
|
+
if (!compiledRules) continue;
|
|
2296
|
+
replacements.push({
|
|
2297
|
+
start: init.start,
|
|
2298
|
+
end: init.end,
|
|
2299
|
+
replacement: `{ ${compiledRules.entries.map(([k, expr]) => `${k}: ${expr}`).join(", ")} }`
|
|
2300
|
+
});
|
|
2301
|
+
continue;
|
|
2302
|
+
}
|
|
2303
|
+
const mapFnSources = [];
|
|
2304
|
+
const parser2 = evaluateExpr(init, scope, code, mapFnSources);
|
|
2305
|
+
if (parser2 === null) {
|
|
2306
|
+
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
const compiled = compile(parser2);
|
|
2310
|
+
if (compiled.inlineExpression === null) {
|
|
2311
|
+
warn(init.start, `"${varName}" couldn't be inlined (likely closes over a runtime value)`);
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
replacements.push({
|
|
2315
|
+
start: init.start,
|
|
2316
|
+
end: init.end,
|
|
2317
|
+
replacement: compiled.inlineExpression
|
|
2318
|
+
});
|
|
2319
|
+
scope.set(varName, { combi: parser2, mfSrcs: mapFnSources });
|
|
2320
|
+
} else if (d.id.type === "ObjectPattern") {
|
|
2321
|
+
if (!referencesAny(init, allNames, scope)) continue;
|
|
2322
|
+
if (!isRulesCall(init)) {
|
|
2323
|
+
warn(init.start, `destructured macro binding must come from rules(...)`);
|
|
2324
|
+
continue;
|
|
2325
|
+
}
|
|
2326
|
+
const compiledRules = compileRulesFactory(init, "{ \u2026 }");
|
|
2327
|
+
if (!compiledRules) continue;
|
|
2328
|
+
const byKey = new Map(compiledRules.entries);
|
|
2329
|
+
const pattern = d.id;
|
|
2330
|
+
const lines = [];
|
|
2331
|
+
let allOk = true;
|
|
2332
|
+
for (const prop of pattern.properties) {
|
|
2333
|
+
const p = prop;
|
|
2334
|
+
if (p.type === "RestElement" || p.type === "BindingRestElement") {
|
|
2335
|
+
warn(init.start, `rest element in a rules() destructure isn't supported`);
|
|
2336
|
+
allOk = false;
|
|
2337
|
+
break;
|
|
2338
|
+
}
|
|
2339
|
+
const ruleKey = p.key.type === "Identifier" ? p.key.name : p.key.type === "StringLiteral" ? String(p.key.value) : null;
|
|
2340
|
+
const localName = p.value.type === "Identifier" || p.value.type === "BindingIdentifier" ? p.value.name : ruleKey;
|
|
2341
|
+
if (!ruleKey || !localName) {
|
|
2342
|
+
allOk = false;
|
|
2343
|
+
break;
|
|
2344
|
+
}
|
|
2345
|
+
const inlineExpr = byKey.get(ruleKey);
|
|
2346
|
+
if (inlineExpr === void 0) {
|
|
2347
|
+
warn(init.start, `destructured rule "${ruleKey}" isn't returned by the rules() factory`);
|
|
2348
|
+
allOk = false;
|
|
2349
|
+
break;
|
|
2350
|
+
}
|
|
2351
|
+
lines.push(`${exportPrefix}${kind} ${localName} = ${inlineExpr}`);
|
|
2352
|
+
const rule = compiledRules.ruleMap.get(ruleKey);
|
|
2353
|
+
if (rule) scope.set(localName, { combi: rule, mfSrcs: [] });
|
|
2354
|
+
}
|
|
2355
|
+
if (!allOk) continue;
|
|
2356
|
+
replacements.push({
|
|
2357
|
+
start: stmtStart,
|
|
2358
|
+
end: stmtEnd,
|
|
2359
|
+
replacement: lines.join("\n")
|
|
2360
|
+
});
|
|
1407
2361
|
}
|
|
1408
|
-
replacements.push({
|
|
1409
|
-
start: init.start,
|
|
1410
|
-
end: init.end,
|
|
1411
|
-
replacement: compiled.inlineExpression
|
|
1412
|
-
});
|
|
1413
|
-
scope.set(varName, parser2);
|
|
1414
2362
|
}
|
|
1415
2363
|
}
|
|
1416
|
-
if (replacements.length === 0) return null;
|
|
2364
|
+
if (replacements.length === 0 && warnings.length === 0) return null;
|
|
1417
2365
|
for (const imp of macroImports) {
|
|
1418
2366
|
imp.fullyResolved = !anyUnresolved;
|
|
1419
2367
|
}
|
|
@@ -1432,7 +2380,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
1432
2380
|
}
|
|
1433
2381
|
return {
|
|
1434
2382
|
code: ms.toString(),
|
|
1435
|
-
map: ms.generateMap({ hires: true })
|
|
2383
|
+
map: ms.generateMap({ hires: true }),
|
|
2384
|
+
warnings
|
|
1436
2385
|
};
|
|
1437
2386
|
}
|
|
1438
2387
|
export {
|