parseman 0.58.3 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/analysis/diagnostics.js +141 -93
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +143 -94
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/dispatch.d.ts.map +1 -1
  6. package/dist/combinators/field-trivia.d.ts.map +1 -1
  7. package/dist/combinators/keywords.d.ts.map +1 -1
  8. package/dist/combinators/literal.d.ts.map +1 -1
  9. package/dist/combinators/node.d.ts.map +1 -1
  10. package/dist/combinators/regex.d.ts.map +1 -1
  11. package/dist/combinators/scanTo.d.ts.map +1 -1
  12. package/dist/combinators/token.d.ts.map +1 -1
  13. package/dist/compiler/linker.d.ts.map +1 -1
  14. package/dist/compiler/token-capability.js.map +1 -1
  15. package/dist/cst/capture-buffer.d.ts.map +1 -1
  16. package/dist/cst/plain.js +69 -0
  17. package/dist/cst/plain.js.map +6 -0
  18. package/dist/index.js +144 -98
  19. package/dist/index.js.map +3 -3
  20. package/dist/language-service/index.js +19 -2
  21. package/dist/language-service/index.js.map +2 -2
  22. package/dist/line-index.d.ts +13 -0
  23. package/dist/line-index.d.ts.map +1 -1
  24. package/dist/plugin/entry-supercompiler.d.ts.map +1 -1
  25. package/dist/plugin/index.js +146 -100
  26. package/dist/plugin/index.js.map +3 -3
  27. package/dist/recovery/scan.d.ts.map +1 -1
  28. package/dist/run/index.js +4 -1
  29. package/dist/run/index.js.map +2 -2
  30. package/dist/spec/index.js +18 -1
  31. package/dist/spec/index.js.map +2 -2
  32. package/dist/table/assemble.d.ts.map +1 -1
  33. package/dist/table/emit-assembly.d.ts +1 -1
  34. package/dist/table/emit-assembly.d.ts.map +1 -1
  35. package/dist/table/emit.d.ts +6 -0
  36. package/dist/table/emit.d.ts.map +1 -1
  37. package/dist/table/index.js +124 -89
  38. package/dist/table/index.js.map +3 -3
  39. package/dist/table/run-support.d.ts.map +1 -1
  40. package/dist/version.d.ts +1 -1
  41. package/package.json +2 -1
  42. package/src/combinators/dispatch.ts +2 -1
  43. package/src/combinators/field-trivia.ts +6 -5
  44. package/src/combinators/keywords.ts +3 -2
  45. package/src/combinators/literal.ts +5 -4
  46. package/src/combinators/node.ts +3 -1
  47. package/src/combinators/regex.ts +5 -4
  48. package/src/combinators/scanTo.ts +2 -1
  49. package/src/combinators/token.ts +3 -6
  50. package/src/compiler/linker.ts +4 -2
  51. package/src/cst/capture-buffer.ts +13 -5
  52. package/src/cst/plain.d.ts +35 -0
  53. package/src/cst/plain.js +74 -0
  54. package/src/line-index.ts +37 -0
  55. package/src/plugin/entry-supercompiler.ts +3 -2
  56. package/src/recovery/scan.ts +2 -1
  57. package/src/table/assemble.ts +33 -35
  58. package/src/table/emit-assembly.ts +27 -24
  59. package/src/table/emit.ts +9 -1
  60. package/src/table/run-support.ts +4 -7
  61. package/src/version.ts +1 -1
@@ -83,6 +83,7 @@ import {
83
83
  demoteCapturedToRaw, pushCstChild, pushCstLeaf,
84
84
  type CstCaptureBuf,
85
85
  } from '../cst/capture-buffer.ts'
86
+ import { PlainBuf, PlainField, PlainLeaf, PlainNode, PlainSpan } from '../cst/plain.js'
86
87
  import {
87
88
  OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_SOURCE_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
88
89
  OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
@@ -197,7 +198,6 @@ function linkMatcher(m: readonly [number, string, string, number]): (key: string
197
198
  }
198
199
  }
199
200
 
200
- type Leaf = { _tag: 'leaf'; value: string; span: { start: number; end: number } }
201
201
 
