eyeling 2.34.7 → 2.35.0
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/README.md +33 -0
- package/dist/browser/eyeling.browser.js +284 -14
- package/examples/collatz-1000.n3 +4 -0
- package/examples/fibonacci.n3 +13 -8
- package/examples/fundamental-theorem-arithmetic.n3 +6 -0
- package/eyeling.js +284 -14
- package/lib/cli.js +2 -2
- package/lib/engine.js +269 -4
- package/lib/multisource.js +1 -1
- package/lib/parser.js +12 -7
- package/package.json +1 -1
package/lib/engine.js
CHANGED
|
@@ -44,6 +44,7 @@ const LOG_COLLECT_ALL_IN_IRI = LOG_NS + 'collectAllIn';
|
|
|
44
44
|
const LOG_FOR_ALL_IN_IRI = LOG_NS + 'forAllIn';
|
|
45
45
|
const LOG_INCLUDES_IRI = LOG_NS + 'includes';
|
|
46
46
|
const LOG_NOT_INCLUDES_IRI = LOG_NS + 'notIncludes';
|
|
47
|
+
const LOG_MEMOIZE_IRI = LOG_NS + 'memoize';
|
|
47
48
|
const LOG_IMPLIES_IRI = LOG_NS + 'implies';
|
|
48
49
|
const LOG_IMPLIED_BY_IRI = LOG_NS + 'impliedBy';
|
|
49
50
|
|
|
@@ -145,6 +146,7 @@ const FACT_INDEX_ARRAY_MAP_FIELDS = ['__byPred', '__byPNonFastS', '__byPNonFastO
|
|
|
145
146
|
const FACT_INDEX_NESTED_ARRAY_MAP_FIELDS = ['__byPS', '__byPO'];
|
|
146
147
|
const FACT_INDEX_MAP_FIELDS = FACT_INDEX_ARRAY_MAP_FIELDS.concat(FACT_INDEX_NESTED_ARRAY_MAP_FIELDS);
|
|
147
148
|
const FACT_INDEX_REQUIRED_FIELDS = FACT_INDEX_ARRAY_FIELDS.concat(FACT_INDEX_MAP_FIELDS, ['__keySet']);
|
|
149
|
+
const FACT_INDEX_ALL_FIELDS = FACT_INDEX_REQUIRED_FIELDS.concat(['__keySetComplete']);
|
|
148
150
|
|
|
149
151
|
let version = 'dev';
|
|
150
152
|
try {
|
|
@@ -1212,7 +1214,13 @@ function termLookupKey(t) {
|
|
|
1212
1214
|
return t.__tid;
|
|
1213
1215
|
}
|
|
1214
1216
|
if (t instanceof Blank) return t.__tid;
|
|
1215
|
-
if (t instanceof Literal)
|
|
1217
|
+
if (t instanceof Literal) {
|
|
1218
|
+
const cached = t.__lookupKey;
|
|
1219
|
+
if (cached !== undefined) return cached;
|
|
1220
|
+
const key = literalLookupKey(t);
|
|
1221
|
+
Object.defineProperty(t, '__lookupKey', { value: key, enumerable: false });
|
|
1222
|
+
return key;
|
|
1223
|
+
}
|
|
1216
1224
|
|
|
1217
1225
|
if (t instanceof ListTerm) {
|
|
1218
1226
|
const cached = t.__lookupKey;
|
|
@@ -1250,6 +1258,13 @@ function tripleFastKey(tr) {
|
|
|
1250
1258
|
return ks + '\t' + kp + '\t' + ko;
|
|
1251
1259
|
}
|
|
1252
1260
|
|
|
1261
|
+
function resetFactIndexes(facts) {
|
|
1262
|
+
if (!facts) return;
|
|
1263
|
+
for (const name of FACT_INDEX_ALL_FIELDS) {
|
|
1264
|
+
try { delete facts[name]; } catch {}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1253
1268
|
function ensureFactIndexes(facts) {
|
|
1254
1269
|
if (FACT_INDEX_REQUIRED_FIELDS.every((name) => facts[name])) return;
|
|
1255
1270
|
|
|
@@ -1680,6 +1695,157 @@ function isLogImpliedBy(p) {
|
|
|
1680
1695
|
return p instanceof Iri && p.value === LOG_IMPLIED_BY_IRI;
|
|
1681
1696
|
}
|
|
1682
1697
|
|
|
1698
|
+
function isLogMemoize(p) {
|
|
1699
|
+
return p instanceof Iri && p.value === LOG_MEMOIZE_IRI;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
function isTruthyMemoizeObject(o) {
|
|
1703
|
+
if (!(o instanceof Literal)) return false;
|
|
1704
|
+
if (o.value === 'true') return true;
|
|
1705
|
+
const info = parseBooleanLiteralInfo(o);
|
|
1706
|
+
return !!(info && info.value === true);
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
// ===========================================================================
|
|
1710
|
+
// Predicate memoization declarations
|
|
1711
|
+
// ===========================================================================
|
|
1712
|
+
//
|
|
1713
|
+
// Eyeling accepts top-level declarations of the form:
|
|
1714
|
+
// :predicate log:memoize true.
|
|
1715
|
+
// They are engine directives, not data facts. Each declaration asks the
|
|
1716
|
+
// backward prover to table completed answers for that predicate during the
|
|
1717
|
+
// current reasoning scope. The hint is deliberately predicate-local and
|
|
1718
|
+
// conservative: unbound calls and finite-result probes still use the normal
|
|
1719
|
+
// path, and cached answers are invalidated when the fact/rule scope changes.
|
|
1720
|
+
|
|
1721
|
+
function __extractLogMemoizeDeclarations(facts) {
|
|
1722
|
+
const memoized = new Set();
|
|
1723
|
+
if (!Array.isArray(facts) || facts.length === 0) return memoized;
|
|
1724
|
+
|
|
1725
|
+
let write = 0;
|
|
1726
|
+
let removed = false;
|
|
1727
|
+
for (let read = 0; read < facts.length; read++) {
|
|
1728
|
+
const tr = facts[read];
|
|
1729
|
+
if (tr && isLogMemoize(tr.p) && tr.s instanceof Iri && isTruthyMemoizeObject(tr.o)) {
|
|
1730
|
+
memoized.add(tr.s.__tid);
|
|
1731
|
+
removed = true;
|
|
1732
|
+
continue;
|
|
1733
|
+
}
|
|
1734
|
+
if (write !== read) facts[write] = tr;
|
|
1735
|
+
write++;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
if (removed) {
|
|
1739
|
+
facts.length = write;
|
|
1740
|
+
resetFactIndexes(facts);
|
|
1741
|
+
}
|
|
1742
|
+
return memoized;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
function __attachMemoizedPredicates(scopeCarrier, memoized) {
|
|
1746
|
+
if (!scopeCarrier || !memoized || memoized.size === 0) return;
|
|
1747
|
+
__setHiddenWritable(scopeCarrier, 'memoizedPredicates', memoized);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
function __memoizedPredicateSet(facts, backRules) {
|
|
1751
|
+
return (facts && facts.memoizedPredicates) || (backRules && backRules.memoizedPredicates) || null;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
function __predicateIsMemoized(facts, backRules, p) {
|
|
1755
|
+
if (!(p instanceof Iri)) return false;
|
|
1756
|
+
const memoized = __memoizedPredicateSet(facts, backRules);
|
|
1757
|
+
return !!(memoized && memoized.has(p.__tid));
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
function __makePredicateMemoTable() {
|
|
1761
|
+
return {
|
|
1762
|
+
scopeVersion: null,
|
|
1763
|
+
entries: new Map(),
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
function __ensurePredicateMemoTable(facts, backRules) {
|
|
1768
|
+
let table = (facts && facts.predicateMemoTable) || (backRules && backRules.predicateMemoTable) || null;
|
|
1769
|
+
if (!table) table = __makePredicateMemoTable();
|
|
1770
|
+
__setHiddenWritable(facts, 'predicateMemoTable', table);
|
|
1771
|
+
__setHiddenWritable(backRules, 'predicateMemoTable', table);
|
|
1772
|
+
|
|
1773
|
+
const version = goalTableScopeVersion(facts, backRules);
|
|
1774
|
+
if (table.scopeVersion !== version) {
|
|
1775
|
+
table.scopeVersion = version;
|
|
1776
|
+
table.entries.clear();
|
|
1777
|
+
}
|
|
1778
|
+
return table;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
function __memoKeyPart(t) {
|
|
1782
|
+
if (__termHasVarOrBlank(t)) return { bound: false, text: '_' };
|
|
1783
|
+
const fast = termLookupKey(t);
|
|
1784
|
+
if (fast !== null) return { bound: true, text: encodeLookupKeyPart(fast) };
|
|
1785
|
+
return { bound: true, text: skolemKeyFromTerm(t) };
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
function __predicateMemoKey(goal) {
|
|
1789
|
+
if (!(goal && goal.p instanceof Iri)) return null;
|
|
1790
|
+
const sPart = __memoKeyPart(goal.s);
|
|
1791
|
+
const oPart = __memoKeyPart(goal.o);
|
|
1792
|
+
if (!sPart.bound && !oPart.bound) return null;
|
|
1793
|
+
return `${goal.p.__tid}|${sPart.text}|${oPart.text}`;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
function __makePredicateMemoEntry() {
|
|
1797
|
+
return {
|
|
1798
|
+
computing: false,
|
|
1799
|
+
complete: false,
|
|
1800
|
+
unsafe: false,
|
|
1801
|
+
answers: [],
|
|
1802
|
+
answerKeys: new Set(),
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
function __getPredicateMemoEntry(facts, backRules, key) {
|
|
1807
|
+
const table = __ensurePredicateMemoTable(facts, backRules);
|
|
1808
|
+
let entry = table.entries.get(key);
|
|
1809
|
+
if (!entry) {
|
|
1810
|
+
entry = __makePredicateMemoEntry();
|
|
1811
|
+
table.entries.set(key, entry);
|
|
1812
|
+
}
|
|
1813
|
+
return entry;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
function __canStorePredicateMemo(maxResults) {
|
|
1817
|
+
return !(typeof maxResults === 'number' && maxResults > 0);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
function __canMemoizeAnswerTerm(t) {
|
|
1821
|
+
if (t instanceof Var || t instanceof OpenListTerm) return false;
|
|
1822
|
+
if (t instanceof ListTerm) return t.elems.every(__canMemoizeAnswerTerm);
|
|
1823
|
+
if (t instanceof GraphTerm) return t.triples.every((tr) => __canMemoizeAnswerTerm(tr.s) && __canMemoizeAnswerTerm(tr.p) && __canMemoizeAnswerTerm(tr.o));
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
function __memoAnswerKeyPart(t) {
|
|
1828
|
+
const fast = termLookupKey(t);
|
|
1829
|
+
if (fast !== null) return encodeLookupKeyPart(fast);
|
|
1830
|
+
return skolemKeyFromTerm(t);
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
function __memoAnswerKey(tr) {
|
|
1834
|
+
return __memoAnswerKeyPart(tr.s) + '\t' + __memoAnswerKeyPart(tr.p) + '\t' + __memoAnswerKeyPart(tr.o);
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
function __storePredicateMemoAnswer(entry, rawGoal, subst) {
|
|
1838
|
+
const answer = applySubstTriple(rawGoal, subst || {});
|
|
1839
|
+
if (!__canMemoizeAnswerTerm(answer.s) || !__canMemoizeAnswerTerm(answer.p) || !__canMemoizeAnswerTerm(answer.o)) {
|
|
1840
|
+
entry.unsafe = true;
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
const key = __memoAnswerKey(answer);
|
|
1844
|
+
if (entry.answerKeys.has(key)) return;
|
|
1845
|
+
entry.answerKeys.add(key);
|
|
1846
|
+
entry.answers.push(answer);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1683
1849
|
// ===========================================================================
|
|
1684
1850
|
// Completed-goal answer tables (minimal tabling)
|
|
1685
1851
|
// ===========================================================================
|
|
@@ -2593,6 +2759,47 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2593
2759
|
continue;
|
|
2594
2760
|
}
|
|
2595
2761
|
|
|
2762
|
+
if (frame.kind === 'memoComplete') {
|
|
2763
|
+
frame.entry.computing = false;
|
|
2764
|
+
if (frame.entry.unsafe) {
|
|
2765
|
+
frame.table.entries.delete(frame.key);
|
|
2766
|
+
} else {
|
|
2767
|
+
frame.entry.complete = true;
|
|
2768
|
+
}
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
if (frame.kind === 'memoAnswerIter') {
|
|
2773
|
+
const answers = frame.entry.answers;
|
|
2774
|
+
while (frame.idx < answers.length && results.length < max) {
|
|
2775
|
+
const answer = answers[frame.idx++];
|
|
2776
|
+
const mark = trail.length;
|
|
2777
|
+
if (!unifyTripleTrail(frame.goal0, answer)) {
|
|
2778
|
+
undoTo(mark);
|
|
2779
|
+
continue;
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
if (!frame.restGoals.length) {
|
|
2783
|
+
results.push(gcCompactForGoals(substMut, [], answerVars));
|
|
2784
|
+
undoTo(mark);
|
|
2785
|
+
if (results.length >= max) return results;
|
|
2786
|
+
continue;
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
stack.push(frame);
|
|
2790
|
+
stack.push({ kind: 'undo', substMark: mark, visitedMark: visitedTrail.length });
|
|
2791
|
+
stack.push({
|
|
2792
|
+
kind: 'node',
|
|
2793
|
+
goalsNow: frame.restGoals,
|
|
2794
|
+
curDepth: frame.curDepth + 1,
|
|
2795
|
+
canDeferBuiltins: frame.canDeferBuiltins,
|
|
2796
|
+
deferCount: 0,
|
|
2797
|
+
});
|
|
2798
|
+
break;
|
|
2799
|
+
}
|
|
2800
|
+
continue;
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2596
2803
|
if (frame.kind === 'deltaIter') {
|
|
2597
2804
|
const deltas = frame.deltas;
|
|
2598
2805
|
while (frame.idx < deltas.length && results.length < max) {
|
|
@@ -2734,7 +2941,21 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2734
2941
|
}
|
|
2735
2942
|
|
|
2736
2943
|
const rawGoal = goalsNow[0];
|
|
2737
|
-
|
|
2944
|
+
let restGoals = goalsNow.length > 1 ? goalsNow.slice(1) : [];
|
|
2945
|
+
|
|
2946
|
+
if (rawGoal && rawGoal.__kind === 'memoStore') {
|
|
2947
|
+
__storePredicateMemoAnswer(rawGoal.entry, rawGoal.goal, substMut);
|
|
2948
|
+
if (rawGoal.stop && restGoals.length === 0) continue;
|
|
2949
|
+
stack.push({
|
|
2950
|
+
kind: 'node',
|
|
2951
|
+
goalsNow: restGoals,
|
|
2952
|
+
curDepth: frame.curDepth,
|
|
2953
|
+
canDeferBuiltins: frame.canDeferBuiltins,
|
|
2954
|
+
deferCount: 0,
|
|
2955
|
+
});
|
|
2956
|
+
continue;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2738
2959
|
const goal0 = applySubstTriple(rawGoal, substMut);
|
|
2739
2960
|
|
|
2740
2961
|
// 1) Builtins
|
|
@@ -2830,8 +3051,46 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2830
3051
|
const goalKey = tripleKeyForVisited(goal0);
|
|
2831
3052
|
const goalWasVisited = visitedCounts.has(goalKey);
|
|
2832
3053
|
|
|
3054
|
+
let memoCompleteFrame = null;
|
|
3055
|
+
let memoReplayFrame = null;
|
|
3056
|
+
if (__predicateIsMemoized(facts, backRules, goal0.p)) {
|
|
3057
|
+
const memoKey = __predicateMemoKey(goal0);
|
|
3058
|
+
if (memoKey !== null) {
|
|
3059
|
+
const memoEntry = __getPredicateMemoEntry(facts, backRules, memoKey);
|
|
3060
|
+
if (memoEntry.complete) {
|
|
3061
|
+
stack.push({
|
|
3062
|
+
kind: 'memoAnswerIter',
|
|
3063
|
+
entry: memoEntry,
|
|
3064
|
+
idx: 0,
|
|
3065
|
+
goal0,
|
|
3066
|
+
restGoals,
|
|
3067
|
+
curDepth: frame.curDepth,
|
|
3068
|
+
canDeferBuiltins: frame.canDeferBuiltins,
|
|
3069
|
+
});
|
|
3070
|
+
continue;
|
|
3071
|
+
}
|
|
3072
|
+
if (!memoEntry.computing && __canStorePredicateMemo(maxResults)) {
|
|
3073
|
+
memoEntry.computing = true;
|
|
3074
|
+
const table = __ensurePredicateMemoTable(facts, backRules);
|
|
3075
|
+
memoReplayFrame = {
|
|
3076
|
+
kind: 'memoAnswerIter',
|
|
3077
|
+
entry: memoEntry,
|
|
3078
|
+
idx: 0,
|
|
3079
|
+
goal0,
|
|
3080
|
+
restGoals,
|
|
3081
|
+
curDepth: frame.curDepth,
|
|
3082
|
+
canDeferBuiltins: frame.canDeferBuiltins,
|
|
3083
|
+
};
|
|
3084
|
+
memoCompleteFrame = { kind: 'memoComplete', entry: memoEntry, table, key: memoKey };
|
|
3085
|
+
restGoals = [{ __kind: 'memoStore', entry: memoEntry, goal: rawGoal, stop: true }];
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
|
|
2833
3090
|
// 3) Backward rules (indexed by head predicate) — explored first
|
|
2834
3091
|
if (goal0.p instanceof Iri) {
|
|
3092
|
+
if (memoReplayFrame) stack.push(memoReplayFrame);
|
|
3093
|
+
if (memoCompleteFrame) stack.push(memoCompleteFrame);
|
|
2835
3094
|
ensureBackRuleIndexes(backRules);
|
|
2836
3095
|
const candRules = (backRules.__byHeadPred.get(goal0.p.__tid) || []).concat(backRules.__wildHeadPred);
|
|
2837
3096
|
|
|
@@ -2863,6 +3122,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
2863
3122
|
});
|
|
2864
3123
|
}
|
|
2865
3124
|
} else {
|
|
3125
|
+
if (memoReplayFrame) stack.push(memoReplayFrame);
|
|
3126
|
+
if (memoCompleteFrame) stack.push(memoCompleteFrame);
|
|
2866
3127
|
// No IRI predicate: rule indexing doesn't apply; only try all facts.
|
|
2867
3128
|
stack.push({
|
|
2868
3129
|
kind: 'factIter',
|
|
@@ -3068,6 +3329,10 @@ function __exitReasoning(code, message /* optional */) {
|
|
|
3068
3329
|
function forwardChain(facts, forwardRules, backRules, onDerived /* optional */, opts = {}) {
|
|
3069
3330
|
enterReasoningRun();
|
|
3070
3331
|
try {
|
|
3332
|
+
const memoizedPredicates = __extractLogMemoizeDeclarations(facts);
|
|
3333
|
+
__attachMemoizedPredicates(facts, memoizedPredicates);
|
|
3334
|
+
__attachMemoizedPredicates(backRules, memoizedPredicates);
|
|
3335
|
+
|
|
3071
3336
|
ensureFactIndexes(facts);
|
|
3072
3337
|
ensureBackRuleIndexes(backRules);
|
|
3073
3338
|
|
|
@@ -3706,7 +3971,7 @@ function reasonStream(input, opts = {}) {
|
|
|
3706
3971
|
if (Array.isArray(logQueryRules) && logQueryRules.length) {
|
|
3707
3972
|
// Query-selection mode: derive full closure, then output only the unique
|
|
3708
3973
|
// instantiated conclusion triples of the log:query directives.
|
|
3709
|
-
const res = forwardChainAndCollectLogQueryConclusions(facts, frules, brules, logQueryRules, { prefixes });
|
|
3974
|
+
const res = forwardChainAndCollectLogQueryConclusions(facts, frules, brules, logQueryRules, null, { captureExplanations: proof, prefixes });
|
|
3710
3975
|
derived = res.derived;
|
|
3711
3976
|
queryTriples = res.queryTriples;
|
|
3712
3977
|
queryDerived = res.queryDerived;
|
|
@@ -3740,7 +4005,7 @@ function reasonStream(input, opts = {}) {
|
|
|
3740
4005
|
onDerived(payload);
|
|
3741
4006
|
}
|
|
3742
4007
|
},
|
|
3743
|
-
{ prefixes },
|
|
4008
|
+
{ captureExplanations: proof, prefixes },
|
|
3744
4009
|
);
|
|
3745
4010
|
}
|
|
3746
4011
|
|
package/lib/multisource.js
CHANGED
|
@@ -184,7 +184,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
const tokens = lex(text, { rdf });
|
|
187
|
-
const parser = new Parser(tokens);
|
|
187
|
+
const parser = new Parser(tokens, { sourceOffsets: sourceLocations });
|
|
188
188
|
if (baseIri) parser.prefixes.setBase(baseIri);
|
|
189
189
|
const [prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
|
|
190
190
|
|
package/lib/parser.js
CHANGED
|
@@ -54,7 +54,7 @@ function annotateSourceOffset(obj, offset) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
class Parser {
|
|
57
|
-
constructor(tokens) {
|
|
57
|
+
constructor(tokens, options = {}) {
|
|
58
58
|
this.toks = tokens;
|
|
59
59
|
this.pos = 0;
|
|
60
60
|
this.prefixes = PrefixEnv.newDefault();
|
|
@@ -68,6 +68,7 @@ class Parser {
|
|
|
68
68
|
// makes derived output read naturally, e.g. ':s :p _:b.' preceding
|
|
69
69
|
// '_:b :q :r.'
|
|
70
70
|
this.pendingTriplesAfter = [];
|
|
71
|
+
this.trackSourceOffsets = !!(options && options.sourceOffsets);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
peek() {
|
|
@@ -80,6 +81,10 @@ class Parser {
|
|
|
80
81
|
return tok;
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
annotateSourceOffset(obj, offset) {
|
|
85
|
+
return this.trackSourceOffsets ? annotateSourceOffset(obj, offset) : obj;
|
|
86
|
+
}
|
|
87
|
+
|
|
83
88
|
fail(message, tok = this.peek()) {
|
|
84
89
|
const off = tok && typeof tok.offset === 'number' ? tok.offset : null;
|
|
85
90
|
throw new N3SyntaxError(message, off);
|
|
@@ -184,12 +189,12 @@ class Parser {
|
|
|
184
189
|
this.next();
|
|
185
190
|
const second = this.parseTerm();
|
|
186
191
|
this.expectDot();
|
|
187
|
-
forwardRules.push(annotateSourceOffset(this.makeRule(first, second, true), statementOffset));
|
|
192
|
+
forwardRules.push(this.annotateSourceOffset(this.makeRule(first, second, true), statementOffset));
|
|
188
193
|
} else if (this.peek().typ === 'OpImpliedBy') {
|
|
189
194
|
this.next();
|
|
190
195
|
const second = this.parseTerm();
|
|
191
196
|
this.expectDot();
|
|
192
|
-
backwardRules.push(annotateSourceOffset(this.makeRule(first, second, false), statementOffset));
|
|
197
|
+
backwardRules.push(this.annotateSourceOffset(this.makeRule(first, second, false), statementOffset));
|
|
193
198
|
} else {
|
|
194
199
|
let more;
|
|
195
200
|
|
|
@@ -208,16 +213,16 @@ class Parser {
|
|
|
208
213
|
|
|
209
214
|
// normalize explicit log:implies / log:impliedBy at top-level
|
|
210
215
|
for (const tr0 of more) {
|
|
211
|
-
const tr = annotateSourceOffset(tr0, statementOffset);
|
|
216
|
+
const tr = this.annotateSourceOffset(tr0, statementOffset);
|
|
212
217
|
if (isLogImplies(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
213
|
-
forwardRules.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
218
|
+
forwardRules.push(this.annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
214
219
|
} else if (isLogImpliedBy(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
215
|
-
backwardRules.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, false), statementOffset));
|
|
220
|
+
backwardRules.push(this.annotateSourceOffset(this.makeRule(tr.s, tr.o, false), statementOffset));
|
|
216
221
|
} else if (isLogQuery(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
217
222
|
// Output-selection directive: { premise } log:query { conclusion }.
|
|
218
223
|
// When present at top-level, eyeling prints only the instantiated conclusion
|
|
219
224
|
// triples (unique) instead of all newly derived facts.
|
|
220
|
-
logQueries.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
225
|
+
logQueries.push(this.annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
221
226
|
} else {
|
|
222
227
|
triples.push(tr);
|
|
223
228
|
}
|