refactor: eliminate remaining hardcoded predicate-name dispatch
Extraction.ts (3 fixes):
- Replace 2 'inStackingContext' string checks with isVariableArityPredicate()
- Replace 7-name diagnostic formatting if/else with spec-driven
getPredicateSpec() checks (isDirectional → gap message,
isSize → threshold hint, else generic)
Grammar.ts: Replace 8 hardcoded parser routing checks
(atLeast/atMost/aspectRatio/between/clippedBy/attachedToScrollContainer/
escapeClippingChainOf/inStackingContext) with SIZE_PREDICATE_NAMES and
TOPOLOGY_PREDICATE_NAMES Sets derived from spec table.
Pipeline.ts: Replace 15-entry CODE_TO_CLAUSE_KIND map with runtime
generation from PREDICATE_SPECS. Prefix derived from spec.isSize
('size.*') / validOptions.includes('axis') ('alignment.*') /
else ('relation.*'). Manual override for aspectRatio code 15.
Proofs.ts: Replace 11-case switch(kind) with 5 spec-driven if/else
branches categorized by validOptions presence (hasGap→directional,
hasAxis→alignment) + 2 specific name checks (inside overflow,
aspectRatio ratio). 11 predicate names → 0 hardcoded.
Lexer.ts: Export KEYWORDS map for conformance testing.
Conformance tests:
- Solver: every BUILTIN_PREDICATES entry matches its PREDICATE_SPECS
counterpart; every spec name (incl. aliases) has a registered
evaluator with matching descriptor (2 tests)
- DSL: every predicate name from collectAllPredicateNames() appears
in the lexer KEYWORDS table (1 test)
598 SDK + 3 conformance + 57 E2E = 658 tests pass.
This commit is contained in:
@@ -106,6 +106,7 @@ import type {
|
||||
} from './diagnostics.js'
|
||||
|
||||
import { createDiagnostic } from './diagnostics.js'
|
||||
import { PREDICATE_SPECS } from './predicate-specs.js'
|
||||
|
||||
// Adapter interfaces - implementations injected at runtime
|
||||
interface ExtractorRequest {
|
||||
@@ -433,25 +434,23 @@ export interface PipelineResult {
|
||||
|
||||
/**
|
||||
* Reverse mapping from execution IR clause type codes to solver clause kinds.
|
||||
* Mirrors the relationCodes table in imhotep-dsl/compiler.ts.
|
||||
* Built from the predicate spec table — any predicate with a relationCode
|
||||
* automatically gets a clause kind entry.
|
||||
*/
|
||||
const CODE_TO_CLAUSE_KIND: Record<number, string> = {
|
||||
1: 'relation.leftOf',
|
||||
2: 'relation.rightOf',
|
||||
3: 'relation.above',
|
||||
4: 'relation.below',
|
||||
5: 'alignment.alignedWith',
|
||||
6: 'alignment.leftAlignedWith',
|
||||
7: 'alignment.rightAlignedWith',
|
||||
8: 'alignment.topAlignedWith',
|
||||
9: 'alignment.bottomAlignedWith',
|
||||
10: 'alignment.centeredWithin',
|
||||
11: 'relation.inside',
|
||||
12: 'relation.contains',
|
||||
13: 'relation.overlaps',
|
||||
14: 'relation.separatedFrom',
|
||||
15: 'size.aspectRatio',
|
||||
}
|
||||
const CODE_TO_CLAUSE_KIND: Record<number, string> = (() => {
|
||||
const map: Record<number, string> = {}
|
||||
for (const spec of PREDICATE_SPECS) {
|
||||
if (!spec.relationCode) continue
|
||||
let prefix = 'relation'
|
||||
if (spec.isSize) prefix = 'size'
|
||||
else if (spec.validOptions.includes('axis')) prefix = 'alignment'
|
||||
map[spec.relationCode] = `${prefix}.${spec.name}`
|
||||
}
|
||||
return map
|
||||
})()
|
||||
// DSL keyword 'aspectRatioBetween' uses code 15; maps to the canonical
|
||||
// 'aspectRatio' predicate which has no separate relationCode.
|
||||
CODE_TO_CLAUSE_KIND[15] = 'size.aspectRatio'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main Pipeline Orchestrator
|
||||
|
||||
Reference in New Issue
Block a user