202
202
  /**
203
203
  * The `COV` slot's value when a parse installs no collector. ONE shared function
@@ -542,7 +542,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
542
542
  const CLEAN = REC ? (): boolean => false : failCleanAnalysis(code)
543
543
 
544
544
  function pushLeaf(ctx: ParseContext, value: string, s: number, e: number): void {
545
- const lf: Leaf = { _tag: 'leaf', value, span: { start: s, end: e } }
545
+ const lf = new PlainLeaf(value, new PlainSpan(s, e))
546
546
  pushCstLeaf(ctx, lf)
547
547
  }
548
548
 
@@ -592,7 +592,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
592
592
  ctx.captureTrivia = sCap
593
593
  if (value === FAIL) return FAIL
594
594
  const end = EC.e
595
- const span = { start: pos, end }
595
+ const span = new PlainSpan(pos, end)
596
596
  const node = build(kids, undefined, span, rawKids, EMPTY_TL, undefined)
597
597
  if (sBuf !== undefined || sCh !== undefined) {
598
598
  pushCstChild(ctx, node, rawEntry(node, input, pos, end))
@@ -646,7 +646,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
646
646
  ctx.captureTrivia = sCap
647
647
  if (value === FAIL) return FAIL
648
648
  const end = EC.e
649
- const node = build(captured, undefined, { start: pos, end }, EMPTY_CH, EMPTY_TL, undefined)
649
+ const node = build(captured, undefined, new PlainSpan(pos, end), EMPTY_CH, EMPTY_TL, undefined)
650
650
  if (sBuf !== undefined || sCh !== undefined) {
651
651
  pushCstChild(ctx, node, sBuf !== undefined || sRaw !== undefined ? rawEntry(node, input, pos, end) : undefined)
652
652
  }
@@ -684,7 +684,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
684
684
  ctx.captureTrivia = sCap
685
685
  if (value === FAIL) return FAIL
686
686
  const end = EC.e
687
- const node = build(captured, fieldMap, { start: pos, end }, EMPTY_CH, EMPTY_TL, undefined)
687
+ const node = build(captured, fieldMap, new PlainSpan(pos, end), EMPTY_CH, EMPTY_TL, undefined)
688
688
  if (sBuf !== undefined || sCh !== undefined) {
689
689
  pushCstChild(ctx, node, sBuf !== undefined || sRaw !== undefined ? rawEntry(node, input, pos, end) : undefined)
690
690
  }
@@ -722,7 +722,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
722
722
  ctx.captureTrivia = sCap
723
723
  if (value === FAIL) return FAIL
724
724
  const end = EC.e
725
- const span = { start: pos, end }
725
+ const span = new PlainSpan(pos, end)
726
726
  const node = kids.length === 1
727
727
  ? kids[0]
728
728
  : build(kids, undefined, span, rawKids, EMPTY_TL, undefined)
@@ -764,7 +764,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
764
764
  const end = EC.e
765
765
  const node = captured.length === 1
766
766
  ? captured[0]
767
- : build(captured, undefined, { start: pos, end }, EMPTY_CH, EMPTY_TL, undefined)
767
+ : build(captured, undefined, new PlainSpan(pos, end), EMPTY_CH, EMPTY_TL, undefined)
768
768
  if (sBuf !== undefined || sCh !== undefined) {
769
769
  pushCstChild(ctx, node, sBuf !== undefined || sRaw !== undefined ? rawEntry(node, input, pos, end) : undefined)
770
770
  }
@@ -1380,7 +1380,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1380
1380
  return (input, pos, selEnd, key, ctx, need, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot) => {
1381
1381
  const savedRouted = ctx._routed
1382
1382
  if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
1383
- ctx._routed = { value: key, span: { start: pos, end: selEnd } }
1383
+ ctx._routed = { value: key, span: new PlainSpan(pos, selEnd) }
1384
1384
  let v: unknown
1385
1385
  try {
1386
1386
  v = child(input, pos, ctx)
@@ -1912,7 +1912,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1912
1912
  // table engines. Do not use the incoming ctx bit: a grammar scope can
1913
1913
  // declare tracking even when the outer run context begins untracked.
1914
1914
  const expectSpan = (ctx: ParseContext, pos: number) =>
1915
- prog.lines === 1 ? spanLines(ctx, pos, pos) : { start: pos, end: pos }
1915
+ prog.lines === 1 ? spanLines(ctx, pos, pos) : new PlainSpan(pos, pos)
1916
1916
  // TOLERANT `expect()` EMBEDS ITS ERROR IN THE TREE, not only in the flat
1917
1917
  // `_errors` side-channel (`combinators/expect.ts:150`, and codegen's
1918
1918
  // `_ctx._rec.capture` at codegen.ts:4470) — so a tree walk finds every
@@ -1959,7 +1959,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1959
1959
  return (input, pos, ctx) => {
1960
1960
  const v = child(input, pos, ctx)
1961
1961
  if (v === FAIL) return FAIL
1962
- ctx._fields?.push({ name, value: v, span: { start: pos, end: EC.e } })
1962
+ ctx._fields?.push(new PlainField(name, v, new PlainSpan(pos, EC.e)))
1963
1963
  return v
1964
1964
  }
1965
1965
  }
@@ -1984,7 +1984,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
1984
1984
  return (input, pos, ctx) => {
1985
1985
  const v = child(input, pos, ctx)
1986
1986
  if (v === FAIL) return FAIL
1987
- return fn(v, { start: pos, end: EC.e })
1987
+ return fn(v, new PlainSpan(pos, EC.e))
1988
1988
  }
1989
1989
  }
1990
1990
 
@@ -2107,7 +2107,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2107
2107
  ctx._fe = pos; ctx._fx = ROUTED_FX
2108
2108
  return FAIL
2109
2109
  }
2110
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: 'leaf', value: item.value, span: item.span })
2110
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, new PlainLeaf(item.value, item.span))
2111
2111
  EC.e = item.span.end
2112
2112
  return item.value
2113
2113
  }
@@ -2295,7 +2295,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2295
2295
  if (v === FAIL) return FAIL
2296
2296
  const end = EC.e
2297
2297
  const value = input.slice(pos, end)
2298
- if (wasCapturing) pushCstLeaf(ctx, { _tag: 'leaf', value, span: { start: pos, end } })
2298
+ if (wasCapturing) pushCstLeaf(ctx, new PlainLeaf(value, new PlainSpan(pos, end)))
2299
2299
  EC.e = end
2300
2300
  return value
2301
2301
  }
@@ -2330,7 +2330,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2330
2330
  if (ctx._probe !== undefined) failAt(ctx, suffixExpected, end)
2331
2331
  }
2332
2332
  const value = input.slice(pos, end)
2333
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: 'leaf', value, span: { start: pos, end } })
2333
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, new PlainLeaf(value, new PlainSpan(pos, end)))
2334
2334
  EC.e = end
2335
2335
  return value
2336
2336
  }
@@ -2373,7 +2373,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2373
2373
  }
2374
2374
  if (end < 0) return FAIL
2375
2375
  const value = input.slice(pos, end)
2376
- if (wasCapturing) pushCstLeaf(ctx, { _tag: 'leaf', value, span: { start: pos, end } })
2376
+ if (wasCapturing) pushCstLeaf(ctx, new PlainLeaf(value, new PlainSpan(pos, end)))
2377
2377
  EC.e = end
2378
2378
  return value
2379
2379
  }
@@ -2382,7 +2382,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2382
2382
  const end = run(input, pos, ctx)
2383
2383
  if (end < 0) return FAIL
2384
2384
  const value = input.slice(pos, end)
2385
- if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: 'leaf', value, span: { start: pos, end } })
2385
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, new PlainLeaf(value, new PlainSpan(pos, end)))
2386
2386
  EC.e = end
2387
2387
  return value
2388
2388
  }
@@ -2418,12 +2418,8 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2418
2418
  }
2419
2419
  if (v === FAIL) return FAIL
2420
2420
  const end = EC.e
2421
- const out = fn(v, { start: pos, end })
2422
- if (wasCapturing) pushCstLeaf(ctx, {
2423
- _tag: 'leaf',
2424
- value: op === OP_SOURCE_LEAF && hostCst ? input.slice(pos, end) : out,
2425
- span: { start: pos, end },
2426
- })
2421
+ const out = fn(v, new PlainSpan(pos, end))
2422
+ if (wasCapturing) pushCstLeaf(ctx, new PlainLeaf(op === OP_SOURCE_LEAF && hostCst ? input.slice(pos, end) : out, new PlainSpan(pos, end)))
2427
2423
  EC.e = end
2428
2424
  return out
2429
2425
  }
@@ -2605,7 +2601,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2605
2601
  const cur = runSyncTerms(input, pos, ctx, values)
2606
2602
  if (cur < 0) return FAIL
2607
2603
  EC.e = cur
2608
- return projection >= 0 ? values[projection] : fn!(values, { start: pos, end: cur })
2604
+ return projection >= 0 ? values[projection] : fn!(values, new PlainSpan(pos, cur))
2609
2605
  }
2610
2606
  }
2611
2607
  if (wantValues) {
@@ -2700,7 +2696,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2700
2696
  const cur = runAdjTerms(input, pos, ctx, values)
2701
2697
  if (cur < 0) return FAIL
2702
2698
  EC.e = cur
2703
- return projection >= 0 ? values[projection] : fn!(values, { start: pos, end: cur })
2699
+ return projection >= 0 ? values[projection] : fn!(values, new PlainSpan(pos, cur))
2704
2700
  }
2705
2701
  }
2706
2702
  if (wantValues) {
@@ -2743,7 +2739,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2743
2739
  return (input, pos, ctx) => {
2744
2740
  const v = k0(input, pos, ctx)
2745
2741
  if (v === FAIL) return FAIL
2746
- return projection === 0 ? v : fn!([v], { start: pos, end: EC.e })
2742
+ return projection === 0 ? v : fn!([v], new PlainSpan(pos, EC.e))
2747
2743
  }
2748
2744
  }
2749
2745
  if (wantValues) {
@@ -2771,7 +2767,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2771
2767
  EC.e = cur
2772
2768
  return projection === 0 ? v0
2773
2769
  : projection === 1 ? TERMV
2774
- : fn!([v0, TERMV], { start: pos, end: cur })
2770
+ : fn!([v0, TERMV], new PlainSpan(pos, cur))
2775
2771
  }
2776
2772
  }
2777
2773
  if (wantValues) {
@@ -2809,7 +2805,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2809
2805
  return projection === 0 ? v0
2810
2806
  : projection === 1 ? v1
2811
2807
  : projection === 2 ? TERMV
2812
- : fn!([v0, v1, TERMV], { start: pos, end: cur })
2808
+ : fn!([v0, v1, TERMV], new PlainSpan(pos, cur))
2813
2809
  }
2814
2810
  }
2815
2811
  if (wantValues) {
@@ -2914,7 +2910,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2914
2910
  const cur = runDirectTerms(input, pos, ctx, values)
2915
2911
  if (cur < 0) return FAIL
2916
2912
  EC.e = cur
2917
- return projection >= 0 ? values[projection] : fn!(values, { start: pos, end: cur })
2913
+ return projection >= 0 ? values[projection] : fn!(values, new PlainSpan(pos, cur))
2918
2914
  }
2919
2915
  }
2920
2916
  if (wantValues) {
@@ -3781,10 +3777,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3781
3777
  return FAIL
3782
3778
  }
3783
3779
  const value = regexValue ? input.slice(pos, end) : spec as string
3784
- const leaf = { _tag: 'leaf', value, span: { start: pos, end } }
3780
+ const leaf = new PlainLeaf(value, new PlainSpan(pos, end))
3785
3781
  const kids = [leaf]
3786
3782
  const rawKids = [leaf]
3787
- const span = { start: pos, end }
3783
+ const span = new PlainSpan(pos, end)
3788
3784
  EC.e = end
3789
3785
  const nd = build(kids, undefined, span, rawKids, EMPTY_TL, undefined)
3790
3786
  if (ctx._cstBuf !== undefined || ctx._cstChildren !== undefined) {
@@ -3897,8 +3893,8 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3897
3893
  const sCap = ctx.captureTrivia
3898
3894
  const sBuf = ctx._cstBuf
3899
3895
  const buf: CstCaptureBuf = rawOnly
3900
- ? { rawOnly: true }
3901
- : omitsRaw ? { noRaw: true, rawLen: 0 } : {}
3896
+ ? new PlainBuf(true, undefined, 0)
3897
+ : omitsRaw ? new PlainBuf(undefined, true, 0) : new PlainBuf(undefined, undefined, 0)
3902
3898
  ctx._cstBuf = buf
3903
3899
  // `begin` sets this true and the caller immediately cleared it when the
3904
3900
  // node does not capture wide. Net: the flag IS `captureWide`, a const.
@@ -3929,7 +3925,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3929
3925
  ctx.captureTrivia = sCap
3930
3926
  if (v === FAIL) return FAIL
3931
3927
  const end = EC.e
3932
- const span = tracked ? spanLines(ctx, pos, end) : { start: pos, end }
3928
+ const span = tracked ? spanLines(ctx, pos, end) : new PlainSpan(pos, end)
3933
3929
  const st = readsState ? ctx.state : undefined
3934
3930
 
3935
3931
  let nd: unknown
@@ -3962,7 +3958,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
3962
3958
  } else if (host !== undefined) {
3963
3959
  nd = host(type, hostKids, fieldMap, span, rawKids, tlog, st, tags)
3964
3960
  } else {
3965
- nd = { _tag: 'node', type, span, state: st ?? null, children: kids }
3961
+ nd = new PlainNode(type, span, st ?? null, kids === EMPTY_CH ? kids : [...kids])
3966
3962
  }
3967
3963
  // A ROOT NODE IS NOT A CHILD. `node()` pushes only when it was entered
3968
3964
  // from an enclosing collector — `saved.buf !== undefined || saved.ch !==
@@ -4003,7 +3999,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
4003
3999
  const at = fe === undefined || fe < 0 ? pos : fe
4004
4000
  return { ok: false, expected: (ctx._fx ?? EMPTY_FX) as string[], span: { start: at, end: at } }
4005
4001
  }
4006
- return { ok: true, value: v, span: { start: pos, end: EC.e } }
4002
+ return { ok: true, value: v, span: new PlainSpan(pos, EC.e) }
4007
4003
  },
4008
4004
  }
4009
4005
  }
@@ -4119,6 +4115,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
4119
4115
  scalarRecognizers, commitTriviaScan, scanTriviaCompact, t.lex, adjacencyHolds, t.lexPrograms,
4120
4116
  LEAD, triviaFieldCapture, skipDeferredTrivia,
4121
4117
  collapseEmpty,
4118
+ PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf,
4122
4119
  )
4123
4120
  emitReached = new Set(pre.reached)
4124
4121
  if (emitted.ext !== undefined) HYBRID = emitted
@@ -4203,6 +4200,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
4203
4200
  scalarRecognizers, commitTriviaScan, scanTriviaCompact, t.lex, adjacencyHolds, t.lexPrograms,
4204
4201
  LEAD, triviaFieldCapture, skipDeferredTrivia,
4205
4202
  collapseEmpty,
4203
+ PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf,
4206
4204
  )
4207
4205
  emitReached = em.reached
4208
4206
  } catch (e) {
@@ -142,6 +142,9 @@ export const EMITTED_PARAMS = [
142
142
  // Appended for the pass-through collapse (`run-support.ts`); old factories
143
143
  // ignore it.
144
144
  'collapseEmpty',
145
+ // Appended for constructor-built tree objects (`cst/plain.d.ts`): a `new` call has
146
+ // no allocation site, so V8 cannot pretenure them. Old factories ignore them.
147
+ '_SP', '_LF', '_ND', '_FC', '_BUF',
145
148
  ] as const
146
149
 
147
150
  /**
@@ -180,9 +183,9 @@ if(s!==null)return skipTriviaScanned(s,input,cur,ctx)
180
183
  if(needsDeferredTriviaCommit(ctx))return skipDeferredTrivia(input,cur,ctx)
181
184
  return advanceTrivia(input,cur,ctx)
182
185
  }
183
- function _pushLeaf(ctx,value,s,e){pushCstLeaf(ctx,{_tag:'leaf',value,span:{start:s,end:e}})}
186
+ function _pushLeaf(ctx,value,s,e){pushCstLeaf(ctx,new _LF(value,new _SP(s,e)))}
184
187
  function _pushLeafBuf(ctx,value,s,e){
185
- const l={_tag:'leaf',value,span:{start:s,end:e}}
188
+ const l=new _LF(value,new _SP(s,e))
186
189
  const b=ctx._cstBuf
187
190
  if(b.ch!==undefined)b.ch.push(l)
188
191
  else if(b.single!==undefined){b.ch=[b.single,l];b.single=undefined}
@@ -242,7 +245,7 @@ if(ctx._rootTriviaLog!==undefined&&ctx._rootTriviaLog.length!==rt)ctx._rootTrivi
242
245
  /** Printed only into assemblies that open a count-only raw buffer. */
