eyeling 1.23.0 → 1.23.1
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 +4 -1
- package/dist/browser/eyeling.browser.js +28 -4
- package/eyeling.js +20 -12
- package/lib/rules.js +28 -4
- package/package.json +1 -1
- package/test/api.test.js +24 -0
package/HANDBOOK.md
CHANGED
|
@@ -358,7 +358,9 @@ That distinction matters because quoted formulas still play **two different role
|
|
|
358
358
|
|
|
359
359
|
The practical rule is:
|
|
360
360
|
|
|
361
|
-
> **Eyeling lifts blanks inside quoted formulas only when the quoted formula appears directly in
|
|
361
|
+
> **Eyeling lifts blanks inside quoted formulas only when the quoted formula appears directly in an ordinary premise triple position.**
|
|
362
|
+
>
|
|
363
|
+
> For `log:includes` and `log:notIncludes`, quoted formula operands keep their own blank-node scope. The builtin may treat blanks in the goal formula existentially while proving it, but blanks in an explicit scope graph remain formula-local blanks and may be returned as blank nodes rather than synthetic variables such as `?_b1`.
|
|
362
364
|
|
|
363
365
|
This keeps `log:conjunction` and formula printing honest, while still allowing direct quoted-formula premise patterns such as `{ _:X :B :C } a :Statement.` to match interoperably.
|
|
364
366
|
|
|
@@ -1526,6 +1528,7 @@ Eyeling has **two modes**:
|
|
|
1526
1528
|
1. **Explicit scope graph**: if `Scope` is a formula `{...}`
|
|
1527
1529
|
- Eyeling reasons _only inside that formula_ (its triples are the fact store).
|
|
1528
1530
|
- External rules are not used.
|
|
1531
|
+
- Blank nodes inside the explicit scope graph are preserved as graph-local blanks; if a goal variable matches one, the binding is a blank node, not a lifted rule variable.
|
|
1529
1532
|
|
|
1530
1533
|
2. **Priority-gated global scope**: otherwise
|
|
1531
1534
|
- Eyeling uses a _frozen snapshot_ of the current global closure.
|
|
@@ -13272,9 +13272,23 @@ ${triples.map((tr) => ` ${tripleToN3(tr, prefixes)}`).join('\n')}
|
|
|
13272
13272
|
|
|
13273
13273
|
'use strict';
|
|
13274
13274
|
|
|
13275
|
-
const {
|
|
13275
|
+
const {
|
|
13276
|
+
LOG_NS,
|
|
13277
|
+
Iri,
|
|
13278
|
+
Var,
|
|
13279
|
+
Blank,
|
|
13280
|
+
ListTerm,
|
|
13281
|
+
OpenListTerm,
|
|
13282
|
+
GraphTerm,
|
|
13283
|
+
Triple,
|
|
13284
|
+
copyQuotedGraphMetadata,
|
|
13285
|
+
} = require('./prelude');
|
|
13276
13286
|
|
|
13277
13287
|
function liftBlankRuleVars(premise, conclusion) {
|
|
13288
|
+
function isLogIncludesLikePredicate(p) {
|
|
13289
|
+
return p instanceof Iri && (p.value === LOG_NS + 'includes' || p.value === LOG_NS + 'notIncludes');
|
|
13290
|
+
}
|
|
13291
|
+
|
|
13278
13292
|
// Map blank labels to stable rule-local variable names.
|
|
13279
13293
|
// This runs at rule construction time; keep it simple and allocation-light.
|
|
13280
13294
|
const mapping = Object.create(null);
|
|
@@ -13335,9 +13349,19 @@ ${triples.map((tr) => ` ${tripleToN3(tr, prefixes)}`).join('\n')}
|
|
|
13335
13349
|
return t;
|
|
13336
13350
|
}
|
|
13337
13351
|
|
|
13338
|
-
const newPremise = premise.map(
|
|
13339
|
-
|
|
13340
|
-
|
|
13352
|
+
const newPremise = premise.map((tr) => {
|
|
13353
|
+
// In log:includes / log:notIncludes, quoted formula operands are formulas
|
|
13354
|
+
// consumed by the builtin rather than ordinary triple patterns. Keep their
|
|
13355
|
+
// local blank nodes as Blank terms so the builtin can treat them as local
|
|
13356
|
+
// existentials, and bindings returned from an explicit scope are blank nodes
|
|
13357
|
+
// instead of synthetic rule variables such as ?_b1.
|
|
13358
|
+
const keepFormulaBlanks = isLogIncludesLikePredicate(tr.p);
|
|
13359
|
+
return new Triple(
|
|
13360
|
+
keepFormulaBlanks && tr.s instanceof GraphTerm ? copyQuotedTerm(tr.s) : convertTerm(tr.s, true),
|
|
13361
|
+
convertTerm(tr.p, true),
|
|
13362
|
+
keepFormulaBlanks && tr.o instanceof GraphTerm ? copyQuotedTerm(tr.o) : convertTerm(tr.o, true),
|
|
13363
|
+
);
|
|
13364
|
+
});
|
|
13341
13365
|
return [newPremise, conclusion];
|
|
13342
13366
|
}
|
|
13343
13367
|
|
package/eyeling.js
CHANGED
|
@@ -10673,8 +10673,7 @@ function mergePrefixEnvs(target, source) {
|
|
|
10673
10673
|
|
|
10674
10674
|
function mergeParsedDocuments(docs, opts = {}) {
|
|
10675
10675
|
const documents = Array.isArray(docs) ? docs : [];
|
|
10676
|
-
const scopeBlankNodes =
|
|
10677
|
-
typeof opts.scopeBlankNodes === 'boolean' ? opts.scopeBlankNodes : documents.length > 1;
|
|
10676
|
+
const scopeBlankNodes = typeof opts.scopeBlankNodes === 'boolean' ? opts.scopeBlankNodes : documents.length > 1;
|
|
10678
10677
|
|
|
10679
10678
|
const merged = emptyParsedDocument();
|
|
10680
10679
|
const mergedSources = [];
|
|
@@ -10702,12 +10701,7 @@ function mergeParsedDocuments(docs, opts = {}) {
|
|
|
10702
10701
|
}
|
|
10703
10702
|
|
|
10704
10703
|
function isN3SourceListInput(input) {
|
|
10705
|
-
return !!(
|
|
10706
|
-
input &&
|
|
10707
|
-
typeof input === 'object' &&
|
|
10708
|
-
!Array.isArray(input) &&
|
|
10709
|
-
Array.isArray(input.sources)
|
|
10710
|
-
);
|
|
10704
|
+
return !!(input && typeof input === 'object' && !Array.isArray(input) && Array.isArray(input.sources));
|
|
10711
10705
|
}
|
|
10712
10706
|
|
|
10713
10707
|
function normalizeN3SourceItem(source, index) {
|
|
@@ -13237,9 +13231,13 @@ module.exports = {
|
|
|
13237
13231
|
|
|
13238
13232
|
'use strict';
|
|
13239
13233
|
|
|
13240
|
-
const { Var, Blank, ListTerm, OpenListTerm, GraphTerm, Triple, copyQuotedGraphMetadata } = require('./prelude');
|
|
13234
|
+
const { LOG_NS, Iri, Var, Blank, ListTerm, OpenListTerm, GraphTerm, Triple, copyQuotedGraphMetadata } = require('./prelude');
|
|
13241
13235
|
|
|
13242
13236
|
function liftBlankRuleVars(premise, conclusion) {
|
|
13237
|
+
function isLogIncludesLikePredicate(p) {
|
|
13238
|
+
return p instanceof Iri && (p.value === LOG_NS + 'includes' || p.value === LOG_NS + 'notIncludes');
|
|
13239
|
+
}
|
|
13240
|
+
|
|
13243
13241
|
// Map blank labels to stable rule-local variable names.
|
|
13244
13242
|
// This runs at rule construction time; keep it simple and allocation-light.
|
|
13245
13243
|
const mapping = Object.create(null);
|
|
@@ -13296,9 +13294,19 @@ function liftBlankRuleVars(premise, conclusion) {
|
|
|
13296
13294
|
return t;
|
|
13297
13295
|
}
|
|
13298
13296
|
|
|
13299
|
-
const newPremise = premise.map(
|
|
13300
|
-
|
|
13301
|
-
|
|
13297
|
+
const newPremise = premise.map((tr) => {
|
|
13298
|
+
// In log:includes / log:notIncludes, quoted formula operands are formulas
|
|
13299
|
+
// consumed by the builtin rather than ordinary triple patterns. Keep their
|
|
13300
|
+
// local blank nodes as Blank terms so the builtin can treat them as local
|
|
13301
|
+
// existentials, and bindings returned from an explicit scope are blank nodes
|
|
13302
|
+
// instead of synthetic rule variables such as ?_b1.
|
|
13303
|
+
const keepFormulaBlanks = isLogIncludesLikePredicate(tr.p);
|
|
13304
|
+
return new Triple(
|
|
13305
|
+
keepFormulaBlanks && tr.s instanceof GraphTerm ? copyQuotedTerm(tr.s) : convertTerm(tr.s, true),
|
|
13306
|
+
convertTerm(tr.p, true),
|
|
13307
|
+
keepFormulaBlanks && tr.o instanceof GraphTerm ? copyQuotedTerm(tr.o) : convertTerm(tr.o, true),
|
|
13308
|
+
);
|
|
13309
|
+
});
|
|
13302
13310
|
return [newPremise, conclusion];
|
|
13303
13311
|
}
|
|
13304
13312
|
|
package/lib/rules.js
CHANGED
|
@@ -7,9 +7,23 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
const {
|
|
10
|
+
const {
|
|
11
|
+
LOG_NS,
|
|
12
|
+
Iri,
|
|
13
|
+
Var,
|
|
14
|
+
Blank,
|
|
15
|
+
ListTerm,
|
|
16
|
+
OpenListTerm,
|
|
17
|
+
GraphTerm,
|
|
18
|
+
Triple,
|
|
19
|
+
copyQuotedGraphMetadata,
|
|
20
|
+
} = require('./prelude');
|
|
11
21
|
|
|
12
22
|
function liftBlankRuleVars(premise, conclusion) {
|
|
23
|
+
function isLogIncludesLikePredicate(p) {
|
|
24
|
+
return p instanceof Iri && (p.value === LOG_NS + 'includes' || p.value === LOG_NS + 'notIncludes');
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
// Map blank labels to stable rule-local variable names.
|
|
14
28
|
// This runs at rule construction time; keep it simple and allocation-light.
|
|
15
29
|
const mapping = Object.create(null);
|
|
@@ -66,9 +80,19 @@ function liftBlankRuleVars(premise, conclusion) {
|
|
|
66
80
|
return t;
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
const newPremise = premise.map(
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
const newPremise = premise.map((tr) => {
|
|
84
|
+
// In log:includes / log:notIncludes, quoted formula operands are formulas
|
|
85
|
+
// consumed by the builtin rather than ordinary triple patterns. Keep their
|
|
86
|
+
// local blank nodes as Blank terms so the builtin can treat them as local
|
|
87
|
+
// existentials, and bindings returned from an explicit scope are blank nodes
|
|
88
|
+
// instead of synthetic rule variables such as ?_b1.
|
|
89
|
+
const keepFormulaBlanks = isLogIncludesLikePredicate(tr.p);
|
|
90
|
+
return new Triple(
|
|
91
|
+
keepFormulaBlanks && tr.s instanceof GraphTerm ? copyQuotedTerm(tr.s) : convertTerm(tr.s, true),
|
|
92
|
+
convertTerm(tr.p, true),
|
|
93
|
+
keepFormulaBlanks && tr.o instanceof GraphTerm ? copyQuotedTerm(tr.o) : convertTerm(tr.o, true),
|
|
94
|
+
);
|
|
95
|
+
});
|
|
72
96
|
return [newPremise, conclusion];
|
|
73
97
|
}
|
|
74
98
|
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -1643,6 +1643,30 @@ _:x :hates { _:foo :making :mess }.
|
|
|
1643
1643
|
expect: [/:(?:test)\s+:(?:contains)\s+:(?:success-literal-3)\s*\./, /:(?:test)\s+:(?:is)\s+true\s*\./],
|
|
1644
1644
|
},
|
|
1645
1645
|
|
|
1646
|
+
{
|
|
1647
|
+
name: '60a regression: log:includes explicit-scope blank node is returned as blank, not synthetic variable',
|
|
1648
|
+
opt: { proofComments: false },
|
|
1649
|
+
input: `@prefix : <http://example.org/ns#> .
|
|
1650
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
|
|
1651
|
+
|
|
1652
|
+
{
|
|
1653
|
+
{
|
|
1654
|
+
_:b1 a :Mortal .
|
|
1655
|
+
} log:includes {
|
|
1656
|
+
?CS ?CP ?CO .
|
|
1657
|
+
} .
|
|
1658
|
+
}
|
|
1659
|
+
=>
|
|
1660
|
+
{
|
|
1661
|
+
_:b2 :conclusion {
|
|
1662
|
+
?CS ?CP ?CO .
|
|
1663
|
+
} .
|
|
1664
|
+
} .
|
|
1665
|
+
`,
|
|
1666
|
+
expect: [/_:sk_\d+\s+:(?:conclusion)\s+\{\s*_:b\d+\s+a\s+:(?:Mortal)\s*\.\s*\}\s*\./s],
|
|
1667
|
+
notExpect: [/\?_b\d+\s+a\s+:(?:Mortal)/],
|
|
1668
|
+
},
|
|
1669
|
+
|
|
1646
1670
|
{
|
|
1647
1671
|
name: '61 RDF/JS input + rule objects: reason() accepts quads with rules',
|
|
1648
1672
|
run() {
|