eyeling 1.26.0 → 1.26.2
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 +247 -314
- package/examples/proof/age.n3 +14 -5
- package/examples/proof/socrates.n3 +7 -2
- package/examples/proof/witch.n3 +27 -9
- package/eyeling.js +247 -314
- package/lib/cli.js +2 -2
- package/lib/engine.js +130 -216
- package/lib/explain.js +98 -79
- package/lib/multisource.js +17 -17
- package/package.json +1 -1
|
@@ -4826,8 +4826,8 @@ function main() {
|
|
|
4826
4826
|
baseIri: __sourceLabelToBaseIri(sourceLabel),
|
|
4827
4827
|
label: sourceLabel,
|
|
4828
4828
|
collectUsedPrefixes: streamMode,
|
|
4829
|
-
collectSourceLocations: engine.getProofCommentsEnabled(),
|
|
4830
4829
|
keepSourceArtifacts: false,
|
|
4830
|
+
sourceLocations: engine.getProofCommentsEnabled(),
|
|
4831
4831
|
rdf: rdfMode,
|
|
4832
4832
|
}),
|
|
4833
4833
|
);
|
|
@@ -4983,7 +4983,7 @@ function main() {
|
|
|
4983
4983
|
}
|
|
4984
4984
|
|
|
4985
4985
|
if (engine.getProofCommentsEnabled()) {
|
|
4986
|
-
process.stdout.write(engine.renderProofDocument(outDerived, derived, triples, prefixes, brules));
|
|
4986
|
+
process.stdout.write(engine.renderProofDocument(outDerived, derived.concat(outDerived || []), triples, prefixes, brules));
|
|
4987
4987
|
return;
|
|
4988
4988
|
}
|
|
4989
4989
|
|
|
@@ -5520,6 +5520,7 @@ const {
|
|
|
5520
5520
|
Triple,
|
|
5521
5521
|
Rule,
|
|
5522
5522
|
DerivedFact,
|
|
5523
|
+
varsInRule,
|
|
5523
5524
|
internIri,
|
|
5524
5525
|
collectBlankLabelsInTriples,
|
|
5525
5526
|
copyQuotedGraphMetadata,
|
|
@@ -5537,7 +5538,7 @@ const EMPTY_LIST_TERM = new ListTerm([]);
|
|
|
5537
5538
|
const { lex, N3SyntaxError } = require('./lexer');
|
|
5538
5539
|
const { Parser } = require('./parser');
|
|
5539
5540
|
const { liftBlankRuleVars } = require('./rules');
|
|
5540
|
-
const { parseN3SourceList } = require('./multisource');
|
|
5541
|
+
const { parseN3SourceList, parseN3Text } = require('./multisource');
|
|
5541
5542
|
|
|
5542
5543
|
const {
|
|
5543
5544
|
makeBuiltins,
|
|
@@ -7930,217 +7931,6 @@ function unifyTriple(pat, fact, subst) {
|
|
|
7930
7931
|
return s3;
|
|
7931
7932
|
}
|
|
7932
7933
|
|
|
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
|
-
|
|
8144
7934
|
// Strategy: when the substitution is "large" or search depth is high,
|
|
8145
7935
|
// keep only bindings that are still relevant to:
|
|
8146
7936
|
// - variables appearing in the remaining goals
|
|
@@ -8862,6 +8652,120 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
8862
8652
|
return results;
|
|
8863
8653
|
}
|
|
8864
8654
|
|
|
8655
|
+
|
|
8656
|
+
// Reconstruct one backward proof for N3 proof output. This is intentionally
|
|
8657
|
+
// called only by renderProofDocument(), so normal reasoning does not pay for it.
|
|
8658
|
+
function __proofTripleKey(tr) {
|
|
8659
|
+
if (!tr) return '';
|
|
8660
|
+
return `${skolemKeyFromTerm(tr.s)}\t${skolemKeyFromTerm(tr.p)}\t${skolemKeyFromTerm(tr.o)}`;
|
|
8661
|
+
}
|
|
8662
|
+
|
|
8663
|
+
function __copyProofSource(from, to) {
|
|
8664
|
+
if (from && to && Object.prototype.hasOwnProperty.call(from, '__source')) {
|
|
8665
|
+
Object.defineProperty(to, '__source', {
|
|
8666
|
+
value: from.__source,
|
|
8667
|
+
enumerable: false,
|
|
8668
|
+
writable: false,
|
|
8669
|
+
configurable: true,
|
|
8670
|
+
});
|
|
8671
|
+
}
|
|
8672
|
+
return to;
|
|
8673
|
+
}
|
|
8674
|
+
|
|
8675
|
+
function __annotateProofVarSourceNames(rule) {
|
|
8676
|
+
if (!rule) return rule;
|
|
8677
|
+
const sourceNames = Object.create(null);
|
|
8678
|
+
for (const name of varsInRule(rule)) {
|
|
8679
|
+
const m = /^(.*)__\d+$/.exec(name);
|
|
8680
|
+
sourceNames[name] = m ? m[1] : name;
|
|
8681
|
+
}
|
|
8682
|
+
Object.defineProperty(rule, '__proofVarSourceNames', {
|
|
8683
|
+
value: sourceNames,
|
|
8684
|
+
enumerable: false,
|
|
8685
|
+
writable: false,
|
|
8686
|
+
configurable: true,
|
|
8687
|
+
});
|
|
8688
|
+
return rule;
|
|
8689
|
+
}
|
|
8690
|
+
|
|
8691
|
+
function findBackwardProofForGoal(goal, facts, backRules, opts = {}) {
|
|
8692
|
+
const maxDepth = Number.isInteger(opts.maxDepth) && opts.maxDepth >= 0 ? opts.maxDepth : 64;
|
|
8693
|
+
const varGen = Array.isArray(opts.varGen) ? opts.varGen : [1];
|
|
8694
|
+
const visited = opts.visited instanceof Set ? opts.visited : new Set();
|
|
8695
|
+
const factList = Array.isArray(facts) ? facts : [];
|
|
8696
|
+
const ruleList = Array.isArray(backRules) ? backRules : [];
|
|
8697
|
+
|
|
8698
|
+
function matchingBaseFact(g) {
|
|
8699
|
+
const candidates = g && g.p instanceof Iri ? candidateFacts(factList, g) : null;
|
|
8700
|
+
const total = candidates ? candidates.totalLen : factList.length;
|
|
8701
|
+
for (let i = 0; i < total; i++) {
|
|
8702
|
+
let f;
|
|
8703
|
+
if (candidates) {
|
|
8704
|
+
if (i < candidates.exactLen) f = factList[candidates.exact[i]];
|
|
8705
|
+
else f = factList[candidates.wild[i - candidates.exactLen]];
|
|
8706
|
+
} else {
|
|
8707
|
+
f = factList[i];
|
|
8708
|
+
}
|
|
8709
|
+
if (unifyTriple(g, f, __emptySubst()) !== null) return f;
|
|
8710
|
+
}
|
|
8711
|
+
return null;
|
|
8712
|
+
}
|
|
8713
|
+
|
|
8714
|
+
function builtinProof(g) {
|
|
8715
|
+
if (!(g && isBuiltinPred(g.p))) return null;
|
|
8716
|
+
return { kind: 'builtin', fact: g, builtin: g.p };
|
|
8717
|
+
}
|
|
8718
|
+
|
|
8719
|
+
function solve(g, depth) {
|
|
8720
|
+
if (!g || depth > maxDepth) return null;
|
|
8721
|
+
|
|
8722
|
+
const base = matchingBaseFact(g);
|
|
8723
|
+
if (base) return { kind: 'fact', fact: base, source: base.__source };
|
|
8724
|
+
|
|
8725
|
+
const builtin = builtinProof(g);
|
|
8726
|
+
if (builtin) return builtin;
|
|
8727
|
+
|
|
8728
|
+
if (!(g.p instanceof Iri)) return null;
|
|
8729
|
+
const gKey = __proofTripleKey(g);
|
|
8730
|
+
if (visited.has(gKey)) return null;
|
|
8731
|
+
visited.add(gKey);
|
|
8732
|
+
|
|
8733
|
+
try {
|
|
8734
|
+
ensureBackRuleIndexes(ruleList);
|
|
8735
|
+
const candRules = (ruleList.__byHeadPred.get(g.p.__tid) || []).concat(ruleList.__wildHeadPred);
|
|
8736
|
+
for (const r of candRules) {
|
|
8737
|
+
if (!r || !Array.isArray(r.conclusion) || r.conclusion.length !== 1) continue;
|
|
8738
|
+
const rawHead = r.conclusion[0];
|
|
8739
|
+
if (rawHead.p instanceof Iri && rawHead.p.__tid !== g.p.__tid) continue;
|
|
8740
|
+
|
|
8741
|
+
const rStd = __annotateProofVarSourceNames(__copyProofSource(r, standardizeRule(r, varGen)));
|
|
8742
|
+
const head = rStd.conclusion[0];
|
|
8743
|
+
const s0 = unifyTriple(head, g, __emptySubst());
|
|
8744
|
+
if (s0 === null) continue;
|
|
8745
|
+
|
|
8746
|
+
const solutions = proveGoals(rStd.premise, s0, factList, ruleList, depth + 1, [], varGen, 1, {
|
|
8747
|
+
keepVars: varsInRule(rStd),
|
|
8748
|
+
deferBuiltins: true,
|
|
8749
|
+
});
|
|
8750
|
+
if (!solutions.length) continue;
|
|
8751
|
+
|
|
8752
|
+
const subst = solutions[0];
|
|
8753
|
+
const fact = applySubstTriple(head, subst);
|
|
8754
|
+
const premises = rStd.premise.map((prem) => applySubstTriple(prem, subst));
|
|
8755
|
+
const df = new DerivedFact(fact, rStd, premises, __cloneSubst(subst));
|
|
8756
|
+
const children = premises.map((prem) => builtinProof(prem) || solve(prem, depth + 1));
|
|
8757
|
+
return { kind: 'rule', df, children };
|
|
8758
|
+
}
|
|
8759
|
+
} finally {
|
|
8760
|
+
visited.delete(gKey);
|
|
8761
|
+
}
|
|
8762
|
+
|
|
8763
|
+
return null;
|
|
8764
|
+
}
|
|
8765
|
+
|
|
8766
|
+
return solve(goal, 0);
|
|
8767
|
+
}
|
|
8768
|
+
|
|
8865
8769
|
// ===========================================================================
|
|
8866
8770
|
// Forward chaining to fixpoint
|
|
8867
8771
|
// ===========================================================================
|
|
@@ -9543,12 +9447,22 @@ function reasonStream(input, opts = {}) {
|
|
|
9543
9447
|
skipUnsupportedRdfJs = false,
|
|
9544
9448
|
builtinModules = null,
|
|
9545
9449
|
rdf = false,
|
|
9450
|
+
sourceLabel = '<input>',
|
|
9546
9451
|
} = opts;
|
|
9547
9452
|
|
|
9548
9453
|
const useRdfCompatibility = !!rdf;
|
|
9549
9454
|
|
|
9550
|
-
const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility });
|
|
9551
|
-
const
|
|
9455
|
+
const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility, sourceLocations: proof });
|
|
9456
|
+
const parsedTextInput = (!parsedSourceList && proof && typeof input === 'string')
|
|
9457
|
+
? parseN3Text(input, {
|
|
9458
|
+
baseIri: baseIri || '',
|
|
9459
|
+
label: sourceLabel || '<input>',
|
|
9460
|
+
keepSourceArtifacts: false,
|
|
9461
|
+
sourceLocations: true,
|
|
9462
|
+
rdf: useRdfCompatibility,
|
|
9463
|
+
})
|
|
9464
|
+
: null;
|
|
9465
|
+
const parsedInput = parsedSourceList || parsedTextInput || normalizeParsedReasonerInputSync(input);
|
|
9552
9466
|
const rdfFactory = rdfjs ? getDataFactory(dataFactory) : null;
|
|
9553
9467
|
|
|
9554
9468
|
const __oldEnforceHttps = deref.getEnforceHttpsEnabled();
|
|
@@ -9658,7 +9572,7 @@ function reasonStream(input, opts = {}) {
|
|
|
9658
9572
|
const closureN3 = proof
|
|
9659
9573
|
? renderProofDocument(
|
|
9660
9574
|
Array.isArray(logQueryRules) && logQueryRules.length ? queryDerived : derived,
|
|
9661
|
-
derived,
|
|
9575
|
+
derived.concat(queryDerived || []),
|
|
9662
9576
|
triples,
|
|
9663
9577
|
prefixes,
|
|
9664
9578
|
brules,
|
|
@@ -9711,7 +9625,7 @@ function reasonRdfJs(input, opts = {}) {
|
|
|
9711
9625
|
|
|
9712
9626
|
Promise.resolve().then(async () => {
|
|
9713
9627
|
try {
|
|
9714
|
-
const normalizedInput = parseN3SourceList(input, restOpts) || (await normalizeReasonerInputAsync(input));
|
|
9628
|
+
const normalizedInput = parseN3SourceList(input, { ...restOpts, sourceLocations: !!(restOpts.proof || restOpts.proofComments) }) || (await normalizeReasonerInputAsync(input));
|
|
9715
9629
|
reasonStream(normalizedInput, {
|
|
9716
9630
|
...restOpts,
|
|
9717
9631
|
rdfjs: false,
|
|
@@ -10020,7 +9934,6 @@ ${lineIndent(body, ' ')}
|
|
|
10020
9934
|
}`;
|
|
10021
9935
|
}
|
|
10022
9936
|
|
|
10023
|
-
|
|
10024
9937
|
function clonePrefixEnvWithProofVocabulary(prefixes) {
|
|
10025
9938
|
const map = { ...(prefixes && prefixes.map ? prefixes.map : {}) };
|
|
10026
9939
|
if (!map.pe) map.pe = PE_NS;
|
|
@@ -10038,6 +9951,11 @@ ${lineIndent(body, ' ')}
|
|
|
10038
9951
|
return source.label.replace(/\\/g, '/').split('/').pop() || source.label;
|
|
10039
9952
|
}
|
|
10040
9953
|
|
|
9954
|
+
function sourceKeyForProof(source) {
|
|
9955
|
+
if (!source) return '<unknown>';
|
|
9956
|
+
return `${sourceLabelForProof(source)}:${Number.isInteger(source.line) ? source.line : ''}`;
|
|
9957
|
+
}
|
|
9958
|
+
|
|
10041
9959
|
function byBlankNode(kind, source) {
|
|
10042
9960
|
const src = source || {};
|
|
10043
9961
|
const props = [`pe:${kind} ${n3String(sourceLabelForProof(src))}`];
|
|
@@ -10045,121 +9963,129 @@ ${lineIndent(body, ' ')}
|
|
|
10045
9963
|
return `[ ${props.join('; ')} ]`;
|
|
10046
9964
|
}
|
|
10047
9965
|
|
|
10048
|
-
function
|
|
10049
|
-
if (!df || !df.rule || !df.subst) return
|
|
9966
|
+
function renderBindingItems(df, prefixes) {
|
|
9967
|
+
if (!df || !df.rule || !df.subst) return [];
|
|
10050
9968
|
const ruleVars = varsInRule(df.rule);
|
|
10051
9969
|
const visibleNames = Object.keys(df.subst)
|
|
10052
9970
|
.filter((name) => ruleVars.has(name))
|
|
10053
9971
|
.sort();
|
|
10054
|
-
if (!visibleNames.length) return
|
|
9972
|
+
if (!visibleNames.length) return [];
|
|
10055
9973
|
const sourceNames = (df.rule && df.rule.__proofVarSourceNames) || null;
|
|
10056
|
-
return visibleNames
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
})
|
|
10062
|
-
.join(', ');
|
|
9974
|
+
return visibleNames.map((name) => {
|
|
9975
|
+
const value = applySubstTerm(new Var(name), df.subst);
|
|
9976
|
+
const displayName = sourceNames && sourceNames[name] ? sourceNames[name] : name;
|
|
9977
|
+
return `[ pe:var ${n3String(displayName)}; pe:value ${termToN3(value, prefixes)} ]`;
|
|
9978
|
+
});
|
|
10063
9979
|
}
|
|
10064
9980
|
|
|
10065
|
-
function
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
return `${label}\t${line}`;
|
|
9981
|
+
function withLastLineSuffix(text, suffix) {
|
|
9982
|
+
const lines = String(text).split(/\r?\n/);
|
|
9983
|
+
lines[lines.length - 1] += suffix;
|
|
9984
|
+
return lines.join('\n');
|
|
10070
9985
|
}
|
|
10071
9986
|
|
|
10072
|
-
function
|
|
10073
|
-
|
|
9987
|
+
function renderPredicateObjects(predicate, objects, isLast) {
|
|
9988
|
+
const values = (objects || []).filter((value) => value);
|
|
9989
|
+
if (!values.length) return [];
|
|
9990
|
+
const end = isLast ? '.' : ';';
|
|
9991
|
+
if (values.length === 1 && !values[0].includes('\n')) {
|
|
9992
|
+
return [` ${predicate} ${values[0]}${end}`];
|
|
9993
|
+
}
|
|
9994
|
+
const out = [` ${predicate}`];
|
|
9995
|
+
for (let i = 0; i < values.length; i++) {
|
|
9996
|
+
const suffix = i === values.length - 1 ? end : ',';
|
|
9997
|
+
out.push(lineIndent(withLastLineSuffix(values[i], suffix), ' '));
|
|
9998
|
+
}
|
|
9999
|
+
return out;
|
|
10074
10000
|
}
|
|
10075
10001
|
|
|
10076
|
-
function
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10002
|
+
function proofEntryKey(entry) {
|
|
10003
|
+
if (!entry) return '';
|
|
10004
|
+
if (entry.kind === 'rule') {
|
|
10005
|
+
const df = entry.df;
|
|
10006
|
+
const source = df && df.rule && df.rule.__source;
|
|
10007
|
+
const premiseKey = (df && df.premises ? df.premises : []).map(proofTripleKey).join('|');
|
|
10008
|
+
return `rule:${proofTripleKey(df && df.fact)}:${sourceKeyForProof(source)}:${premiseKey}`;
|
|
10009
|
+
}
|
|
10010
|
+
if (entry.kind === 'builtin') return `builtin:${proofTripleKey(entry.fact)}`;
|
|
10011
|
+
return `fact:${proofTripleKey(entry.fact)}:${sourceKeyForProof(entry.source)}`;
|
|
10080
10012
|
}
|
|
10081
10013
|
|
|
10082
10014
|
function collectProofEntries(rootDf, derivedByKey, baseFactByKey, resolveBackwardProof) {
|
|
10083
10015
|
const entries = [];
|
|
10084
10016
|
const seen = new Set();
|
|
10085
10017
|
|
|
10086
|
-
function
|
|
10087
|
-
|
|
10088
|
-
if (
|
|
10089
|
-
|
|
10090
|
-
|
|
10018
|
+
function remember(entry) {
|
|
10019
|
+
const key = proofEntryKey(entry);
|
|
10020
|
+
if (!key || seen.has(key)) return false;
|
|
10021
|
+
seen.add(key);
|
|
10022
|
+
entries.push(entry);
|
|
10023
|
+
return true;
|
|
10024
|
+
}
|
|
10025
|
+
|
|
10026
|
+
function derivedCandidatesForKey(key) {
|
|
10027
|
+
const found = derivedByKey.get(key);
|
|
10028
|
+
if (!found) return [];
|
|
10029
|
+
return Array.isArray(found) ? found : [found];
|
|
10091
10030
|
}
|
|
10092
10031
|
|
|
10093
|
-
function visitProofNode(proof, fallbackTriple) {
|
|
10032
|
+
function visitProofNode(proof, fallbackTriple, parentDf) {
|
|
10094
10033
|
if (!proof) {
|
|
10095
|
-
visitFactTriple(fallbackTriple);
|
|
10034
|
+
visitFactTriple(fallbackTriple, parentDf);
|
|
10096
10035
|
return;
|
|
10097
10036
|
}
|
|
10098
|
-
const key = entryKeyForProof(proof, fallbackTriple);
|
|
10099
|
-
if (!key || seen.has(key)) return;
|
|
10100
10037
|
if (proof.kind === 'rule' && proof.df) {
|
|
10101
10038
|
visitDerivedFact(proof.df, proof.children || null);
|
|
10102
10039
|
return;
|
|
10103
10040
|
}
|
|
10104
|
-
seen.add(key);
|
|
10105
10041
|
if (proof.kind === 'builtin') {
|
|
10106
|
-
|
|
10107
|
-
|
|
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 });
|
|
10042
|
+
remember({ kind: 'builtin', fact: proof.fact || fallbackTriple, builtin: proof.builtin || (proof.fact && proof.fact.p) });
|
|
10043
|
+
return;
|
|
10113
10044
|
}
|
|
10045
|
+
remember({ kind: 'fact', fact: proof.fact || fallbackTriple, source: proof.source });
|
|
10114
10046
|
}
|
|
10115
10047
|
|
|
10116
|
-
function visitFactTriple(tr) {
|
|
10117
|
-
const
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
visitDerivedFact(df);
|
|
10048
|
+
function visitFactTriple(tr, parentDf) {
|
|
10049
|
+
const key = proofTripleKey(tr);
|
|
10050
|
+
const base = baseFactByKey.get(key) || null;
|
|
10051
|
+
if (base) {
|
|
10052
|
+
remember({ kind: 'fact', fact: base, source: base.__source });
|
|
10122
10053
|
return;
|
|
10123
10054
|
}
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
entries.push({ kind: 'fact', fact: base, source: base.__source });
|
|
10055
|
+
|
|
10056
|
+
const candidates = derivedCandidatesForKey(key);
|
|
10057
|
+
const df = candidates.find((candidate) => candidate !== parentDf) || null;
|
|
10058
|
+
if (df) {
|
|
10059
|
+
visitDerivedFact(df);
|
|
10130
10060
|
return;
|
|
10131
10061
|
}
|
|
10062
|
+
|
|
10132
10063
|
if (tr && isBuiltinPred(tr.p)) {
|
|
10133
|
-
|
|
10134
|
-
if (seen.has(key)) return;
|
|
10135
|
-
seen.add(key);
|
|
10136
|
-
entries.push({ kind: 'builtin', fact: tr, builtin: tr.p });
|
|
10064
|
+
remember({ kind: 'builtin', fact: tr, builtin: tr.p });
|
|
10137
10065
|
return;
|
|
10138
10066
|
}
|
|
10067
|
+
|
|
10139
10068
|
if (resolveBackwardProof) {
|
|
10140
10069
|
const proof = resolveBackwardProof(tr);
|
|
10141
10070
|
if (proof) {
|
|
10142
|
-
visitProofNode(proof, tr);
|
|
10071
|
+
visitProofNode(proof, tr, parentDf);
|
|
10143
10072
|
return;
|
|
10144
10073
|
}
|
|
10145
10074
|
}
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
seen.add(key);
|
|
10149
|
-
entries.push({ kind: 'fact', fact: tr, source: null });
|
|
10075
|
+
|
|
10076
|
+
remember({ kind: 'fact', fact: tr, source: null });
|
|
10150
10077
|
}
|
|
10151
10078
|
|
|
10152
10079
|
function visitDerivedFact(df, children) {
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
entries.push({ kind: 'rule', df });
|
|
10080
|
+
if (!df || !df.fact) return;
|
|
10081
|
+
const entry = { kind: 'rule', df };
|
|
10082
|
+
if (!remember(entry)) return;
|
|
10157
10083
|
|
|
10158
10084
|
if (Array.isArray(children) && children.length) {
|
|
10159
|
-
for (const child of children) visitProofNode(child);
|
|
10085
|
+
for (const child of children) visitProofNode(child, null, df);
|
|
10160
10086
|
return;
|
|
10161
10087
|
}
|
|
10162
|
-
for (const prem of df.premises || []) visitFactTriple(prem);
|
|
10088
|
+
for (const prem of df.premises || []) visitFactTriple(prem, df);
|
|
10163
10089
|
}
|
|
10164
10090
|
|
|
10165
10091
|
visitDerivedFact(rootDf);
|
|
@@ -10189,16 +10115,18 @@ ${lineIndent(body, ' ')}
|
|
|
10189
10115
|
}
|
|
10190
10116
|
|
|
10191
10117
|
const df = entry.df;
|
|
10192
|
-
const
|
|
10193
|
-
const
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10118
|
+
const bindingItems = renderBindingItems(df, prefixes);
|
|
10119
|
+
const useItems = (df.premises || []).map((prem) => graphForTriple(prem, prefixes));
|
|
10120
|
+
const propertyGroups = [
|
|
10121
|
+
{ predicate: 'pe:by', objects: [byBlankNode('rule', df.rule && df.rule.__source)] },
|
|
10122
|
+
{ predicate: 'pe:binding', objects: bindingItems },
|
|
10123
|
+
{ predicate: 'pe:uses', objects: useItems },
|
|
10124
|
+
].filter((group) => group.objects.length);
|
|
10198
10125
|
|
|
10199
10126
|
let out = ` ${graphForTriple(df.fact, prefixes)}\n`;
|
|
10200
|
-
for (let i = 0; i <
|
|
10201
|
-
|
|
10127
|
+
for (let i = 0; i < propertyGroups.length; i++) {
|
|
10128
|
+
const group = propertyGroups[i];
|
|
10129
|
+
out += renderPredicateObjects(group.predicate, group.objects, i === propertyGroups.length - 1).join('\n') + '\n';
|
|
10202
10130
|
}
|
|
10203
10131
|
return out.trimEnd();
|
|
10204
10132
|
}
|
|
@@ -10219,13 +10147,18 @@ ${proofBody}
|
|
|
10219
10147
|
|
|
10220
10148
|
const proofPrefixes = clonePrefixEnvWithProofVocabulary(prefixes);
|
|
10221
10149
|
const derivedByKey = new Map();
|
|
10222
|
-
|
|
10223
|
-
if (!df || !df.fact)
|
|
10150
|
+
function addDerived(df) {
|
|
10151
|
+
if (!df || !df.fact) return;
|
|
10224
10152
|
const key = proofTripleKey(df.fact);
|
|
10225
|
-
|
|
10153
|
+
let bucket = derivedByKey.get(key);
|
|
10154
|
+
if (!bucket) {
|
|
10155
|
+
bucket = [];
|
|
10156
|
+
derivedByKey.set(key, bucket);
|
|
10157
|
+
}
|
|
10158
|
+
if (!bucket.includes(df)) bucket.push(df);
|
|
10226
10159
|
}
|
|
10227
|
-
|
|
10228
|
-
|
|
10160
|
+
for (const df of allDerived || []) addDerived(df);
|
|
10161
|
+
for (const df of selectedDerived) addDerived(df);
|
|
10229
10162
|
|
|
10230
10163
|
const baseFactByKey = new Map();
|
|
10231
10164
|
for (const tr of baseFacts || []) {
|
|
@@ -12173,20 +12106,20 @@ function emptyParsedDocument() {
|
|
|
12173
12106
|
}
|
|
12174
12107
|
|
|
12175
12108
|
function lineStartsForText(text) {
|
|
12176
|
-
const s = String(text);
|
|
12177
12109
|
const starts = [0];
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
starts.push(i + 1);
|
|
12110
|
+
const str = String(text);
|
|
12111
|
+
for (let i = 0; i < str.length; i++) {
|
|
12112
|
+
const c = str[i];
|
|
12113
|
+
if (c === '\n') starts.push(i + 1);
|
|
12114
|
+
else if (c === '\r') {
|
|
12115
|
+
starts.push(i + 1 < str.length && str[i + 1] === '\n' ? i + 2 : i + 1);
|
|
12116
|
+
if (i + 1 < str.length && str[i + 1] === '\n') i++;
|
|
12184
12117
|
}
|
|
12185
12118
|
}
|
|
12186
12119
|
return starts;
|
|
12187
12120
|
}
|
|
12188
12121
|
|
|
12189
|
-
function
|
|
12122
|
+
function offsetToLine(lineStarts, offset) {
|
|
12190
12123
|
if (typeof offset !== 'number') return null;
|
|
12191
12124
|
let lo = 0;
|
|
12192
12125
|
let hi = lineStarts.length;
|
|
@@ -12198,9 +12131,9 @@ function offsetToLineFromStarts(offset, lineStarts) {
|
|
|
12198
12131
|
return lo + 1;
|
|
12199
12132
|
}
|
|
12200
12133
|
|
|
12201
|
-
function annotateSourceLocation(obj,
|
|
12134
|
+
function annotateSourceLocation(obj, lineStarts, label) {
|
|
12202
12135
|
if (!obj || typeof obj.__sourceOffset !== 'number') return obj;
|
|
12203
|
-
const line =
|
|
12136
|
+
const line = offsetToLine(lineStarts, obj.__sourceOffset);
|
|
12204
12137
|
Object.defineProperty(obj, '__source', {
|
|
12205
12138
|
value: { label, line },
|
|
12206
12139
|
enumerable: false,
|
|
@@ -12212,10 +12145,10 @@ function annotateSourceLocation(obj, label, lineStarts) {
|
|
|
12212
12145
|
|
|
12213
12146
|
function annotateParsedSourceLocations(doc, text, label) {
|
|
12214
12147
|
const lineStarts = lineStartsForText(text);
|
|
12215
|
-
for (const tr of doc.triples || []) annotateSourceLocation(tr,
|
|
12216
|
-
for (const r of doc.frules || []) annotateSourceLocation(r,
|
|
12217
|
-
for (const r of doc.brules || []) annotateSourceLocation(r,
|
|
12218
|
-
for (const r of doc.logQueryRules || []) annotateSourceLocation(r,
|
|
12148
|
+
for (const tr of doc.triples || []) annotateSourceLocation(tr, lineStarts, label);
|
|
12149
|
+
for (const r of doc.frules || []) annotateSourceLocation(r, lineStarts, label);
|
|
12150
|
+
for (const r of doc.brules || []) annotateSourceLocation(r, lineStarts, label);
|
|
12151
|
+
for (const r of doc.logQueryRules || []) annotateSourceLocation(r, lineStarts, label);
|
|
12219
12152
|
}
|
|
12220
12153
|
|
|
12221
12154
|
function copySourceMetadata(from, to) {
|
|
@@ -12310,7 +12243,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
12310
12243
|
label = '<input>',
|
|
12311
12244
|
keepSourceArtifacts = true,
|
|
12312
12245
|
collectUsedPrefixes = false,
|
|
12313
|
-
|
|
12246
|
+
sourceLocations = false,
|
|
12314
12247
|
rdf = false,
|
|
12315
12248
|
} = opts || {};
|
|
12316
12249
|
const tokens = lex(text, { rdf });
|
|
@@ -12319,7 +12252,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
12319
12252
|
const [prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
|
|
12320
12253
|
|
|
12321
12254
|
const doc = { prefixes, triples, frules, brules, logQueryRules, label };
|
|
12322
|
-
if (
|
|
12255
|
+
if (sourceLocations) annotateParsedSourceLocations(doc, text, label);
|
|
12323
12256
|
|
|
12324
12257
|
if (collectUsedPrefixes) {
|
|
12325
12258
|
Object.defineProperty(doc, 'usedPrefixes', {
|
|
@@ -12510,8 +12443,8 @@ function parseN3SourceList(input, opts = {}) {
|
|
|
12510
12443
|
label: source.label,
|
|
12511
12444
|
baseIri: source.baseIri || (sources.length === 1 ? defaultBaseIri : ''),
|
|
12512
12445
|
collectUsedPrefixes: true,
|
|
12513
|
-
collectSourceLocations: !!opts.collectSourceLocations,
|
|
12514
12446
|
keepSourceArtifacts: !!opts.keepSourceArtifacts,
|
|
12447
|
+
sourceLocations: !!opts.sourceLocations,
|
|
12515
12448
|
rdf: !!opts.rdf,
|
|
12516
12449
|
}),
|
|
12517
12450
|
);
|