eyeling 1.25.5 → 1.26.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/HANDBOOK.md +8 -8
- package/dist/browser/eyeling.browser.js +614 -25
- package/examples/output/socrates.n3 +0 -1
- package/examples/proof/age.n3 +31 -0
- package/examples/proof/socrates.n3 +19 -0
- package/examples/proof/witch.n3 +120 -0
- package/examples/socrates.n3 +0 -3
- package/eyeling.js +614 -25
- package/index.d.ts +1 -0
- package/index.js +16 -13
- package/lib/cli.js +10 -4
- package/lib/engine.js +228 -6
- package/lib/entry.js +1 -0
- package/lib/explain.js +280 -2
- package/lib/multisource.js +74 -7
- package/lib/parser.js +20 -6
- package/package.json +1 -1
- package/test/api.test.js +6 -6
- package/tools/bundle.js +3 -0
|
@@ -4721,7 +4721,7 @@ function main() {
|
|
|
4721
4721
|
` -d, --deterministic-skolem Make log:skolem stable across reasoning runs.\n` +
|
|
4722
4722
|
` -e, --enforce-https Rewrite http:// IRIs to https:// for log dereferencing builtins.\n` +
|
|
4723
4723
|
` -h, --help Show this help and exit.\n` +
|
|
4724
|
-
` -p, --proof
|
|
4724
|
+
` -p, --proof Enable proof explanations.\n` +
|
|
4725
4725
|
` -r, --rdf Enable RDF/TriG input/output compatibility.\n` +
|
|
4726
4726
|
` -s, --super-restricted Disable all builtins except => and <=.\n` +
|
|
4727
4727
|
` -t, --stream Stream derived triples as soon as they are derived.\n` +
|
|
@@ -4776,8 +4776,8 @@ function main() {
|
|
|
4776
4776
|
if (typeof engine.setDeterministicSkolemEnabled === 'function') engine.setDeterministicSkolemEnabled(true);
|
|
4777
4777
|
}
|
|
4778
4778
|
|
|
4779
|
-
// --proof
|
|
4780
|
-
if (argv.includes('--proof-comments') || argv.includes('-p')) {
|
|
4779
|
+
// --proof / -p: enable proof explanations as N3 proof graphs
|
|
4780
|
+
if (argv.includes('--proof') || argv.includes('--proof-comments') || argv.includes('-p')) {
|
|
4781
4781
|
engine.setProofCommentsEnabled(true);
|
|
4782
4782
|
}
|
|
4783
4783
|
|
|
@@ -4826,6 +4826,7 @@ function main() {
|
|
|
4826
4826
|
baseIri: __sourceLabelToBaseIri(sourceLabel),
|
|
4827
4827
|
label: sourceLabel,
|
|
4828
4828
|
collectUsedPrefixes: streamMode,
|
|
4829
|
+
collectSourceLocations: engine.getProofCommentsEnabled(),
|
|
4829
4830
|
keepSourceArtifacts: false,
|
|
4830
4831
|
rdf: rdfMode,
|
|
4831
4832
|
}),
|
|
@@ -4916,7 +4917,7 @@ function main() {
|
|
|
4916
4917
|
const hasQueries = Array.isArray(qrules) && qrules.length;
|
|
4917
4918
|
const mayAutoRenderOutputStrings = programMayProduceOutputStrings(triples, frules, qrules);
|
|
4918
4919
|
|
|
4919
|
-
if (streamMode && !hasQueries && !mayAutoRenderOutputStrings) {
|
|
4920
|
+
if (streamMode && !hasQueries && !mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled()) {
|
|
4920
4921
|
const usedInInput = mergedDocument.usedPrefixes instanceof Set ? new Set(mergedDocument.usedPrefixes) : new Set();
|
|
4921
4922
|
const outPrefixes = restrictPrefixEnv(prefixes, usedInInput);
|
|
4922
4923
|
|
|
@@ -4981,6 +4982,11 @@ function main() {
|
|
|
4981
4982
|
return;
|
|
4982
4983
|
}
|
|
4983
4984
|
|
|
4985
|
+
if (engine.getProofCommentsEnabled()) {
|
|
4986
|
+
process.stdout.write(engine.renderProofDocument(outDerived, derived, triples, prefixes, brules));
|
|
4987
|
+
return;
|
|
4988
|
+
}
|
|
4989
|
+
|
|
4984
4990
|
let bodyText = '';
|
|
4985
4991
|
if (rdfMode && !engine.getProofCommentsEnabled()) {
|
|
4986
4992
|
bodyText = outTriples.map((tr) => engine.tripleToRdfCompatible(tr, prefixes)).join('\n');
|
|
@@ -6269,9 +6275,11 @@ const { evalBuiltin, isBuiltinPred } = makeBuiltins({
|
|
|
6269
6275
|
});
|
|
6270
6276
|
|
|
6271
6277
|
// Initialize proof/output helpers (implemented in lib/explain.js).
|
|
6272
|
-
const { printExplanation, collectOutputStringsFromFacts } = makeExplain({
|
|
6278
|
+
const { printExplanation, renderProofDocument, collectOutputStringsFromFacts } = makeExplain({
|
|
6273
6279
|
applySubstTerm,
|
|
6274
6280
|
skolemKeyFromTerm,
|
|
6281
|
+
isBuiltinPred,
|
|
6282
|
+
findBackwardProofForGoal,
|
|
6275
6283
|
});
|
|
6276
6284
|
|
|
6277
6285
|
function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
|
|
@@ -7922,6 +7930,217 @@ function unifyTriple(pat, fact, subst) {
|
|
|
7922
7930
|
return s3;
|
|
7923
7931
|
}
|
|
7924
7932
|
|
|
7933
|
+
|
|
7934
|
+
function __copyProofSourceMetadata(from, to) {
|
|
7935
|
+
if (!from || !to) return to;
|
|
7936
|
+
for (const key of ['__sourceOffset', '__source']) {
|
|
7937
|
+
if (hasOwn.call(from, key)) {
|
|
7938
|
+
Object.defineProperty(to, key, {
|
|
7939
|
+
value: from[key],
|
|
7940
|
+
enumerable: false,
|
|
7941
|
+
writable: false,
|
|
7942
|
+
configurable: true,
|
|
7943
|
+
});
|
|
7944
|
+
}
|
|
7945
|
+
}
|
|
7946
|
+
return to;
|
|
7947
|
+
}
|
|
7948
|
+
|
|
7949
|
+
function __standardizeRuleForProof(rule, gen) {
|
|
7950
|
+
const proofVarNames = Object.create(null);
|
|
7951
|
+
|
|
7952
|
+
function renameTerm(t, vmapName, vmapVar, genArr) {
|
|
7953
|
+
if (t instanceof Var) {
|
|
7954
|
+
if (!hasOwn.call(vmapVar, t.name)) {
|
|
7955
|
+
const name = `${t.name}__proof_${genArr[0]}`;
|
|
7956
|
+
genArr[0] += 1;
|
|
7957
|
+
vmapName[t.name] = name;
|
|
7958
|
+
vmapVar[t.name] = new Var(name);
|
|
7959
|
+
proofVarNames[name] = t.name;
|
|
7960
|
+
}
|
|
7961
|
+
return vmapVar[t.name];
|
|
7962
|
+
}
|
|
7963
|
+
if (t instanceof ListTerm) {
|
|
7964
|
+
let changed = false;
|
|
7965
|
+
const elems2 = t.elems.map((e) => {
|
|
7966
|
+
const e2 = renameTerm(e, vmapName, vmapVar, genArr);
|
|
7967
|
+
if (e2 !== e) changed = true;
|
|
7968
|
+
return e2;
|
|
7969
|
+
});
|
|
7970
|
+
return changed ? new ListTerm(elems2) : t;
|
|
7971
|
+
}
|
|
7972
|
+
if (t instanceof OpenListTerm) {
|
|
7973
|
+
let changed = false;
|
|
7974
|
+
const newXs = t.prefix.map((e) => {
|
|
7975
|
+
const e2 = renameTerm(e, vmapName, vmapVar, genArr);
|
|
7976
|
+
if (e2 !== e) changed = true;
|
|
7977
|
+
return e2;
|
|
7978
|
+
});
|
|
7979
|
+
if (!hasOwn.call(vmapName, t.tailVar)) {
|
|
7980
|
+
const name = `${t.tailVar}__proof_${genArr[0]}`;
|
|
7981
|
+
genArr[0] += 1;
|
|
7982
|
+
vmapName[t.tailVar] = name;
|
|
7983
|
+
vmapVar[t.tailVar] = new Var(name);
|
|
7984
|
+
proofVarNames[name] = t.tailVar;
|
|
7985
|
+
}
|
|
7986
|
+
const newTail = vmapName[t.tailVar];
|
|
7987
|
+
if (newTail !== t.tailVar) changed = true;
|
|
7988
|
+
return changed ? new OpenListTerm(newXs, newTail) : t;
|
|
7989
|
+
}
|
|
7990
|
+
if (t instanceof GraphTerm) {
|
|
7991
|
+
let changed = false;
|
|
7992
|
+
const triples2 = t.triples.map((tr) => {
|
|
7993
|
+
const s2 = renameTerm(tr.s, vmapName, vmapVar, genArr);
|
|
7994
|
+
const p2 = renameTerm(tr.p, vmapName, vmapVar, genArr);
|
|
7995
|
+
const o2 = renameTerm(tr.o, vmapName, vmapVar, genArr);
|
|
7996
|
+
if (s2 !== tr.s || p2 !== tr.p || o2 !== tr.o) changed = true;
|
|
7997
|
+
return s2 === tr.s && p2 === tr.p && o2 === tr.o ? tr : new Triple(s2, p2, o2);
|
|
7998
|
+
});
|
|
7999
|
+
return changed ? copyQuotedGraphMetadata(t, new GraphTerm(triples2)) : t;
|
|
8000
|
+
}
|
|
8001
|
+
return t;
|
|
8002
|
+
}
|
|
8003
|
+
|
|
8004
|
+
const vmapName = Object.create(null);
|
|
8005
|
+
const vmapVar = Object.create(null);
|
|
8006
|
+
const premise = rule.premise.map((tr) => {
|
|
8007
|
+
const s2 = renameTerm(tr.s, vmapName, vmapVar, gen);
|
|
8008
|
+
const p2 = renameTerm(tr.p, vmapName, vmapVar, gen);
|
|
8009
|
+
const o2 = renameTerm(tr.o, vmapName, vmapVar, gen);
|
|
8010
|
+
return s2 === tr.s && p2 === tr.p && o2 === tr.o ? tr : new Triple(s2, p2, o2);
|
|
8011
|
+
});
|
|
8012
|
+
const conclusion = rule.conclusion.map((tr) => {
|
|
8013
|
+
const s2 = renameTerm(tr.s, vmapName, vmapVar, gen);
|
|
8014
|
+
const p2 = renameTerm(tr.p, vmapName, vmapVar, gen);
|
|
8015
|
+
const o2 = renameTerm(tr.o, vmapName, vmapVar, gen);
|
|
8016
|
+
return s2 === tr.s && p2 === tr.p && o2 === tr.o ? tr : new Triple(s2, p2, o2);
|
|
8017
|
+
});
|
|
8018
|
+
const out = new Rule(premise, conclusion, rule.isForward, rule.isFuse, rule.headBlankLabels);
|
|
8019
|
+
Object.defineProperty(out, '__proofVarSourceNames', {
|
|
8020
|
+
value: proofVarNames,
|
|
8021
|
+
enumerable: false,
|
|
8022
|
+
writable: false,
|
|
8023
|
+
configurable: true,
|
|
8024
|
+
});
|
|
8025
|
+
return __copyProofSourceMetadata(rule, out);
|
|
8026
|
+
}
|
|
8027
|
+
|
|
8028
|
+
function __mergeProofSubst(base, delta) {
|
|
8029
|
+
const out = __cloneSubst(base);
|
|
8030
|
+
for (const k in delta || {}) {
|
|
8031
|
+
if (!hasOwn.call(delta, k)) continue;
|
|
8032
|
+
const v = applySubstTerm(delta[k], out);
|
|
8033
|
+
if (hasOwn.call(out, k)) {
|
|
8034
|
+
if (!termsEqual(applySubstTerm(out[k], out), v)) return null;
|
|
8035
|
+
} else {
|
|
8036
|
+
out[k] = v;
|
|
8037
|
+
}
|
|
8038
|
+
}
|
|
8039
|
+
return out;
|
|
8040
|
+
}
|
|
8041
|
+
|
|
8042
|
+
function __sourceSortKey(obj) {
|
|
8043
|
+
const src = obj && obj.__source;
|
|
8044
|
+
const label = src && typeof src.label === 'string' ? src.label : '';
|
|
8045
|
+
const line = src && Number.isInteger(src.line) ? src.line : 0;
|
|
8046
|
+
return `${label}\t${line}`;
|
|
8047
|
+
}
|
|
8048
|
+
|
|
8049
|
+
function __candidateFactsForProof(facts, goal) {
|
|
8050
|
+
if (!Array.isArray(facts)) return [];
|
|
8051
|
+
ensureFactIndexes(facts);
|
|
8052
|
+
const candidates = candidateFacts(facts, goal);
|
|
8053
|
+
if (!candidates) return facts;
|
|
8054
|
+
const out = [];
|
|
8055
|
+
for (let i = 0; i < candidates.exactLen; i++) out.push(facts[candidates.exact[i]]);
|
|
8056
|
+
for (let i = 0; i < candidates.wildLen; i++) out.push(facts[candidates.wild[i]]);
|
|
8057
|
+
return out;
|
|
8058
|
+
}
|
|
8059
|
+
|
|
8060
|
+
function findBackwardProofForGoal(goal, facts, backRules, opts = {}) {
|
|
8061
|
+
const maxDepth = Number.isInteger(opts.maxDepth) && opts.maxDepth > 0 ? opts.maxDepth : 64;
|
|
8062
|
+
const varGen = [0];
|
|
8063
|
+
|
|
8064
|
+
function proofKey(tr) {
|
|
8065
|
+
return `${skolemKeyFromTerm(tr.s)}\t${skolemKeyFromTerm(tr.p)}\t${skolemKeyFromTerm(tr.o)}`;
|
|
8066
|
+
}
|
|
8067
|
+
|
|
8068
|
+
function proveGoal(goal0, subst, depth, visited) {
|
|
8069
|
+
if (depth > maxDepth) return [];
|
|
8070
|
+
const g = applySubstTriple(goal0, subst);
|
|
8071
|
+
const key = proofKey(g);
|
|
8072
|
+
if (visited.has(key)) return [];
|
|
8073
|
+
|
|
8074
|
+
if (isBuiltinPred(g.p)) {
|
|
8075
|
+
const builtinGoalForEval = g.p instanceof Iri && g.p.value === LOG_NS + 'rawType' ? goal0 : g;
|
|
8076
|
+
const builtinSubstForEval = g.p instanceof Iri && g.p.value === LOG_NS + 'rawType' ? subst : __emptySubst();
|
|
8077
|
+
const deltas = evalBuiltin(builtinGoalForEval, builtinSubstForEval, facts, backRules, depth, varGen, 1) || [];
|
|
8078
|
+
const out = [];
|
|
8079
|
+
for (const delta of deltas) {
|
|
8080
|
+
const subst2 = __mergeProofSubst(subst, delta);
|
|
8081
|
+
if (subst2 === null) continue;
|
|
8082
|
+
const fact = applySubstTriple(g, subst2);
|
|
8083
|
+
out.push({ subst: subst2, proof: { kind: 'builtin', fact, builtin: fact.p } });
|
|
8084
|
+
break;
|
|
8085
|
+
}
|
|
8086
|
+
return out;
|
|
8087
|
+
}
|
|
8088
|
+
|
|
8089
|
+
const factResults = [];
|
|
8090
|
+
for (const f of __candidateFactsForProof(facts, g)) {
|
|
8091
|
+
const subst2 = unifyTriple(g, f, subst);
|
|
8092
|
+
if (subst2 === null) continue;
|
|
8093
|
+
factResults.push({ subst: subst2, proof: { kind: 'fact', fact: applySubstTriple(f, subst2), source: f.__source } });
|
|
8094
|
+
break;
|
|
8095
|
+
}
|
|
8096
|
+
if (factResults.length) return factResults;
|
|
8097
|
+
|
|
8098
|
+
if (!(g.p instanceof Iri)) return [];
|
|
8099
|
+
ensureBackRuleIndexes(backRules);
|
|
8100
|
+
const rules = (backRules.__byHeadPred.get(g.p.__tid) || []).concat(backRules.__wildHeadPred || []);
|
|
8101
|
+
rules.sort((a, b) => (__sourceSortKey(a) < __sourceSortKey(b) ? -1 : __sourceSortKey(a) > __sourceSortKey(b) ? 1 : 0));
|
|
8102
|
+
|
|
8103
|
+
const visited2 = new Set(visited);
|
|
8104
|
+
visited2.add(key);
|
|
8105
|
+
|
|
8106
|
+
for (const r of rules) {
|
|
8107
|
+
if (!r || !Array.isArray(r.conclusion) || r.conclusion.length !== 1) continue;
|
|
8108
|
+
const rStd = __standardizeRuleForProof(r, varGen);
|
|
8109
|
+
const head = rStd.conclusion[0];
|
|
8110
|
+
if (head.p instanceof Iri && head.p.__tid !== g.p.__tid) continue;
|
|
8111
|
+
const subst1 = unifyTriple(head, g, subst);
|
|
8112
|
+
if (subst1 === null) continue;
|
|
8113
|
+
const bodyProof = proveGoalList(rStd.premise || [], subst1, depth + 1, visited2);
|
|
8114
|
+
if (!bodyProof) continue;
|
|
8115
|
+
const fact = applySubstTriple(g, bodyProof.subst);
|
|
8116
|
+
const premises = (rStd.premise || []).map((prem) => applySubstTriple(prem, bodyProof.subst));
|
|
8117
|
+
const df = new DerivedFact(fact, rStd, premises, bodyProof.subst);
|
|
8118
|
+
return [{ subst: bodyProof.subst, proof: { kind: 'rule', df, children: bodyProof.proofs } }];
|
|
8119
|
+
}
|
|
8120
|
+
|
|
8121
|
+
return [];
|
|
8122
|
+
}
|
|
8123
|
+
|
|
8124
|
+
function proveGoalList(goals, subst, depth, visited) {
|
|
8125
|
+
let states = [{ subst, proofs: [] }];
|
|
8126
|
+
for (const goal1 of goals || []) {
|
|
8127
|
+
const next = [];
|
|
8128
|
+
for (const state of states) {
|
|
8129
|
+
const proofs = proveGoal(goal1, state.subst, depth, visited);
|
|
8130
|
+
for (const pr of proofs) next.push({ subst: pr.subst, proofs: state.proofs.concat([pr.proof]) });
|
|
8131
|
+
}
|
|
8132
|
+
if (!next.length) return null;
|
|
8133
|
+
// Keep proof reconstruction deterministic and cheap: one proof is enough
|
|
8134
|
+
// for an explanation of the already-derived enclosing fact.
|
|
8135
|
+
states = [next[0]];
|
|
8136
|
+
}
|
|
8137
|
+
return states[0] || { subst, proofs: [] };
|
|
8138
|
+
}
|
|
8139
|
+
|
|
8140
|
+
const found = proveGoal(goal, __emptySubst(), 0, new Set());
|
|
8141
|
+
return found.length ? found[0].proof : null;
|
|
8142
|
+
}
|
|
8143
|
+
|
|
7925
8144
|
// Strategy: when the substitution is "large" or search depth is high,
|
|
7926
8145
|
// keep only bindings that are still relevant to:
|
|
7927
8146
|
// - variables appearing in the remaining goals
|
|
@@ -9436,11 +9655,19 @@ function reasonStream(input, opts = {}) {
|
|
|
9436
9655
|
? facts
|
|
9437
9656
|
: derived.map((d) => d.fact);
|
|
9438
9657
|
|
|
9439
|
-
const closureN3 =
|
|
9440
|
-
?
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9658
|
+
const closureN3 = proof
|
|
9659
|
+
? renderProofDocument(
|
|
9660
|
+
Array.isArray(logQueryRules) && logQueryRules.length ? queryDerived : derived,
|
|
9661
|
+
derived,
|
|
9662
|
+
triples,
|
|
9663
|
+
prefixes,
|
|
9664
|
+
brules,
|
|
9665
|
+
).replace(/\n$/g, '')
|
|
9666
|
+
: useRdfCompatibility
|
|
9667
|
+
? closureTriples.map((t) => tripleToRdfCompatible(t, prefixes)).join('\n')
|
|
9668
|
+
: Array.isArray(logQueryRules) && logQueryRules.length
|
|
9669
|
+
? prettyPrintQueryTriples(closureTriples, prefixes)
|
|
9670
|
+
: closureTriples.map((t) => tripleToN3(t, prefixes)).join('\n');
|
|
9444
9671
|
|
|
9445
9672
|
const __out = {
|
|
9446
9673
|
prefixes,
|
|
@@ -9567,6 +9794,7 @@ module.exports = {
|
|
|
9567
9794
|
collectLogQueryConclusions,
|
|
9568
9795
|
forwardChainAndCollectLogQueryConclusions,
|
|
9569
9796
|
collectOutputStringsFromFacts,
|
|
9797
|
+
renderProofDocument,
|
|
9570
9798
|
main,
|
|
9571
9799
|
version,
|
|
9572
9800
|
N3SyntaxError,
|
|
@@ -9636,6 +9864,7 @@ module.exports = {
|
|
|
9636
9864
|
materializeRdfLists: engine.materializeRdfLists,
|
|
9637
9865
|
isGroundTriple: engine.isGroundTriple,
|
|
9638
9866
|
printExplanation: engine.printExplanation,
|
|
9867
|
+
renderProofDocument: engine.renderProofDocument,
|
|
9639
9868
|
tripleToN3: engine.tripleToN3,
|
|
9640
9869
|
collectOutputStringsFromFacts: engine.collectOutputStringsFromFacts,
|
|
9641
9870
|
prettyPrintQueryTriples: engine.prettyPrintQueryTriples,
|
|
@@ -9662,7 +9891,7 @@ module.exports = {
|
|
|
9662
9891
|
*/
|
|
9663
9892
|
'use strict';
|
|
9664
9893
|
|
|
9665
|
-
const { LOG_NS, Literal, Iri, Blank, Var, varsInRule, literalParts } = require('./prelude');
|
|
9894
|
+
const { LOG_NS, Literal, Iri, Blank, Var, GraphTerm, varsInRule, literalParts, PrefixEnv } = require('./prelude');
|
|
9666
9895
|
|
|
9667
9896
|
const { termToN3, tripleToN3 } = require('./printing');
|
|
9668
9897
|
const { parseNumericLiteralInfo, termToJsString } = require('./builtins');
|
|
@@ -9670,6 +9899,8 @@ const { parseNumericLiteralInfo, termToJsString } = require('./builtins');
|
|
|
9670
9899
|
function makeExplain(deps) {
|
|
9671
9900
|
const applySubstTerm = deps.applySubstTerm;
|
|
9672
9901
|
const skolemKeyFromTerm = deps.skolemKeyFromTerm;
|
|
9902
|
+
const isBuiltinPred = typeof deps.isBuiltinPred === 'function' ? deps.isBuiltinPred : () => false;
|
|
9903
|
+
const findBackwardProofForGoal = typeof deps.findBackwardProofForGoal === 'function' ? deps.findBackwardProofForGoal : null;
|
|
9673
9904
|
|
|
9674
9905
|
function printExplanation(df, prefixes) {
|
|
9675
9906
|
console.log('# ----------------------------------------------------------------------');
|
|
@@ -9767,6 +9998,282 @@ function makeExplain(deps) {
|
|
|
9767
9998
|
console.log('# ----------------------------------------------------------------------\n');
|
|
9768
9999
|
}
|
|
9769
10000
|
|
|
10001
|
+
|
|
10002
|
+
const PE_NS = 'https://eyereasoner.github.io/pe#';
|
|
10003
|
+
|
|
10004
|
+
function n3String(value) {
|
|
10005
|
+
return JSON.stringify(String(value));
|
|
10006
|
+
}
|
|
10007
|
+
|
|
10008
|
+
function lineIndent(text, prefix) {
|
|
10009
|
+
return String(text)
|
|
10010
|
+
.split(/\r?\n/)
|
|
10011
|
+
.map((line) => (line.length ? prefix + line : line))
|
|
10012
|
+
.join('\n');
|
|
10013
|
+
}
|
|
10014
|
+
|
|
10015
|
+
function graphForTriple(tr, prefixes) {
|
|
10016
|
+
const body = tripleToN3(tr, prefixes).trimEnd();
|
|
10017
|
+
if (!body.includes('\n')) return `{ ${body} }`;
|
|
10018
|
+
return `{
|
|
10019
|
+
${lineIndent(body, ' ')}
|
|
10020
|
+
}`;
|
|
10021
|
+
}
|
|
10022
|
+
|
|
10023
|
+
|
|
10024
|
+
function clonePrefixEnvWithProofVocabulary(prefixes) {
|
|
10025
|
+
const map = { ...(prefixes && prefixes.map ? prefixes.map : {}) };
|
|
10026
|
+
if (!map.pe) map.pe = PE_NS;
|
|
10027
|
+
return new PrefixEnv(map, (prefixes && prefixes.baseIri) || '');
|
|
10028
|
+
}
|
|
10029
|
+
|
|
10030
|
+
function proofTripleKey(tr) {
|
|
10031
|
+
if (!tr) return '';
|
|
10032
|
+
return `${skolemKeyFromTerm(tr.s)}\t${skolemKeyFromTerm(tr.p)}\t${skolemKeyFromTerm(tr.o)}`;
|
|
10033
|
+
}
|
|
10034
|
+
|
|
10035
|
+
function sourceLabelForProof(source) {
|
|
10036
|
+
if (!source || typeof source.label !== 'string' || !source.label) return '<unknown>';
|
|
10037
|
+
// Keep proof output stable when the CLI is invoked with paths such as examples/foo.n3.
|
|
10038
|
+
return source.label.replace(/\\/g, '/').split('/').pop() || source.label;
|
|
10039
|
+
}
|
|
10040
|
+
|
|
10041
|
+
function byBlankNode(kind, source) {
|
|
10042
|
+
const src = source || {};
|
|
10043
|
+
const props = [`pe:${kind} ${n3String(sourceLabelForProof(src))}`];
|
|
10044
|
+
if (Number.isInteger(src.line) && src.line > 0) props.push(`pe:line ${src.line}`);
|
|
10045
|
+
return `[ ${props.join('; ')} ]`;
|
|
10046
|
+
}
|
|
10047
|
+
|
|
10048
|
+
function renderBindingList(df, prefixes) {
|
|
10049
|
+
if (!df || !df.rule || !df.subst) return '';
|
|
10050
|
+
const ruleVars = varsInRule(df.rule);
|
|
10051
|
+
const visibleNames = Object.keys(df.subst)
|
|
10052
|
+
.filter((name) => ruleVars.has(name))
|
|
10053
|
+
.sort();
|
|
10054
|
+
if (!visibleNames.length) return '';
|
|
10055
|
+
const sourceNames = (df.rule && df.rule.__proofVarSourceNames) || null;
|
|
10056
|
+
return visibleNames
|
|
10057
|
+
.map((name) => {
|
|
10058
|
+
const value = applySubstTerm(new Var(name), df.subst);
|
|
10059
|
+
const displayName = sourceNames && sourceNames[name] ? sourceNames[name] : name;
|
|
10060
|
+
return `[ pe:var ${n3String(displayName)}; pe:value ${termToN3(value, prefixes)} ]`;
|
|
10061
|
+
})
|
|
10062
|
+
.join(', ');
|
|
10063
|
+
}
|
|
10064
|
+
|
|
10065
|
+
function proofSourceKey(source) {
|
|
10066
|
+
if (!source) return '';
|
|
10067
|
+
const label = typeof source.label === 'string' ? source.label : '';
|
|
10068
|
+
const line = Number.isInteger(source.line) ? source.line : 0;
|
|
10069
|
+
return `${label}\t${line}`;
|
|
10070
|
+
}
|
|
10071
|
+
|
|
10072
|
+
function proofEntryKey(kind, fact, source, extra) {
|
|
10073
|
+
return `${kind}\t${proofTripleKey(fact)}\t${proofSourceKey(source)}\t${extra || ''}`;
|
|
10074
|
+
}
|
|
10075
|
+
|
|
10076
|
+
function ruleEntryKey(df) {
|
|
10077
|
+
const rule = df && df.rule;
|
|
10078
|
+
const premises = (df && df.premises ? df.premises : []).map((prem) => proofTripleKey(prem)).join('\t');
|
|
10079
|
+
return proofEntryKey('rule', df && df.fact, rule && rule.__source, premises);
|
|
10080
|
+
}
|
|
10081
|
+
|
|
10082
|
+
function collectProofEntries(rootDf, derivedByKey, baseFactByKey, resolveBackwardProof) {
|
|
10083
|
+
const entries = [];
|
|
10084
|
+
const seen = new Set();
|
|
10085
|
+
|
|
10086
|
+
function entryKeyForProof(proof, fallbackTriple) {
|
|
10087
|
+
if (!proof) return proofEntryKey('fact', fallbackTriple, null);
|
|
10088
|
+
if (proof.kind === 'rule') return ruleEntryKey(proof.df);
|
|
10089
|
+
if (proof.kind === 'builtin') return proofEntryKey('builtin', proof.fact || fallbackTriple, null);
|
|
10090
|
+
return proofEntryKey('fact', proof.fact || fallbackTriple, proof.source);
|
|
10091
|
+
}
|
|
10092
|
+
|
|
10093
|
+
function visitProofNode(proof, fallbackTriple) {
|
|
10094
|
+
if (!proof) {
|
|
10095
|
+
visitFactTriple(fallbackTriple);
|
|
10096
|
+
return;
|
|
10097
|
+
}
|
|
10098
|
+
const key = entryKeyForProof(proof, fallbackTriple);
|
|
10099
|
+
if (!key || seen.has(key)) return;
|
|
10100
|
+
if (proof.kind === 'rule' && proof.df) {
|
|
10101
|
+
visitDerivedFact(proof.df, proof.children || null);
|
|
10102
|
+
return;
|
|
10103
|
+
}
|
|
10104
|
+
seen.add(key);
|
|
10105
|
+
if (proof.kind === 'builtin') {
|
|
10106
|
+
entries.push({
|
|
10107
|
+
kind: 'builtin',
|
|
10108
|
+
fact: proof.fact || fallbackTriple,
|
|
10109
|
+
builtin: proof.builtin || (proof.fact && proof.fact.p),
|
|
10110
|
+
});
|
|
10111
|
+
} else {
|
|
10112
|
+
entries.push({ kind: 'fact', fact: proof.fact || fallbackTriple, source: proof.source });
|
|
10113
|
+
}
|
|
10114
|
+
}
|
|
10115
|
+
|
|
10116
|
+
function visitFactTriple(tr) {
|
|
10117
|
+
const tripleKey = proofTripleKey(tr);
|
|
10118
|
+
if (!tripleKey) return;
|
|
10119
|
+
const df = derivedByKey.get(tripleKey);
|
|
10120
|
+
if (df) {
|
|
10121
|
+
visitDerivedFact(df);
|
|
10122
|
+
return;
|
|
10123
|
+
}
|
|
10124
|
+
const base = baseFactByKey.get(tripleKey) || null;
|
|
10125
|
+
if (base) {
|
|
10126
|
+
const key = proofEntryKey('fact', base, base.__source);
|
|
10127
|
+
if (seen.has(key)) return;
|
|
10128
|
+
seen.add(key);
|
|
10129
|
+
entries.push({ kind: 'fact', fact: base, source: base.__source });
|
|
10130
|
+
return;
|
|
10131
|
+
}
|
|
10132
|
+
if (tr && isBuiltinPred(tr.p)) {
|
|
10133
|
+
const key = proofEntryKey('builtin', tr, null);
|
|
10134
|
+
if (seen.has(key)) return;
|
|
10135
|
+
seen.add(key);
|
|
10136
|
+
entries.push({ kind: 'builtin', fact: tr, builtin: tr.p });
|
|
10137
|
+
return;
|
|
10138
|
+
}
|
|
10139
|
+
if (resolveBackwardProof) {
|
|
10140
|
+
const proof = resolveBackwardProof(tr);
|
|
10141
|
+
if (proof) {
|
|
10142
|
+
visitProofNode(proof, tr);
|
|
10143
|
+
return;
|
|
10144
|
+
}
|
|
10145
|
+
}
|
|
10146
|
+
const key = proofEntryKey('fact', tr, null);
|
|
10147
|
+
if (seen.has(key)) return;
|
|
10148
|
+
seen.add(key);
|
|
10149
|
+
entries.push({ kind: 'fact', fact: tr, source: null });
|
|
10150
|
+
}
|
|
10151
|
+
|
|
10152
|
+
function visitDerivedFact(df, children) {
|
|
10153
|
+
const key = ruleEntryKey(df);
|
|
10154
|
+
if (!key || seen.has(key)) return;
|
|
10155
|
+
seen.add(key);
|
|
10156
|
+
entries.push({ kind: 'rule', df });
|
|
10157
|
+
|
|
10158
|
+
if (Array.isArray(children) && children.length) {
|
|
10159
|
+
for (const child of children) visitProofNode(child);
|
|
10160
|
+
return;
|
|
10161
|
+
}
|
|
10162
|
+
for (const prem of df.premises || []) visitFactTriple(prem);
|
|
10163
|
+
}
|
|
10164
|
+
|
|
10165
|
+
visitDerivedFact(rootDf);
|
|
10166
|
+
return entries;
|
|
10167
|
+
}
|
|
10168
|
+
|
|
10169
|
+
function collectProofOutputTriples(outputDerived) {
|
|
10170
|
+
const out = [];
|
|
10171
|
+
const seen = new Set();
|
|
10172
|
+
for (const df of outputDerived || []) {
|
|
10173
|
+
if (!df || !df.fact) continue;
|
|
10174
|
+
const key = proofTripleKey(df.fact);
|
|
10175
|
+
if (seen.has(key)) continue;
|
|
10176
|
+
seen.add(key);
|
|
10177
|
+
out.push(df.fact);
|
|
10178
|
+
}
|
|
10179
|
+
return out;
|
|
10180
|
+
}
|
|
10181
|
+
|
|
10182
|
+
function renderProofEntry(entry, prefixes) {
|
|
10183
|
+
if (!entry) return '';
|
|
10184
|
+
if (entry.kind === 'fact') {
|
|
10185
|
+
return ` ${graphForTriple(entry.fact, prefixes)}\n pe:by ${byBlankNode('fact', entry.source)}.`;
|
|
10186
|
+
}
|
|
10187
|
+
if (entry.kind === 'builtin') {
|
|
10188
|
+
return ` ${graphForTriple(entry.fact, prefixes)}\n pe:by [ pe:builtin ${termToN3(entry.builtin, prefixes)} ].`;
|
|
10189
|
+
}
|
|
10190
|
+
|
|
10191
|
+
const df = entry.df;
|
|
10192
|
+
const props = [`pe:by ${byBlankNode('rule', df.rule && df.rule.__source)}`];
|
|
10193
|
+
const bindings = renderBindingList(df, prefixes);
|
|
10194
|
+
if (bindings) props.push(`pe:binding ${bindings}`);
|
|
10195
|
+
if (df.premises && df.premises.length) {
|
|
10196
|
+
props.push(`pe:uses ${df.premises.map((prem) => graphForTriple(prem, prefixes)).join(', ')}`);
|
|
10197
|
+
}
|
|
10198
|
+
|
|
10199
|
+
let out = ` ${graphForTriple(df.fact, prefixes)}\n`;
|
|
10200
|
+
for (let i = 0; i < props.length; i++) {
|
|
10201
|
+
out += ` ${props[i]}${i === props.length - 1 ? '.' : ';'}\n`;
|
|
10202
|
+
}
|
|
10203
|
+
return out.trimEnd();
|
|
10204
|
+
}
|
|
10205
|
+
|
|
10206
|
+
function renderProofBlock(rootDf, derivedByKey, baseFactByKey, prefixes, resolveBackwardProof) {
|
|
10207
|
+
const entries = collectProofEntries(rootDf, derivedByKey, baseFactByKey, resolveBackwardProof);
|
|
10208
|
+
const rootGraph = graphForTriple(rootDf.fact, prefixes);
|
|
10209
|
+
const proofBody = entries.map((entry) => renderProofEntry(entry, prefixes)).join('\n\n');
|
|
10210
|
+
const proofGraph = proofBody ? `{
|
|
10211
|
+
${proofBody}
|
|
10212
|
+
}` : '{}';
|
|
10213
|
+
return `${rootGraph} pe:why ${proofGraph}.`;
|
|
10214
|
+
}
|
|
10215
|
+
|
|
10216
|
+
function renderProofDocument(outputDerived, allDerived, baseFacts, prefixes, backRules) {
|
|
10217
|
+
const selectedDerived = Array.isArray(outputDerived) ? outputDerived.filter((df) => df && df.fact) : [];
|
|
10218
|
+
if (!selectedDerived.length) return '';
|
|
10219
|
+
|
|
10220
|
+
const proofPrefixes = clonePrefixEnvWithProofVocabulary(prefixes);
|
|
10221
|
+
const derivedByKey = new Map();
|
|
10222
|
+
for (const df of allDerived || []) {
|
|
10223
|
+
if (!df || !df.fact) continue;
|
|
10224
|
+
const key = proofTripleKey(df.fact);
|
|
10225
|
+
if (!derivedByKey.has(key)) derivedByKey.set(key, df);
|
|
10226
|
+
}
|
|
10227
|
+
// Do not insert query-wrapper output facts here: those wrappers often derive
|
|
10228
|
+
// the same triple they use, and would hide the underlying fact/rule proof.
|
|
10229
|
+
|
|
10230
|
+
const baseFactByKey = new Map();
|
|
10231
|
+
for (const tr of baseFacts || []) {
|
|
10232
|
+
if (!tr) continue;
|
|
10233
|
+
const key = proofTripleKey(tr);
|
|
10234
|
+
if (!baseFactByKey.has(key)) baseFactByKey.set(key, tr);
|
|
10235
|
+
}
|
|
10236
|
+
|
|
10237
|
+
const resolveBackwardProof = findBackwardProofForGoal
|
|
10238
|
+
? (tr) => findBackwardProofForGoal(tr, baseFacts || [], backRules || [], { maxDepth: 64 })
|
|
10239
|
+
: null;
|
|
10240
|
+
|
|
10241
|
+
const outputTriples = collectProofOutputTriples(selectedDerived);
|
|
10242
|
+
const proofRelationTriples = [];
|
|
10243
|
+
for (const df of selectedDerived) {
|
|
10244
|
+
proofRelationTriples.push({ s: new GraphTerm([df.fact]), p: new Iri(PE_NS + 'why'), o: new GraphTerm([]) });
|
|
10245
|
+
for (const entry of collectProofEntries(df, derivedByKey, baseFactByKey, resolveBackwardProof)) {
|
|
10246
|
+
const fact = entry.kind === 'rule' ? entry.df.fact : entry.fact;
|
|
10247
|
+
const byObject = entry.kind === 'builtin' && entry.builtin ? entry.builtin : new Iri(PE_NS + 'source');
|
|
10248
|
+
proofRelationTriples.push({ s: new GraphTerm([fact]), p: new Iri(PE_NS + 'by'), o: byObject });
|
|
10249
|
+
if (entry.kind === 'rule') {
|
|
10250
|
+
for (const prem of entry.df.premises || []) proofRelationTriples.push({ s: new GraphTerm([fact]), p: new Iri(PE_NS + 'uses'), o: new GraphTerm([prem]) });
|
|
10251
|
+
}
|
|
10252
|
+
}
|
|
10253
|
+
}
|
|
10254
|
+
|
|
10255
|
+
const usedPrefixes = proofPrefixes.prefixesUsedForOutput(outputTriples.concat(proofRelationTriples));
|
|
10256
|
+
if (!usedPrefixes.some(([pfx]) => pfx === 'pe')) usedPrefixes.push(['pe', PE_NS]);
|
|
10257
|
+
usedPrefixes.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
|
|
10258
|
+
|
|
10259
|
+
const parts = [];
|
|
10260
|
+
for (const [pfx, base] of usedPrefixes) {
|
|
10261
|
+
if (!base) continue;
|
|
10262
|
+
if (pfx === '') parts.push(`@prefix : <${base}> .`);
|
|
10263
|
+
else parts.push(`@prefix ${pfx}: <${base}> .`);
|
|
10264
|
+
}
|
|
10265
|
+
if (parts.length) parts.push('');
|
|
10266
|
+
|
|
10267
|
+
parts.push(...outputTriples.map((tr) => tripleToN3(tr, proofPrefixes)));
|
|
10268
|
+
parts.push('');
|
|
10269
|
+
for (let i = 0; i < selectedDerived.length; i++) {
|
|
10270
|
+
if (i > 0) parts.push('');
|
|
10271
|
+
parts.push(renderProofBlock(selectedDerived[i], derivedByKey, baseFactByKey, proofPrefixes, resolveBackwardProof));
|
|
10272
|
+
}
|
|
10273
|
+
|
|
10274
|
+
return parts.join('\n').replace(/[ \t]+$/gm, '').replace(/\s*$/g, '') + '\n';
|
|
10275
|
+
}
|
|
10276
|
+
|
|
9770
10277
|
// ===========================================================================
|
|
9771
10278
|
// CLI entry point
|
|
9772
10279
|
// ===========================================================================
|
|
@@ -9873,7 +10380,7 @@ function makeExplain(deps) {
|
|
|
9873
10380
|
return addMarkdownHardBreaks(pairs.map((p) => p.text).join(''));
|
|
9874
10381
|
}
|
|
9875
10382
|
|
|
9876
|
-
return { printExplanation, collectOutputStringsFromFacts };
|
|
10383
|
+
return { printExplanation, renderProofDocument, collectOutputStringsFromFacts };
|
|
9877
10384
|
}
|
|
9878
10385
|
|
|
9879
10386
|
module.exports = { makeExplain };
|
|
@@ -11665,6 +12172,67 @@ function emptyParsedDocument() {
|
|
|
11665
12172
|
};
|
|
11666
12173
|
}
|
|
11667
12174
|
|
|
12175
|
+
function lineStartsForText(text) {
|
|
12176
|
+
const s = String(text);
|
|
12177
|
+
const starts = [0];
|
|
12178
|
+
for (let i = 0; i < s.length; i++) {
|
|
12179
|
+
const c = s.charCodeAt(i);
|
|
12180
|
+
if (c === 10) starts.push(i + 1); // LF
|
|
12181
|
+
else if (c === 13) { // CR or CRLF
|
|
12182
|
+
if (i + 1 < s.length && s.charCodeAt(i + 1) === 10) i++;
|
|
12183
|
+
starts.push(i + 1);
|
|
12184
|
+
}
|
|
12185
|
+
}
|
|
12186
|
+
return starts;
|
|
12187
|
+
}
|
|
12188
|
+
|
|
12189
|
+
function offsetToLineFromStarts(offset, lineStarts) {
|
|
12190
|
+
if (typeof offset !== 'number') return null;
|
|
12191
|
+
let lo = 0;
|
|
12192
|
+
let hi = lineStarts.length;
|
|
12193
|
+
while (lo + 1 < hi) {
|
|
12194
|
+
const mid = (lo + hi) >> 1;
|
|
12195
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
12196
|
+
else hi = mid;
|
|
12197
|
+
}
|
|
12198
|
+
return lo + 1;
|
|
12199
|
+
}
|
|
12200
|
+
|
|
12201
|
+
function annotateSourceLocation(obj, label, lineStarts) {
|
|
12202
|
+
if (!obj || typeof obj.__sourceOffset !== 'number') return obj;
|
|
12203
|
+
const line = offsetToLineFromStarts(obj.__sourceOffset, lineStarts);
|
|
12204
|
+
Object.defineProperty(obj, '__source', {
|
|
12205
|
+
value: { label, line },
|
|
12206
|
+
enumerable: false,
|
|
12207
|
+
writable: false,
|
|
12208
|
+
configurable: true,
|
|
12209
|
+
});
|
|
12210
|
+
return obj;
|
|
12211
|
+
}
|
|
12212
|
+
|
|
12213
|
+
function annotateParsedSourceLocations(doc, text, label) {
|
|
12214
|
+
const lineStarts = lineStartsForText(text);
|
|
12215
|
+
for (const tr of doc.triples || []) annotateSourceLocation(tr, label, lineStarts);
|
|
12216
|
+
for (const r of doc.frules || []) annotateSourceLocation(r, label, lineStarts);
|
|
12217
|
+
for (const r of doc.brules || []) annotateSourceLocation(r, label, lineStarts);
|
|
12218
|
+
for (const r of doc.logQueryRules || []) annotateSourceLocation(r, label, lineStarts);
|
|
12219
|
+
}
|
|
12220
|
+
|
|
12221
|
+
function copySourceMetadata(from, to) {
|
|
12222
|
+
if (!from || !to) return to;
|
|
12223
|
+
for (const key of ['__sourceOffset', '__source']) {
|
|
12224
|
+
if (Object.prototype.hasOwnProperty.call(from, key)) {
|
|
12225
|
+
Object.defineProperty(to, key, {
|
|
12226
|
+
value: from[key],
|
|
12227
|
+
enumerable: false,
|
|
12228
|
+
writable: false,
|
|
12229
|
+
configurable: true,
|
|
12230
|
+
});
|
|
12231
|
+
}
|
|
12232
|
+
}
|
|
12233
|
+
return to;
|
|
12234
|
+
}
|
|
12235
|
+
|
|
11668
12236
|
function prefixesUsedInTokens(tokens, prefEnv) {
|
|
11669
12237
|
const used = new Set();
|
|
11670
12238
|
const toks = Array.isArray(tokens) ? tokens : [];
|
|
@@ -11742,6 +12310,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
11742
12310
|
label = '<input>',
|
|
11743
12311
|
keepSourceArtifacts = true,
|
|
11744
12312
|
collectUsedPrefixes = false,
|
|
12313
|
+
collectSourceLocations = true,
|
|
11745
12314
|
rdf = false,
|
|
11746
12315
|
} = opts || {};
|
|
11747
12316
|
const tokens = lex(text, { rdf });
|
|
@@ -11750,6 +12319,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
11750
12319
|
const [prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
|
|
11751
12320
|
|
|
11752
12321
|
const doc = { prefixes, triples, frules, brules, logQueryRules, label };
|
|
12322
|
+
if (collectSourceLocations) annotateParsedSourceLocations(doc, text, label);
|
|
11753
12323
|
|
|
11754
12324
|
if (collectUsedPrefixes) {
|
|
11755
12325
|
Object.defineProperty(doc, 'usedPrefixes', {
|
|
@@ -11795,7 +12365,7 @@ function scopeBlankNodesInDocument(doc, sourceIndex) {
|
|
|
11795
12365
|
}
|
|
11796
12366
|
|
|
11797
12367
|
function cloneTriple(triple) {
|
|
11798
|
-
return new Triple(cloneTerm(triple.s), cloneTerm(triple.p), cloneTerm(triple.o));
|
|
12368
|
+
return copySourceMetadata(triple, new Triple(cloneTerm(triple.s), cloneTerm(triple.p), cloneTerm(triple.o)));
|
|
11799
12369
|
}
|
|
11800
12370
|
|
|
11801
12371
|
function cloneRule(rule) {
|
|
@@ -11804,12 +12374,15 @@ function scopeBlankNodesInDocument(doc, sourceIndex) {
|
|
|
11804
12374
|
for (const label of rule.headBlankLabels) headBlankLabels.add(scopedBlankLabel(label, sourceIndex, mapping));
|
|
11805
12375
|
}
|
|
11806
12376
|
|
|
11807
|
-
const out =
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
12377
|
+
const out = copySourceMetadata(
|
|
12378
|
+
rule,
|
|
12379
|
+
new Rule(
|
|
12380
|
+
(rule.premise || []).map(cloneTriple),
|
|
12381
|
+
(rule.conclusion || []).map(cloneTriple),
|
|
12382
|
+
rule.isForward,
|
|
12383
|
+
rule.isFuse,
|
|
12384
|
+
headBlankLabels,
|
|
12385
|
+
),
|
|
11813
12386
|
);
|
|
11814
12387
|
|
|
11815
12388
|
if (rule && Object.prototype.hasOwnProperty.call(rule, '__dynamicConclusionTerm')) {
|
|
@@ -11937,6 +12510,7 @@ function parseN3SourceList(input, opts = {}) {
|
|
|
11937
12510
|
label: source.label,
|
|
11938
12511
|
baseIri: source.baseIri || (sources.length === 1 ? defaultBaseIri : ''),
|
|
11939
12512
|
collectUsedPrefixes: true,
|
|
12513
|
+
collectSourceLocations: !!opts.collectSourceLocations,
|
|
11940
12514
|
keepSourceArtifacts: !!opts.keepSourceArtifacts,
|
|
11941
12515
|
rdf: !!opts.rdf,
|
|
11942
12516
|
}),
|
|
@@ -12003,6 +12577,17 @@ function failInvalidKeywordLikeIdent(fail, tok, name) {
|
|
|
12003
12577
|
fail(`invalid_keyword(${name})`, tok);
|
|
12004
12578
|
}
|
|
12005
12579
|
|
|
12580
|
+
function annotateSourceOffset(obj, offset) {
|
|
12581
|
+
if (!obj || typeof offset !== 'number') return obj;
|
|
12582
|
+
Object.defineProperty(obj, '__sourceOffset', {
|
|
12583
|
+
value: offset,
|
|
12584
|
+
enumerable: false,
|
|
12585
|
+
writable: false,
|
|
12586
|
+
configurable: true,
|
|
12587
|
+
});
|
|
12588
|
+
return obj;
|
|
12589
|
+
}
|
|
12590
|
+
|
|
12006
12591
|
class Parser {
|
|
12007
12592
|
constructor(tokens) {
|
|
12008
12593
|
this.toks = tokens;
|
|
@@ -12127,17 +12712,19 @@ class Parser {
|
|
|
12127
12712
|
continue;
|
|
12128
12713
|
}
|
|
12129
12714
|
|
|
12715
|
+
const statementToken = this.peek();
|
|
12716
|
+
const statementOffset = statementToken && typeof statementToken.offset === 'number' ? statementToken.offset : null;
|
|
12130
12717
|
const first = this.parseTerm();
|
|
12131
12718
|
if (this.peek().typ === 'OpImplies') {
|
|
12132
12719
|
this.next();
|
|
12133
12720
|
const second = this.parseTerm();
|
|
12134
12721
|
this.expectDot();
|
|
12135
|
-
forwardRules.push(this.makeRule(first, second, true));
|
|
12722
|
+
forwardRules.push(annotateSourceOffset(this.makeRule(first, second, true), statementOffset));
|
|
12136
12723
|
} else if (this.peek().typ === 'OpImpliedBy') {
|
|
12137
12724
|
this.next();
|
|
12138
12725
|
const second = this.parseTerm();
|
|
12139
12726
|
this.expectDot();
|
|
12140
|
-
backwardRules.push(this.makeRule(first, second, false));
|
|
12727
|
+
backwardRules.push(annotateSourceOffset(this.makeRule(first, second, false), statementOffset));
|
|
12141
12728
|
} else {
|
|
12142
12729
|
let more;
|
|
12143
12730
|
|
|
@@ -12155,16 +12742,17 @@ class Parser {
|
|
|
12155
12742
|
}
|
|
12156
12743
|
|
|
12157
12744
|
// normalize explicit log:implies / log:impliedBy at top-level
|
|
12158
|
-
for (const
|
|
12745
|
+
for (const tr0 of more) {
|
|
12746
|
+
const tr = annotateSourceOffset(tr0, statementOffset);
|
|
12159
12747
|
if (isLogImplies(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
12160
|
-
forwardRules.push(this.makeRule(tr.s, tr.o, true));
|
|
12748
|
+
forwardRules.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
12161
12749
|
} else if (isLogImpliedBy(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
12162
|
-
backwardRules.push(this.makeRule(tr.s, tr.o, false));
|
|
12750
|
+
backwardRules.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, false), statementOffset));
|
|
12163
12751
|
} else if (isLogQuery(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
12164
12752
|
// Output-selection directive: { premise } log:query { conclusion }.
|
|
12165
12753
|
// When present at top-level, eyeling prints only the instantiated conclusion
|
|
12166
12754
|
// triples (unique) instead of all newly derived facts.
|
|
12167
|
-
logQueries.push(this.makeRule(tr.s, tr.o, true));
|
|
12755
|
+
logQueries.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
12168
12756
|
} else {
|
|
12169
12757
|
triples.push(tr);
|
|
12170
12758
|
}
|
|
@@ -15105,6 +15693,7 @@ module.exports = {
|
|
|
15105
15693
|
if (typeof __entry.materializeRdfLists === "function") __outerSelf.materializeRdfLists = __entry.materializeRdfLists;
|
|
15106
15694
|
if (typeof __entry.isGroundTriple === "function") __outerSelf.isGroundTriple = __entry.isGroundTriple;
|
|
15107
15695
|
if (typeof __entry.printExplanation === "function") __outerSelf.printExplanation = __entry.printExplanation;
|
|
15696
|
+
if (typeof __entry.renderProofDocument === "function") __outerSelf.renderProofDocument = __entry.renderProofDocument;
|
|
15108
15697
|
if (typeof __entry.tripleToN3 === "function") __outerSelf.tripleToN3 = __entry.tripleToN3;
|
|
15109
15698
|
if (typeof __entry.collectOutputStringsFromFacts === "function") __outerSelf.collectOutputStringsFromFacts = __entry.collectOutputStringsFromFacts;
|
|
15110
15699
|
if (typeof __entry.prettyPrintQueryTriples === "function") __outerSelf.prettyPrintQueryTriples = __entry.prettyPrintQueryTriples;
|