parseman 0.60.5 → 0.60.6

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.
@@ -210,6 +210,12 @@ export declare const OP_TOKEN = 29;
210
210
  * is why this restores the saved value rather than writing `false`.
211
211
  */
212
212
  export declare const OP_SCOPE_CAP = 30;
213
+ /**
214
+ * `k` of a `SCOPE_CAP` row whose `parser({ captureTrivia: true })` names no trivia.
215
+ * It raises capture and leaves the trivia the scope was entered with in force,
216
+ * where `k = -1` clears it (`trivia: null`).
217
+ */
218
+ export declare const SCOPE_INHERIT = -2;
213
219
  /**
214
220
  * `WITHCTX k c` — `withCtx(extra, c)`. `k >= 0` is `extra` in the const pool
215
221
  * (the replace form); `k < 0` is the derive form, `~k` indexing the author's
@@ -1 +1 @@
1
- {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/table/ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/table/ops.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -13,5 +13,5 @@
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 declare const PARSEMAN_VERSION = "0.60.5";
16
+ export declare const PARSEMAN_VERSION = "0.60.6";
17
17
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parseman",
3
- "version": "0.60.5",
3
+ "version": "0.60.6",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "engines": {
6
6
  "node": "^20.19.0 || >=22.13.0"
@@ -215,7 +215,7 @@ export function parser<T>(opts: ParserOptions, root: Combinator<T>): ParsemanPar
215
215
  ctx.triviaKindLabels = undefined
216
216
  } else if (scopeTrivia !== undefined) {
217
217
  ctx.trivia = scopeTrivia
218
- if (scopeLabels) ctx.triviaKindLabels = scopeLabels
218
+ ctx.triviaKindLabels = scopeLabels
219
219
  }
220
220
  if (forceCaptureTrivia || _ctx?.captureTrivia) ctx.captureTrivia = true
221
221
  // Kind-filter for per-node capture. Resolve against this scope's trivia
@@ -20,9 +20,11 @@ const MAX_DEPTH = 12
20
20
  *
21
21
  * `lazy` is deliberately false and is never followed: a reference is the
22
22
  * delegation this question is about, so following it would both loop and answer
23
- * for a different rule. `grammar` is false because it declares its own scope, so
24
- * an outer install never reaches its body. `dispatch` is false because it is a
25
- * ROUTE: its arms re-enter from the routed token and spell their own padding.
23
+ * for a different rule. A `grammar` that names or clears trivia declares its own
24
+ * scope, so an outer install never reaches its body and the answer is false; one
25
+ * that does not (`parser({ trackLines: true }, …)`, which `rules({ trackLines })`
26
+ * wraps every rule in) inherits, so it is transparent. `dispatch` is false because
27
+ * it is a ROUTE: its arms re-enter from the routed token and spell their own padding.
26
28
  *
27
29
  * Structural and pure — callers resolve it ONCE, not per parse.
28
30
  */
