parseman 0.17.0 → 0.18.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.
@@ -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);
@@ -1451,7 +1454,11 @@ function label(name, combinator) {
1451
1454
  _tag: combinator._tag,
1452
1455
  _meta: combinator._meta,
1453
1456
  _def: { tag: "label", label: name, parser: combinator },
1454
- parse: combinator.parse.bind(combinator)
1457
+ parse(input, pos, ctx) {
1458
+ const result = combinator.parse(input, pos, ctx);
1459
+ if (!result.ok) return { ...result, expected: [name] };
1460
+ return result;
1461
+ }
1455
1462
  };
1456
1463
  }
1457
1464
 
@@ -1527,8 +1534,60 @@ function noTrivia(root) {
1527
1534
  return parser({ trivia: null }, root);
1528
1535
  }
1529
1536
 
1537
+ // src/combinators/token.ts
1538
+ function token(root) {
1539
+ const meta = {
1540
+ firstSet: root._meta.firstSet,
1541
+ canMatchNewline: root._meta.canMatchNewline,
1542
+ isTrivia: false
1543
+ };
1544
+ return {
1545
+ _tag: "token",
1546
+ _meta: meta,
1547
+ _def: { tag: "token", parser: root },
1548
+ parse(input, pos, ctx) {
1549
+ const savedTrivia = ctx.trivia;
1550
+ const savedKinds = ctx.triviaKindLabels;
1551
+ const savedBuf = ctx._cstBuf;
1552
+ const savedChildren = ctx._cstChildren;
1553
+ const savedLeaves = ctx._cstLeaves;
1554
+ const savedRaw = ctx._cstRawChildren;
1555
+ const savedTriviaLog = ctx._cstTriviaLog;
1556
+ const savedOuterTriviaLog = ctx._triviaLog;
1557
+ const wasCapturing = cstCaptureActive(ctx);
1558
+ ctx.trivia = void 0;
1559
+ ctx.triviaKindLabels = void 0;
1560
+ ctx._cstBuf = void 0;
1561
+ ctx._cstChildren = void 0;
1562
+ ctx._cstLeaves = void 0;
1563
+ ctx._cstRawChildren = void 0;
1564
+ ctx._cstTriviaLog = void 0;
1565
+ delete ctx._triviaLog;
1566
+ let result;
1567
+ try {
1568
+ result = root.parse(input, pos, ctx);
1569
+ } finally {
1570
+ ctx.trivia = savedTrivia;
1571
+ ctx.triviaKindLabels = savedKinds;
1572
+ ctx._cstBuf = savedBuf;
1573
+ ctx._cstChildren = savedChildren;
1574
+ ctx._cstLeaves = savedLeaves;
1575
+ ctx._cstRawChildren = savedRaw;
1576
+ ctx._cstTriviaLog = savedTriviaLog;
1577
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
1578
+ else ctx._triviaLog = savedOuterTriviaLog;
1579
+ }
1580
+ if (!result.ok) return result;
1581
+ const span = result.span;
1582
+ const value = input.slice(pos, span.end);
1583
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
1584
+ return { ok: true, value, span };
1585
+ }
1586
+ };
1587
+ }
1588
+
1530
1589
  // src/combinators/expect.ts
