eyeling 1.25.1 → 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 +252 -99
- package/eyeling.js +252 -99
- package/lib/cli.js +3 -1
- package/lib/engine.js +99 -25
- package/lib/lexer.js +123 -44
- package/lib/parser.js +27 -38
- 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;
|
|
@@ -5849,6 +5851,14 @@ function __prepareForwardRule(r) {
|
|
|
5849
5851
|
configurable: true,
|
|
5850
5852
|
});
|
|
5851
5853
|
}
|
|
5854
|
+
if (!hasOwn.call(r, '__needsForwardSkipCheck')) {
|
|
5855
|
+
Object.defineProperty(r, '__needsForwardSkipCheck', {
|
|
5856
|
+
value: !!(r.__headIsStrictGround || (r.__scopedSkipInfo && r.__scopedSkipInfo.needsSnap)),
|
|
5857
|
+
enumerable: false,
|
|
5858
|
+
writable: false,
|
|
5859
|
+
configurable: true,
|
|
5860
|
+
});
|
|
5861
|
+
}
|
|
5852
5862
|
}
|
|
5853
5863
|
|
|
5854
5864
|
function __graphTriplesOrTrue(term) {
|
|
@@ -6167,6 +6177,11 @@ function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firi
|
|
|
6167
6177
|
}
|
|
6168
6178
|
|
|
6169
6179
|
function skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
|
|
6180
|
+
// Fast path: the common case has no explicit head blanks. Do not allocate a
|
|
6181
|
+
// replacement Triple or compute a firing key when skolemization cannot change
|
|
6182
|
+
// anything. This matters for long single-premise chains such as
|
|
6183
|
+
// deep-taxonomy-100000, where every derived head triple is otherwise copied.
|
|
6184
|
+
if (!headBlankLabels || headBlankLabels.size === 0) return tr;
|
|
6170
6185
|
return new Triple(
|
|
6171
6186
|
skolemizeTermForHeadBlanks(tr.s, headBlankLabels, mapping, skCounter, firingKey, globalMap),
|
|
6172
6187
|
skolemizeTermForHeadBlanks(tr.p, headBlankLabels, mapping, skCounter, firingKey, globalMap),
|
|
@@ -6642,6 +6657,35 @@ function ensureFactIndexes(facts) {
|
|
|
6642
6657
|
for (let i = 0; i < facts.length; i++) indexFact(facts, facts[i], i, false);
|
|
6643
6658
|
}
|
|
6644
6659
|
|
|
6660
|
+
function cloneFactIndexesForSnapshot(src, dest) {
|
|
6661
|
+
ensureFactIndexes(src);
|
|
6662
|
+
|
|
6663
|
+
function cloneArrayMap(map) {
|
|
6664
|
+
const out = new Map();
|
|
6665
|
+
for (const [k, arr] of map) out.set(k, arr.slice());
|
|
6666
|
+
return out;
|
|
6667
|
+
}
|
|
6668
|
+
|
|
6669
|
+
function cloneNestedArrayMap(map) {
|
|
6670
|
+
const out = new Map();
|
|
6671
|
+
for (const [k, inner] of map) {
|
|
6672
|
+
const innerOut = new Map();
|
|
6673
|
+
for (const [k2, arr] of inner) innerOut.set(k2, arr.slice());
|
|
6674
|
+
out.set(k, innerOut);
|
|
6675
|
+
}
|
|
6676
|
+
return out;
|
|
6677
|
+
}
|
|
6678
|
+
|
|
6679
|
+
Object.defineProperty(dest, '__byPred', { value: cloneArrayMap(src.__byPred), enumerable: false, writable: true });
|
|
6680
|
+
Object.defineProperty(dest, '__byPS', { value: cloneNestedArrayMap(src.__byPS), enumerable: false, writable: true });
|
|
6681
|
+
Object.defineProperty(dest, '__byPO', { value: cloneNestedArrayMap(src.__byPO), enumerable: false, writable: true });
|
|
6682
|
+
Object.defineProperty(dest, '__wildPred', { value: src.__wildPred.slice(), enumerable: false, writable: true });
|
|
6683
|
+
Object.defineProperty(dest, '__wildPS', { value: cloneArrayMap(src.__wildPS), enumerable: false, writable: true });
|
|
6684
|
+
Object.defineProperty(dest, '__wildPO', { value: cloneArrayMap(src.__wildPO), enumerable: false, writable: true });
|
|
6685
|
+
Object.defineProperty(dest, '__keySet', { value: new Set(src.__keySet), enumerable: false, writable: true });
|
|
6686
|
+
Object.defineProperty(dest, '__keySetComplete', { value: !!src.__keySetComplete, enumerable: false, writable: true });
|
|
6687
|
+
}
|
|
6688
|
+
|
|
6645
6689
|
function indexFact(facts, tr, idx, addKeySet = true) {
|
|
6646
6690
|
const sk = termFastKey(tr.s);
|
|
6647
6691
|
const ok = termFastKey(tr.o);
|
|
@@ -6928,13 +6972,20 @@ function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
|
|
|
6928
6972
|
if (!isSinglePremiseAgendaRuleSafe(r, backRules)) continue;
|
|
6929
6973
|
|
|
6930
6974
|
const goal = r.premise[0];
|
|
6975
|
+
const goalSKey = termFastKey(goal.s);
|
|
6976
|
+
const goalOKey = termFastKey(goal.o);
|
|
6977
|
+
const fastSubjectVar = goal.p instanceof Iri && goal.s instanceof Var && goalOKey !== null ? goal.s.name : null;
|
|
6978
|
+
const fastObjectVar = goal.p instanceof Iri && goal.o instanceof Var && goalSKey !== null ? goal.o.name : null;
|
|
6931
6979
|
const entry = {
|
|
6932
6980
|
rule: r,
|
|
6933
6981
|
ruleIndex: i,
|
|
6934
6982
|
goal,
|
|
6935
6983
|
goalPredTid: goal.p instanceof Iri ? goal.p.__tid : null,
|
|
6936
|
-
goalSKey
|
|
6937
|
-
goalOKey
|
|
6984
|
+
goalSKey,
|
|
6985
|
+
goalOKey,
|
|
6986
|
+
needsSkipCheck: !!r.__needsForwardSkipCheck,
|
|
6987
|
+
fastSubjectVar,
|
|
6988
|
+
fastObjectVar,
|
|
6938
6989
|
};
|
|
6939
6990
|
|
|
6940
6991
|
index.indexed.add(r);
|
|
@@ -8339,6 +8390,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8339
8390
|
__attachGoalTable(backRules, goalTable);
|
|
8340
8391
|
|
|
8341
8392
|
const captureExplanations = !(opts && opts.captureExplanations === false);
|
|
8393
|
+
const collectDerived = !(opts && opts.collectDerived === false);
|
|
8394
|
+
const hasDerivedCallback = typeof onDerived === 'function';
|
|
8342
8395
|
const derivedForward = [];
|
|
8343
8396
|
const varGen = [0];
|
|
8344
8397
|
const skCounter = [0];
|
|
@@ -8395,7 +8448,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8395
8448
|
|
|
8396
8449
|
function makeScopedSnapshot() {
|
|
8397
8450
|
const snap = facts.slice();
|
|
8398
|
-
|
|
8451
|
+
cloneFactIndexesForSnapshot(facts, snap);
|
|
8399
8452
|
Object.defineProperty(snap, '__scopedSnapshot', {
|
|
8400
8453
|
value: snap,
|
|
8401
8454
|
enumerable: false,
|
|
@@ -8449,10 +8502,21 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8449
8502
|
let changedHere = false;
|
|
8450
8503
|
let rulesChanged = false;
|
|
8451
8504
|
|
|
8452
|
-
// IMPORTANT: one skolem map per *rule firing
|
|
8505
|
+
// IMPORTANT: one skolem map per *rule firing*. Instantiate premise
|
|
8506
|
+
// triples and build the firing key lazily: normal CLI runs do not capture
|
|
8507
|
+
// proof records, and most rules have no explicit head blanks, so the eager
|
|
8508
|
+
// work was pure allocation on large forward chains.
|
|
8453
8509
|
const skMap = {};
|
|
8454
|
-
|
|
8455
|
-
|
|
8510
|
+
let instantiatedPremises = null;
|
|
8511
|
+
let fireKey = null;
|
|
8512
|
+
function getInstantiatedPremises() {
|
|
8513
|
+
if (instantiatedPremises === null) instantiatedPremises = r.premise.map((b) => applySubstTriple(b, s));
|
|
8514
|
+
return instantiatedPremises;
|
|
8515
|
+
}
|
|
8516
|
+
function getFireKey() {
|
|
8517
|
+
if (fireKey === null) fireKey = __firingKey(ruleIndex, getInstantiatedPremises());
|
|
8518
|
+
return fireKey;
|
|
8519
|
+
}
|
|
8456
8520
|
|
|
8457
8521
|
// Support "dynamic" rule heads where the consequent is a term that
|
|
8458
8522
|
// (after substitution) evaluates to a quoted formula.
|
|
@@ -8505,9 +8569,9 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8505
8569
|
if (isFwRuleTriple || isBwRuleTriple) {
|
|
8506
8570
|
if (!hasFactIndexed(facts, instantiated)) {
|
|
8507
8571
|
pushFactIndexed(facts, instantiated);
|
|
8508
|
-
const df = makeDerivedRecord(instantiated, r,
|
|
8509
|
-
derivedForward.push(df);
|
|
8510
|
-
if (
|
|
8572
|
+
const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
|
|
8573
|
+
if (collectDerived) derivedForward.push(df);
|
|
8574
|
+
if (hasDerivedCallback) onDerived(df);
|
|
8511
8575
|
changedHere = true;
|
|
8512
8576
|
}
|
|
8513
8577
|
|
|
@@ -8553,22 +8617,25 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8553
8617
|
}
|
|
8554
8618
|
|
|
8555
8619
|
// Only skolemize blank nodes that occur explicitly in the rule head
|
|
8556
|
-
const inst =
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8620
|
+
const inst =
|
|
8621
|
+
headBlankLabelsHere && headBlankLabelsHere.size
|
|
8622
|
+
? skolemizeTripleForHeadBlanks(
|
|
8623
|
+
instantiated,
|
|
8624
|
+
headBlankLabelsHere,
|
|
8625
|
+
skMap,
|
|
8626
|
+
skCounter,
|
|
8627
|
+
getFireKey(),
|
|
8628
|
+
headSkolemCache,
|
|
8629
|
+
)
|
|
8630
|
+
: instantiated;
|
|
8564
8631
|
|
|
8565
8632
|
if (!isGroundTriple(inst)) continue;
|
|
8566
8633
|
if (hasFactIndexed(facts, inst)) continue;
|
|
8567
8634
|
|
|
8568
8635
|
pushFactIndexed(facts, inst);
|
|
8569
|
-
const df = makeDerivedRecord(inst, r,
|
|
8570
|
-
derivedForward.push(df);
|
|
8571
|
-
if (
|
|
8636
|
+
const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
|
|
8637
|
+
if (collectDerived) derivedForward.push(df);
|
|
8638
|
+
if (hasDerivedCallback) onDerived(df);
|
|
8572
8639
|
|
|
8573
8640
|
changedHere = true;
|
|
8574
8641
|
}
|
|
@@ -8593,10 +8660,19 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8593
8660
|
for (let ci = 0; ci < total; ci++) {
|
|
8594
8661
|
const entry = ci < candidates.exactLen ? candidates.exact[ci] : candidates.wild[ci - candidates.exactLen];
|
|
8595
8662
|
const r = entry.rule;
|
|
8596
|
-
if (__skipForwardRuleNow(r)) continue;
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
if (
|
|
8663
|
+
if (entry.needsSkipCheck && __skipForwardRuleNow(r)) continue;
|
|
8664
|
+
|
|
8665
|
+
let s;
|
|
8666
|
+
if (entry.fastSubjectVar !== null) {
|
|
8667
|
+
s = __emptySubst();
|
|
8668
|
+
s[entry.fastSubjectVar] = fact.s;
|
|
8669
|
+
} else if (entry.fastObjectVar !== null) {
|
|
8670
|
+
s = __emptySubst();
|
|
8671
|
+
s[entry.fastObjectVar] = fact.o;
|
|
8672
|
+
} else {
|
|
8673
|
+
s = unifyTriple(entry.goal, fact, __emptySubst());
|
|
8674
|
+
if (s === null) continue;
|
|
8675
|
+
}
|
|
8600
8676
|
|
|
8601
8677
|
const outcome = __emitForwardRuleSolution(r, entry.ruleIndex, s);
|
|
8602
8678
|
if (outcome.rulesChanged) {
|
|
@@ -8613,7 +8689,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8613
8689
|
for (let i = 0; i < forwardRules.length; i++) {
|
|
8614
8690
|
const r = forwardRules[i];
|
|
8615
8691
|
if (agendaIndex.indexed.has(r)) continue;
|
|
8616
|
-
if (__skipForwardRuleNow(r)) continue;
|
|
8692
|
+
if (r.__needsForwardSkipCheck && __skipForwardRuleNow(r)) continue;
|
|
8617
8693
|
|
|
8618
8694
|
const headIsStrictGround = r.__headIsStrictGround;
|
|
8619
8695
|
const maxSols = r.isFuse || headIsStrictGround ? 1 : undefined;
|
|
@@ -10639,13 +10715,25 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
10639
10715
|
return text;
|
|
10640
10716
|
}
|
|
10641
10717
|
|
|
10718
|
+
|
|
10719
|
+
function isNumericLikeIdentifier(word) {
|
|
10720
|
+
if (typeof word !== 'string' || word.length === 0) return false;
|
|
10721
|
+
for (let j = 0; j < word.length; j++) {
|
|
10722
|
+
const code = word.charCodeAt(j);
|
|
10723
|
+
if (!((code >= 48 && code <= 57) || code === 46 || code === 45)) return false;
|
|
10724
|
+
}
|
|
10725
|
+
return true;
|
|
10726
|
+
}
|
|
10727
|
+
|
|
10642
10728
|
function lex(inputText, opts = {}) {
|
|
10643
10729
|
const rdf = !!(opts && opts.rdf);
|
|
10644
10730
|
if (rdf) inputText = normalizeRdfCompatibility(inputText);
|
|
10645
10731
|
// Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
|
|
10646
10732
|
// only needed when the text contains surrogate pairs and we want the old
|
|
10647
10733
|
// code-point iteration behavior for non-BMP characters.
|
|
10648
|
-
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;
|
|
10649
10737
|
const n = chars.length;
|
|
10650
10738
|
let i = 0;
|
|
10651
10739
|
const tokens = [];
|
|
@@ -10680,14 +10768,47 @@ function lex(inputText, opts = {}) {
|
|
|
10680
10768
|
// Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
|
|
10681
10769
|
if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
|
|
10682
10770
|
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
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);
|
|
10687
10785
|
i++;
|
|
10688
10786
|
continue;
|
|
10689
10787
|
}
|
|
10690
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
|
+
|
|
10691
10812
|
// Percent escape: %HH
|
|
10692
10813
|
if (cc === '%') {
|
|
10693
10814
|
const h1 = peek(1);
|
|
@@ -10806,22 +10927,47 @@ function lex(inputText, opts = {}) {
|
|
|
10806
10927
|
continue;
|
|
10807
10928
|
}
|
|
10808
10929
|
|
|
10809
|
-
// 5) Single-character punctuation
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10930
|
+
// 5) Single-character punctuation. Use a switch rather than allocating a
|
|
10931
|
+
// mapping object for every punctuation token in large inputs.
|
|
10932
|
+
switch (c) {
|
|
10933
|
+
case '{':
|
|
10934
|
+
tokens.push(new Token('LBrace', null, i));
|
|
10935
|
+
i++;
|
|
10936
|
+
continue;
|
|
10937
|
+
case '}':
|
|
10938
|
+
tokens.push(new Token('RBrace', null, i));
|
|
10939
|
+
i++;
|
|
10940
|
+
continue;
|
|
10941
|
+
case '(':
|
|
10942
|
+
tokens.push(new Token('LParen', null, i));
|
|
10943
|
+
i++;
|
|
10944
|
+
continue;
|
|
10945
|
+
case ')':
|
|
10946
|
+
tokens.push(new Token('RParen', null, i));
|
|
10947
|
+
i++;
|
|
10948
|
+
continue;
|
|
10949
|
+
case '[':
|
|
10950
|
+
tokens.push(new Token('LBracket', null, i));
|
|
10951
|
+
i++;
|
|
10952
|
+
continue;
|
|
10953
|
+
case ']':
|
|
10954
|
+
tokens.push(new Token('RBracket', null, i));
|
|
10955
|
+
i++;
|
|
10956
|
+
continue;
|
|
10957
|
+
case ';':
|
|
10958
|
+
tokens.push(new Token('Semicolon', null, i));
|
|
10959
|
+
i++;
|
|
10960
|
+
continue;
|
|
10961
|
+
case ',':
|
|
10962
|
+
tokens.push(new Token('Comma', null, i));
|
|
10963
|
+
i++;
|
|
10964
|
+
continue;
|
|
10965
|
+
case '.':
|
|
10966
|
+
tokens.push(new Token('Dot', null, i));
|
|
10967
|
+
i++;
|
|
10968
|
+
continue;
|
|
10969
|
+
default:
|
|
10970
|
+
break;
|
|
10825
10971
|
}
|
|
10826
10972
|
|
|
10827
10973
|
// String literal: short "..." or long """..."""
|
|
@@ -10880,27 +11026,37 @@ function lex(inputText, opts = {}) {
|
|
|
10880
11026
|
continue;
|
|
10881
11027
|
}
|
|
10882
11028
|
|
|
10883
|
-
// Short string literal " ... "
|
|
11029
|
+
// Short string literal " ... ". Most data files contain plain
|
|
11030
|
+
// unescaped labels; keep that path slice-based and avoid building an
|
|
11031
|
+
// intermediate character array + raw quoted string.
|
|
10884
11032
|
i++; // consume opening "
|
|
10885
|
-
const
|
|
11033
|
+
const contentStart = i;
|
|
11034
|
+
let sChars = null;
|
|
11035
|
+
let closed = false;
|
|
10886
11036
|
while (i < n) {
|
|
10887
11037
|
const cc = chars[i];
|
|
10888
11038
|
i++;
|
|
10889
11039
|
if (cc === '\\') {
|
|
11040
|
+
if (sChars === null) sChars = [sliceChars(contentStart, i - 1)];
|
|
10890
11041
|
if (i < n) {
|
|
10891
11042
|
const esc = chars[i];
|
|
10892
11043
|
i++;
|
|
10893
11044
|
sChars.push('\\');
|
|
10894
11045
|
sChars.push(esc);
|
|
11046
|
+
} else {
|
|
11047
|
+
sChars.push('\\');
|
|
10895
11048
|
}
|
|
10896
11049
|
continue;
|
|
10897
11050
|
}
|
|
10898
|
-
if (cc === '"')
|
|
10899
|
-
|
|
11051
|
+
if (cc === '"') {
|
|
11052
|
+
closed = true;
|
|
11053
|
+
break;
|
|
11054
|
+
}
|
|
11055
|
+
if (sChars !== null) sChars.push(cc);
|
|
10900
11056
|
}
|
|
10901
|
-
const
|
|
10902
|
-
const decoded = decodeN3StringEscapes(
|
|
10903
|
-
assertValidStringLiteralValue(decoded, start);
|
|
11057
|
+
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
11058
|
+
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
11059
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
10904
11060
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
10905
11061
|
tokens.push(new Token('Literal', s, start));
|
|
10906
11062
|
continue;
|
|
@@ -10964,25 +11120,33 @@ function lex(inputText, opts = {}) {
|
|
|
10964
11120
|
|
|
10965
11121
|
// Short string literal ' ... '
|
|
10966
11122
|
i++; // consume opening '
|
|
10967
|
-
const
|
|
11123
|
+
const contentStart = i;
|
|
11124
|
+
let sChars = null;
|
|
11125
|
+
let closed = false;
|
|
10968
11126
|
while (i < n) {
|
|
10969
11127
|
const cc = chars[i];
|
|
10970
11128
|
i++;
|
|
10971
11129
|
if (cc === '\\') {
|
|
11130
|
+
if (sChars === null) sChars = [sliceChars(contentStart, i - 1)];
|
|
10972
11131
|
if (i < n) {
|
|
10973
11132
|
const esc = chars[i];
|
|
10974
11133
|
i++;
|
|
10975
11134
|
sChars.push('\\');
|
|
10976
11135
|
sChars.push(esc);
|
|
11136
|
+
} else {
|
|
11137
|
+
sChars.push('\\');
|
|
10977
11138
|
}
|
|
10978
11139
|
continue;
|
|
10979
11140
|
}
|
|
10980
|
-
if (cc === "'")
|
|
10981
|
-
|
|
11141
|
+
if (cc === "'") {
|
|
11142
|
+
closed = true;
|
|
11143
|
+
break;
|
|
11144
|
+
}
|
|
11145
|
+
if (sChars !== null) sChars.push(cc);
|
|
10982
11146
|
}
|
|
10983
|
-
const
|
|
10984
|
-
const decoded = decodeN3StringEscapes(
|
|
10985
|
-
assertValidStringLiteralValue(decoded, start);
|
|
11147
|
+
const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
|
|
11148
|
+
const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
|
|
11149
|
+
if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
|
|
10986
11150
|
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
10987
11151
|
tokens.push(new Token('Literal', s, start));
|
|
10988
11152
|
continue;
|
|
@@ -11106,7 +11270,7 @@ function lex(inputText, opts = {}) {
|
|
|
11106
11270
|
}
|
|
11107
11271
|
if (word === 'true' || word === 'false') {
|
|
11108
11272
|
tokens.push(new Token('Literal', word, start));
|
|
11109
|
-
} else if (
|
|
11273
|
+
} else if (isNumericLikeIdentifier(word)) {
|
|
11110
11274
|
tokens.push(new Token('Literal', word, start));
|
|
11111
11275
|
} else {
|
|
11112
11276
|
tokens.push(new Token('Ident', word, start));
|
|
@@ -11691,7 +11855,7 @@ class Parser {
|
|
|
11691
11855
|
} else if (tok2.typ === 'Ident') {
|
|
11692
11856
|
const qn = tok2.value || '';
|
|
11693
11857
|
if (!qn.includes(':')) failInvalidKeywordLikeIdent(this.fail.bind(this), tok2, qn);
|
|
11694
|
-
assertValidQNamePrefix(qn.
|
|
11858
|
+
assertValidQNamePrefix(qn.slice(0, qn.indexOf(':')), this.fail.bind(this), tok2, '@prefix directive IRI');
|
|
11695
11859
|
iri = this.prefixes.expandQName(qn);
|
|
11696
11860
|
} else {
|
|
11697
11861
|
this.fail(`Expected IRI after @prefix, got ${tok2.toString()}`, tok2);
|
|
@@ -11708,7 +11872,7 @@ class Parser {
|
|
|
11708
11872
|
} else if (tok.typ === 'Ident') {
|
|
11709
11873
|
const qn = tok.value || '';
|
|
11710
11874
|
if (!qn.includes(':')) failInvalidKeywordLikeIdent(this.fail.bind(this), tok, qn);
|
|
11711
|
-
assertValidQNamePrefix(qn.
|
|
11875
|
+
assertValidQNamePrefix(qn.slice(0, qn.indexOf(':')), this.fail.bind(this), tok, '@base directive IRI');
|
|
11712
11876
|
iri = this.prefixes.expandQName(qn);
|
|
11713
11877
|
} else {
|
|
11714
11878
|
this.fail(`Expected IRI after @base, got ${tok.toString()}`, tok);
|
|
@@ -11737,7 +11901,7 @@ class Parser {
|
|
|
11737
11901
|
} else if (tok2.typ === 'Ident') {
|
|
11738
11902
|
const qn = tok2.value || '';
|
|
11739
11903
|
if (!qn.includes(':')) failInvalidKeywordLikeIdent(this.fail.bind(this), tok2, qn);
|
|
11740
|
-
assertValidQNamePrefix(qn.
|
|
11904
|
+
assertValidQNamePrefix(qn.slice(0, qn.indexOf(':')), this.fail.bind(this), tok2, '@prefix directive IRI');
|
|
11741
11905
|
iri = this.prefixes.expandQName(qn);
|
|
11742
11906
|
} else {
|
|
11743
11907
|
this.fail(`Expected IRI after PREFIX, got ${tok2.toString()}`, tok2);
|
|
@@ -11758,7 +11922,7 @@ class Parser {
|
|
|
11758
11922
|
} else if (tok.typ === 'Ident') {
|
|
11759
11923
|
const qn = tok.value || '';
|
|
11760
11924
|
if (!qn.includes(':')) failInvalidKeywordLikeIdent(this.fail.bind(this), tok, qn);
|
|
11761
|
-
assertValidQNamePrefix(qn.
|
|
11925
|
+
assertValidQNamePrefix(qn.slice(0, qn.indexOf(':')), this.fail.bind(this), tok, 'BASE directive IRI');
|
|
11762
11926
|
iri = this.prefixes.expandQName(qn);
|
|
11763
11927
|
} else {
|
|
11764
11928
|
this.fail(`Expected IRI after BASE, got ${tok.toString()}`, tok);
|
|
@@ -11805,14 +11969,18 @@ class Parser {
|
|
|
11805
11969
|
const name = val || '';
|
|
11806
11970
|
if (name === 'a') {
|
|
11807
11971
|
return internIri(RDF_NS + 'type');
|
|
11808
|
-
}
|
|
11972
|
+
}
|
|
11973
|
+
const sep = name.indexOf(':');
|
|
11974
|
+
if (sep === 1 && name.charCodeAt(0) === 95) {
|
|
11809
11975
|
return new Blank(name);
|
|
11810
|
-
} else if (name.includes(':')) {
|
|
11811
|
-
assertValidQNamePrefix(name.split(':', 1)[0], this.fail.bind(this), tok);
|
|
11812
|
-
return internIri(this.prefixes.expandQName(name));
|
|
11813
|
-
} else {
|
|
11814
|
-
failInvalidKeywordLikeIdent(this.fail.bind(this), tok, name);
|
|
11815
11976
|
}
|
|
11977
|
+
if (sep >= 0) {
|
|
11978
|
+
const prefixName = name.slice(0, sep);
|
|
11979
|
+
assertValidQNamePrefix(prefixName, this.fail.bind(this), tok);
|
|
11980
|
+
const base = this.prefixes.map[prefixName] || '';
|
|
11981
|
+
return internIri(base ? base + name.slice(sep + 1) : name);
|
|
11982
|
+
}
|
|
11983
|
+
failInvalidKeywordLikeIdent(this.fail.bind(this), tok, name);
|
|
11816
11984
|
}
|
|
11817
11985
|
|
|
11818
11986
|
if (typ === 'Literal') {
|
|
@@ -11843,7 +12011,7 @@ class Parser {
|
|
|
11843
12011
|
} else if (dtTok.typ === 'Ident') {
|
|
11844
12012
|
const qn = dtTok.value || '';
|
|
11845
12013
|
if (!qn.includes(':')) failInvalidKeywordLikeIdent(this.fail.bind(this), dtTok, qn);
|
|
11846
|
-
assertValidQNamePrefix(qn.
|
|
12014
|
+
assertValidQNamePrefix(qn.slice(0, qn.indexOf(':')), this.fail.bind(this), dtTok, 'datatype prefixed name');
|
|
11847
12015
|
dtIri = this.prefixes.expandQName(qn);
|
|
11848
12016
|
} else {
|
|
11849
12017
|
this.fail(`Expected datatype after ^^, got ${dtTok.toString()}`, dtTok);
|
|
@@ -12088,15 +12256,21 @@ class Parser {
|
|
|
12088
12256
|
|
|
12089
12257
|
while (true) {
|
|
12090
12258
|
const { verb, invert } = this.parseStatementVerb();
|
|
12091
|
-
const objects = this.parseObjectList();
|
|
12092
12259
|
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
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);
|
|
12096
12268
|
|
|
12097
|
-
for (const { term: o, postTriples } of objects) {
|
|
12098
12269
|
out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
|
|
12099
|
-
if (postTriples
|
|
12270
|
+
if (postTriples.length) out.push(...postTriples);
|
|
12271
|
+
|
|
12272
|
+
if (this.peek().typ !== 'Comma') break;
|
|
12273
|
+
this.next();
|
|
12100
12274
|
}
|
|
12101
12275
|
|
|
12102
12276
|
if (this.peek().typ === 'Semicolon') {
|
|
@@ -12110,27 +12284,6 @@ class Parser {
|
|
|
12110
12284
|
return out;
|
|
12111
12285
|
}
|
|
12112
12286
|
|
|
12113
|
-
parseObjectList() {
|
|
12114
|
-
// Capture any trailing property-list triples produced while parsing each
|
|
12115
|
-
// object term so we can emit them *after* the triple that references the
|
|
12116
|
-
// term. (See pendingTriplesAfter in the constructor.)
|
|
12117
|
-
|
|
12118
|
-
const objs = [];
|
|
12119
|
-
const readObj = () => {
|
|
12120
|
-
const o = this.parseTerm();
|
|
12121
|
-
const post = this.pendingTriplesAfter;
|
|
12122
|
-
this.pendingTriplesAfter = [];
|
|
12123
|
-
objs.push({ term: o, postTriples: post });
|
|
12124
|
-
};
|
|
12125
|
-
|
|
12126
|
-
readObj();
|
|
12127
|
-
while (this.peek().typ === 'Comma') {
|
|
12128
|
-
this.next();
|
|
12129
|
-
readObj();
|
|
12130
|
-
}
|
|
12131
|
-
return objs;
|
|
12132
|
-
}
|
|
12133
|
-
|
|
12134
12287
|
makeRule(left, right, isForward) {
|
|
12135
12288
|
let premiseTerm, conclTerm;
|
|
12136
12289
|
|