parseman 0.47.0 → 0.47.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/dist/analysis/diagnostics.cjs +133 -45
- package/dist/analysis/diagnostics.cjs.map +2 -2
- package/dist/analysis/diagnostics.js +133 -45
- package/dist/analysis/diagnostics.js.map +2 -2
- package/dist/cli/index.cjs +133 -45
- package/dist/cli/index.cjs.map +2 -2
- package/dist/cli/index.js +133 -45
- package/dist/cli/index.js.map +2 -2
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +5 -0
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/index.cjs +134 -46
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +134 -46
- package/dist/index.js.map +2 -2
- package/dist/language-service/index.cjs +3 -1
- package/dist/language-service/index.cjs.map +1 -1
- package/dist/language-service/index.js +3 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/index.cjs +134 -46
- package/dist/plugin/index.cjs.map +2 -2
- package/dist/plugin/index.js +134 -46
- package/dist/plugin/index.js.map +2 -2
- package/dist/spec/index.cjs +55 -7
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.js +55 -7
- package/dist/spec/index.js.map +1 -1
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts +2 -2
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/emit.d.ts.map +1 -1
- package/dist/table/exec.d.ts.map +1 -1
- package/dist/table/index.cjs +1566 -1478
- package/dist/table/index.cjs.map +3 -3
- package/dist/table/index.js +1566 -1478
- package/dist/table/index.js.map +3 -3
- package/dist/table/ops.d.ts +8 -1
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/table/program.d.ts +4 -1
- package/dist/table/program.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/combinators/first-set.ts +29 -3
- package/src/combinators/sequence.ts +23 -7
- package/src/combinators/trivia-skip.ts +31 -0
- package/src/table/assemble.ts +30 -18
- package/src/table/child-slots.ts +2 -2
- package/src/table/emit-assembly.ts +36 -25
- package/src/table/emit.ts +12 -1
- package/src/table/encode.ts +4 -4
- package/src/table/exec.ts +20 -12
- package/src/table/ops.ts +9 -1
- package/src/table/program.ts +22 -1
- package/src/table/site-labels.ts +2 -2
- package/src/table/stamp.ts +2 -2
- package/src/version.ts +1 -1
package/src/table/encode.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { asciiFoldKey, branchUsesRouted, parserUsesRouted } from '../combinators
|
|
|
9
9
|
import {
|
|
10
10
|
OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
|
|
11
11
|
OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
|
|
12
|
-
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
12
|
+
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
13
13
|
OP_LIVE, OP_ATTEMPT, OP_LABEL,
|
|
14
14
|
OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD,
|
|
15
15
|
OP_ADJ, OP_GREEDY, OP_REJECT, OP_ARMGATE, OP_COV,
|
|
@@ -610,7 +610,7 @@ class Encoder {
|
|
|
610
610
|
// straight to the body's offset (`case 'lazy'`), so every recursive call and
|
|
611
611
|
// every cross-rule reference would jump past the counter, and a grammar with
|
|
612
612
|
// one entry would report one hit rule however much of it ran.
|
|
613
|
-
this.rules[name] = amb === undefined ? body : this.emit(
|
|
613
|
+
this.rules[name] = amb === undefined ? body : this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), body)
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
/**
|
|
@@ -656,7 +656,7 @@ class Encoder {
|
|
|
656
656
|
const amb = p._meta.grammarTrivia ?? target._meta.grammarTrivia
|
|
657
657
|
if (amb === undefined || this.activeTrivia !== undefined) return ip
|
|
658
658
|
if (!hasOwnTriviaBoundary(target)) return ip
|
|
659
|
-
return this.emit(
|
|
659
|
+
return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip)
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
node(p: Combinator<unknown>): Emitted {
|
|
@@ -1399,7 +1399,7 @@ class Encoder {
|
|
|
1399
1399
|
switch (this.code[ip]) {
|
|
1400
1400
|
case OP_GATE: return [ip + 2]
|
|
1401
1401
|
case OP_RULE: case OP_OPT: case OP_NOT: case OP_PEEK: case OP_EXPECT: case OP_ATTEMPT: case OP_LABEL: case OP_COV: return [ip + 1]
|
|
1402
|
-
case OP_SCOPE: case OP_SCOPE_CAP: case OP_WITHCTX: case OP_XFORM: case OP_LEAF: case OP_NODE: case OP_NODE_TRACK: return [ip + 2]
|
|
1402
|
+
case OP_SCOPE: case OP_SCOPE_CAP: case OP_SCOPE_PLAIN: case OP_WITHCTX: case OP_XFORM: case OP_LEAF: case OP_NODE: case OP_NODE_TRACK: return [ip + 2]
|
|
1403
1403
|
case OP_SEQ: case OP_SEQV: return Array.from({ length: this.code[ip + 1]! }, (_, i) => ip + 2 + i)
|
|
1404
1404
|
case OP_SEQX: return Array.from({ length: this.code[ip + 2]! }, (_, i) => ip + 3 + i)
|
|
1405
1405
|
// ARMS START AT ip+4. `ip+3` is the choice's own EXPECTED-SET index, and
|
package/src/table/exec.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { projectChild, unwrapChild } from '../combinators/node.ts'
|
|
|
6
6
|
import { asciiFoldEq } from '../combinators/literal.ts'
|
|
7
7
|
import { cstOutputHost } from '../compiler/build-arity.ts'
|
|
8
8
|
import { consumeTrivia } from '../combinators/trivia-skip.ts'
|
|
9
|
-
import { advanceTrivia, needsDeferredTriviaCommit, rollbackTrivia, rollbackTriviaAt, saveTriviaMark, scanTrivia, skipTriviaScanned, type FastTriviaScanner } from '../combinators/trivia-skip.ts'
|
|
9
|
+
import { advanceTrivia, needsDeferredTriviaCommit, rollbackScannedTriviaAt, rollbackTrivia, rollbackTriviaAt, saveTriviaMark, scanTrivia, skipTriviaScanned, type FastTriviaScanner } from '../combinators/trivia-skip.ts'
|
|
10
10
|
import {
|
|
11
11
|
beginCstNodeCapture, cstCaptureActive, cstLeavesLen, cstRawLen, cstTlLen,
|
|
12
12
|
demoteCapturedToRaw, endCstNodeCapture, pushCstChild, pushCstLeaf,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
|
|
16
16
|
OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
|
|
17
|
-
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
17
|
+
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
18
18
|
OP_LIVE,
|
|
19
19
|
OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD, OP_ATTEMPT, OP_LABEL,
|
|
20
20
|
OP_COV,
|
|
@@ -609,15 +609,21 @@ function makeDriver(
|
|
|
609
609
|
usesRouted = spec.routed[arm] === 1
|
|
610
610
|
}
|
|
611
611
|
|
|
612
|
-
const savedRouted = ctx._routed
|
|
613
612
|
let mark = saveTriviaMark(ctx)
|
|
613
|
+
let v: unknown
|
|
614
614
|
if (usesRouted) {
|
|
615
|
+
const savedRouted = ctx._routed
|
|
615
616
|
rollbackTrivia(ctx, selectorMark)
|
|
616
617
|
mark = saveTriviaMark(ctx)
|
|
617
618
|
ctx._routed = { value: key, span: { start: pos, end: selEnd } }
|
|
619
|
+
try {
|
|
620
|
+
v = exec(target, input, pos, ctx)
|
|
621
|
+
} finally {
|
|
622
|
+
ctx._routed = savedRouted
|
|
623
|
+
}
|
|
624
|
+
} else {
|
|
625
|
+
v = exec(target, input, selEnd, ctx)
|
|
618
626
|
}
|
|
619
|
-
const v = exec(target, input, usesRouted ? pos : selEnd, ctx)
|
|
620
|
-
if (usesRouted) ctx._routed = savedRouted
|
|
621
627
|
if (v === FAIL) {
|
|
622
628
|
rollbackTrivia(ctx, mark)
|
|
623
629
|
// The interpreter marks a failed dispatch branch COMMITTED: the
|
|
@@ -706,7 +712,8 @@ function makeDriver(
|
|
|
706
712
|
}
|
|
707
713
|
|
|
708
714
|
case OP_SCOPE:
|
|
709
|
-
case OP_SCOPE_CAP:
|
|
715
|
+
case OP_SCOPE_CAP:
|
|
716
|
+
case OP_SCOPE_PLAIN: {
|
|
710
717
|
const ki = code[ip + 1]!
|
|
711
718
|
const saved = ctx.trivia
|
|
712
719
|
const savedLabels = ctx.triviaKindLabels
|
|
@@ -735,7 +742,7 @@ function makeDriver(
|
|
|
735
742
|
// (`grammar.ts:141`), and the flag is restored here because the table
|
|
736
743
|
// shares one ctx where `parser()` copies it. Bit 2 = the unclassified-scope
|
|
737
744
|
// refusal `grammar.ts:98` raises.
|
|
738
|
-
const policy = code[ip + 3]!
|
|
745
|
+
const policy = code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]!
|
|
739
746
|
if ((policy & 2) !== 0) refuseUnclassifiedRootScope(ctx._rootTriviaStrictScopes)
|
|
740
747
|
const savedRootCap = ctx._rootTriviaCapture
|
|
741
748
|
if ((policy & 1) !== 0) ctx._rootTriviaCapture = false
|
|
@@ -786,18 +793,19 @@ function makeDriver(
|
|
|
786
793
|
// SCALAR MARKS — `saveTriviaMark` allocated TWICE per term (its own
|
|
787
794
|
// seven-field object plus the five-field CST mark it delegates to).
|
|
788
795
|
const need = rollbackNeeded(ctx)
|
|
789
|
-
const mRaw = need ? cstRawLen(ctx) : 0
|
|
790
796
|
const mTl = need ? cstTlLen(ctx) : 0
|
|
791
|
-
const mLv = need ? cstLeavesLen(ctx) : 0
|
|
792
|
-
const mFl = need ? ctx._fields?.length ?? 0 : 0
|
|
793
|
-
const mEr = need ? ctx._errors?.length ?? 0 : 0
|
|
794
797
|
const mLog = need ? ctx._triviaLog?.length ?? 0 : 0
|
|
795
798
|
const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0
|
|
796
799
|
const scanEnd = skipTrivia(input, cur, ctx)
|
|
800
|
+
const scanTl = need ? cstTlLen(ctx) : 0
|
|
801
|
+
const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0
|
|
802
|
+
const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0
|
|
797
803
|
const v = exec(child, input, scanEnd, ctx)
|
|
798
804
|
if (v === FAIL) { if (REC) ctx._sync = inheritedSync; return FAIL }
|
|
799
805
|
if (EC.e > scanEnd) cur = EC.e
|
|
800
|
-
else if (need)
|
|
806
|
+
else if (need) rollbackScannedTriviaAt(
|
|
807
|
+
ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot,
|
|
808
|
+
)
|
|
801
809
|
if (values !== undefined) values.push(v)
|
|
802
810
|
continue
|
|
803
811
|
}
|
package/src/table/ops.ts
CHANGED
|
@@ -104,12 +104,14 @@ export const OP_LIT_TRACK = 17
|
|
|
104
104
|
export const OP_RX_TRACK = 18
|
|
105
105
|
export const OP_NODE_TRACK = 19
|
|
106
106
|
/**
|
|
107
|
-
* `SCOPE k c` — a `parser({ trivia })`
|
|
107
|
+
* `SCOPE k c policy` — a policy-bearing `parser({ trivia })` scope.
|
|
108
108
|
*
|
|
109
109
|
* `k` is the scope's trivia COMBINATOR in the const pool. The driver installs it
|
|
110
110
|
* on `ctx.trivia` for the duration and restores the outer one after, which is
|
|
111
111
|
* how the runtime's own `advanceTrivia` fast scanner gets reached — the same
|
|
112
112
|
* shared machinery the interpreter uses, not a second copy of it.
|
|
113
|
+
* Synthetic rule-entry/restoration scopes use `OP_SCOPE_PLAIN` so a zero
|
|
114
|
+
* policy stays a three-word row without changing this opcode's ABI.
|
|
113
115
|
*/
|
|
114
116
|
export const OP_SCOPE = 20
|
|
115
117
|
/**
|
|
@@ -425,6 +427,11 @@ export const OP_LABEL = 39
|
|
|
425
427
|
* which is the granularity the IDs are minted at.
|
|
426
428
|
*/
|
|
427
429
|
export const OP_COV = 40
|
|
430
|
+
/**
|
|
431
|
+
* `SCOPE_PLAIN k c` — a synthetic ambient-trivia scope with policy fixed to zero.
|
|
432
|
+
* A distinct opcode prevents the next row's opcode from being read as policy.
|
|
433
|
+
*/
|
|
434
|
+
export const OP_SCOPE_PLAIN = 41
|
|
428
435
|
/**
|
|
429
436
|
* `DISPATCH sel d other otherRouted n a1 … an` — `dispatch()`.
|
|
430
437
|
*
|
|
@@ -456,4 +463,5 @@ export const OP_NAMES: Record<number, string> = {
|
|
|
456
463
|
[OP_ADJ]: 'ADJ',
|
|
457
464
|
[OP_GREEDY]: 'GREEDY', [OP_REJECT]: 'REJECT', [OP_ARMGATE]: 'ARMGATE',
|
|
458
465
|
[OP_LIVE]: 'LIVE', [OP_ATTEMPT]: 'ATTEMPT', [OP_LABEL]: 'LABEL', [OP_COV]: 'COV',
|
|
466
|
+
[OP_SCOPE_PLAIN]: 'SCOPE_PLAIN',
|
|
459
467
|
}
|
package/src/table/program.ts
CHANGED
|
@@ -124,7 +124,8 @@ export type TableProgram = {
|
|
|
124
124
|
*/
|
|
125
125
|
readonly runtimeOnly?: readonly string[]
|
|
126
126
|
/**
|
|
127
|
-
* Trivia specs, referenced by index from `OP_SCOPE` and
|
|
127
|
+
* Trivia specs, referenced by index from `OP_SCOPE`, `OP_SCOPE_CAP` and
|
|
128
|
+
* `OP_SCOPE_PLAIN` rule/restoration entries.
|
|
128
129
|
*
|
|
129
130
|
* `classifiedTrivia()` is `trivia(oneOrMore(choice(label(name, arm)…)))` with
|
|
130
131
|
* regex arms — entirely structural, so it lowers to DATA and is rebuilt at
|
|
@@ -352,6 +353,26 @@ export type ResolvedDispatchSpec = {
|
|
|
352
353
|
readonly expected: readonly string[]
|
|
353
354
|
}
|
|
354
355
|
|
|
356
|
+
/** Refuse malformed dispatch arm references before closure/emitted linking. */
|
|
357
|
+
export function validateDispatchSpec(
|
|
358
|
+
spec: ResolvedDispatchSpec | undefined,
|
|
359
|
+
arity: number,
|
|
360
|
+
fallbackRouted: number,
|
|
361
|
+
): asserts spec is ResolvedDispatchSpec {
|
|
362
|
+
const invalid = (arms: Iterable<number>): boolean => {
|
|
363
|
+
for (const arm of arms) if (!Number.isInteger(arm) || arm < 0 || arm >= arity) return true
|
|
364
|
+
return false
|
|
365
|
+
}
|
|
366
|
+
if (spec === undefined || !Number.isInteger(arity) || arity < 0
|
|
367
|
+
|| (fallbackRouted !== 0 && fallbackRouted !== 1)
|
|
368
|
+
|| spec.routed.length !== arity
|
|
369
|
+
|| spec.routed.some(value => value !== 0 && value !== 1)
|
|
370
|
+
|| invalid(spec.byKey.values()) || invalid(spec.byFold.values())
|
|
371
|
+
|| spec.match.some(matcher => invalid([matcher[3]]))) {
|
|
372
|
+
throw new TypeError('table: malformed dispatch')
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
355
376
|
/** A char class expanded for execution: O(1) for ASCII, ranges above it. */
|
|
356
377
|
export type ResolvedClass = {
|
|
357
378
|
readonly ascii: Uint8Array
|
package/src/table/site-labels.ts
CHANGED
|
@@ -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,
|
|
64
64
|
OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT, OP_PEEK, OP_REP, OP_REPV, OP_ROUTED, OP_RULE,
|
|
65
|
-
OP_SCOPE, OP_SCOPE_CAP, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_XFORM,
|
|
65
|
+
OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, 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
|
|
|
@@ -138,7 +138,7 @@ export function reachableSites(code: Int32Array, roots: Iterable<number>): Set<n
|
|
|
138
138
|
*/
|
|
139
139
|
function transfer(code: Int32Array, ip: number, at: SiteLabel, hostCst: boolean): SiteLabel {
|
|
140
140
|
const op = code[ip]
|
|
141
|
-
if (op === OP_SCOPE || op === OP_SCOPE_CAP) {
|
|
141
|
+
if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
|
|
142
142
|
const ki = code[ip + 1]!
|
|
143
143
|
const tri = ki < 0 ? TRI_NONE : ki
|
|
144
144
|
// `OP_SCOPE_CAP` is an OR with the inherited context, never a switch-off
|
package/src/table/stamp.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { Combinator, ParseContext, ParseResult } from '../types.ts'
|
|
|
14
14
|
import { FUSED_HOST_ELIDED, FUSED_HOST_MODE } from '../cst/host-mode.ts'
|
|
15
15
|
import { GRAMMAR_COVERAGE_DEFINITIONS } from '../grammar-metadata.ts'
|
|
16
16
|
import { reachableIps } from './inspect.ts'
|
|
17
|
-
import { OP_NODE, OP_NODE_TRACK, OP_SCOPE } from './ops.ts'
|
|
17
|
+
import { OP_NODE, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_PLAIN } from './ops.ts'
|
|
18
18
|
import { covDefinitions, resolveTable, type ResolvedTable, type TableProgram, type TableRule } from './program.ts'
|
|
19
19
|
|
|
20
20
|
const EMPTY_FX: string[] = []
|
|
@@ -103,7 +103,7 @@ export function stampRuleMap(
|
|
|
103
103
|
// `scanSkipOf` exists for). The owning driver passes its resolved table, so
|
|
104
104
|
// this is the exact trivia array it already built.
|
|
105
105
|
const triviaOfRule = (ip: number): Combinator<unknown> | undefined => {
|
|
106
|
-
if (prog.code[ip] !== OP_SCOPE) return undefined
|
|
106
|
+
if (prog.code[ip] !== OP_SCOPE_PLAIN && prog.code[ip] !== OP_SCOPE) return undefined
|
|
107
107
|
const slot = prog.code[ip + 1]!
|
|
108
108
|
return slot < 0 ? undefined : resolved.trivia[slot]
|
|
109
109
|
}
|
package/src/version.ts
CHANGED