1531
- function staticExpected(c) {
1590
+ function deriveExpected(c) {
1532
1591
  const def = c._def;
1533
1592
  switch (def.tag) {
1534
1593
  case "literal":
@@ -1540,22 +1599,23 @@ function staticExpected(c) {
1540
1599
  case "label":
1541
1600
  return [def.label];
1542
1601
  case "choice":
1543
- return def.parsers.flatMap(staticExpected);
1602
+ return def.parsers.flatMap(deriveExpected);
1544
1603
  case "sequence":
1545
- return def.parsers.length > 0 ? staticExpected(def.parsers[0]) : [];
1604
+ return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1546
1605
  case "node":
1547
1606
  case "grammar":
1548
1607
  case "trivia":
1608
+ case "token":
1549
1609
  case "optional":
1550
1610
  case "many":
1551
1611
  case "oneOrMore":
1552
1612
  case "transform":
1553
1613
  case "not":
1554
- return staticExpected(def.parser);
1614
+ return deriveExpected(def.parser);
1555
1615
  case "lazy": {
1556
1616
  const name = c._ruleName;
1557
1617
  try {
1558
- return staticExpected(def.thunk());
1618
+ return deriveExpected(def.thunk());
1559
1619
  } catch {
1560
1620
  return name ? [name] : [];
1561
1621
  }
@@ -1565,7 +1625,7 @@ function staticExpected(c) {
1565
1625
  }
1566
1626
  }
1567
1627
  function expect(combinator, label2) {
1568
- const expected = label2 !== void 0 ? [label2] : staticExpected(combinator);
1628
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
1569
1629
  const meta = {
1570
1630
  firstSet: combinator._meta.firstSet,
1571
1631
  canMatchNewline: combinator._meta.canMatchNewline,
@@ -3225,6 +3285,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
3225
3285
  case "guard":
3226
3286
  case "not":
3227
3287
  case "trivia":
3288
+ case "token":
3228
3289
  case "scanTo":
3229
3290
  case "unknown":
3230
3291
  return false;
@@ -3286,6 +3347,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
3286
3347
  case "regex":
3287
3348
  case "keywords":
3288
3349
  case "node":
3350
+ case "token":
3289
3351
  return true;
3290
3352
  case "not":
3291
3353
  case "guard":
@@ -3564,9 +3626,9 @@ function emitSeq(def, ctx, pos) {
3564
3626
  stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
3565
3627
  return { stmts, valueVar: arrV, endVar };
3566
3628
  }
3567
- function staticExpectedArr(parsers) {
3629
+ function deriveExpectedArr(parsers) {
3568
3630
  return JSON.stringify(parsers.flatMap((p) => {
3569
- const e = staticExpected(p);
3631
+ const e = deriveExpected(p);
3570
3632
  return e.length > 0 ? e : [p._tag];
3571
3633
  }));
3572
3634
  }
@@ -3587,7 +3649,7 @@ function failsAtStart(p) {
3587
3649
  }
3588
3650
  }
3589
3651
  function armStaticExpected(ctx, p) {
3590
- return hoistExpected(ctx, staticExpectedArr([p]));
3652
+ return hoistExpected(ctx, deriveExpectedArr([p]));
3591
3653
  }
3592
3654
  function canMatchEmptyAtStart(p) {
3593
3655
  const d = p._def;
@@ -3625,7 +3687,7 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
3625
3687
  ];
3626
3688
  }
3627
3689
  function emitChoice(def, ctx, pos) {
3628
- const allExpected = staticExpectedArr(def.parsers);
3690
+ const allExpected = deriveExpectedArr(def.parsers);
3629
3691
  if (def.disjoint) {
3630
3692
  const codeV = v(ctx, "_code");
3631
3693
  const valV = v(ctx, "_chv");
@@ -3686,7 +3748,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
3686
3748
  const wordV = v(ctx, "_gw");
3687
3749
  const endV = v(ctx, "_ge");
3688
3750
  const valV = v(ctx, "_gcv");
3689
- const regexExpected = JSON.stringify(staticExpected(superParser));
3751
+ const regexExpected = JSON.stringify(deriveExpected(superParser));
3690
3752
  const stmts = [
3691
3753
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
3692
3754
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
@@ -4078,6 +4140,116 @@ function emitNot(def, ctx, pos) {
4078
4140
  endVar: pos
4079
4141
  };
4080
4142
  }
4143
+ function escapeTokenLiteral(value) {
4144
+ return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
4145
+ }
4146
+ function regexMatchesEmpty(source, flags) {
4147
+ try {
4148
+ return new RegExp(`^(?:${source})$`, flags).test("");
4149
+ } catch {
4150
+ return true;
4151
+ }
4152
+ }
4153
+ function tokenTerminalSource(p) {
4154
+ const def = p._def;
4155
+ switch (def.tag) {
4156
+ case "literal":
4157
+ if (def.value.length === 0) return null;
4158
+ return {
4159
+ source: escapeTokenLiteral(def.value),
4160
+ caseInsensitive: def.caseInsensitive,
4161
+ rawCaseSensitive: def.caseInsensitive ? "" : def.value
4162
+ };
4163
+ case "regex": {
4164
+ if (def.flags.replace(/i/g, "") !== "") return null;
4165
+ if (regexMatchesEmpty(def.source, def.flags)) return null;
4166
+ return {
4167
+ source: `(?:${def.source})`,
4168
+ caseInsensitive: def.flags.includes("i"),
4169
+ rawCaseSensitive: def.flags.includes("i") ? "" : def.source
4170
+ };
4171
+ }
4172
+ default:
4173
+ return null;
4174
+ }
4175
+ }
4176
+ function tokenSequenceSource(p) {
4177
+ const def = p._def;
4178
+ const parts = def.tag === "sequence" ? def.parsers.map(tokenTerminalSource) : [tokenTerminalSource(p)];
4179
+ if (parts.some((part) => part === null)) return null;
4180
+ const typed = parts;
4181
+ const flags = typed.some((part) => part.caseInsensitive) ? "i" : "";
4182
+ if (flags.includes("i") && typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))) return null;
4183
+ return {
4184
+ source: typed.map((part) => part.source).join(""),
4185
+ flags,
4186
+ hasCaseSensitiveLetters: typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))
4187
+ };
4188
+ }
4189
+ function combineTokenRegexSources(parts) {
4190
+ const flags = parts.some((part) => part.flags.includes("i")) ? "i" : "";
4191
+ if (flags.includes("i") && parts.some((part) => part.flags === "" && part.hasCaseSensitiveLetters)) return null;
4192
+ return { source: parts.map((part) => part.source).join(""), flags };
4193
+ }
4194
+ function tokenNullableRegex(def) {
4195
+ const inner = def.parser._def;
4196
+ if (inner.tag === "many") {
4197
+ const seq = tokenSequenceSource(inner.parser);
4198
+ if (!seq) return null;
4199
+ return { tag: "regex", source: `(?:${seq.source})*`, flags: seq.flags };
4200
+ }
4201
+ if (inner.tag === "optional") {
4202
+ const seq = tokenSequenceSource(inner.parser);
4203
+ if (!seq) return null;
4204
+ return { tag: "regex", source: `(?:${seq.source})?`, flags: seq.flags };
4205
+ }
4206
+ if (inner.tag === "sepBy") {
4207
+ const item = tokenSequenceSource(inner.parser);
4208
+ const sep = tokenSequenceSource(inner.separator);
4209
+ if (!item || !sep) return null;
4210
+ const combined = combineTokenRegexSources([item, sep]);
4211
+ if (!combined) return null;
4212
+ return { tag: "regex", source: `(?:${item.source}(?:${sep.source}${item.source})*)?`, flags: combined.flags };
4213
+ }
4214
+ return null;
4215
+ }
4216
+ function emitToken(def, ctx, pos) {
4217
+ const lowered = tokenNullableRegex(def);
4218
+ if (lowered) return emitRegex(lowered, ctx, pos);
4219
+ const savedTrivia = ctx.activeTrivia;
4220
+ const savedKindLabels = ctx.triviaKindLabels;
4221
+ ctx.activeTrivia = void 0;
4222
+ ctx.triviaKindLabels = void 0;
4223
+ const inner = emitFallible(def.parser, ctx, pos);
4224
+ ctx.activeTrivia = savedTrivia;
4225
+ ctx.triviaKindLabels = savedKindLabels;
4226
+ const i = ind(ctx);
4227
+ const sc = v(ctx, "_tokCh");
4228
+ const sl = v(ctx, "_tokLv");
4229
+ const sr = v(ctx, "_tokRaw");
4230
+ const sv = v(ctx, "_tokTr");
4231
+ const sk = v(ctx, "_tokKinds");
4232
+ const stl = v(ctx, "_tokTl");
4233
+ const sol = v(ctx, "_tokLog");
4234
+ const sb = v(ctx, "_tokBuf");
4235
+ const valV = v(ctx, "_tok");
4236
+ return {
4237
+ stmts: [
4238
+ `${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`,
4239
+ `${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`,
4240
+ `${i}try {`,
4241
+ ...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
4242
+ `${i}} finally {`,
4243
+ `${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}`,
4244
+ `${i}}`,
4245
+ ...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
4246
+ `${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
4247
+ ...emitLeafCapture(ctx, valV, pos, inner.endVar)
4248
+ ],
4249
+ valueVar: valV,
4250
+ endVar: inner.endVar
4251
+ };
4252
+ }
4081
4253
  function emitNode(def, ctx, pos) {
4082
4254
  const structural = def.build === void 0;
4083
4255
  const mkType = structural ? null : analyzeMkInlineBuild(def);
@@ -4197,7 +4369,7 @@ function emitRecover(def, ctx, pos) {
4197
4369
  `${ind0} if (${sentOk}) break`,
4198
4370
  `${ind0} ${scanV}++`,
4199
4371
  `${ind0} }`,
4200
- `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(staticExpected(def.parser))} }`,
4372
+ `${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
4201
4373
  `${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
4202
4374
  `${ind0} ${valVar} = ${errV}`,
4203
4375
  `${ind0} ${endVar} = ${scanV}`,
@@ -4327,8 +4499,19 @@ function emitDispatch(p, ctx, pos) {
4327
4499
  return emitLazy(p, def, ctx, pos);
4328
4500
  case "trivia":
4329
4501
  return emit(def.parser, ctx, pos);
4330
- case "label":
4331
- return emit(def.parser, ctx, pos);
4502
+ case "token":
4503
+ return emitToken(def, ctx, pos);
4504
+ case "label": {
4505
+ const inner = emitFallible(def.parser, ctx, pos);
4506
+ return {
4507
+ stmts: [
4508
+ ...inner.stmts,
4509
+ ...emitIfFail(ctx, `!${inner.okVar}`, failBody(ctx, JSON.stringify(def.label), "_ctx._fe"))
4510
+ ],
4511
+ valueVar: inner.valVar,
4512
+ endVar: inner.endVar
4513
+ };
4514
+ }
4332
4515
  case "grammar": {
4333
4516
  const savedTrivia = ctx.activeTrivia;
4334
4517
  const savedKindLabels = ctx.triviaKindLabels;
@@ -4428,6 +4611,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
4428
4611
  }
4429
4612
  case "grammar":
4430
4613
  case "trivia":
4614
+ case "token":
4431
4615
  case "label":
4432
4616
  case "optional":
4433
4617
  case "many":
@@ -4463,6 +4647,7 @@ function childrenOf(def) {
4463
4647
  case "optional":
4464
4648
  case "transform":
4465
4649
  case "trivia":
4650
+ case "token":
4466
4651
  case "label":
4467
4652
  case "grammar":
4468
4653
  case "not":
@@ -5046,7 +5231,7 @@ function balanced(open, close, options = {}) {
5046
5231
  const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
5047
5232
  const inner = many(choice(self, ...skips, content));
5048
5233
  const combi = transform(
5049
- sequence(literal(open), inner, expect(literal(close), close)),
5234
+ sequence(literal(open), inner, expect(literal(close))),
5050
5235
  // parts: strings (content/self) or arrays (a sequence-shaped skip) or a
5051
5236
  // ParseError (recovered close). `c` is the close string or a ParseError.
5052
5237
  ([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
@@ -5083,6 +5268,7 @@ function childrenOf2(def) {
5083
5268
  case "optional":
5084
5269
  case "transform":
5085
5270
  case "trivia":
5271
+ case "token":
5086
5272
  case "label":
5087
5273
  case "not":
5088
5274
  case "node":
@@ -5164,6 +5350,7 @@ function evalRuleMapIR(ir) {
5164
5350
  "node",
5165
5351
  "parser",
5166
5352
  "scanTo",
5353
+ "token",
5167
5354
  "transform",
5168
5355
  "skip",
5169
5356
  "trivia",
@@ -5189,6 +5376,7 @@ function evalRuleMapIR(ir) {
5189
5376
  node,
5190
5377
  parser,
5191
5378
  scanTo,
5379
+ token,
5192
5380
  transform,
5193
5381
  skip,
5194
5382
  trivia,
@@ -5322,6 +5510,8 @@ ${body}
5322
5510
  return `not(${kid(def.parser)})`;
5323
5511
  case "trivia":
5324
5512
  return `trivia(${kid(def.parser)})`;
5513
+ case "token":
5514
+ return `token(${kid(def.parser)})`;
5325
5515
  case "label":
5326
5516
  return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
5327
5517
  case "expect":
@@ -5444,6 +5634,7 @@ var SUPPORTED = {
5444
5634
  trivia: (...a) => trivia(a[0]),
5445
5635
  label: (...a) => label(a[0], a[1]),
5446
5636
  noTrivia: (...a) => noTrivia(a[0]),
5637
+ token: (...a) => token(a[0]),
5447
5638
  expect: (...a) => expect(a[0], a[1])
5448
5639
  };
5449
5640
  function isScopeEntry(v2) {