243
246
  const NO_RAW_RUNTIME_PRELUDE = `
244
247
  function _pushLeafNoRawBuf(ctx,value,s,e){
245
- const l={_tag:'leaf',value,span:{start:s,end:e}}
248
+ const l=new _LF(value,new _SP(s,e))
246
249
  const b=ctx._cstBuf
247
250
  if(b.ch!==undefined)b.ch.push(l)
248
251
  else if(b.single!==undefined){b.ch=[b.single,l];b.single=undefined}
@@ -1431,7 +1434,7 @@ try{return ${child}(input,pos,ctx)}finally{ctx.state=saved}
1431
1434
  return `${head}
1432
1435
  const v=${child}(input,pos,ctx)
1433
1436
  if(v===FAIL)return FAIL
1434
- return ${fn}(v,{start:pos,end:EC.e})
1437
+ return ${fn}(v,new _SP(pos,EC.e))
1435
1438
  }`
1436
1439
  }
1437
1440
 
@@ -1461,7 +1464,7 @@ return v
1461
1464
  const v=${child}(input,pos,ctx)
1462
1465
  if(v===FAIL)return FAIL
1463
1466
  const f=ctx._fields
1464
- if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
1467
+ if(f!==undefined)f.push(new _FC(${name},v,new _SP(pos,EC.e)))
1465
1468
  return v
1466
1469
  }`
