parseman 0.60.4 → 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/linker.d.ts +11 -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 +63 -21
- package/dist/index.js.map +1 -1
- package/dist/plugin/evaluator.d.ts +3 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +86 -71
- package/dist/plugin/index.js.map +1 -1
- 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 +10 -4
- package/src/compiler/linker.ts +22 -12
- package/src/index.ts +1 -0
- package/src/plugin/evaluator.ts +16 -5
- package/src/plugin/index.ts +27 -104
- package/src/spec/model.ts +3 -1
- package/src/version.ts +1 -1
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, externalAccesses, 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'
|
|
@@ -223,12 +223,6 @@ const DEFAULT_ASSEMBLY_BUDGET = 0.25
|
|
|
223
223
|
/** A build failure the lowering must not soften into a warning and a fallback. */
|
|
224
224
|
class LinkRefusal extends Error {}
|
|
225
225
|
|
|
226
|
-
/** Whether a rule-map entry has a definition (a `g.X` merely read does not). */
|
|
227
|
-
function isResolved(rule: Combinator<unknown>): boolean {
|
|
228
|
-
if (rule._def.tag !== 'lazy') return true
|
|
229
|
-
try { rule._def.thunk(); return true } catch { return false }
|
|
230
|
-
}
|
|
231
|
-
|
|
232
226
|
function reasonSuffix(runtimeOnly: readonly string[] | undefined): string {
|
|
233
227
|
return runtimeOnly === undefined || runtimeOnly.length === 0
|
|
234
228
|
? ''
|
|
@@ -2061,7 +2055,7 @@ function transformMacroImpl(
|
|
|
2061
2055
|
/**
|
|
2062
2056
|
* Evaluate a carried list back to combinators, one entry per piece: its rule map
|
|
2063
2057
|
* and the `rules()` recipe it was built from. `compose()` links the recipes into
|
|
2064
|
-
* one namespace (`mergedCarriedRules`)
|
|
2058
|
+
* one namespace (`mergedCarriedRules`), and `composeLeaf()` does the same.
|
|
2065
2059
|
* Either way the merged grammar is encoded ONCE by `compileRuleMap` — no relocation
|
|
2066
2060
|
* of code offsets and no merging of const / fn / expected pools between two
|
|
2067
2061
|
* already-encoded programs.
|
|
@@ -2097,38 +2091,6 @@ function transformMacroImpl(
|
|
|
2097
2091
|
return { pieces, trackLines }
|
|
2098
2092
|
}
|
|
2099
2093
|
|
|
2100
|
-
/**
|
|
2101
|
-
* Fold ordered rule maps into the composed map: a later piece's name WINS, and
|
|
2102
|
-
* `Map` keeps each name at its first-sighting position so the encoded rule order
|
|
2103
|
-
* tracks the source lowering's rather than drifting per compose.
|
|
2104
|
-
*
|
|
2105
|
-
* A REFERENCE IS NOT A DEFINITION. A `rules(g => …)` cache also holds every `g.X`
|
|
2106
|
-
* that was merely ACCESSED, so a delta that calls `g.Pair` carries a `Pair` entry
|
|
2107
|
-
* that is an unresolved named lazy. Merged in name order that entry lands LAST and
|
|
2108
|
-
* shadows the base piece which actually defines `Pair` — the encoder then finds a
|
|
2109
|
-
* hole where the winner should be and refuses the whole grammar with "ref() used
|
|
2110
|
-
* before .define()". The same filter guards `compileLinkableTable`'s `isLocal`
|
|
2111
|
-
* (`compile-linkable-table.ts`) and `recoverComposedRules`; this site needs it
|
|
2112
|
-
* for the same reason, and skipping it is why cross-piece composition looked blocked.
|
|
2113
|
-
*
|
|
2114
|
-
* The reference itself is not lost: it stays inside the delta's own rule bodies and
|
|
2115
|
-
* `enc.winners` binds it BY NAME to whichever piece supplies the definition.
|
|
2116
|
-
*/
|
|
2117
|
-
const mergeRuleMaps = (
|
|
2118
|
-
maps: ReadonlyArray<ReadonlyArray<readonly [string, Combinator<unknown>]>>,
|
|
2119
|
-
): Array<[string, Combinator<unknown>]> => {
|
|
2120
|
-
const winners = new Map<string, Combinator<unknown>>()
|
|
2121
|
-
for (const map of maps) {
|
|
2122
|
-
for (const [name, rule] of map) {
|
|
2123
|
-
if (rule._def.tag === 'lazy') {
|
|
2124
|
-
try { rule._def.thunk() } catch { continue }
|
|
2125
|
-
}
|
|
2126
|
-
winners.set(name, rule)
|
|
2127
|
-
}
|
|
2128
|
-
}
|
|
2129
|
-
return [...winners]
|
|
2130
|
-
}
|
|
2131
|
-
|
|
2132
2094
|
/**
|
|
2133
2095
|
* LINK a carried list into the composed map, exactly as runtime `compose()` does:
|
|
2134
2096
|
* every piece's carried `rules()` recipe runs again against ONE namespace
|
|
@@ -2156,25 +2118,6 @@ function transformMacroImpl(
|
|
|
2156
2118
|
return { rules: Object.entries(linked), trackLines: carriedMaps.trackLines, dangling }
|
|
2157
2119
|
}
|
|
2158
2120
|
|
|
2159
|
-
/**
|
|
2160
|
-
* COMPOSING-WINS for `composeLeaf()`'s carried pieces, as an OVERRIDE rather than
|
|
2161
|
-
* a gap-fill: `compileRuleMap`'s `applyAmbient` only fills a rule that carries no
|
|
2162
|
-
* trivia of its own. (`compose()` gets the same override from `linkRules`.)
|
|
2163
|
-
*
|
|
2164
|
-
* Safe to mutate: every rule here came from `evalRuleMapIR`, which constructs FRESH
|
|
2165
|
-
* combinators per piece per compose, so this cannot leak into another compose of the
|
|
2166
|
-
* same base grammar.
|
|
2167
|
-
*/
|
|
2168
|
-
const applyComposingTrivia = (
|
|
2169
|
-
ruleMap: ReadonlyArray<readonly [string, Combinator<unknown>]>,
|
|
2170
|
-
composing: Combinator<unknown>,
|
|
2171
|
-
): void => {
|
|
2172
|
-
for (const [, rule] of ruleMap) {
|
|
2173
|
-
if (rule._meta.isTrivia) continue
|
|
2174
|
-
;(rule._meta as { grammarTrivia?: Combinator<unknown> }).grammarTrivia = composing
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
2121
|
/** Resolve one `compose([...])` argument to its RE-LOWERABLE carried items (IR
|
|
2179
2122
|
* pieces / import spreads / baked-pieces fallback). The composing grammar's trivia
|
|
2180
2123
|
* is applied later, uniformly, in materializeCarried — never per-piece here. */
|
|
@@ -2340,10 +2283,17 @@ function transformMacroImpl(
|
|
|
2340
2283
|
// does — one encode, one `tableRules(…)` expression, no linker. `carried` is
|
|
2341
2284
|
// unchanged either way: it is the re-lowerable IR list, not a lowering artifact,
|
|
2342
2285
|
// so a downstream re-compose behaves identically whichever engine emitted here.
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
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
|
+
}
|
|
2347
2297
|
if (merged?.dangling !== undefined) throw new Error(`${id}:${lineOf(init.start)} — compose: ${merged.dangling}`)
|
|
2348
2298
|
if (merged !== null) {
|
|
2349
2299
|
// Harvest the direct-builder import provenance carried on the merged graph so
|
|
@@ -2475,22 +2425,15 @@ function transformMacroImpl(
|
|
|
2475
2425
|
return null
|
|
2476
2426
|
}
|
|
2477
2427
|
const localArg = elements[elements.length - 1]!
|
|
2478
|
-
let localRules:
|
|
2479
|
-
// The LOCAL leaf grammar's own ambient scanSkip (from its `rules({ scanSkip })`)
|
|
2480
|
-
// governs the scanTo/balanced sites IT defines — unlike trivia (composing-wins),
|
|
2481
|
-
// opaque units are dialect-specific, so the local declaration is threaded to the
|
|
2482
|
-
// local piece's compile.
|
|
2483
|
-
let localScanSkip: Combinator<unknown>[] | undefined
|
|
2428
|
+
let localRules: ReadonlyMap<string, Combinator<unknown>> | null = null
|
|
2484
2429
|
const importedFactories: string[] = []
|
|
2485
2430
|
if (isRulesCall(localArg)) {
|
|
2486
2431
|
const evaluated = evaluateRulesFactory(localArg, `composeLeaf${init.start}`)
|
|
2487
2432
|
localRules = evaluated?.ruleMap ?? null
|
|
2488
|
-
localScanSkip = evaluated?.scanSkip
|
|
2489
2433
|
if (evaluated?.importedFactory) importedFactories.push(evaluated.importedFactory)
|
|
2490
2434
|
} else if (localArg.type === 'Identifier') {
|
|
2491
2435
|
const name = (localArg as unknown as { name: string }).name
|
|
2492
2436
|
localRules = localRuleMaps.get(name) ?? null
|
|
2493
|
-
localScanSkip = localGrammarScanSkip.get(name)
|
|
2494
2437
|
}
|
|
2495
2438
|
if (!localRules) {
|
|
2496
2439
|
// Distinguish "the argument is the wrong SHAPE" from "the argument is the right
|
|
@@ -2525,13 +2468,6 @@ function transformMacroImpl(
|
|
|
2525
2468
|
// may place one beneath a direct node(). Re-lower their terminals with
|
|
2526
2469
|
// capture enabled so that node receives the imported token values in its
|
|
2527
2470
|
// normal child collector; the pieces still contain no semantic callback.
|
|
2528
|
-
const localNs = nsFor(`composeLeaf${init.start}`)
|
|
2529
|
-
const localEntries = [...localRules] as Array<[string, Combinator<unknown>]>
|
|
2530
|
-
|
|
2531
|
-
// TABLE FIRST — same merge as `compose()`, with the local leaf map appended LAST
|
|
2532
|
-
// so it wins every name and binds the imported shapes' holes (`enc.winners`
|
|
2533
|
-
// resolves those by name; see `mergedCarriedRules`).
|
|
2534
|
-
//
|
|
2535
2471
|
// The recognition-only gate is preserved EXACTLY, and is the reason this path
|
|
2536
2472
|
// needs no `compileLinkable`: `hasDirectBuilders` / `isRecognitionOnly` are
|
|
2537
2473
|
// predicates over the combinator graph, not products of lowering it, so
|
|
@@ -2554,36 +2490,23 @@ function transformMacroImpl(
|
|
|
2554
2490
|
warn(init.start, 'composeLeaf(): every pre-final grammar must explicitly prove recognition-only')
|
|
2555
2491
|
return null
|
|
2556
2492
|
}
|
|
2557
|
-
// The
|
|
2558
|
-
//
|
|
2559
|
-
//
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
}
|
|
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 })
|
|
2568
2504
|
}
|
|
2569
|
-
const
|
|
2570
|
-
// The same refusal as `compose()`, over a merge by name: a name some piece only
|
|
2571
|
-
// reads (an unresolved entry of a carried map, or a local factory's external
|
|
2572
|
-
// access) that no piece defines.
|
|
2573
|
-
const accessed = [
|
|
2574
|
-
...carriedMaps.pieces.flatMap(p => p.rules).filter(([, rule]) => !isResolved(rule)).map(([name]) => name),
|
|
2575
|
-
...(localRules instanceof Map ? externalAccesses.get(localRules) ?? [] : []),
|
|
2576
|
-
]
|
|
2577
|
-
const dangling = danglingReference(Object.fromEntries(leafMerged), accessed)
|
|
2505
|
+
const dangling = danglingReference(linked)
|
|
2578
2506
|
if (dangling !== undefined) throw new LinkRefusal(`${id}:${lineOf(init.start)} — composeLeaf: ${dangling}`)
|
|
2579
|
-
// Composing-wins governs the leaf fuse too. The local entries are NOT freshly
|
|
2580
|
-
// evaluated (they come from this module's own `rules()` factory), so they are
|
|
2581
|
-
// excluded from the override — their declared trivia IS the composing candidate,
|
|
2582
|
-
// and rewriting `_meta` on them would mutate the module-level grammar object.
|
|
2583
|
-
if (composing) applyComposingTrivia(carriedMaps.pieces.flatMap(p => p.rules), composing)
|
|
2584
2507
|
const refusals: string[] = []
|
|
2585
2508
|
const compiled = compileRuleMap(
|
|
2586
|
-
|
|
2509
|
+
Object.entries(linked),
|
|
2587
2510
|
{
|
|
2588
2511
|
...(composing ? { trivia: composing } : {}),
|
|
2589
2512
|
...(carriedMaps.trackLines ? { trackLines: true } : {}),
|
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