eyeling 1.25.2 → 1.25.3
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/dist/browser/eyeling.browser.js +63 -39
- package/eyeling.js +63 -39
- package/lib/cli.js +3 -1
- package/lib/engine.js +6 -4
- package/lib/lexer.js +42 -16
- package/lib/parser.js +12 -27
- package/package.json +1 -1
|
@@ -4965,12 +4965,14 @@ function main() {
|
|
|
4965
4965
|
outTriples = res.queryTriples;
|
|
4966
4966
|
outDerived = res.queryDerived;
|
|
4967
4967
|
} else {
|
|
4968
|
+
const skipDerivedCollection = mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled();
|
|
4968
4969
|
derived = engine.forwardChain(facts, frules, brules, null, {
|
|
4969
4970
|
captureExplanations: engine.getProofCommentsEnabled(),
|
|
4971
|
+
collectDerived: !skipDerivedCollection,
|
|
4970
4972
|
prefixes,
|
|
4971
4973
|
});
|
|
4972
4974
|
outDerived = derived;
|
|
4973
|
-
outTriples = derived.map((df) => df.fact);
|
|
4975
|
+
outTriples = skipDerivedCollection ? [] : derived.map((df) => df.fact);
|
|
4974
4976
|
}
|
|
4975
4977
|
|
|
4976
4978
|
const renderedOutputTriples = hasQueries ? outTriples : facts;
|
|
@@ -8388,6 +8390,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8388
8390
|
__attachGoalTable(backRules, goalTable);
|
|
8389
8391
|
|
|
8390
8392
|
const captureExplanations = !(opts && opts.captureExplanations === false);
|
|
8393
|
+
const collectDerived = !(opts && opts.collectDerived === false);
|
|
8394
|
+
const hasDerivedCallback = typeof onDerived === 'function';
|
|
8391
8395
|
const derivedForward = [];
|
|
8392
8396
|
const varGen = [0];
|
|
8393
8397
|
const skCounter = [0];
|
|
@@ -8566,8 +8570,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8566
8570
|
if (!hasFactIndexed(facts, instantiated)) {
|
|
8567
8571
|
pushFactIndexed(facts, instantiated);
|
|
8568
8572
|
const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
|
|
8569
|
-
derivedForward.push(df);
|
|
8570
|
-
if (
|
|
8573
|
+
if (collectDerived) derivedForward.push(df);
|
|
8574
|
+
if (hasDerivedCallback) onDerived(df);
|
|
8571
8575
|
changedHere = true;
|
|
8572
8576
|
}
|
|
8573
8577
|
|
|
@@ -8630,8 +8634,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8630
8634
|
|
|
8631
8635
|
pushFactIndexed(facts, inst);
|
|
8632
8636
|
const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
|
|
8633
|
-
derivedForward.push(df);
|
|
8634
|
-
if (
|
|
8637
|
+
if (collectDerived) derivedForward.push(df);
|
|
8638
|
+
if (hasDerivedCallback) onDerived(df);
|
|
8635
8639
|
|
|
8636
8640
|
changedHere = true;
|
|
8637
8641
|
}
|
|
@@ -10727,7 +10731,9 @@ function lex(inputText, opts = {}) {
|
|
|
10727
10731
|
// Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
|
|
10728
10732
|
// only needed when the text contains surrogate pairs and we want the old
|
|
10729
10733
|
// code-point iteration behavior for non-BMP characters.
|
|
10730
|
-
const
|
|
10734
|
+
const hasSurrogates = /[\uD800-\uDFFF]/.test(inputText);
|
|
10735
|
+
const inputMayContainInvalidStringChar = hasSurrogates || /[\u0000\uFFFE\uFFFF]/.test(inputText);
|
|
10736
|
+
const chars = hasSurrogates ? Array.from(inputText) : inputText;
|
|
10731
10737
|
const n = chars.length;
|
|
10732
10738
|
let i = 0;
|
|
10733
10739
|
const tokens = [];
|
|
@@ -10762,14 +10768,47 @@ function lex(inputText, opts = {}) {
|
|
|
10762
10768
|
// Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
|
|
10763
10769
|
if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
|
|
10764
10770
|
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10771
|
+
const code = cc.charCodeAt(0);
|
|
10772
|
+
|
|
10773
|
+
// Common ASCII QName/identifier characters. Keep this branch inline so
|
|
10774
|
+
// ordinary N3 files do not call through the full Unicode PN_CHARS predicate
|
|
10775
|
+
// for every character.
|
|
10776
|
+
if (
|
|
10777
|
+
code === 58 || // ':'
|
|
10778
|
+
code === 95 || // '_'
|
|
10779
|
+
code === 45 || // '-'
|
|
10780
|
+
(code >= 48 && code <= 57) ||
|
|
10781
|
+
(code >= 65 && code <= 90) ||
|
|
10782
|
+
(code >= 97 && code <= 122)
|
|
10783
|
+
) {
|
|
10784
|
+
if (out !== null) out.push(cc);
|
|
10769
10785
|
i++;
|
|
10770
10786
|
continue;
|
|
10771
10787
|
}
|
|
10772
10788
|
|
|
10789
|
+
// Dot is allowed inside PN_LOCAL, but not at the end.
|
|
10790
|
+
if (cc === '.') {
|
|
10791
|
+
const next = peek(1);
|
|
10792
|
+
if (next === null) break;
|
|
10793
|
+
const ncode = next.charCodeAt(0);
|
|
10794
|
+
if (
|
|
10795
|
+
next === '%' ||
|
|
10796
|
+
next === '\\' ||
|
|
10797
|
+
ncode === 58 ||
|
|
10798
|
+
ncode === 95 ||
|
|
10799
|
+
ncode === 45 ||
|
|
10800
|
+
(ncode >= 48 && ncode <= 57) ||
|
|
10801
|
+
(ncode >= 65 && ncode <= 90) ||
|
|
10802
|
+
(ncode >= 97 && ncode <= 122) ||
|
|
10803
|
+
isIdentChar(next)
|
|
10804
|
+
) {
|
|
10805
|
+
if (out !== null) out.push('.');
|
|
10806
|
+
i++;
|
|
10807
|
+
continue;
|
|
10808
|
+
}
|
|
10809
|
+
break;
|
|
10810
|
+
}
|
|
10811
|
+
|
|
10773
10812
|
// Percent escape: %HH
|
|
10774
10813
|
if (cc === '%') {
|
|
10775
10814
|
const h1 = peek(1);
|
|
@@ -11017,7 +11056,7 @@ function lex(inputText, opts = {}) {
|
|
|
11017
11056
|
}
|
|
11018
11057
|
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
11019
11058
|
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
11020
|
-
assertValidStringLiteralValue(decoded, start);
|
|
11059
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
11021
11060
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
11022
11061
|
tokens.push(new Token('Literal', s, start));
|
|
11023
11062
|
continue;
|
|
@@ -11107,7 +11146,7 @@ function lex(inputText, opts = {}) {
|
|
|
11107
11146
|
}
|
|
11108
11147
|
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
11109
11148
|
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
11110
|
-
assertValidStringLiteralValue(decoded, start);
|
|
11149
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
11111
11150
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
11112
11151
|
tokens.push(new Token('Literal', s, start));
|
|
11113
11152
|
continue;
|
|
@@ -12217,15 +12256,21 @@ class Parser {
|
|
|
12217
12256
|
|
|
12218
12257
|
while (true) {
|
|
12219
12258
|
const { verb, invert } = this.parseStatementVerb();
|
|
12220
|
-
const objects = this.parseObjectList();
|
|
12221
12259
|
|
|
12222
|
-
|
|
12223
|
-
|
|
12224
|
-
|
|
12260
|
+
while (true) {
|
|
12261
|
+
const o = this.parseTerm();
|
|
12262
|
+
const postTriples = this.pendingTriplesAfter;
|
|
12263
|
+
this.pendingTriplesAfter = [];
|
|
12264
|
+
|
|
12265
|
+
// If VERB or OBJECT contained paths, their helper triples must come
|
|
12266
|
+
// before the triple that consumes the path result (Easter depends on this).
|
|
12267
|
+
this.flushPendingTriples(out);
|
|
12225
12268
|
|
|
12226
|
-
for (const { term: o, postTriples } of objects) {
|
|
12227
12269
|
out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
|
|
12228
|
-
if (postTriples
|
|
12270
|
+
if (postTriples.length) out.push(...postTriples);
|
|
12271
|
+
|
|
12272
|
+
if (this.peek().typ !== 'Comma') break;
|
|
12273
|
+
this.next();
|
|
12229
12274
|
}
|
|
12230
12275
|
|
|
12231
12276
|
if (this.peek().typ === 'Semicolon') {
|
|
@@ -12239,27 +12284,6 @@ class Parser {
|
|
|
12239
12284
|
return out;
|
|
12240
12285
|
}
|
|
12241
12286
|
|
|
12242
|
-
parseObjectList() {
|
|
12243
|
-
// Capture any trailing property-list triples produced while parsing each
|
|
12244
|
-
// object term so we can emit them *after* the triple that references the
|
|
12245
|
-
// term. (See pendingTriplesAfter in the constructor.)
|
|
12246
|
-
|
|
12247
|
-
const objs = [];
|
|
12248
|
-
const readObj = () => {
|
|
12249
|
-
const o = this.parseTerm();
|
|
12250
|
-
const post = this.pendingTriplesAfter;
|
|
12251
|
-
this.pendingTriplesAfter = [];
|
|
12252
|
-
objs.push({ term: o, postTriples: post });
|
|
12253
|
-
};
|
|
12254
|
-
|
|
12255
|
-
readObj();
|
|
12256
|
-
while (this.peek().typ === 'Comma') {
|
|
12257
|
-
this.next();
|
|
12258
|
-
readObj();
|
|
12259
|
-
}
|
|
12260
|
-
return objs;
|
|
12261
|
-
}
|
|
12262
|
-
|
|
12263
12287
|
makeRule(left, right, isForward) {
|
|
12264
12288
|
let premiseTerm, conclTerm;
|
|
12265
12289
|
|
package/eyeling.js
CHANGED
|
@@ -4965,12 +4965,14 @@ function main() {
|
|
|
4965
4965
|
outTriples = res.queryTriples;
|
|
4966
4966
|
outDerived = res.queryDerived;
|
|
4967
4967
|
} else {
|
|
4968
|
+
const skipDerivedCollection = mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled();
|
|
4968
4969
|
derived = engine.forwardChain(facts, frules, brules, null, {
|
|
4969
4970
|
captureExplanations: engine.getProofCommentsEnabled(),
|
|
4971
|
+
collectDerived: !skipDerivedCollection,
|
|
4970
4972
|
prefixes,
|
|
4971
4973
|
});
|
|
4972
4974
|
outDerived = derived;
|
|
4973
|
-
outTriples = derived.map((df) => df.fact);
|
|
4975
|
+
outTriples = skipDerivedCollection ? [] : derived.map((df) => df.fact);
|
|
4974
4976
|
}
|
|
4975
4977
|
|
|
4976
4978
|
const renderedOutputTriples = hasQueries ? outTriples : facts;
|
|
@@ -8388,6 +8390,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8388
8390
|
__attachGoalTable(backRules, goalTable);
|
|
8389
8391
|
|
|
8390
8392
|
const captureExplanations = !(opts && opts.captureExplanations === false);
|
|
8393
|
+
const collectDerived = !(opts && opts.collectDerived === false);
|
|
8394
|
+
const hasDerivedCallback = typeof onDerived === 'function';
|
|
8391
8395
|
const derivedForward = [];
|
|
8392
8396
|
const varGen = [0];
|
|
8393
8397
|
const skCounter = [0];
|
|
@@ -8566,8 +8570,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8566
8570
|
if (!hasFactIndexed(facts, instantiated)) {
|
|
8567
8571
|
pushFactIndexed(facts, instantiated);
|
|
8568
8572
|
const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
|
|
8569
|
-
derivedForward.push(df);
|
|
8570
|
-
if (
|
|
8573
|
+
if (collectDerived) derivedForward.push(df);
|
|
8574
|
+
if (hasDerivedCallback) onDerived(df);
|
|
8571
8575
|
changedHere = true;
|
|
8572
8576
|
}
|
|
8573
8577
|
|
|
@@ -8630,8 +8634,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8630
8634
|
|
|
8631
8635
|
pushFactIndexed(facts, inst);
|
|
8632
8636
|
const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
|
|
8633
|
-
derivedForward.push(df);
|
|
8634
|
-
if (
|
|
8637
|
+
if (collectDerived) derivedForward.push(df);
|
|
8638
|
+
if (hasDerivedCallback) onDerived(df);
|
|
8635
8639
|
|
|
8636
8640
|
changedHere = true;
|
|
8637
8641
|
}
|
|
@@ -10727,7 +10731,9 @@ function lex(inputText, opts = {}) {
|
|
|
10727
10731
|
// Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
|
|
10728
10732
|
// only needed when the text contains surrogate pairs and we want the old
|
|
10729
10733
|
// code-point iteration behavior for non-BMP characters.
|
|
10730
|
-
const
|
|
10734
|
+
const hasSurrogates = /[\uD800-\uDFFF]/.test(inputText);
|
|
10735
|
+
const inputMayContainInvalidStringChar = hasSurrogates || /[\u0000\uFFFE\uFFFF]/.test(inputText);
|
|
10736
|
+
const chars = hasSurrogates ? Array.from(inputText) : inputText;
|
|
10731
10737
|
const n = chars.length;
|
|
10732
10738
|
let i = 0;
|
|
10733
10739
|
const tokens = [];
|
|
@@ -10762,14 +10768,47 @@ function lex(inputText, opts = {}) {
|
|
|
10762
10768
|
// Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
|
|
10763
10769
|
if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
|
|
10764
10770
|
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10771
|
+
const code = cc.charCodeAt(0);
|
|
10772
|
+
|
|
10773
|
+
// Common ASCII QName/identifier characters. Keep this branch inline so
|
|
10774
|
+
// ordinary N3 files do not call through the full Unicode PN_CHARS predicate
|
|
10775
|
+
// for every character.
|
|
10776
|
+
if (
|
|
10777
|
+
code === 58 || // ':'
|
|
10778
|
+
code === 95 || // '_'
|
|
10779
|
+
code === 45 || // '-'
|
|
10780
|
+
(code >= 48 && code <= 57) ||
|
|
10781
|
+
(code >= 65 && code <= 90) ||
|
|
10782
|
+
(code >= 97 && code <= 122)
|
|
10783
|
+
) {
|
|
10784
|
+
if (out !== null) out.push(cc);
|
|
10769
10785
|
i++;
|
|
10770
10786
|
continue;
|
|
10771
10787
|
}
|
|
10772
10788
|
|
|
10789
|
+
// Dot is allowed inside PN_LOCAL, but not at the end.
|
|
10790
|
+
if (cc === '.') {
|
|
10791
|
+
const next = peek(1);
|
|
10792
|
+
if (next === null) break;
|
|
10793
|
+
const ncode = next.charCodeAt(0);
|
|
10794
|
+
if (
|
|
10795
|
+
next === '%' ||
|
|
10796
|
+
next === '\\' ||
|
|
10797
|
+
ncode === 58 ||
|
|
10798
|
+
ncode === 95 ||
|
|
10799
|
+
ncode === 45 ||
|
|
10800
|
+
(ncode >= 48 && ncode <= 57) ||
|
|
10801
|
+
(ncode >= 65 && ncode <= 90) ||
|
|
10802
|
+
(ncode >= 97 && ncode <= 122) ||
|
|
10803
|
+
isIdentChar(next)
|
|
10804
|
+
) {
|
|
10805
|
+
if (out !== null) out.push('.');
|
|
10806
|
+
i++;
|
|
10807
|
+
continue;
|
|
10808
|
+
}
|
|
10809
|
+
break;
|
|
10810
|
+
}
|
|
10811
|
+
|
|
10773
10812
|
// Percent escape: %HH
|
|
10774
10813
|
if (cc === '%') {
|
|
10775
10814
|
const h1 = peek(1);
|
|
@@ -11017,7 +11056,7 @@ function lex(inputText, opts = {}) {
|
|
|
11017
11056
|
}
|
|
11018
11057
|
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
11019
11058
|
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
11020
|
-
assertValidStringLiteralValue(decoded, start);
|
|
11059
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
11021
11060
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
11022
11061
|
tokens.push(new Token('Literal', s, start));
|
|
11023
11062
|
continue;
|
|
@@ -11107,7 +11146,7 @@ function lex(inputText, opts = {}) {
|
|
|
11107
11146
|
}
|
|
11108
11147
|
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
11109
11148
|
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
11110
|
-
assertValidStringLiteralValue(decoded, start);
|
|
11149
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
11111
11150
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
11112
11151
|
tokens.push(new Token('Literal', s, start));
|
|
11113
11152
|
continue;
|
|
@@ -12217,15 +12256,21 @@ class Parser {
|
|
|
12217
12256
|
|
|
12218
12257
|
while (true) {
|
|
12219
12258
|
const { verb, invert } = this.parseStatementVerb();
|
|
12220
|
-
const objects = this.parseObjectList();
|
|
12221
12259
|
|
|
12222
|
-
|
|
12223
|
-
|
|
12224
|
-
|
|
12260
|
+
while (true) {
|
|
12261
|
+
const o = this.parseTerm();
|
|
12262
|
+
const postTriples = this.pendingTriplesAfter;
|
|
12263
|
+
this.pendingTriplesAfter = [];
|
|
12264
|
+
|
|
12265
|
+
// If VERB or OBJECT contained paths, their helper triples must come
|
|
12266
|
+
// before the triple that consumes the path result (Easter depends on this).
|
|
12267
|
+
this.flushPendingTriples(out);
|
|
12225
12268
|
|
|
12226
|
-
for (const { term: o, postTriples } of objects) {
|
|
12227
12269
|
out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
|
|
12228
|
-
if (postTriples
|
|
12270
|
+
if (postTriples.length) out.push(...postTriples);
|
|
12271
|
+
|
|
12272
|
+
if (this.peek().typ !== 'Comma') break;
|
|
12273
|
+
this.next();
|
|
12229
12274
|
}
|
|
12230
12275
|
|
|
12231
12276
|
if (this.peek().typ === 'Semicolon') {
|
|
@@ -12239,27 +12284,6 @@ class Parser {
|
|
|
12239
12284
|
return out;
|
|
12240
12285
|
}
|
|
12241
12286
|
|
|
12242
|
-
parseObjectList() {
|
|
12243
|
-
// Capture any trailing property-list triples produced while parsing each
|
|
12244
|
-
// object term so we can emit them *after* the triple that references the
|
|
12245
|
-
// term. (See pendingTriplesAfter in the constructor.)
|
|
12246
|
-
|
|
12247
|
-
const objs = [];
|
|
12248
|
-
const readObj = () => {
|
|
12249
|
-
const o = this.parseTerm();
|
|
12250
|
-
const post = this.pendingTriplesAfter;
|
|
12251
|
-
this.pendingTriplesAfter = [];
|
|
12252
|
-
objs.push({ term: o, postTriples: post });
|
|
12253
|
-
};
|
|
12254
|
-
|
|
12255
|
-
readObj();
|
|
12256
|
-
while (this.peek().typ === 'Comma') {
|
|
12257
|
-
this.next();
|
|
12258
|
-
readObj();
|
|
12259
|
-
}
|
|
12260
|
-
return objs;
|
|
12261
|
-
}
|
|
12262
|
-
|
|
12263
12287
|
makeRule(left, right, isForward) {
|
|
12264
12288
|
let premiseTerm, conclTerm;
|
|
12265
12289
|
|
package/lib/cli.js
CHANGED
|
@@ -350,12 +350,14 @@ function main() {
|
|
|
350
350
|
outTriples = res.queryTriples;
|
|
351
351
|
outDerived = res.queryDerived;
|
|
352
352
|
} else {
|
|
353
|
+
const skipDerivedCollection = mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled();
|
|
353
354
|
derived = engine.forwardChain(facts, frules, brules, null, {
|
|
354
355
|
captureExplanations: engine.getProofCommentsEnabled(),
|
|
356
|
+
collectDerived: !skipDerivedCollection,
|
|
355
357
|
prefixes,
|
|
356
358
|
});
|
|
357
359
|
outDerived = derived;
|
|
358
|
-
outTriples = derived.map((df) => df.fact);
|
|
360
|
+
outTriples = skipDerivedCollection ? [] : derived.map((df) => df.fact);
|
|
359
361
|
}
|
|
360
362
|
|
|
361
363
|
const renderedOutputTriples = hasQueries ? outTriples : facts;
|
package/lib/engine.js
CHANGED
|
@@ -2901,6 +2901,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
2901
2901
|
__attachGoalTable(backRules, goalTable);
|
|
2902
2902
|
|
|
2903
2903
|
const captureExplanations = !(opts && opts.captureExplanations === false);
|
|
2904
|
+
const collectDerived = !(opts && opts.collectDerived === false);
|
|
2905
|
+
const hasDerivedCallback = typeof onDerived === 'function';
|
|
2904
2906
|
const derivedForward = [];
|
|
2905
2907
|
const varGen = [0];
|
|
2906
2908
|
const skCounter = [0];
|
|
@@ -3079,8 +3081,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3079
3081
|
if (!hasFactIndexed(facts, instantiated)) {
|
|
3080
3082
|
pushFactIndexed(facts, instantiated);
|
|
3081
3083
|
const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
|
|
3082
|
-
derivedForward.push(df);
|
|
3083
|
-
if (
|
|
3084
|
+
if (collectDerived) derivedForward.push(df);
|
|
3085
|
+
if (hasDerivedCallback) onDerived(df);
|
|
3084
3086
|
changedHere = true;
|
|
3085
3087
|
}
|
|
3086
3088
|
|
|
@@ -3143,8 +3145,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3143
3145
|
|
|
3144
3146
|
pushFactIndexed(facts, inst);
|
|
3145
3147
|
const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
|
|
3146
|
-
derivedForward.push(df);
|
|
3147
|
-
if (
|
|
3148
|
+
if (collectDerived) derivedForward.push(df);
|
|
3149
|
+
if (hasDerivedCallback) onDerived(df);
|
|
3148
3150
|
|
|
3149
3151
|
changedHere = true;
|
|
3150
3152
|
}
|
package/lib/lexer.js
CHANGED
|
@@ -121,15 +121,6 @@ function isIdentChar(c) {
|
|
|
121
121
|
return c === ':' || isPnChars(c);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
function canContinueAfterDot(next) {
|
|
125
|
-
// PN_LOCAL allows '.' but it cannot appear at the end.
|
|
126
|
-
// We include '.' only if it is followed by something that could continue a name.
|
|
127
|
-
if (next === null) return false;
|
|
128
|
-
if (isIdentChar(next)) return true;
|
|
129
|
-
if (next === '%' || next === '\\') return true;
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
124
|
function isForbiddenNoncharacterCodePoint(cp) {
|
|
134
125
|
return (cp & 0xffff) === 0xfffe || (cp & 0xffff) === 0xffff;
|
|
135
126
|
}
|
|
@@ -1205,7 +1196,9 @@ function lex(inputText, opts = {}) {
|
|
|
1205
1196
|
// Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
|
|
1206
1197
|
// only needed when the text contains surrogate pairs and we want the old
|
|
1207
1198
|
// code-point iteration behavior for non-BMP characters.
|
|
1208
|
-
const
|
|
1199
|
+
const hasSurrogates = /[\uD800-\uDFFF]/.test(inputText);
|
|
1200
|
+
const inputMayContainInvalidStringChar = hasSurrogates || /[\u0000\uFFFE\uFFFF]/.test(inputText);
|
|
1201
|
+
const chars = hasSurrogates ? Array.from(inputText) : inputText;
|
|
1209
1202
|
const n = chars.length;
|
|
1210
1203
|
let i = 0;
|
|
1211
1204
|
const tokens = [];
|
|
@@ -1240,14 +1233,47 @@ function lex(inputText, opts = {}) {
|
|
|
1240
1233
|
// Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
|
|
1241
1234
|
if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
|
|
1242
1235
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1236
|
+
const code = cc.charCodeAt(0);
|
|
1237
|
+
|
|
1238
|
+
// Common ASCII QName/identifier characters. Keep this branch inline so
|
|
1239
|
+
// ordinary N3 files do not call through the full Unicode PN_CHARS predicate
|
|
1240
|
+
// for every character.
|
|
1241
|
+
if (
|
|
1242
|
+
code === 58 || // ':'
|
|
1243
|
+
code === 95 || // '_'
|
|
1244
|
+
code === 45 || // '-'
|
|
1245
|
+
(code >= 48 && code <= 57) ||
|
|
1246
|
+
(code >= 65 && code <= 90) ||
|
|
1247
|
+
(code >= 97 && code <= 122)
|
|
1248
|
+
) {
|
|
1249
|
+
if (out !== null) out.push(cc);
|
|
1247
1250
|
i++;
|
|
1248
1251
|
continue;
|
|
1249
1252
|
}
|
|
1250
1253
|
|
|
1254
|
+
// Dot is allowed inside PN_LOCAL, but not at the end.
|
|
1255
|
+
if (cc === '.') {
|
|
1256
|
+
const next = peek(1);
|
|
1257
|
+
if (next === null) break;
|
|
1258
|
+
const ncode = next.charCodeAt(0);
|
|
1259
|
+
if (
|
|
1260
|
+
next === '%' ||
|
|
1261
|
+
next === '\\' ||
|
|
1262
|
+
ncode === 58 ||
|
|
1263
|
+
ncode === 95 ||
|
|
1264
|
+
ncode === 45 ||
|
|
1265
|
+
(ncode >= 48 && ncode <= 57) ||
|
|
1266
|
+
(ncode >= 65 && ncode <= 90) ||
|
|
1267
|
+
(ncode >= 97 && ncode <= 122) ||
|
|
1268
|
+
isIdentChar(next)
|
|
1269
|
+
) {
|
|
1270
|
+
if (out !== null) out.push('.');
|
|
1271
|
+
i++;
|
|
1272
|
+
continue;
|
|
1273
|
+
}
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1251
1277
|
// Percent escape: %HH
|
|
1252
1278
|
if (cc === '%') {
|
|
1253
1279
|
const h1 = peek(1);
|
|
@@ -1495,7 +1521,7 @@ function lex(inputText, opts = {}) {
|
|
|
1495
1521
|
}
|
|
1496
1522
|
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
1497
1523
|
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
1498
|
-
assertValidStringLiteralValue(decoded, start);
|
|
1524
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
1499
1525
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
1500
1526
|
tokens.push(new Token('Literal', s, start));
|
|
1501
1527
|
continue;
|
|
@@ -1585,7 +1611,7 @@ function lex(inputText, opts = {}) {
|
|
|
1585
1611
|
}
|
|
1586
1612
|
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
1587
1613
|
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
1588
|
-
assertValidStringLiteralValue(decoded, start);
|
|
1614
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
1589
1615
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
1590
1616
|
tokens.push(new Token('Literal', s, start));
|
|
1591
1617
|
continue;
|
package/lib/parser.js
CHANGED
|
@@ -642,15 +642,21 @@ class Parser {
|
|
|
642
642
|
|
|
643
643
|
while (true) {
|
|
644
644
|
const { verb, invert } = this.parseStatementVerb();
|
|
645
|
-
const objects = this.parseObjectList();
|
|
646
645
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
646
|
+
while (true) {
|
|
647
|
+
const o = this.parseTerm();
|
|
648
|
+
const postTriples = this.pendingTriplesAfter;
|
|
649
|
+
this.pendingTriplesAfter = [];
|
|
650
|
+
|
|
651
|
+
// If VERB or OBJECT contained paths, their helper triples must come
|
|
652
|
+
// before the triple that consumes the path result (Easter depends on this).
|
|
653
|
+
this.flushPendingTriples(out);
|
|
650
654
|
|
|
651
|
-
for (const { term: o, postTriples } of objects) {
|
|
652
655
|
out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
|
|
653
|
-
if (postTriples
|
|
656
|
+
if (postTriples.length) out.push(...postTriples);
|
|
657
|
+
|
|
658
|
+
if (this.peek().typ !== 'Comma') break;
|
|
659
|
+
this.next();
|
|
654
660
|
}
|
|
655
661
|
|
|
656
662
|
if (this.peek().typ === 'Semicolon') {
|
|
@@ -664,27 +670,6 @@ class Parser {
|
|
|
664
670
|
return out;
|
|
665
671
|
}
|
|
666
672
|
|
|
667
|
-
parseObjectList() {
|
|
668
|
-
// Capture any trailing property-list triples produced while parsing each
|
|
669
|
-
// object term so we can emit them *after* the triple that references the
|
|
670
|
-
// term. (See pendingTriplesAfter in the constructor.)
|
|
671
|
-
|
|
672
|
-
const objs = [];
|
|
673
|
-
const readObj = () => {
|
|
674
|
-
const o = this.parseTerm();
|
|
675
|
-
const post = this.pendingTriplesAfter;
|
|
676
|
-
this.pendingTriplesAfter = [];
|
|
677
|
-
objs.push({ term: o, postTriples: post });
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
readObj();
|
|
681
|
-
while (this.peek().typ === 'Comma') {
|
|
682
|
-
this.next();
|
|
683
|
-
readObj();
|
|
684
|
-
}
|
|
685
|
-
return objs;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
673
|
makeRule(left, right, isForward) {
|
|
689
674
|
let premiseTerm, conclTerm;
|
|
690
675
|
|