1467
1470
  }
@@ -1497,7 +1500,7 @@ return v
1497
1500
  return `${head}
1498
1501
  const v=${child}(input,pos,ctx)
1499
1502
  if(v!==FAIL)return v
1500
- const err={_tag:'parseError',span:${prog.lines === 1 ? 'spanLines(ctx,pos,pos)' : '{start:pos,end:pos}'},expected:${xf}}
1503
+ const err={_tag:'parseError',span:${prog.lines === 1 ? 'spanLines(ctx,pos,pos)' : 'new _SP(pos,pos)'},expected:${xf}}
1501
1504
  const es=ctx._errors
1502
1505
  if(es!==undefined)es.push(err)
1503
1506
  ${REC ? 'if(ctx._tolerant===true)captureError(ctx,err)\n' : ''}ctx._fc=false
@@ -1512,7 +1515,7 @@ return err
1512
1515
  // The SPAN is the routed item's own object, not a copy — `assemble.ts`
1513
1516
  // hands the same one to the leaf, and a fresh `{start,end}` here would
1514
1517
  // be a different tree for any consumer comparing by identity.
1515
- const push = `pushCstLeaf(ctx,{_tag:'leaf',value:it.value,span:it.span})`
1518
+ const push = `pushCstLeaf(ctx,new _LF(it.value,it.span))`
1516
1519
  return `${head}
