eyeling 1.22.13 → 1.22.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HANDBOOK.md +2 -0
- package/dist/browser/eyeling.browser.js +232 -180
- package/examples/control-system-becoming.n3 +203 -0
- package/examples/developmental-genetics-becoming.n3 +204 -0
- package/examples/engineering-becoming.n3 +167 -0
- package/examples/output/control-system-becoming.n3 +35 -0
- package/examples/output/developmental-genetics-becoming.n3 +32 -0
- package/examples/output/engineering-becoming.n3 +26 -0
- package/examples/output/whitehead-becoming.n3 +42 -0
- package/examples/whitehead-becoming.n3 +155 -0
- package/eyeling.js +240 -184
- package/lib/builtins.js +164 -151
- package/lib/engine.js +67 -29
- package/package.json +1 -1
- package/test/api.test.js +28 -0
package/lib/engine.js
CHANGED
|
@@ -76,6 +76,19 @@ const deref = require('./deref');
|
|
|
76
76
|
|
|
77
77
|
const hasOwn = Object.prototype.hasOwnProperty;
|
|
78
78
|
|
|
79
|
+
function __emptySubst() {
|
|
80
|
+
return Object.create(null);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function __cloneSubst(subst) {
|
|
84
|
+
if (!subst) return __emptySubst();
|
|
85
|
+
const out = Object.create(null);
|
|
86
|
+
for (const k in subst) {
|
|
87
|
+
if (hasOwn.call(subst, k)) out[k] = subst[k];
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
let version = 'dev';
|
|
80
93
|
try {
|
|
81
94
|
// Node: keep package.json version if available
|
|
@@ -1287,7 +1300,7 @@ function pushFactIndexed(facts, tr) {
|
|
|
1287
1300
|
|
|
1288
1301
|
function makeDerivedRecord(fact, rule, premises, subst, captureExplanations) {
|
|
1289
1302
|
if (captureExplanations === false) return { fact };
|
|
1290
|
-
return new DerivedFact(fact, rule, premises.slice(),
|
|
1303
|
+
return new DerivedFact(fact, rule, premises.slice(), __cloneSubst(subst));
|
|
1291
1304
|
}
|
|
1292
1305
|
|
|
1293
1306
|
function ensureBackRuleIndexes(backRules) {
|
|
@@ -1795,6 +1808,21 @@ function unifyOpenWithList(prefix, tailv, ys, subst) {
|
|
|
1795
1808
|
return s2;
|
|
1796
1809
|
}
|
|
1797
1810
|
|
|
1811
|
+
function graphTriplesContainVars(triples) {
|
|
1812
|
+
function termHasVar(t) {
|
|
1813
|
+
if (t instanceof Var) return true;
|
|
1814
|
+
if (t instanceof ListTerm) return t.elems.some(termHasVar);
|
|
1815
|
+
if (t instanceof OpenListTerm) return t.prefix.some(termHasVar) || true;
|
|
1816
|
+
if (t instanceof GraphTerm) return t.triples.some((tr) => termHasVar(tr.s) || termHasVar(tr.p) || termHasVar(tr.o));
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
for (const tr of triples) {
|
|
1821
|
+
if (termHasVar(tr.s) || termHasVar(tr.p) || termHasVar(tr.o)) return true;
|
|
1822
|
+
}
|
|
1823
|
+
return false;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1798
1826
|
function unifyGraphTriples(xs, ys, subst) {
|
|
1799
1827
|
if (xs.length !== ys.length) return null;
|
|
1800
1828
|
|
|
@@ -1863,7 +1891,7 @@ function unifyTermWithOptions(a, b, subst, opts) {
|
|
|
1863
1891
|
const t = b;
|
|
1864
1892
|
if (t instanceof Var && t.name === v) return subst;
|
|
1865
1893
|
if (containsVarTerm(t, v)) return null;
|
|
1866
|
-
const s2 =
|
|
1894
|
+
const s2 = __cloneSubst(subst);
|
|
1867
1895
|
s2[v] = t;
|
|
1868
1896
|
return s2;
|
|
1869
1897
|
}
|
|
@@ -1956,17 +1984,22 @@ function unifyTermWithOptions(a, b, subst, opts) {
|
|
|
1956
1984
|
|
|
1957
1985
|
// Graphs
|
|
1958
1986
|
if (a instanceof GraphTerm && b instanceof GraphTerm) {
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1987
|
+
// Only use alpha-equivalence as a binding-free fast path when both quoted
|
|
1988
|
+
// formulas are variable-free after substitution. If unbound variables remain,
|
|
1989
|
+
// they may be shared with the outer rule and must unify/bind structurally.
|
|
1990
|
+
if (!graphTriplesContainVars(a.triples) && !graphTriplesContainVars(b.triples)) {
|
|
1991
|
+
const protectedNamesA = collectProtectedNamesForTerm(aRaw, subst);
|
|
1992
|
+
const protectedNamesB = collectProtectedNamesForTerm(bRaw, subst);
|
|
1993
|
+
if (
|
|
1994
|
+
alphaEqGraphTriples(a.triples, b.triples, {
|
|
1995
|
+
protectedVarsA: protectedNamesA.protectedVars,
|
|
1996
|
+
protectedVarsB: protectedNamesB.protectedVars,
|
|
1997
|
+
protectedBlanksA: protectedNamesA.protectedBlanks,
|
|
1998
|
+
protectedBlanksB: protectedNamesB.protectedBlanks,
|
|
1999
|
+
})
|
|
2000
|
+
) {
|
|
2001
|
+
return subst;
|
|
2002
|
+
}
|
|
1970
2003
|
}
|
|
1971
2004
|
return unifyGraphTriples(a.triples, b.triples, subst);
|
|
1972
2005
|
}
|
|
@@ -2048,7 +2081,7 @@ function gcCompactForGoals(subst, goals, answerVars) {
|
|
|
2048
2081
|
}
|
|
2049
2082
|
}
|
|
2050
2083
|
|
|
2051
|
-
const out =
|
|
2084
|
+
const out = __emptySubst();
|
|
2052
2085
|
for (const k of Object.keys(subst)) {
|
|
2053
2086
|
if (keep.has(k)) out[k] = subst[k];
|
|
2054
2087
|
}
|
|
@@ -2111,7 +2144,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2111
2144
|
const allowDeferredBuiltins = !!(opts && opts.deferBuiltins);
|
|
2112
2145
|
|
|
2113
2146
|
const initialGoals = Array.isArray(goals) ? goals.slice() : [];
|
|
2114
|
-
const substMut = subst ?
|
|
2147
|
+
const substMut = subst ? __cloneSubst(subst) : {};
|
|
2115
2148
|
const initialVisited = visited ? visited.slice() : [];
|
|
2116
2149
|
|
|
2117
2150
|
// Variables from the original goal list (needed by the caller to instantiate conclusions)
|
|
@@ -2347,17 +2380,22 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2347
2380
|
|
|
2348
2381
|
// Graphs
|
|
2349
2382
|
if (a instanceof GraphTerm && b instanceof GraphTerm) {
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2383
|
+
// Only use alpha-equivalence as a binding-free fast path when both quoted
|
|
2384
|
+
// formulas are variable-free after substitution. If unbound variables remain,
|
|
2385
|
+
// they may be shared with the outer rule and must unify/bind structurally.
|
|
2386
|
+
if (!graphTriplesContainVars(a.triples) && !graphTriplesContainVars(b.triples)) {
|
|
2387
|
+
const protectedNamesA = collectProtectedNamesForTerm(aRaw, substMut);
|
|
2388
|
+
const protectedNamesB = collectProtectedNamesForTerm(bRaw, substMut);
|
|
2389
|
+
if (
|
|
2390
|
+
alphaEqGraphTriples(a.triples, b.triples, {
|
|
2391
|
+
protectedVarsA: protectedNamesA.protectedVars,
|
|
2392
|
+
protectedVarsB: protectedNamesB.protectedVars,
|
|
2393
|
+
protectedBlanksA: protectedNamesA.protectedBlanks,
|
|
2394
|
+
protectedBlanksB: protectedNamesB.protectedBlanks,
|
|
2395
|
+
})
|
|
2396
|
+
) {
|
|
2397
|
+
return true;
|
|
2398
|
+
}
|
|
2361
2399
|
}
|
|
2362
2400
|
const merged = unifyGraphTriples(a.triples, b.triples, substMut);
|
|
2363
2401
|
if (merged === null) return false;
|
|
@@ -2568,7 +2606,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2568
2606
|
const builtinMax = Number.isFinite(remaining) && !restGoals.length ? remaining : undefined;
|
|
2569
2607
|
|
|
2570
2608
|
const builtinGoalForEval = goalPredicateIri === LOG_NS + 'rawType' ? rawGoal : goal0;
|
|
2571
|
-
const builtinSubstForEval = goalPredicateIri === LOG_NS + 'rawType' ? substMut :
|
|
2609
|
+
const builtinSubstForEval = goalPredicateIri === LOG_NS + 'rawType' ? substMut : __emptySubst();
|
|
2572
2610
|
let deltas = evalBuiltin(
|
|
2573
2611
|
builtinGoalForEval,
|
|
2574
2612
|
builtinSubstForEval,
|
|
@@ -2610,7 +2648,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2610
2648
|
subjectAndObjectAreFullyUnbound &&
|
|
2611
2649
|
(!restGoals.length || dc >= goalsNow.length)
|
|
2612
2650
|
) {
|
|
2613
|
-
deltas = [
|
|
2651
|
+
deltas = [__emptySubst()];
|
|
2614
2652
|
}
|
|
2615
2653
|
|
|
2616
2654
|
if (deltas.length) {
|
|
@@ -3043,7 +3081,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3043
3081
|
const r = entry.rule;
|
|
3044
3082
|
if (__skipForwardRuleNow(r)) continue;
|
|
3045
3083
|
|
|
3046
|
-
const s = unifyTriple(entry.goal, fact,
|
|
3084
|
+
const s = unifyTriple(entry.goal, fact, __emptySubst());
|
|
3047
3085
|
if (s === null) continue;
|
|
3048
3086
|
|
|
3049
3087
|
const outcome = __emitForwardRuleSolution(r, entry.ruleIndex, s);
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -2278,6 +2278,34 @@ _:b a ex:Person ; ex:name "B" .
|
|
|
2278
2278
|
{
|
|
2279
2279
|
:test :is true .
|
|
2280
2280
|
}.
|
|
2281
|
+
`,
|
|
2282
|
+
expect: [/^:test\s+:is\s+true\s*\./m],
|
|
2283
|
+
},
|
|
2284
|
+
{
|
|
2285
|
+
name: 'regression: quoted-formula backward-rule heads must bind shared variables for later goals',
|
|
2286
|
+
opt: { proofComments: false },
|
|
2287
|
+
input: `@prefix : <http://example.org/> .
|
|
2288
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
2289
|
+
|
|
2290
|
+
{ :a :b :c } a :Statement .
|
|
2291
|
+
|
|
2292
|
+
{ ?A :has { ?S ?P ?O } }
|
|
2293
|
+
<=
|
|
2294
|
+
{
|
|
2295
|
+
?A log:includes { ?S ?P ?O }.
|
|
2296
|
+
}.
|
|
2297
|
+
|
|
2298
|
+
{
|
|
2299
|
+
?A a :Statement .
|
|
2300
|
+
?A :has { ?S ?P ?O }.
|
|
2301
|
+
?S log:rawType log:Other.
|
|
2302
|
+
?P log:rawType log:Other.
|
|
2303
|
+
?O log:rawType log:Other.
|
|
2304
|
+
}
|
|
2305
|
+
=>
|
|
2306
|
+
{
|
|
2307
|
+
:test :is true .
|
|
2308
|
+
}.
|
|
2281
2309
|
`,
|
|
2282
2310
|
expect: [/^:test\s+:is\s+true\s*\./m],
|
|
2283
2311
|
},
|