parseman 0.60.3 → 0.60.5
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/commitment.d.ts.map +1 -1
- package/dist/analysis/diagnostics.js +1 -1
- package/dist/cli/index.js +420 -420
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/parser.d.ts +34 -3
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/compiler/compile-linkable-table.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts +3 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +21 -3
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -35
- package/dist/index.js.map +1 -1
- package/dist/plugin/evaluator.d.ts +11 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +162 -73
- package/dist/plugin/index.js.map +2 -2
- package/dist/spec/index.js +3 -1
- package/dist/spec/index.js.map +1 -1
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/table/index.js +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/analysis/commitment.ts +3 -1
- package/src/combinators/parser.ts +82 -9
- package/src/compiler/compile-linkable-table.ts +4 -1
- package/src/compiler/ir-serialize.ts +24 -7
- package/src/compiler/linker.ts +50 -24
- package/src/index.ts +1 -0
- package/src/plugin/evaluator.ts +27 -5
- package/src/plugin/index.ts +41 -100
- package/src/spec/model.ts +3 -1
- package/src/version.ts +1 -1
package/src/plugin/evaluator.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
import type { Combinator } from '../types.ts'
|
|
17
17
|
import type { DispatchArm } from '../combinators/dispatch.ts'
|
|
18
18
|
import { ref } from '../combinators/ref.ts'
|
|
19
|
-
import { rules, type RulesOptions } from '../combinators/parser.ts'
|
|
19
|
+
import { rules, RULES_RECIPE, type PriorRules, type RulesOptions, type RulesRecipe } from '../combinators/parser.ts'
|
|
20
20
|
import * as parseman from '../index.ts'
|
|
21
21
|
import { confirmedBuildParamUnused } from '../compiler/build-arity.ts'
|
|
22
22
|
import { directBuilderBindings } from './direct-builder-static.ts'
|
|
@@ -1478,11 +1478,17 @@ export function evaluateParserFactory(
|
|
|
1478
1478
|
|
|
1479
1479
|
const factory = factoryNode as unknown as ArrowFunctionExpression | OxcFunction
|
|
1480
1480
|
const params = factory.params
|
|
1481
|
-
if (params.length !== 1) return null
|
|
1482
|
-
const param = params[0] as unknown as { type: string; name?: string }
|
|
1481
|
+
if (params.length !== 1 && params.length !== 2) return null
|
|
1483
1482
|
// FormalParameter is { decorators? } & BindingPattern — BindingIdentifier has type "Identifier"
|
|
1484
|
-
const
|
|
1483
|
+
const paramName = (param: unknown): string | null => {
|
|
1484
|
+
const p = param as { type: string; name?: string }
|
|
1485
|
+
return p.type === 'Identifier' ? p.name ?? null : null
|
|
1486
|
+
}
|
|
1487
|
+
const proxyName = paramName(params[0])
|
|
1485
1488
|
if (!proxyName) return null
|
|
1489
|
+
// `(g, prior)`: the second parameter is the `prior` handle (`PriorRules`).
|
|
1490
|
+
const priorName = params.length === 2 ? paramName(params[1]) : undefined
|
|
1491
|
+
if (priorName === null) return null
|
|
1486
1492
|
|
|
1487
1493
|
const body = factory.body
|
|
1488
1494
|
if (!body) return null
|
|
@@ -1566,11 +1572,12 @@ export function evaluateParserFactory(
|
|
|
1566
1572
|
const ABORT = Symbol('parseman: factory not statically evaluable')
|
|
1567
1573
|
let built: Record<string, Combinator<unknown>>
|
|
1568
1574
|
try {
|
|
1569
|
-
built = rules(options ?? {}, (g: Record<string, Combinator<unknown
|
|
1575
|
+
built = rules(options ?? {}, (g: Record<string, Combinator<unknown>>, prior: PriorRules) => {
|
|
1570
1576
|
// Outer ScopeEntry values carry their mfSrcs and are replayed by scopeGet()
|
|
1571
1577
|
// when body statements or return expressions reference them.
|
|
1572
1578
|
const localScope: XScope = scope instanceof ModuleScope ? scope.fork() : new Map(scope as XScope)
|
|
1573
1579
|
localScope.set(proxyName, g)
|
|
1580
|
+
if (priorName !== undefined) localScope.set(priorName, prior)
|
|
1574
1581
|
|
|
1575
1582
|
// ── Phase 1: the factory's own body statements ────────────────────────
|
|
1576
1583
|
if (!evalBodyStatements(statements, localScope, code, out)) throw ABORT
|
|
@@ -1613,9 +1620,24 @@ export function evaluateParserFactory(
|
|
|
1613
1620
|
*/
|
|
1614
1621
|
const map = new Map<string, Combinator<unknown>>()
|
|
1615
1622
|
for (const key of keys) map.set(key, built[key]!)
|
|
1623
|
+
const declared = new Set(keys)
|
|
1624
|
+
externalAccesses.set(map, Object.keys(built).filter(name => !declared.has(name)))
|
|
1625
|
+
ruleMapRecipes.set(map, (built as unknown as Record<symbol, readonly RulesRecipe[]>)[RULES_RECIPE]!)
|
|
1616
1626
|
return map
|
|
1617
1627
|
}
|
|
1618
1628
|
|
|
1629
|
+
/** The recipe an evaluated rule map came from, for a composition that links it. */
|
|
1630
|
+
export const ruleMapRecipes = new WeakMap<ReadonlyMap<string, Combinator<unknown>>, readonly RulesRecipe[]>()
|
|
1631
|
+
|
|
1632
|
+
/**
|
|
1633
|
+
* Every EXTERNAL name an evaluated factory read through `g`, keyed by the map
|
|
1634
|
+
* `evaluateParserFactory` returned. The map holds declared rules only, so a `g.X`
|
|
1635
|
+
* read outside every rule body (`const unused = g.X`) leaves no trace in it; the
|
|
1636
|
+
* IR serializer reads this to keep that access, so a composition refuses an `X`
|
|
1637
|
+
* nobody defines exactly as runtime `compose()` does.
|
|
1638
|
+
*/
|
|
1639
|
+
export const externalAccesses = new WeakMap<ReadonlyMap<string, Combinator<unknown>>, readonly string[]>()
|
|
1640
|
+
|
|
1619
1641
|
/** A combinator slot created by ref() — has a callable `define`. */
|
|
1620
1642
|
type DefinableRef = Combinator<unknown> & { define(p: Combinator<unknown>): void }
|
|
1621
1643
|
|
package/src/plugin/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { createUnplugin } from 'unplugin'
|
|
|
24
24
|
import { parseSync } from 'oxc-parser'
|
|
25
25
|
import { ResolverFactory } from 'oxc-resolver'
|
|
26
26
|
import MagicString from 'magic-string'
|
|
27
|
-
import { evaluateExpr, evaluateCombinatorArray, evaluateParserFactory, evaluateStaticValue, evaluateWordFactory, evaluateWhenFactory, evaluateRefDeclaration, applyDefineStatement, referencesAny, setReducerResolver, setBuilderImportResolver, propName, ModuleScope, type FreeNameResolution, type Scope, type ScopeEntry } from './evaluator.ts'
|
|
27
|
+
import { evaluateExpr, evaluateCombinatorArray, evaluateParserFactory, externalAccesses, ruleMapRecipes, evaluateStaticValue, evaluateWordFactory, evaluateWhenFactory, evaluateRefDeclaration, applyDefineStatement, referencesAny, setReducerResolver, setBuilderImportResolver, propName, ModuleScope, type FreeNameResolution, type Scope, type ScopeEntry } from './evaluator.ts'
|
|
28
28
|
import { classifyRuleMap } from '../analysis/commitment.ts'
|
|
29
29
|
import { compile } from '../table/compile.ts'
|
|
30
30
|
import { compileRuleMap, type CompiledRuleMapTable } from '../table/compile-rule-map.ts'
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
resolveDegradationLevel, recordDegradation, degradationCaptureDepth, unwindDegradationCapture,
|
|
38
38
|
} from '../compiler/degradation.ts'
|
|
39
39
|
import type { HostMode } from '../cst/host-mode.ts'
|
|
40
|
-
import { COMPOSED_PIECES, type IRPiece } from '../compiler/linker.ts'
|
|
40
|
+
import { COMPOSED_PIECES, danglingReference, type IRPiece } from '../compiler/linker.ts'
|
|
41
41
|
import { serializeCombinator, serializeRuleMap } from '../compiler/ir-serialize.ts'
|
|
42
42
|
import { evalCombinatorIR, evalRulesIR, INERT_BUILDER } from './ir-eval.ts'
|
|
43
43
|
import { countSiteVisits } from '../table/assemble.ts'
|
|
@@ -220,6 +220,9 @@ const DEFAULT_ASSEMBLY_BUDGET = 0.25
|
|
|
220
220
|
* ~79 ms against ~14 ms on `benchmark.less`. "Couldn't be inlined" alone does not
|
|
221
221
|
* tell an author which construct to change; the compiler knows, so it says.
|
|
222
222
|
*/
|
|
223
|
+
/** A build failure the lowering must not soften into a warning and a fallback. */
|
|
224
|
+
class LinkRefusal extends Error {}
|
|
225
|
+
|
|
223
226
|
function reasonSuffix(runtimeOnly: readonly string[] | undefined): string {
|
|
224
227
|
return runtimeOnly === undefined || runtimeOnly.length === 0
|
|
225
228
|
? ''
|
|
@@ -2052,7 +2055,7 @@ function transformMacroImpl(
|
|
|
2052
2055
|
/**
|
|
2053
2056
|
* Evaluate a carried list back to combinators, one entry per piece: its rule map
|
|
2054
2057
|
* and the `rules()` recipe it was built from. `compose()` links the recipes into
|
|
2055
|
-
* one namespace (`mergedCarriedRules`)
|
|
2058
|
+
* one namespace (`mergedCarriedRules`), and `composeLeaf()` does the same.
|
|
2056
2059
|
* Either way the merged grammar is encoded ONCE by `compileRuleMap` — no relocation
|
|
2057
2060
|
* of code offsets and no merging of const / fn / expected pools between two
|
|
2058
2061
|
* already-encoded programs.
|
|
@@ -2088,38 +2091,6 @@ function transformMacroImpl(
|
|
|
2088
2091
|
return { pieces, trackLines }
|
|
2089
2092
|
}
|
|
2090
2093
|
|
|
2091
|
-
/**
|
|
2092
|
-
* Fold ordered rule maps into the composed map: a later piece's name WINS, and
|
|
2093
|
-
* `Map` keeps each name at its first-sighting position so the encoded rule order
|
|
2094
|
-
* tracks the source lowering's rather than drifting per compose.
|
|
2095
|
-
*
|
|
2096
|
-
* A REFERENCE IS NOT A DEFINITION. A `rules(g => …)` cache also holds every `g.X`
|
|
2097
|
-
* that was merely ACCESSED, so a delta that calls `g.Pair` carries a `Pair` entry
|
|
2098
|
-
* that is an unresolved named lazy. Merged in name order that entry lands LAST and
|
|
2099
|
-
* shadows the base piece which actually defines `Pair` — the encoder then finds a
|
|
2100
|
-
* hole where the winner should be and refuses the whole grammar with "ref() used
|
|
2101
|
-
* before .define()". The same filter guards `compileLinkableTable`'s `isLocal`
|
|
2102
|
-
* (`compile-linkable-table.ts`) and `recoverComposedRules`; this site needs it
|
|
2103
|
-
* for the same reason, and skipping it is why cross-piece composition looked blocked.
|
|
2104
|
-
*
|
|
2105
|
-
* The reference itself is not lost: it stays inside the delta's own rule bodies and
|
|
2106
|
-
* `enc.winners` binds it BY NAME to whichever piece supplies the definition.
|
|
2107
|
-
*/
|
|
2108
|
-
const mergeRuleMaps = (
|
|
2109
|
-
maps: ReadonlyArray<ReadonlyArray<readonly [string, Combinator<unknown>]>>,
|
|
2110
|
-
): Array<[string, Combinator<unknown>]> => {
|
|
2111
|
-
const winners = new Map<string, Combinator<unknown>>()
|
|
2112
|
-
for (const map of maps) {
|
|
2113
|
-
for (const [name, rule] of map) {
|
|
2114
|
-
if (rule._def.tag === 'lazy') {
|
|
2115
|
-
try { rule._def.thunk() } catch { continue }
|
|
2116
|
-
}
|
|
2117
|
-
winners.set(name, rule)
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
return [...winners]
|
|
2121
|
-
}
|
|
2122
|
-
|
|
2123
2094
|
/**
|
|
2124
2095
|
* LINK a carried list into the composed map, exactly as runtime `compose()` does:
|
|
2125
2096
|
* every piece's carried `rules()` recipe runs again against ONE namespace
|
|
@@ -2136,36 +2107,15 @@ function transformMacroImpl(
|
|
|
2136
2107
|
const mergedCarriedRules = (
|
|
2137
2108
|
items: CarriedItem[],
|
|
2138
2109
|
link: LinkOptions,
|
|
2139
|
-
): { rules: Array<[string, Combinator<unknown>]>; trackLines: boolean } | null => {
|
|
2110
|
+
): { rules: Array<[string, Combinator<unknown>]>; trackLines: boolean; dangling: string | undefined } | null => {
|
|
2140
2111
|
const carriedMaps = carriedRuleMaps(items)
|
|
2141
2112
|
if (carriedMaps === null) return null
|
|
2142
2113
|
const linked = linkRules(carriedMaps.pieces.flatMap(p => p.recipes), link)
|
|
2143
2114
|
// A name some piece only REFERENCES and none defines stays an undefined slot in
|
|
2144
|
-
// the namespace.
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
})
|
|
2149
|
-
return { rules, trackLines: carriedMaps.trackLines }
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
/**
|
|
2153
|
-
* COMPOSING-WINS for `composeLeaf()`'s carried pieces, as an OVERRIDE rather than
|
|
2154
|
-
* a gap-fill: `compileRuleMap`'s `applyAmbient` only fills a rule that carries no
|
|
2155
|
-
* trivia of its own. (`compose()` gets the same override from `linkRules`.)
|
|
2156
|
-
*
|
|
2157
|
-
* Safe to mutate: every rule here came from `evalRuleMapIR`, which constructs FRESH
|
|
2158
|
-
* combinators per piece per compose, so this cannot leak into another compose of the
|
|
2159
|
-
* same base grammar.
|
|
2160
|
-
*/
|
|
2161
|
-
const applyComposingTrivia = (
|
|
2162
|
-
ruleMap: ReadonlyArray<readonly [string, Combinator<unknown>]>,
|
|
2163
|
-
composing: Combinator<unknown>,
|
|
2164
|
-
): void => {
|
|
2165
|
-
for (const [, rule] of ruleMap) {
|
|
2166
|
-
if (rule._meta.isTrivia) continue
|
|
2167
|
-
;(rule._meta as { grammarTrivia?: Combinator<unknown> }).grammarTrivia = composing
|
|
2168
|
-
}
|
|
2115
|
+
// the namespace. Runtime `compose()` refuses that grammar at link, so the build
|
|
2116
|
+
// refuses it too (the caller throws `dangling`) rather than encode around the hole.
|
|
2117
|
+
const dangling = danglingReference(linked)
|
|
2118
|
+
return { rules: Object.entries(linked), trackLines: carriedMaps.trackLines, dangling }
|
|
2169
2119
|
}
|
|
2170
2120
|
|
|
2171
2121
|
/** Resolve one `compose([...])` argument to its RE-LOWERABLE carried items (IR
|
|
@@ -2183,7 +2133,7 @@ function transformMacroImpl(
|
|
|
2183
2133
|
// `rules({ scanSkip }, …)` options, which stamps `_meta.grammarScanSkip` when the IR
|
|
2184
2134
|
// is re-lowered (materializePiece → compileLinkable picks it up), and survives to a
|
|
2185
2135
|
// downstream re-compose. The full-pieces fallback bakes it via the compile option.
|
|
2186
|
-
const ir = serializeRuleMap(entries as never, scanSkip)
|
|
2136
|
+
const ir = serializeRuleMap(entries as never, scanSkip, rm instanceof Map ? externalAccesses.get(rm) : undefined)
|
|
2187
2137
|
if (ir) return { carried: [{ ns, ir, ...(trackLines ? { trackLines: true as const } : {}) }] }
|
|
2188
2138
|
// NO FULL-PIECES FALLBACK. It used to bake the grammar to lowered source when the IR
|
|
2189
2139
|
// would not serialize; with one lowering there is nothing to bake to, and IR is not
|
|
@@ -2333,10 +2283,18 @@ function transformMacroImpl(
|
|
|
2333
2283
|
// does — one encode, one `tableRules(…)` expression, no linker. `carried` is
|
|
2334
2284
|
// unchanged either way: it is the re-lowerable IR list, not a lowering artifact,
|
|
2335
2285
|
// so a downstream re-compose behaves identically whichever engine emitted here.
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2286
|
+
let merged: ReturnType<typeof mergedCarriedRules>
|
|
2287
|
+
try {
|
|
2288
|
+
merged = mergedCarriedRules(carried, {
|
|
2289
|
+
trivia: composing,
|
|
2290
|
+
...(cHostMode ? { hostMode: cHostMode as HostMode } : {}),
|
|
2291
|
+
})
|
|
2292
|
+
} catch (e) {
|
|
2293
|
+
// Linking refuses the composition (a `prior.X` no earlier piece defines): a
|
|
2294
|
+
// runtime `compose()` would refuse it the same way, so the build fails, here.
|
|
2295
|
+
throw new Error(`${id}:${lineOf(init.start)} — ${(e as Error).message}`, { cause: e })
|
|
2296
|
+
}
|
|
2297
|
+
if (merged?.dangling !== undefined) throw new Error(`${id}:${lineOf(init.start)} — compose: ${merged.dangling}`)
|
|
2340
2298
|
if (merged !== null) {
|
|
2341
2299
|
// Harvest the direct-builder import provenance carried on the merged graph so
|
|
2342
2300
|
// the re-lower pass at the end of this transform re-emits those imports.
|
|
@@ -2467,22 +2425,15 @@ function transformMacroImpl(
|
|
|
2467
2425
|
return null
|
|
2468
2426
|
}
|
|
2469
2427
|
const localArg = elements[elements.length - 1]!
|
|
2470
|
-
let localRules:
|
|
2471
|
-
// The LOCAL leaf grammar's own ambient scanSkip (from its `rules({ scanSkip })`)
|
|
2472
|
-
// governs the scanTo/balanced sites IT defines — unlike trivia (composing-wins),
|
|
2473
|
-
// opaque units are dialect-specific, so the local declaration is threaded to the
|
|
2474
|
-
// local piece's compile.
|
|
2475
|
-
let localScanSkip: Combinator<unknown>[] | undefined
|
|
2428
|
+
let localRules: ReadonlyMap<string, Combinator<unknown>> | null = null
|
|
2476
2429
|
const importedFactories: string[] = []
|
|
2477
2430
|
if (isRulesCall(localArg)) {
|
|
2478
2431
|
const evaluated = evaluateRulesFactory(localArg, `composeLeaf${init.start}`)
|
|
2479
2432
|
localRules = evaluated?.ruleMap ?? null
|
|
2480
|
-
localScanSkip = evaluated?.scanSkip
|
|
2481
2433
|
if (evaluated?.importedFactory) importedFactories.push(evaluated.importedFactory)
|
|
2482
2434
|
} else if (localArg.type === 'Identifier') {
|
|
2483
2435
|
const name = (localArg as unknown as { name: string }).name
|
|
2484
2436
|
localRules = localRuleMaps.get(name) ?? null
|
|
2485
|
-
localScanSkip = localGrammarScanSkip.get(name)
|
|
2486
2437
|
}
|
|
2487
2438
|
if (!localRules) {
|
|
2488
2439
|
// Distinguish "the argument is the wrong SHAPE" from "the argument is the right
|
|
@@ -2517,13 +2468,6 @@ function transformMacroImpl(
|
|
|
2517
2468
|
// may place one beneath a direct node(). Re-lower their terminals with
|
|
2518
2469
|
// capture enabled so that node receives the imported token values in its
|
|
2519
2470
|
// normal child collector; the pieces still contain no semantic callback.
|
|
2520
|
-
const localNs = nsFor(`composeLeaf${init.start}`)
|
|
2521
|
-
const localEntries = [...localRules] as Array<[string, Combinator<unknown>]>
|
|
2522
|
-
|
|
2523
|
-
// TABLE FIRST — same merge as `compose()`, with the local leaf map appended LAST
|
|
2524
|
-
// so it wins every name and binds the imported shapes' holes (`enc.winners`
|
|
2525
|
-
// resolves those by name; see `mergedCarriedRules`).
|
|
2526
|
-
//
|
|
2527
2471
|
// The recognition-only gate is preserved EXACTLY, and is the reason this path
|
|
2528
2472
|
// needs no `compileLinkable`: `hasDirectBuilders` / `isRecognitionOnly` are
|
|
2529
2473
|
// predicates over the combinator graph, not products of lowering it, so
|
|
@@ -2546,27 +2490,23 @@ function transformMacroImpl(
|
|
|
2546
2490
|
warn(init.start, 'composeLeaf(): every pre-final grammar must explicitly prove recognition-only')
|
|
2547
2491
|
return null
|
|
2548
2492
|
}
|
|
2549
|
-
// The
|
|
2550
|
-
//
|
|
2551
|
-
//
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
}
|
|
2493
|
+
// The same link as `compose()` and runtime `composeLeaf()`: the leaf is the last
|
|
2494
|
+
// recipe, so it wins every name, binds the imported shapes' holes and fills its
|
|
2495
|
+
// `prior.X`. Each recipe keeps its own scanSkip; the composing trivia governs all.
|
|
2496
|
+
let linked: Record<string, Combinator<unknown>>
|
|
2497
|
+
try {
|
|
2498
|
+
linked = linkRules(
|
|
2499
|
+
[...carriedMaps.pieces.flatMap(p => p.recipes), ...ruleMapRecipes.get(localRules)!],
|
|
2500
|
+
{ trivia: composing },
|
|
2501
|
+
)
|
|
2502
|
+
} catch (e) {
|
|
2503
|
+
throw new LinkRefusal(`${id}:${lineOf(init.start)} — composeLeaf: ${(e as Error).message.replace(/^compose: /, '')}`, { cause: e })
|
|
2560
2504
|
}
|
|
2561
|
-
const
|
|
2562
|
-
|
|
2563
|
-
// evaluated (they come from this module's own `rules()` factory), so they are
|
|
2564
|
-
// excluded from the override — their declared trivia IS the composing candidate,
|
|
2565
|
-
// and rewriting `_meta` on them would mutate the module-level grammar object.
|
|
2566
|
-
if (composing) applyComposingTrivia(carriedMaps.pieces.flatMap(p => p.rules), composing)
|
|
2505
|
+
const dangling = danglingReference(linked)
|
|
2506
|
+
if (dangling !== undefined) throw new LinkRefusal(`${id}:${lineOf(init.start)} — composeLeaf: ${dangling}`)
|
|
2567
2507
|
const refusals: string[] = []
|
|
2568
2508
|
const compiled = compileRuleMap(
|
|
2569
|
-
|
|
2509
|
+
Object.entries(linked),
|
|
2570
2510
|
{
|
|
2571
2511
|
...(composing ? { trivia: composing } : {}),
|
|
2572
2512
|
...(carriedMaps.trackLines ? { trackLines: true } : {}),
|
|
@@ -2595,6 +2535,7 @@ function transformMacroImpl(
|
|
|
2595
2535
|
warn(init.start, 'composeLeaf(): a recognition piece has no re-lowerable IR')
|
|
2596
2536
|
return null
|
|
2597
2537
|
} catch (e) {
|
|
2538
|
+
if (e instanceof LinkRefusal) throw e
|
|
2598
2539
|
warn(init.start, `composeLeaf(): ${(e as Error).message}`)
|
|
2599
2540
|
return null
|
|
2600
2541
|
}
|
|
@@ -2796,7 +2737,7 @@ function transformMacroImpl(
|
|
|
2796
2737
|
// lowering there is no such artifact, and a grammar that cannot serialize
|
|
2797
2738
|
// simply is not carried: an absent carried list makes the downstream compose
|
|
2798
2739
|
// say so, where a frozen one did not.
|
|
2799
|
-
const ir = serializeRuleMap([...compiledRules.ruleMap] as never, compiledRules.scanSkip)
|
|
2740
|
+
const ir = serializeRuleMap([...compiledRules.ruleMap] as never, compiledRules.scanSkip, externalAccesses.get(compiledRules.ruleMap))
|
|
2800
2741
|
if (ir) carriedMetadata = [{ ns, ir, ...(compiledRules.trackLines ? { trackLines: true as const } : {}) }]
|
|
2801
2742
|
// NOT SILENT. An export with no carried IR cannot be composed downstream at
|
|
2802
2743
|
// all — the consumer's `compose()` will fall back to runtime and say so, but
|
package/src/spec/model.ts
CHANGED
|
@@ -507,7 +507,9 @@ class Builder {
|
|
|
507
507
|
|
|
508
508
|
case 'lazy': {
|
|
509
509
|
const inner = resolveLazy(self)
|
|
510
|
-
|
|
510
|
+
if (inner) return this.walk(inner)
|
|
511
|
+
const prior = (self as { _priorOf?: string })._priorOf
|
|
512
|
+
return { kind: 'annotation', text: prior === undefined ? '?' : `prior.${prior}` }
|
|
511
513
|
}
|
|
512
514
|
|
|
513
515
|
case 'unknown':
|
package/src/version.ts
CHANGED