1517
1520
  const it=ctx._routed
1518
1521
  if(it===undefined||pos!==it.span.start){
@@ -1621,8 +1624,8 @@ ctx._triviaLog=sOtl
1621
1624
  }
1622
1625
  if(v===FAIL)return FAIL
1623
1626
  const e=EC.e
1624
- const out=${isToken ? 'input.slice(pos,e)' : `${fn}(v,{start:pos,end:e})`}
1625
- if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:${capturesSource ? 'input.slice(pos,e)' : 'out'},span:{start:pos,end:e}})
1627
+ const out=${isToken ? 'input.slice(pos,e)' : `${fn}(v,new _SP(pos,e))`}
1628
+ if(wasCap)pushCstLeaf(ctx,new _LF(${capturesSource ? 'input.slice(pos,e)' : 'out'},new _SP(pos,e)))
1626
1629
  EC.e=e
1627
1630
  return out
1628
1631
  }`
@@ -1647,7 +1650,7 @@ ${hasSuffix && (lineFlags & 2) !== 0 ? 'if(sm)_trackLines(ctx,input,e)' : ''}
1647
1650
  ${hasSuffix ? `if(!sm){ctx._fe=e;ctx._fx=${suffixExpected};if(ctx._probe!==undefined)failAt(ctx,${suffixExpected},e)}` : ''}
1648
1651
  const v=${pending ? 'tp?_pfTokValue:' : ''}input.slice(pos,e)
1649
1652
  ${pending ? 'if(tp){_pfTokBody=-1;_pfTokValue=undefined}' : ''}
1650
- if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
1653
+ if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,new _LF(v,new _SP(pos,e)))
1651
1654
  EC.e=e
1652
1655
  return v
1653
1656
  }`