@@ -35,6 +37,12 @@ export function hasOwnTriviaBoundary(p: Combinator<unknown>, depth: number = MAX
35
37
  // Multi-term forms: the gaps BETWEEN terms are the ambient-trivia positions.
36
38
  case 'sequence': return d.parsers.length > 1
37
39
  case 'many': case 'oneOrMore': case 'sepBy': return true
40
+ // A scope that names or clears trivia keeps an outer install out of its body.
41
+ // Any other inherits, so it falls through at no cost in depth: line tracking
42
+ // wraps every rule in one, and must not change what this walk sees.
43
+ case 'grammar':
44
+ if (d.triviaParser || d.clearTrivia) return false
45
+ depth++
38
46
  // Transparent wrappers — they add no position, so ask what they wrap.
39
47
  case 'node': case 'transform': case 'leaf': case 'label': case 'field':
40
48
  case 'token': case 'attempt': case 'optional': case 'expect': case 'withCtx':
package/src/index.ts CHANGED
@@ -141,7 +141,7 @@ export type {
141
141
  // back to `FusedRule`, `isInterpretedFuse` would have to be re-exported in the same
142
142
  // change — a dual shape with no way to detect it is the worse of the two.
143
143
  export { compose, composeLeaf, cstBuildHost } from './compiler/linker.ts'
144
- export type { CstBuildHostOptions, FusedRule } from './compiler/linker.ts'
144
+ export type { ComposedRules, CstBuildHostOptions, FusedRule } from './compiler/linker.ts'
145
145
 
146
146
  export { buildLineIndex, createLineIndex, recordLineRange, normalizeLineIndex, offsetToLineCol, annotateSpan, annotateTreeSpans } from './line-index.ts'
147
147
  export type { LineIndex } from './line-index.ts'
@@ -88,7 +88,7 @@ import { PlainBuf, PlainField, PlainLeaf, PlainNode, PlainSpan } from '../cst/pl
88
88
  import {
89
89
  OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_SOURCE_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
90
90
  OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
91
- OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
91
+ OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_EXPECT, OP_SEQX, OP_SCAN,
92
92
  OP_LIVE,
93
93
  OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD, OP_ATTEMPT, OP_LABEL,
94
94
  OP_COV, OP_GAPGATE, OP_STRICT,
@@ -2109,6 +2109,16 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
2109
2109
  case OP_SCOPE_CAP:
2110
2110
  case OP_SCOPE_PLAIN: {
2111
2111
  const ki = code[ip + 1]!
2112
+ if (ki === SCOPE_INHERIT) {
2113
+ const body = link(code[ip + 2]!)
2114
+ return (input, pos, ctx) => {
2115
+ const savedCap = ctx.captureTrivia
2116
+ ctx.captureTrivia = true
2117
+ const v = body(input, pos, ctx)
2118
+ ctx.captureTrivia = savedCap
2119
+ return v
2120
+ }
2121
+ }
2112
2122
  const scopeTrivia = ki < 0 ? undefined : (trivia[ki] as ParseContext['trivia'])
2113
2123
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels
2114
2124
  // THE SWAP, RESOLVED AT ASSEMBLY. `exec.ts` computed
@@ -50,7 +50,7 @@ import {
50
50
  OP_ADJ, OP_ARMGATE, OP_RGATE, OP_RGATE2, OP_ATTEMPT, OP_CHOICE, OP_DISPATCH, OP_EMPTY, OP_EXPECT, OP_FIELD, OP_GATE,
51
51
  OP_LABEL, OP_LEAF, OP_SOURCE_LEAF, OP_LIT, OP_LIT_CI, OP_LIT_CI_TRACK, OP_LIT_TRACK, OP_NAMES,
52
52
  OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT, OP_PEEK, OP_REP, OP_REPV, OP_ROUTED, OP_RULE, OP_RX,
53
- OP_RX_TRACK, OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
53
+ OP_RX_TRACK, OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
54
54
  OP_LEX_BODY, OP_LEX_PROGRAM, OP_GAPGATE, OP_STRICT,
55
55
  } from './ops.ts'
56
56
  import {
@@ -1625,6 +1625,15 @@ return r.value
1625
1625
  const cap = op === OP_SCOPE_CAP
1626
1626
  const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3]!
1627
1627
  const child = link(code[ip + 2]!)
1628
+ if (ki === SCOPE_INHERIT) {
1629
+ return `${head}
1630
+ const sC=ctx.captureTrivia
1631
+ ctx.captureTrivia=true
1632
+ const v=${child}(input,pos,ctx)
1633
+ ctx.captureTrivia=sC
1634
+ return v
1635
+ }`
1636
+ }
1628
1637
  // THE SWAP, RESOLVED AT EMIT. `swapLegal` is `!trackLines`, an option;
1629
1638
  // the other two are table data. All three are known here, so the body
1630
1639
  // holds the scanner it installs as a hoisted const.
@@ -15,7 +15,7 @@ import { asciiFoldKey, branchUsesRouted, parserUsesRouted } from '../combinators
15
15
  import {
16
16
  OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_SOURCE_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
17
17
  OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
18
- OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
18
+ OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_EXPECT, OP_SEQX, OP_SCAN,
19
19
  OP_LIVE, OP_ATTEMPT, OP_LABEL,
20
20
  OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD,
21
21
  OP_ADJ, OP_GREEDY, OP_REJECT, OP_ARMGATE, OP_RGATE, OP_COV, OP_GAPGATE, OP_RGATE2, OP_STRICT,
@@ -2182,13 +2182,19 @@ class Encoder {
2182
2182
  // this scope's trivia is opaque to root capture, which `run()` consumes.
2183
2183
  // Nothing in the parse changes, so there is nothing for the table to
2184
2184
  // lower — accepting it is not a gap, it is the correct lowering.
2185
- // ONLY `true` IS MEANINGFUL HERE. `grammar.ts:94` stores
2186
- // `opts.trackLines ?? false`, so an UNSET scope and an explicitly-false
2187
- // one are the same value on the def — the distinction is lost. At parse
2188
- // time `:103` reads `opts.trackLines ?? _ctx?.trackLines ?? false`, i.e.
2189
- // unset INHERITS. So stored-false cannot be read as "force off", and
2190
- // comparing it against the setting refused every inner scope of a
2191
- // trackLines:true grammar — all four `*PositionsGrammar`s.
2185
+ // ONLY `true` IS MEANINGFUL HERE. `def.trackLines` is `opts.trackLines ??
2186
+ // false`, so an unset scope and an explicitly-false one read the same on that
2187
+ // field (`def.constructionTrackLines` keeps the difference, and the encoder
2188
+ // does not read it). An unset scope inherits, so stored-false cannot be read
2189
+ // as "force off", and comparing it against the setting refused every inner
2190
+ // scope of a trackLines:true grammar — all four `*PositionsGrammar`s.
2191
+ //
2192
+ // THIS IS NOT THE INTERPRETER'S SCOPING, AND A REDUCER CAN SEE IT (#258). A
2193
+ // table has one line setting. A node outside a `trackLines: true` scope gets
2194
+ // line fields from the table and none from the interpreter; a
2195
+ // `trackLines: false` scope under a tracked grammar keeps them in the table
2196
+ // and drops them in the interpreter; and a `trackLines: true` scope in a rule
2197
+ // the entry cannot reach still turns them on for `encodeTable`.
2192
2198
  //
2193
2199
  // A SCOPE THAT ASKS FOR TRACKING NO LONGER REFUSES. `encodeTable` folds
2194
2200
  // every such scope into the table's own `track` before encoding begins
@@ -2237,8 +2243,9 @@ class Encoder {
2237
2243
  this.activeTrivia = savedTrivia
2238
2244
  this.triviaKnown = savedKnown
2239
2245
  if (d.clearTrivia === true) return this.emit(op, -1, bodyIp, flags)
2246
+ // No trivia named: `flags` is zero (`rootCapture: 'opaque'` requires one).
2240
2247
  if (d.triviaParser === undefined) {
2241
- return cap || flags !== 0 ? this.emit(op, -1, bodyIp, flags) : bodyIp
2248
+ return cap ? this.emit(op, SCOPE_INHERIT, bodyIp, flags) : bodyIp
2242
2249
  }
2243
2250
  return this.emit(op, this.triviaSlot(d.triviaParser), bodyIp, flags)
2244
2251
  }
package/src/table/exec.ts CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  import {
19
19
  OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_SOURCE_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
20
20
  OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
21
- OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
21
+ OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_EXPECT, OP_SEQX, OP_SCAN,
22
22
  OP_LIVE,
23
23
  OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD, OP_ATTEMPT, OP_LABEL,
24
24
  OP_COV, OP_GAPGATE, OP_STRICT,
@@ -779,14 +779,16 @@ function makeDriver(
779
779
  // labelled trivia is excluded here rather than tested later: `scanTrivia`
780
780
  // suppresses its own fast path when labels are present, so a swap there
781
781
  // would drop the labelled records silently.
782
- SCAN = FAST && ki >= 0 && !triviaLabelled[ki]! ? triviaScan[ki]! : null
783
- ctx.trivia = scopeTrivia
784
- // A scope installs its trivia's KIND LABELS too. Root-trivia rows are
785
- // only ever written on the labelled scan path (trivia-skip.ts:212) — the
786
- // unlabelled fast scanner returns before any root logging and does not
787
- // even test `_rootTriviaLog` — so a scope that sets trivia without its
788
- // labels captures NOTHING at the root, silently.
789
- ctx.triviaKindLabels = scopeTrivia?._meta.triviaKindLabels
782
+ if (ki !== SCOPE_INHERIT) {
783
+ SCAN = FAST && ki >= 0 && !triviaLabelled[ki]! ? triviaScan[ki]! : null
784
+ ctx.trivia = scopeTrivia
785
+ // A scope installs its trivia's KIND LABELS too. Root-trivia rows are
786
+ // only ever written on the labelled scan path (trivia-skip.ts:212) — the
787
+ // unlabelled fast scanner returns before any root logging and does not
788
+ // even test `_rootTriviaLog` — so a scope that sets trivia without its
789
+ // labels captures NOTHING at the root, silently.
790
+ ctx.triviaKindLabels = scopeTrivia?._meta.triviaKindLabels
791
+ }
790
792
  // SCOPE_CAP additionally turns capture ON for the child. It is an OR with
791
793
  // whatever the enclosing context already asked for (`grammar.ts:129`), so
792
794
  // the RESTORE puts the saved value back rather than writing `false` — an
package/src/table/ops.ts CHANGED
@@ -211,6 +211,12 @@ export const OP_TOKEN = 29
211
211
  * is why this restores the saved value rather than writing `false`.
212
212
  */
213
213
  export const OP_SCOPE_CAP = 30
214
+ /**
215
+ * `k` of a `SCOPE_CAP` row whose `parser({ captureTrivia: true })` names no trivia.
216
+ * It raises capture and leaves the trivia the scope was entered with in force,
217
+ * where `k = -1` clears it (`trivia: null`).
218
+ */
219
+ export const SCOPE_INHERIT = -2
214
220
  /**
215
221
  * `WITHCTX k c` — `withCtx(extra, c)`. `k >= 0` is `extra` in the const pool
216
222
  * (the replace form); `k < 0` is the derive form, `~k` indexing the author's
@@ -62,7 +62,7 @@
62
62
  import {
63
63
  OP_ATTEMPT, OP_CHOICE, OP_DISPATCH, OP_EXPECT, OP_FIELD, OP_GATE, OP_LABEL, OP_LEAF, OP_LIT, OP_SOURCE_LEAF,
64
64
  OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT, OP_PEEK, OP_REP, OP_REPV, OP_ROUTED, OP_RULE,
65
- OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_XFORM,
65
+ OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, SCOPE_INHERIT, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_XFORM,
66
66
  } from './ops.ts'
67
67
  import { childSlots } from './child-slots.ts'
68
68
  import { leadRanges } from '../lead-ranges.ts'
@@ -206,7 +206,7 @@ function transfer(code: Int32Array, ip: number, at: SiteLabel, hostCst: boolean)
206
206
  const op = code[ip]
207
207
  if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
208
208
  const ki = code[ip + 1]!
209
- const tri = ki < 0 ? TRI_NONE : ki
209
+ const tri = ki === SCOPE_INHERIT ? at.tri : ki < 0 ? TRI_NONE : ki
210
210
  // `OP_SCOPE_CAP` is an OR with the inherited context, never a switch-off
211
211
  // (`encode.ts:1153-1158`), so it can only ever raise `cap` to `CAP_ON`.
212
212
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap
@@ -358,7 +358,7 @@ export function scanHandoffNeeded(code: Int32Array, ip: number, labels: SiteLabe
358
358
  const op = code[at]
359
359
  // A scan runs interpreted combinators that reach pieces through `prog.scans`.
360
360
  if (op === OP_SCAN) return true
361
- if (op === OP_TOKEN || op === OP_SCOPE_CAP) continue
361
+ if (op === OP_TOKEN || (op === OP_SCOPE_CAP && code[at + 1] !== SCOPE_INHERIT)) continue
362
362
  if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE) && !(code[at + 1]! >= 0 && l.tri === code[at + 1]!
363
363
  && (op === OP_SCOPE_PLAIN || code[at + 3]! === 0))) continue
364
364
  kids.length = 0
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.60.5'
16
+ export const PARSEMAN_VERSION = '0.60.6'