From 2e27693278345958625c8e80ce37c27d36f733ea Mon Sep 17 00:00:00 2001 From: John Dvorak Date: Fri, 22 May 2026 12:48:39 -0700 Subject: [PATCH] refactor: convert DSL compiler relationCodes and unary check to spec table Replace 19-entry relationCodes string-to-integer map with getPredicateRelationCode() from PredicateSpec. Keep only aspectRatioBetween (15) as local DSL-keyword override. Replace string-based unary detection ('atLeast'||'atMost') in compileSimpleAssertionToFormula with isUnaryPredicate() from spec. 595 SDK + 57 E2E tests pass. --- packages/imhotep-dsl/src/compiler.ts | 35 +++++++++------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/packages/imhotep-dsl/src/compiler.ts b/packages/imhotep-dsl/src/compiler.ts index bd13669..1e364e5 100644 --- a/packages/imhotep-dsl/src/compiler.ts +++ b/packages/imhotep-dsl/src/compiler.ts @@ -27,7 +27,7 @@ import type { SelectorRef, } from 'imhotep-core' -import { createEmptySemanticIr, getDefaultContext } from 'imhotep-core' +import { createEmptySemanticIr, getDefaultContext, getPredicateRelationCode, isUnaryPredicate } from 'imhotep-core' import { parseTolerance, parseGap } from './validator.js' // DSL grammar FOL types (distinct from solver FormulaNode imported above) @@ -365,27 +365,15 @@ function toExecutionIr(semanticIr: SemanticIr): ExecutionIr { idx = 0 for (const k of semanticIr.envGuards.keys()) guardIndex.set(k, idx++) - // Encode relation as small integer - const relationCodes: Record = { - leftOf: 1, - rightOf: 2, - above: 3, - below: 4, - alignedWith: 5, - leftAlignedWith: 6, - rightAlignedWith: 7, - topAlignedWith: 8, - bottomAlignedWith: 9, - centeredWithin: 10, - inside: 11, - contains: 12, - overlaps: 13, - separatedFrom: 14, + // Encode relation as small integer (derived from predicate spec table). + // aspectRatioBetween is a DSL keyword, not a registered predicate. + const DSL_RELATION_CODES: Record = { aspectRatioBetween: 15, - between: 16, - intersects: 17, - touches: 18, - hasGap: 19, + } + function getRelationCode(relation: string): number { + const override = DSL_RELATION_CODES[relation] + if (override !== undefined) return override + return getPredicateRelationCode(relation) ?? 0 } const clauseType = new Uint16Array(count) @@ -403,7 +391,7 @@ function toExecutionIr(semanticIr: SemanticIr): ExecutionIr { for (let i = 0; i < count; i++) { const c = clauses[i] - clauseType[i] = relationCodes[c.relation] || 0 + clauseType[i] = getRelationCode(c.relation) clauseSubject[i] = subjectIndex.get(c.subjectRef) ?? 0 clauseReference[i] = c.referenceRef ? (subjectIndex.get(c.referenceRef) ?? 0) : 0 clauseFrame[i] = frameIndex.get(c.frameRef) ?? 0 @@ -527,8 +515,7 @@ function compileSimpleAssertionToFormula( ): FormulaNode { const options = buildOptionsFromAssertion(assertion) const isUnary = assertion.type === 'SizeAssertion' - || (assertion.type === 'RelationAssertion' - && (assertion.relation === 'atLeast' || assertion.relation === 'atMost')) + || (assertion.type === 'RelationAssertion' && isUnaryPredicate(assertion.relation)) let predicateName: string let args: VariableRef[]