@@ -1687,7 +1690,7 @@ ctx._rootTriviaLog=sRtl
1687
1690
  }
1688
1691
  if(e<0)return FAIL
1689
1692
  const v=input.slice(pos,e)
1690
- if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
1693
+ if(wasCap)pushCstLeaf(ctx,new _LF(v,new _SP(pos,e)))
1691
1694
  EC.e=e
1692
1695
  return v
1693
1696
  }`
@@ -1695,7 +1698,7 @@ return v
1695
1698
  const e=${run}(input,pos,ctx)
1696
1699
  if(e<0)return FAIL
1697
1700
  const v=input.slice(pos,e)
1698
- if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
1701
+ if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,new _LF(v,new _SP(pos,e)))
1699
1702
  EC.e=e
1700
1703
  return v
1701
1704
  }`
@@ -1837,7 +1840,7 @@ return v
1837
1840
  const close = (): string => REC ? `${parts.join('\n')}\n}finally{ctx._sync=${sy}}\n}` : `${parts.join('\n')}\n}`
1838
1841
  if (n === 1) {
1839
1842
  parts.push(fused
1840
- ? projection === 0 ? 'return v0' : `return ${fn}([v0],{start:pos,end:EC.e})`
1843
+ ? projection === 0 ? 'return v0' : `return ${fn}([v0],new _SP(pos,EC.e))`
1841
1844
  : wantValues ? 'return [v0]' : 'return undefined')
1842
1845
  return close()
1843
1846
  }
@@ -1870,7 +1873,7 @@ return v
1870
1873
  }
1871
1874
  parts.push('EC.e=cur')
1872
1875
  parts.push(fused
1873
- ? projection >= 0 ? `return ${names[projection]}` : `return ${fn}([${names.join(',')}],{start:pos,end:cur})`
1876
+ ? projection >= 0 ? `return ${names[projection]}` : `return ${fn}([${names.join(',')}],new _SP(pos,cur))`
1874
1877
  : wantValues ? `return [${names.join(',')}]` : 'return undefined')
1875
1878
  return close()
1876
1879
  }
@@ -2210,7 +2213,7 @@ return FAIL
2210
2213
  const routedCall = (target: string): string => `{const savedRouted=ctx._routed
2211
2214
  ${emitRollback(m1, L.buf, L.raw, sinks)}
2212
2215
  ${emitMark(m2, L.buf, L.raw, sinks, false)}
2213
- ctx._routed={value:key,span:{start:pos,end:selEnd}}
2216
+ ctx._routed={value:key,span:new _SP(pos,selEnd)}
2214
2217
  try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
2215
2218
  break}`
2216
2219
  const plainCall = (target: string): string => `v=${target}(input,selEnd,ctx);break`
@@ -2479,8 +2482,8 @@ return out
2479
2482
  const end=${recognize}(input,pos)
