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.
This commit is contained in:
John Dvorak
2026-05-22 12:48:39 -07:00
parent 6f82849b4f
commit 2e27693278
+11 -24
View File
@@ -27,7 +27,7 @@ import type {
SelectorRef, SelectorRef,
} from 'imhotep-core' } from 'imhotep-core'
import { createEmptySemanticIr, getDefaultContext } from 'imhotep-core' import { createEmptySemanticIr, getDefaultContext, getPredicateRelationCode, isUnaryPredicate } from 'imhotep-core'
import { parseTolerance, parseGap } from './validator.js' import { parseTolerance, parseGap } from './validator.js'
// DSL grammar FOL types (distinct from solver FormulaNode imported above) // DSL grammar FOL types (distinct from solver FormulaNode imported above)
@@ -365,27 +365,15 @@ function toExecutionIr(semanticIr: SemanticIr): ExecutionIr {
idx = 0 idx = 0
for (const k of semanticIr.envGuards.keys()) guardIndex.set(k, idx++) for (const k of semanticIr.envGuards.keys()) guardIndex.set(k, idx++)
// Encode relation as small integer // Encode relation as small integer (derived from predicate spec table).
const relationCodes: Record<string, number> = { // aspectRatioBetween is a DSL keyword, not a registered predicate.
leftOf: 1, const DSL_RELATION_CODES: Record<string, number> = {
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,
aspectRatioBetween: 15, aspectRatioBetween: 15,
between: 16, }
intersects: 17, function getRelationCode(relation: string): number {
touches: 18, const override = DSL_RELATION_CODES[relation]
hasGap: 19, if (override !== undefined) return override
return getPredicateRelationCode(relation) ?? 0
} }
const clauseType = new Uint16Array(count) const clauseType = new Uint16Array(count)
@@ -403,7 +391,7 @@ function toExecutionIr(semanticIr: SemanticIr): ExecutionIr {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const c = clauses[i] const c = clauses[i]
clauseType[i] = relationCodes[c.relation] || 0 clauseType[i] = getRelationCode(c.relation)
clauseSubject[i] = subjectIndex.get(c.subjectRef) ?? 0 clauseSubject[i] = subjectIndex.get(c.subjectRef) ?? 0
clauseReference[i] = c.referenceRef ? (subjectIndex.get(c.referenceRef) ?? 0) : 0 clauseReference[i] = c.referenceRef ? (subjectIndex.get(c.referenceRef) ?? 0) : 0
clauseFrame[i] = frameIndex.get(c.frameRef) ?? 0 clauseFrame[i] = frameIndex.get(c.frameRef) ?? 0
@@ -527,8 +515,7 @@ function compileSimpleAssertionToFormula(
): FormulaNode { ): FormulaNode {
const options = buildOptionsFromAssertion(assertion) const options = buildOptionsFromAssertion(assertion)
const isUnary = assertion.type === 'SizeAssertion' const isUnary = assertion.type === 'SizeAssertion'
|| (assertion.type === 'RelationAssertion' || (assertion.type === 'RelationAssertion' && isUnaryPredicate(assertion.relation))
&& (assertion.relation === 'atLeast' || assertion.relation === 'atMost'))
let predicateName: string let predicateName: string
let args: VariableRef[] let args: VariableRef[]