feat: implement variable-bound FOL domain resolution for descendants/children
- Extend DomainResolver.resolve() signature to accept optional BindingEnv so that parentVar domains can be resolved with runtime variable bindings - Pass BindingEnv through evaluateForAll/evaluateExists to resolver calls - Add buildAncestorIndex() to precompute DOM ancestor sets from CDP data - SelectorDomainResolver now filters descendant domains by the bound parent when domain.parentVar is present and ancestor index is available - Return undefined for parentVar domains when no ancestor index or env (prevents silent fallback to global domain resolution) - Update all test DomainResolver mocks for new resolve interface - Add 10 unit tests covering ancestor index construction, backward compat, descendant filtering, exclusion of non-descendants, empty descendants, missing parentVar/env, and no-ancestor-index safety
This commit is contained in:
@@ -137,7 +137,7 @@ function makeWorld(): GeometryWorld {
|
||||
|
||||
function makeResolver(domains: Map<string, { subjectIds: number[] }>): DomainResolver {
|
||||
return {
|
||||
resolve(domain) {
|
||||
resolve(domain, _env?) {
|
||||
const key = domain.selector ?? domain.domain
|
||||
const entry = domains.get(key)
|
||||
if (!entry) return undefined
|
||||
|
||||
@@ -161,7 +161,7 @@ function makeWorld(overrides?: Partial<GeometryWorld>): GeometryWorld {
|
||||
|
||||
function makeResolver(domains: Map<string, DomainValue>): DomainResolver {
|
||||
return {
|
||||
resolve(domain: DomainRef): DomainValue | undefined {
|
||||
resolve(domain: DomainRef, _env?): DomainValue | undefined {
|
||||
const key = domain.selector ?? domain.domain;
|
||||
return domains.get(key);
|
||||
},
|
||||
|
||||
@@ -160,7 +160,7 @@ function makeWorld(overrides?: Partial<GeometryWorld>): GeometryWorld {
|
||||
|
||||
function makeResolver(domains: Map<string, DomainValue>): DomainResolver {
|
||||
return {
|
||||
resolve(domain: DomainRef): DomainValue | undefined {
|
||||
resolve(domain: DomainRef, _env?): DomainValue | undefined {
|
||||
const key = domain.selector ?? domain.domain;
|
||||
return domains.get(key);
|
||||
},
|
||||
|
||||
@@ -97,7 +97,7 @@ export interface FormulaResult {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface DomainResolver {
|
||||
resolve(domain: DomainRef): DomainValue | undefined;
|
||||
resolve(domain: DomainRef, env?: BindingEnv): DomainValue | undefined;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -262,7 +262,7 @@ function evaluateForAll(
|
||||
// Resolve domains and build join specs.
|
||||
const specs: JoinSpec[] = [];
|
||||
for (const binding of formula.bindings) {
|
||||
const domain = state.resolver.resolve(binding.domain);
|
||||
const domain = state.resolver.resolve(binding.domain, env);
|
||||
if (!domain) {
|
||||
addDiagnostic(
|
||||
state,
|
||||
@@ -403,7 +403,7 @@ function evaluateExists(
|
||||
// Resolve domains and build join specs.
|
||||
const specs: JoinSpec[] = [];
|
||||
for (const binding of formula.bindings) {
|
||||
const domain = state.resolver.resolve(binding.domain);
|
||||
const domain = state.resolver.resolve(binding.domain, env);
|
||||
if (!domain) {
|
||||
addDiagnostic(
|
||||
state,
|
||||
|
||||
@@ -146,7 +146,7 @@ function makeWorldWithElements(count: number, overrides?: Partial<GeometryWorld>
|
||||
|
||||
function makeResolver(domains: Map<string, DomainValue>): DomainResolver {
|
||||
return {
|
||||
resolve(domain: any): DomainValue | undefined {
|
||||
resolve(domain: any, _env?: any): DomainValue | undefined {
|
||||
const key = domain.selector ?? domain.domain;
|
||||
return domains.get(key);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user