2480
2483
  if(end<0){ctx._fe=pos;ctx._fx=${xf};return FAIL}
2481
2484
  const value=${value}
2482
- const leaf={_tag:'leaf',value,span:{start:pos,end}}
2483
- const kids=[leaf],rawKids=[leaf],span={start:pos,end}
2485
+ const leaf=new _LF(value,new _SP(pos,end))
2486
+ const kids=[leaf],rawKids=[leaf],span=new _SP(pos,end)
2484
2487
  EC.e=end
2485
2488
  const nd=${build}(kids,undefined,span,rawKids,EMPTY_TL,undefined)
2486
2489
  ${L.buf && L.raw === RAW_OMIT
@@ -2608,8 +2611,8 @@ ctx.captureTrivia=sCap
2608
2611
  if(v===FAIL)return FAIL
2609
2612
  const end=EC.e
2610
2613
  ${collapseChildren
2611
- ? `const nd=captured.length===1?captured[0]:${build}(captured,undefined,{start:pos,end},EMPTY_CH,EMPTY_TL,undefined)`
2612
- : `const nd=${build}(captured,${fields ? 'fieldMap' : 'undefined'},{start:pos,end},EMPTY_CH,EMPTY_TL,undefined)`}
2614
+ ? `const nd=captured.length===1?captured[0]:${build}(captured,undefined,new _SP(pos,end),EMPTY_CH,EMPTY_TL,undefined)`
2615
+ : `const nd=${build}(captured,${fields ? 'fieldMap' : 'undefined'},new _SP(pos,end),EMPTY_CH,EMPTY_TL,undefined)`}
2613
2616
  ${publish}
2614
2617
  EC.e=end
2615
2618
  return nd
@@ -2639,26 +2642,26 @@ return nd
2639
2642
  const direct = `${build}(kids,fieldMap,span,rawKids,${captureWide ? 'tlog' : 'EMPTY_TL'},st)`
2640
2643
  value = hostCst ? `nd=_pfHost!==undefined?${hostCall}:${direct}` : `nd=${direct}`
2641
2644
  } else {
2642
- value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):{_tag:'node',type:${ty},span,state:st??null,children:kids}`
2645
+ value = `nd=_pfHost!==undefined?_pfHost(${ty},hostKids,fieldMap,span,rawKids,tlog,st,${tags}):new _ND(${ty},span,st??null,kids===EMPTY_CH?kids:[...kids])`
2643
2646
  }
2644
2647
  // HOST COLLAPSE applies wherever the node's VALUE comes from the host —
2645
2648
  // any node under a CST host, not only the builder-less ones.
2646
2649
  const collapsible = keepChildren && (hostCst || (build === undefined && proj < 0))
2647
2650
  const openCapture = omitsRaw
2648
- ? `const buf={noRaw:true,rawLen:0}
2651
+ ? `const buf=new _BUF(undefined,true,0)
2649
2652
  ctx._cstBuf=buf
2650
2653
  ctx._cstChildren=undefined
2651
2654
  ctx._cstLeaves=undefined
2652
2655
  ctx._cstRawChildren=undefined
2653
2656
  ctx._cstTriviaLog=undefined`
2654
2657
  : keepChildren
2655
- ? `const buf={}
2658
+ ? `const buf=new _BUF(undefined,undefined,0)
2656
2659
  ctx._cstBuf=buf
2657
2660
  ctx._cstChildren=undefined
2658
2661
  ctx._cstLeaves=undefined
2659
2662
  ctx._cstRawChildren=undefined
2660
2663
  ctx._cstTriviaLog=undefined`
2661
- : `const buf={rawOnly:true}
2664
+ : `const buf=new _BUF(true,undefined,0)
2662
2665
  ctx._cstBuf=buf
2663
2666
  ctx._cstChildren=undefined
2664
2667
  ctx._cstLeaves=undefined
@@ -2701,7 +2704,7 @@ ctx._cstTriviaLog=sTl
2701
2704
  ctx.captureTrivia=sCap
2702
2705
  if(v===FAIL)return FAIL
2703
2706
  const end=EC.e
2704
- const span=${tracked ? 'spanLines(ctx,pos,end)' : '{start:pos,end}'}
2707
+ const span=${tracked ? 'spanLines(ctx,pos,end)' : 'new _SP(pos,end)'}
2705
2708
  const st=${readsState ? 'ctx.state' : 'undefined'}
2706
2709
  let nd
2707
2710
  ${unwrap ? 'if(kids.length===1)nd=unwrapChild(kids[0])\nelse ' : ''}${collapse ? 'if(kids.length===1)nd=kids[0]\nelse ' : ''}${collapsible ? `if(_pfHost!==undefined&&_pfHost._parsemanCstCollapse!==undefined&&kids.length===1&&rawKids.length===1&&_pfHost._parsemanCstCollapse(${ty},kids[0],kids,rawKids))nd=kids[0]
