parseman 0.17.0 → 0.18.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.
@@ -65,6 +65,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
65
65
  case "transform":
66
66
  case "label":
67
67
  case "trivia":
68
+ case "token":
68
69
  case "expect":
69
70
  case "withCtx":
70
71
  case "node":
@@ -127,6 +128,7 @@ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
127
128
  case "transform":
128
129
  case "label":
129
130
  case "trivia":
131
+ case "token":
130
132
  case "node":
131
133
  case "grammar":
132
134
  case "expect":
@@ -1250,6 +1252,7 @@ function markUnusedValues(root) {
1250
1252
  return;
1251
1253
  case "label":
1252
1254
  case "trivia":
1255
+ case "token":
1253
1256
  case "withCtx":
1254
1257
  case "expect":
1255
1258
  visit(def.parser, consumed);
@@ -1527,8 +1530,60 @@ function noTrivia(root) {
1527
1530
  return parser({ trivia: null }, root);
1528
1531
  }
1529
1532
 
1533
+ // src/combinators/token.ts
1534
+ function token(root) {
1535
+ const meta = {
1536
+ firstSet: root._meta.firstSet,
1537
+ canMatchNewline: root._meta.canMatchNewline,
1538
+ isTrivia: false
1539
+ };
1540
+ return {
1541
+ _tag: "token",
1542
+ _meta: meta,
1543
+ _def: { tag: "token", parser: root },
1544
+ parse(input, pos, ctx) {
1545
+ const savedTrivia = ctx.trivia;
1546
+ const savedKinds = ctx.triviaKindLabels;
1547
+ const savedBuf = ctx._cstBuf;
1548
+ const savedChildren = ctx._cstChildren;
1549
+ const savedLeaves = ctx._cstLeaves;
1550
+ const savedRaw = ctx._cstRawChildren;
1551
+ const savedTriviaLog = ctx._cstTriviaLog;
1552
+ const savedOuterTriviaLog = ctx._triviaLog;
1553
+ const wasCapturing = cstCaptureActive(ctx);
1554
+ ctx.trivia = void 0;
1555
+ ctx.triviaKindLabels = void 0;
1556
+ ctx._cstBuf = void 0;
1557
+ ctx._cstChildren = void 0;
1558
+ ctx._cstLeaves = void 0;
1559
+ ctx._cstRawChildren = void 0;
1560
+ ctx._cstTriviaLog = void 0;
1561
+ delete ctx._triviaLog;
1562
+ let result;
1563
+ try {
1564
+ result = root.parse(input, pos, ctx);
1565
+ } finally {
1566
+ ctx.trivia = savedTrivia;
1567
+ ctx.triviaKindLabels = savedKinds;
1568
+ ctx._cstBuf = savedBuf;
1569
+ ctx._cstChildren = savedChildren;
1570
+ ctx._cstLeaves = savedLeaves;
1571
+ ctx._cstRawChildren = savedRaw;
1572
+ ctx._cstTriviaLog = savedTriviaLog;
1573
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
1574
+ else ctx._triviaLog = savedOuterTriviaLog;
1575
+ }
1576
+ if (!result.ok) return result;
1577
+ const span = result.span;
1578
+ const value = input.slice(pos, span.end);
1579
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
1580
+ return { ok: true, value, span };
1581
+ }
1582
+ };
1583
+ }
1584
+
1530
1585
  // src/combinators/expect.ts
1531
- function staticExpected(c) {
1586
+ function deriveExpected(c) {
1532
1587
  const def = c._def;
1533
1588
  switch (def.tag) {
1534
1589
  case "literal":
@@ -1540,22 +1595,23 @@ function staticExpected(c) {
1540
1595
  case "label":
1541
1596
  return [def.label];
1542
1597
  case "choice":
1543
- return def.parsers.flatMap(staticExpected);
1598
+ return def.parsers.flatMap(deriveExpected);
1544
1599
  case "sequence":
1545
- return def.parsers.length > 0 ? staticExpected(def.parsers[0]) : [];
1600
+ return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1546
1601
  case "node":
1547
1602
  case "grammar":
1548
1603
  case "trivia":
1604
+ case "token":
1549
1605
  case "optional":
1550
1606
  case "many":
1551
1607
  case "oneOrMore":
1552
1608
  case "transform":
1553
1609
  case "not":
1554
- return staticExpected(def.parser);
1610
+ return deriveExpected(def.parser);
1555
1611
  case "lazy": {
1556
1612
  const name = c._ruleName;
1557
1613
  try {
1558
- return staticExpected(def.thunk());
1614
+ return deriveExpected(def.thunk());
1559
1615
  } catch {
1560
1616
  return name ? [name] : [];
1561
1617
  }
@@ -1565,7 +1621,7 @@ function staticExpected(c) {
1565
1621
  }
1566
1622
  }
1567
1623
  function expect(combinator, label2) {
1568
- const expected = label2 !== void 0 ? [label2] : staticExpected(combinator);
1624
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1569
1625
  const meta = {
1570
1626
  firstSet: combinator._meta.firstSet,
1571
1627
  canMatchNewline: combinator._meta.canMatchNewline,
@@ -3225,6 +3281,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
3225
3281
  case "guard":
3226
3282
  case "not":
3227
3283
  case "trivia":
3284
+ case "token":
3228
3285
  case "scanTo":
3229
3286
  case "unknown":
3230
3287
  return false;
@@ -3286,6 +3343,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
3286
3343
  case "regex":
3287
3344
  case "keywords":
3288
3345
  case "node":
3346
+ case "token":
3289
3347
  return true;
3290
3348
  case "not":
3291
3349
  case "guard":
@@ -3564,9 +3622,9 @@ function emitSeq(def, ctx, pos) {
3564
3622
  stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
3565
3623
  return { stmts, valueVar: arrV, endVar };
3566
3624
  }
3567
- function staticExpectedArr(parsers) {
3625
+ function deriveExpectedArr(parsers) {
3568
3626
  return JSON.stringify(parsers.flatMap((p) => {
3569
- const e = staticExpected(p);
3627
+ const e = deriveExpected(p);
3570
3628
  return e.length > 0 ? e : [p._tag];
3571
3629
  }));
3572
3630
  }
@@ -3587,7 +3645,7 @@ function failsAtStart(p) {
3587
3645
  }
3588
3646
  }
3589
3647
  function armStaticExpected(ctx, p) {
3590
- return hoistExpected(ctx, staticExpectedArr([p]));
3648
+ return hoistExpected(ctx, deriveExpectedArr([p]));
3591
3649
  }
3592
3650
  function canMatchEmptyAtStart(p) {
3593
3651
  const d = p._def;
@@ -3625,7 +3683,7 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
3625
3683
  ];
3626
3684
  }
3627
3685
  function emitChoice(def, ctx, pos) {
3628
- const allExpected = staticExpectedArr(def.parsers);
3686
+ const allExpected = deriveExpectedArr(def.parsers);
3629
3687
  if (def.disjoint) {
3630
3688
  const codeV = v(ctx, "_code");
3631
3689
  const valV = v(ctx, "_chv");
@@ -3686,7 +3744,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
3686
3744
  const wordV = v(ctx, "_gw");
3687
3745
  const endV = v(ctx, "_ge");
3688
3746
  const valV = v(ctx, "_gcv");
3689
- const regexExpected = JSON.stringify(staticExpected(superParser));
3747
+ const regexExpected = JSON.stringify(deriveExpected(superParser));
3690
3748
  const stmts = [
3691
3749
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
3692
3750
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
@@ -4078,6 +4136,116 @@ function emitNot(def, ctx, pos) {
4078
4136
  endVar: pos
4079
4137
  };
4080
4138
  }
4139
+ function escapeTokenLiteral(value) {
4140
+ return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
4141
+ }
4142
+ function regexMatchesEmpty(source, flags) {
4143
+ try {
4144
+ return new RegExp(`^(?:${source})$`, flags).test("");
4145
+ } catch {
4146
+ return true;
4147
+ }
4148
+ }
4149
+ function tokenTerminalSource(p) {
4150
+ const def = p._def;
4151
+ switch (def.tag) {
4152
+ case "literal":
4153
+ if (def.value.length === 0) return null;
4154
+ return {
4155
+ source: escapeTokenLiteral(def.value),
4156
+ caseInsensitive: def.caseInsensitive,
4157
+ rawCaseSensitive: def.caseInsensitive ? "" : def.value
4158
+ };
4159
+ case "regex": {
4160
+ if (def.flags.replace(/i/g, "") !== "") return null;
4161
+ if (regexMatchesEmpty(def.source, def.flags)) return null;
4162
+ return {
4163
+ source: `(?:${def.source})`,
4164
+ caseInsensitive: def.flags.includes("i"),
4165
+ rawCaseSensitive: def.flags.includes("i") ? "" : def.source
4166
+ };
4167
+ }
4168
+ default:
4169
+ return null;
4170
+ }
4171
+ }
4172
+ function tokenSequenceSource(p) {
4173
+ const def = p._def;
4174
+ const parts = def.tag === "sequence" ? def.parsers.map(tokenTerminalSource) : [tokenTerminalSource(p)];
4175
+ if (parts.some((part) => part === null)) return null;
4176
+ const typed = parts;
4177
+ const flags = typed.some((part) => part.caseInsensitive) ? "i" : "";
4178
+ if (flags.includes("i") && typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))) return null;
4179
+ return {
4180
+ source: typed.map((part) => part.source).join(""),
4181
+ flags,
4182
+ hasCaseSensitiveLetters: typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))
4183
+ };
4184
+ }
4185
+ function combineTokenRegexSources(parts) {
4186
+ const flags = parts.some((part) => part.flags.includes("i")) ? "i" : "";
4187
+ if (flags.includes("i") && parts.some((part) => part.flags === "" && part.hasCaseSensitiveLetters)) return null;
4188
+ return { source: parts.map((part) => part.source).join(""), flags };
4189
+ }
4190
+ function tokenNullableRegex(def) {
4191
+ const inner = def.parser._def;
4192
+ if (inner.tag === "many") {
4193
+ const seq = tokenSequenceSource(inner.parser);
4194
+ if (!seq) return null;
4195
+ return { tag: "regex", source: `(?:${seq.source})*`, flags: seq.flags };
4196
+ }
4197
+ if (inner.tag === "optional") {
4198
+ const seq = tokenSequenceSource(inner.parser);
4199
+ if (!seq) return null;
4200
+ return { tag: "regex", source: `(?:${seq.source})?`, flags: seq.flags };
4201
+ }
4202
+ if (inner.tag === "sepBy") {
4203
+ const item = tokenSequenceSource(inner.parser);
4204
+ const sep = tokenSequenceSource(inner.separator);
4205
+ if (!item || !sep) return null;
4206
+ const combined = combineTokenRegexSources([item, sep]);
4207
+ if (!combined) return null;
4208
+ return { tag: "regex", source: `(?:${item.source}(?:${sep.source}${item.source})*)?`, flags: combined.flags };
4209
+ }
4210
+ return null;
4211
+ }
4212
+ function emitToken(def, ctx, pos) {
4213
+ const lowered = tokenNullableRegex(def);
4214
+ if (lowered) return emitRegex(lowered, ctx, pos);
4215
+ const savedTrivia = ctx.activeTrivia;
4216
+ const savedKindLabels = ctx.triviaKindLabels;
4217
+ ctx.activeTrivia = void 0;
4218
+ ctx.triviaKindLabels = void 0;
4219
+ const inner = emitFallible(def.parser, ctx, pos);
4220
+ ctx.activeTrivia = savedTrivia;
4221
+ ctx.triviaKindLabels = savedKindLabels;
4222
+ const i = ind(ctx);
4223
+ const sc = v(ctx, "_tokCh");
4224
+ const sl = v(ctx, "_tokLv");
4225
+ const sr = v(ctx, "_tokRaw");
4226
+ const sv = v(ctx, "_tokTr");
4227
+ const sk = v(ctx, "_tokKinds");
4228
+ const stl = v(ctx, "_tokTl");
4229
+ const sol = v(ctx, "_tokLog");
4230
+ const sb = v(ctx, "_tokBuf");
4231
+ const valV = v(ctx, "_tok");
4232
+ return {
4233
+ stmts: [
4234
+ `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${sv} = _ctx.trivia, ${sk} = _ctx.triviaKindLabels, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
4235
+ `${i}_ctx.trivia = undefined; _ctx.triviaKindLabels = undefined; _ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
4236
+ `${i}try {`,
4237
+ ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
4238
+ `${i}} finally {`,
4239
+ `${i} _ctx.trivia = ${sv}; _ctx.triviaKindLabels = ${sk}; _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
4240
+ `${i}}`,
4241
+ ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
4242
+ `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
4243
+ ...emitLeafCapture(ctx, valV, pos, inner.endVar)
4244
+ ],
4245
+ valueVar: valV,
4246
+ endVar: inner.endVar
4247
+ };
4248
+ }
4081
4249
  function emitNode(def, ctx, pos) {
4082
4250
  const structural = def.build === void 0;
4083
4251
  const mkType = structural ? null : analyzeMkInlineBuild(def);
@@ -4197,7 +4365,7 @@ function emitRecover(def, ctx, pos) {
4197
4365
  `${ind0} if (${sentOk}) break`,
4198
4366
  `${ind0} ${scanV}++`,
4199
4367
  `${ind0} }`,
4200
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(staticExpected(def.parser))} }`,
4368
+ `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
4201
4369
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
4202
4370
  `${ind0} ${valVar} = ${errV}`,
4203
4371
  `${ind0} ${endVar} = ${scanV}`,
@@ -4327,6 +4495,8 @@ function emitDispatch(p, ctx, pos) {
4327
4495
  return emitLazy(p, def, ctx, pos);
4328
4496
  case "trivia":
4329
4497
  return emit(def.parser, ctx, pos);
4498
+ case "token":
4499
+ return emitToken(def, ctx, pos);
4330
4500
  case "label":
4331
4501
  return emit(def.parser, ctx, pos);
4332
4502
  case "grammar": {
@@ -4428,6 +4598,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
4428
4598
  }
4429
4599
  case "grammar":
4430
4600
  case "trivia":
4601
+ case "token":
4431
4602
  case "label":
4432
4603
  case "optional":
4433
4604
  case "many":
@@ -4463,6 +4634,7 @@ function childrenOf(def) {
4463
4634
  case "optional":
4464
4635
  case "transform":
4465
4636
  case "trivia":
4637
+ case "token":
4466
4638
  case "label":
4467
4639
  case "grammar":
4468
4640
  case "not":
@@ -5046,7 +5218,7 @@ function balanced(open, close, options = {}) {
5046
5218
  const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
5047
5219
  const inner = many(choice(self, ...skips, content));
5048
5220
  const combi = transform(
5049
- sequence(literal(open), inner, expect(literal(close), close)),
5221
+ sequence(literal(open), inner, expect(literal(close))),
5050
5222
  // parts: strings (content/self) or arrays (a sequence-shaped skip) or a
5051
5223
  // ParseError (recovered close). `c` is the close string or a ParseError.
5052
5224
  ([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
@@ -5083,6 +5255,7 @@ function childrenOf2(def) {
5083
5255
  case "optional":
5084
5256
  case "transform":
5085
5257
  case "trivia":
5258
+ case "token":
5086
5259
  case "label":
5087
5260
  case "not":
5088
5261
  case "node":
@@ -5164,6 +5337,7 @@ function evalRuleMapIR(ir) {
5164
5337
  "node",
5165
5338
  "parser",
5166
5339
  "scanTo",
5340
+ "token",
5167
5341
  "transform",
5168
5342
  "skip",
5169
5343
  "trivia",
@@ -5189,6 +5363,7 @@ function evalRuleMapIR(ir) {
5189
5363
  node,
5190
5364
  parser,
5191
5365
  scanTo,
5366
+ token,
5192
5367
  transform,
5193
5368
  skip,
5194
5369
  trivia,
@@ -5322,6 +5497,8 @@ ${body}
5322
5497
  return `not(${kid(def.parser)})`;
5323
5498
  case "trivia":
5324
5499
  return `trivia(${kid(def.parser)})`;
5500
+ case "token":
5501
+ return `token(${kid(def.parser)})`;
5325
5502
  case "label":
5326
5503
  return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
5327
5504
  case "expect":
@@ -5444,6 +5621,7 @@ var SUPPORTED = {
5444
5621
  trivia: (...a) => trivia(a[0]),
5445
5622
  label: (...a) => label(a[0], a[1]),
5446
5623
  noTrivia: (...a) => noTrivia(a[0]),
5624
+ token: (...a) => token(a[0]),
5447
5625
  expect: (...a) => expect(a[0], a[1])
5448
5626
  };
5449
5627
  function isScopeEntry(v2) {