/** * Derived tokenization, part 3: token-KEYED dispatch. * * A `dispatch()` used to emit, per case, a chained condition that re-derived the * key from the selector's STRING one character at a time: * * if (_dkey.length === 6 && _dkey.charCodeAt(0) === 64 && (_dkey.charCodeAt(1) | 32) === 108 && ...) * else if (_dkey.length === 15 && ...) * * Measured on the built css artifact: 40,269 B of 3,336,650 B was exactly these * chains, 10,499 B of it inside `_r_StylesheetAtRule` alone. * * Instead the selector's matched span is walked to a small integer case id, and * the cases select on the integer. Every id strategy below is BUILT, not * reasoned about — `PARSEMAN_DISPATCH=:` picks one so they can be * measured on the shipped artifact rather than in a microbenchmark, which * already misled us once: a standalone "table" looked slow because that * implementation sliced and lowercased and hashed, not because table dispatch * is slow. * * Every strategy is "compute a candidate case cheaply, then VERIFY against the * packed key text", except `trie`, whose walk is already exact. */ /** One dispatch case's keys, in emission order. Case ids are 1-based; 0 = no match. */ export type DispatchKeySet = { keys: readonly string[]; caseInsensitive: boolean; }; export type IdStrategy = 'trie' | 'lenswitch' | 'firstchar' | 'phash'; export type ArmSelection = 'ifchain' | 'switch'; export type DispatchConfig = { id: IdStrategy | 'auto'; sel: ArmSelection; }; /** * `PARSEMAN_DISPATCH=:`. The default is the MEASURED winner on the * shipped css artifact, not a preference. All five configurations were built * into this emitter and compared on the real artifact with the trees diffed for * equality, interleaved in one process (medians of 31 rounds): * * config ms/parse rel raw B gzip B * chain 6.092 1.000 3,336,650 426,247 * trie:ifchain 5.967 0.979 3,311,657 424,465 <- default * trie:switch 5.945 0.976 3,333,421 424,895 * phash:switch 6.011 0.987 3,331,361 424,637 * * `firstchar` and `lenswitch` BUILD but are inapplicable to css's at-keyword * sets — every key starts with `@`, and the lengths collide — so they fall back * and emit the chain. `phash` finds an injective hash (the search works) but * costs more table bytes than the trie saves. `switch` arm selection is within * noise of the chain of integer compares at 3 sites x 8 cases; its larger raw * size is the downstream formatter indenting case bodies, which is why gzip is * the metric that decides here. * * The speed spread across ALL configurations is 2.4% — dispatch keying is not * where css parse time goes. */ export declare function dispatchConfigFromEnv(env: Record): DispatchConfig; /** * ASCII letter-only case fold. Used IDENTICALLY when building the tables and * when reading input — the two must never disagree. The cheaper `c | 32` is * wrong here: it maps '@'(64) to '`'(96), which silently stops every '@'-led * key from ever matching, and maps '_'(95) to DEL(127), which would accept a * character the key does not contain. */ export declare const foldExpr: (c: string) => string; export declare function foldCode(c: number): number; /** * Pack a non-negative int array into a two-chars-per-value string literal. * * Two chars at six bits each is TWELVE BITS: the representable range is 0..4095. * The mask made anything larger wrap SILENTLY, and `unpack` then decoded a wrong * index — a table that looks fine and routes to the wrong arm. Bounded here, and * this is the ONLY implementation: a second copy in token-scanner.ts had the same * encoding and the same missing check, which is how one defect became two. */ export declare const PACK_MAX = 4095; export declare function packInts(values: readonly number[]): string; export type SharedHelper = 'unpack' | 'verify' | 'trie' | 'lenswitch' | 'firstchar' | 'phash'; export declare function sharedHelperDecl(kind: SharedHelper, n: (h: SharedHelper) => string): string; /** Per-site emission: declarations to hoist plus the call expression. */ export type SiteEmission = { strategy: IdStrategy; decls: string[]; callExpr: string; helpers: SharedHelper[]; }; /** * Emit the id computation for one site. `auto` picks by KEY-SET SHAPE measured * at macro time rather than applying one strategy everywhere: separation on * char 0 is the cheapest test there is, a searched perfect hash next, then * length, with the trie as the always-applicable fallback. */ export declare function emitDispatchId(cases: ReadonlyArray, cfg: DispatchConfig, prefix: string, helperName: (h: SharedHelper) => string, pos: string, end: string): SiteEmission | null; //# sourceMappingURL=token-dispatch.d.ts.map