package/src/table/emit.ts CHANGED
@@ -3,6 +3,14 @@ import type { FoldedProgram, TableProgram } from './program.ts'
3
3
  import { resolveTable } from './program.ts'
4
4
  import { EMITTED_PARAMS, Unemittable, emitAssemblySource } from './emit-assembly.ts'
5
5
  import { cfgKey, type RunCfg } from './assemble.ts'
6
+ import { PARSEMAN_VERSION } from '../version.ts'
7
+
8
+ /**
9
+ * Opens every printed assembly factory. A runtime older than the printer passes fewer
10
+ * helpers; refuse it when the assembly is built, instead of failing partway through the
11
+ * first parse on whichever helper is reached first. Runs once per assembly.
12
+ */
13
+ export const FACTORY_ARITY_GUARD = `if(arguments.length<${EMITTED_PARAMS.length})throw new Error(${JSON.stringify(`parseman: this parser was printed by parseman ${PARSEMAN_VERSION}; upgrade the parseman runtime to at least that version`)});`
6
14
 
7
15
  /**
8
16
  * Print a program as the module a build emits.
@@ -221,7 +229,7 @@ function emitAssemblies(prog: TableProgram, cfgs: readonly AssemblyCfg[]): strin
221
229
  const plan = em.plan
222
230
  out.push('{'
223
231
  + `key:${key},`
224
- + `factory:function(${EMITTED_PARAMS.join(',')}){${em.source}\n},`
232
+ + `factory:function(${EMITTED_PARAMS.join(',')}){${FACTORY_ARITY_GUARD}${em.source}\n},`
225
233
  + 'plan:{'
226
234
  + `classes:[${plan.classes.map(r => `[${r.join(',')}]`).join(',')}],`
227
235
  + `armExpected:[${plan.armExpected.map(r => `[${r.join(',')}]`).join(',')}],`
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import type { ParseContext } from '../types.ts'
16
16
  import { popCstChild, pushCstChild } from '../cst/capture-buffer.ts'
17
+ import { PlainLeaf, PlainLineSpan, PlainSpan } from '../cst/plain.js'
17
18
 
18
19
  export type Span = { start: number; end: number }
19
20
  export type LineSpan = Span & {
@@ -37,7 +38,7 @@ export function lineCol(ctx: ParseContext, offset: number): [number, number] {
37
38
 
38
39
  export function spanLines(ctx: ParseContext, start: number, end: number): LineSpan {
39
40
  const s = lineCol(ctx, start), e = lineCol(ctx, end)
40
- return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] }
41
+ return new PlainLineSpan(start, end, s[0], s[1], e[0], e[1])
41
42
  }
42
43
 
43
44
  /**
@@ -51,11 +52,7 @@ export function rawEntry(v: unknown, input: string, s: number, e: number): unkno
51
52
  const tg = (v as { _tag?: string })._tag
52
53
  if (tg === 'node' || tg === 'leaf' || tg === 'parseError') return v
53
54
  }
54
- return {
55
- _tag: 'leaf',
56
- value: typeof v === 'string' ? v : (typeof v === 'object' && v !== null ? input.slice(s, e) : ''),
57
- span: { start: s, end: e },
58
- }
55
+ return new PlainLeaf(typeof v === 'string' ? v : (typeof v === 'object' && v !== null ? input.slice(s, e) : ''), new PlainSpan(s, e))
59
56
  }
60
57
 
61
58
  /** `input`'s code point at `pos`, or −1 at EOF. Surrogate-pair aware. */
@@ -95,7 +92,7 @@ export function collapseEmpty(
95
92
  // A frame keeps the raw entry of the child it does not count, for a reducer
96
93
  // that reads `rawChildren`.
97
94
  const raw = readsRaw ? [rawEntry(undefined, input, pos, end)] : EMPTY_KIDS
98
- const nd = build(EMPTY_KIDS, undefined, { start: pos, end }, raw, EMPTY_TRIVIA, undefined)
95
+ const nd = build(EMPTY_KIDS, undefined, new PlainSpan(pos, end), raw, EMPTY_TRIVIA, undefined)
99
96
  if (collected) pushCstChild(ctx, nd, ctx._cstBuf?.noRaw === true ? undefined : rawEntry(nd, input, pos, end))
100
97
  return nd
101
98
  }
package/src/version.ts CHANGED
@@ -13,4 +13,4 @@
13
13
  * Kept in sync with `package.json` by `test/unit/version-sync.test.ts`, which fails
14
14
  * the build if this constant drifts from the published version.
15
15
  */
16
- export const PARSEMAN_VERSION = '0.58.3'
16
+ export const PARSEMAN_VERSION = '0.59.0'