eyeling 1.25.5 → 1.26.1
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 +555 -32
- package/examples/output/socrates.n3 +0 -1
- package/examples/proof/age.n3 +40 -0
- package/examples/proof/socrates.n3 +24 -0
- package/examples/proof/witch.n3 +138 -0
- package/examples/socrates.n3 +0 -3
- package/eyeling.js +555 -32
- package/index.d.ts +1 -0
- package/index.js +16 -13
- package/lib/cli.js +10 -4
- package/lib/engine.js +150 -13
- package/lib/entry.js +1 -0
- package/lib/explain.js +299 -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
|
|
|
@@ -4827,6 +4827,7 @@ function main() {
|
|
|
4827
4827
|
label: sourceLabel,
|
|
4828
4828
|
collectUsedPrefixes: streamMode,
|
|
4829
4829
|
keepSourceArtifacts: false,
|
|
4830
|
+
sourceLocations: engine.getProofCommentsEnabled(),
|
|
4830
4831
|
rdf: rdfMode,
|
|
4831
4832
|
}),
|
|
4832
4833
|
);
|
|
@@ -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.concat(outDerived || []), 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');
|
|
@@ -5514,6 +5520,7 @@ const {
|
|
|
5514
5520
|
Triple,
|
|
5515
5521
|
Rule,
|
|
5516
5522
|
DerivedFact,
|
|
5523
|
+
varsInRule,
|
|
5517
5524
|
internIri,
|
|
5518
5525
|
collectBlankLabelsInTriples,
|
|
5519
5526
|
copyQuotedGraphMetadata,
|
|
@@ -5531,7 +5538,7 @@ const EMPTY_LIST_TERM = new ListTerm([]);
|
|
|
5531
5538
|
const { lex, N3SyntaxError } = require('./lexer');
|
|
5532
5539
|
const { Parser } = require('./parser');
|
|
5533
5540
|
const { liftBlankRuleVars } = require('./rules');
|
|
5534
|
-
const { parseN3SourceList } = require('./multisource');
|
|
5541
|
+
const { parseN3Text, parseN3SourceList } = require('./multisource');
|
|
5535
5542
|
|
|
5536
5543
|
const {
|
|
5537
5544
|
makeBuiltins,
|
|
@@ -6269,9 +6276,11 @@ const { evalBuiltin, isBuiltinPred } = makeBuiltins({
|
|
|
6269
6276
|
});
|
|
6270
6277
|
|
|
6271
6278
|
// Initialize proof/output helpers (implemented in lib/explain.js).
|
|
6272
|
-
const { printExplanation, collectOutputStringsFromFacts } = makeExplain({
|
|
6279
|
+
const { printExplanation, renderProofDocument, collectOutputStringsFromFacts } = makeExplain({
|
|
6273
6280
|
applySubstTerm,
|
|
6274
6281
|
skolemKeyFromTerm,
|
|
6282
|
+
isBuiltinPred,
|
|
6283
|
+
findBackwardProofForGoal,
|
|
6275
6284
|
});
|
|
6276
6285
|
|
|
6277
6286
|
function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
|
|
@@ -8643,6 +8652,120 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
|
|
|
8643
8652
|
return results;
|
|
8644
8653
|
}
|
|
8645
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
|
+
|
|
8646
8769
|
// ===========================================================================
|
|
8647
8770
|
// Forward chaining to fixpoint
|
|
8648
8771
|
// ===========================================================================
|
|
@@ -9328,7 +9451,7 @@ function reasonStream(input, opts = {}) {
|
|
|
9328
9451
|
|
|
9329
9452
|
const useRdfCompatibility = !!rdf;
|
|
9330
9453
|
|
|
9331
|
-
const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility });
|
|
9454
|
+
const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: useRdfCompatibility, sourceLocations: proof });
|
|
9332
9455
|
const parsedInput = parsedSourceList || normalizeParsedReasonerInputSync(input);
|
|
9333
9456
|
const rdfFactory = rdfjs ? getDataFactory(dataFactory) : null;
|
|
9334
9457
|
|
|
@@ -9364,11 +9487,22 @@ function reasonStream(input, opts = {}) {
|
|
|
9364
9487
|
if (baseIri) prefixes.setBase(baseIri);
|
|
9365
9488
|
} else {
|
|
9366
9489
|
const n3Text = normalizeReasonerInputSync(input);
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9490
|
+
if (proof) {
|
|
9491
|
+
const parsed = parseN3Text(n3Text, {
|
|
9492
|
+
label: 'input.n3',
|
|
9493
|
+
baseIri: baseIri || '',
|
|
9494
|
+
keepSourceArtifacts: false,
|
|
9495
|
+
sourceLocations: true,
|
|
9496
|
+
rdf: useRdfCompatibility,
|
|
9497
|
+
});
|
|
9498
|
+
({ prefixes, triples, frules, brules, logQueryRules } = parsed);
|
|
9499
|
+
} else {
|
|
9500
|
+
const toks = lex(n3Text, { rdf: useRdfCompatibility });
|
|
9501
|
+
const parser = new Parser(toks);
|
|
9502
|
+
if (baseIri) parser.prefixes.setBase(baseIri);
|
|
9370
9503
|
|
|
9371
|
-
|
|
9504
|
+
[prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
|
|
9505
|
+
}
|
|
9372
9506
|
}
|
|
9373
9507
|
// Make the parsed prefixes available to log:trace output
|
|
9374
9508
|
trace.setTracePrefixes(prefixes);
|
|
@@ -9436,11 +9570,19 @@ function reasonStream(input, opts = {}) {
|
|
|
9436
9570
|
? facts
|
|
9437
9571
|
: derived.map((d) => d.fact);
|
|
9438
9572
|
|
|
9439
|
-
const closureN3 =
|
|
9440
|
-
?
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9573
|
+
const closureN3 = proof
|
|
9574
|
+
? renderProofDocument(
|
|
9575
|
+
Array.isArray(logQueryRules) && logQueryRules.length ? queryDerived : derived,
|
|
9576
|
+
derived.concat(queryDerived || []),
|
|
9577
|
+
triples,
|
|
9578
|
+
prefixes,
|
|
9579
|
+
brules,
|
|
9580
|
+
).replace(/\n$/g, '')
|
|
9581
|
+
: useRdfCompatibility
|
|
9582
|
+
? closureTriples.map((t) => tripleToRdfCompatible(t, prefixes)).join('\n')
|
|
9583
|
+
: Array.isArray(logQueryRules) && logQueryRules.length
|
|
9584
|
+
? prettyPrintQueryTriples(closureTriples, prefixes)
|
|
9585
|
+
: closureTriples.map((t) => tripleToN3(t, prefixes)).join('\n');
|
|
9444
9586
|
|
|
9445
9587
|
const __out = {
|
|
9446
9588
|
prefixes,
|
|
@@ -9484,7 +9626,7 @@ function reasonRdfJs(input, opts = {}) {
|
|
|
9484
9626
|
|
|
9485
9627
|
Promise.resolve().then(async () => {
|
|
9486
9628
|
try {
|
|
9487
|
-
const normalizedInput = parseN3SourceList(input, restOpts) || (await normalizeReasonerInputAsync(input));
|
|
9629
|
+
const normalizedInput = parseN3SourceList(input, { ...restOpts, sourceLocations: !!(restOpts.proof || restOpts.proofComments) }) || (await normalizeReasonerInputAsync(input));
|
|
9488
9630
|
reasonStream(normalizedInput, {
|
|
9489
9631
|
...restOpts,
|
|
9490
9632
|
rdfjs: false,
|
|
@@ -9567,6 +9709,7 @@ module.exports = {
|
|
|
9567
9709
|
collectLogQueryConclusions,
|
|
9568
9710
|
forwardChainAndCollectLogQueryConclusions,
|
|
9569
9711
|
collectOutputStringsFromFacts,
|
|
9712
|
+
renderProofDocument,
|
|
9570
9713
|
main,
|
|
9571
9714
|
version,
|
|
9572
9715
|
N3SyntaxError,
|
|
@@ -9636,6 +9779,7 @@ module.exports = {
|
|
|
9636
9779
|
materializeRdfLists: engine.materializeRdfLists,
|
|
9637
9780
|
isGroundTriple: engine.isGroundTriple,
|
|
9638
9781
|
printExplanation: engine.printExplanation,
|
|
9782
|
+
renderProofDocument: engine.renderProofDocument,
|
|
9639
9783
|
tripleToN3: engine.tripleToN3,
|
|
9640
9784
|
collectOutputStringsFromFacts: engine.collectOutputStringsFromFacts,
|
|
9641
9785
|
prettyPrintQueryTriples: engine.prettyPrintQueryTriples,
|
|
@@ -9662,7 +9806,7 @@ module.exports = {
|
|
|
9662
9806
|
*/
|
|
9663
9807
|
'use strict';
|
|
9664
9808
|
|
|
9665
|
-
const { LOG_NS, Literal, Iri, Blank, Var, varsInRule, literalParts } = require('./prelude');
|
|
9809
|
+
const { LOG_NS, Literal, Iri, Blank, Var, GraphTerm, varsInRule, literalParts, PrefixEnv } = require('./prelude');
|
|
9666
9810
|
|
|
9667
9811
|
const { termToN3, tripleToN3 } = require('./printing');
|
|
9668
9812
|
const { parseNumericLiteralInfo, termToJsString } = require('./builtins');
|
|
@@ -9670,6 +9814,8 @@ const { parseNumericLiteralInfo, termToJsString } = require('./builtins');
|
|
|
9670
9814
|
function makeExplain(deps) {
|
|
9671
9815
|
const applySubstTerm = deps.applySubstTerm;
|
|
9672
9816
|
const skolemKeyFromTerm = deps.skolemKeyFromTerm;
|
|
9817
|
+
const isBuiltinPred = typeof deps.isBuiltinPred === 'function' ? deps.isBuiltinPred : () => false;
|
|
9818
|
+
const findBackwardProofForGoal = typeof deps.findBackwardProofForGoal === 'function' ? deps.findBackwardProofForGoal : null;
|
|
9673
9819
|
|
|
9674
9820
|
function printExplanation(df, prefixes) {
|
|
9675
9821
|
console.log('# ----------------------------------------------------------------------');
|
|
@@ -9767,6 +9913,301 @@ function makeExplain(deps) {
|
|
|
9767
9913
|
console.log('# ----------------------------------------------------------------------\n');
|
|
9768
9914
|
}
|
|
9769
9915
|
|
|
9916
|
+
|
|
9917
|
+
const PE_NS = 'https://eyereasoner.github.io/pe#';
|
|
9918
|
+
|
|
9919
|
+
function n3String(value) {
|
|
9920
|
+
return JSON.stringify(String(value));
|
|
9921
|
+
}
|
|
9922
|
+
|
|
9923
|
+
function lineIndent(text, prefix) {
|
|
9924
|
+
return String(text)
|
|
9925
|
+
.split(/\r?\n/)
|
|
9926
|
+
.map((line) => (line.length ? prefix + line : line))
|
|
9927
|
+
.join('\n');
|
|
9928
|
+
}
|
|
9929
|
+
|
|
9930
|
+
function graphForTriple(tr, prefixes) {
|
|
9931
|
+
const body = tripleToN3(tr, prefixes).trimEnd();
|
|
9932
|
+
if (!body.includes('\n')) return `{ ${body} }`;
|
|
9933
|
+
return `{
|
|
9934
|
+
${lineIndent(body, ' ')}
|
|
9935
|
+
}`;
|
|
9936
|
+
}
|
|
9937
|
+
|
|
9938
|
+
function clonePrefixEnvWithProofVocabulary(prefixes) {
|
|
9939
|
+
const map = { ...(prefixes && prefixes.map ? prefixes.map : {}) };
|
|
9940
|
+
if (!map.pe) map.pe = PE_NS;
|
|
9941
|
+
return new PrefixEnv(map, (prefixes && prefixes.baseIri) || '');
|
|
9942
|
+
}
|
|
9943
|
+
|
|
9944
|
+
function proofTripleKey(tr) {
|
|
9945
|
+
if (!tr) return '';
|
|
9946
|
+
return `${skolemKeyFromTerm(tr.s)}\t${skolemKeyFromTerm(tr.p)}\t${skolemKeyFromTerm(tr.o)}`;
|
|
9947
|
+
}
|
|
9948
|
+
|
|
9949
|
+
function sourceLabelForProof(source) {
|
|
9950
|
+
if (!source || typeof source.label !== 'string' || !source.label) return '<unknown>';
|
|
9951
|
+
// Keep proof output stable when the CLI is invoked with paths such as examples/foo.n3.
|
|
9952
|
+
return source.label.replace(/\\/g, '/').split('/').pop() || source.label;
|
|
9953
|
+
}
|
|
9954
|
+
|
|
9955
|
+
function sourceKeyForProof(source) {
|
|
9956
|
+
if (!source) return '<unknown>';
|
|
9957
|
+
return `${sourceLabelForProof(source)}:${Number.isInteger(source.line) ? source.line : ''}`;
|
|
9958
|
+
}
|
|
9959
|
+
|
|
9960
|
+
function byBlankNode(kind, source) {
|
|
9961
|
+
const src = source || {};
|
|
9962
|
+
const props = [`pe:${kind} ${n3String(sourceLabelForProof(src))}`];
|
|
9963
|
+
if (Number.isInteger(src.line) && src.line > 0) props.push(`pe:line ${src.line}`);
|
|
9964
|
+
return `[ ${props.join('; ')} ]`;
|
|
9965
|
+
}
|
|
9966
|
+
|
|
9967
|
+
function renderBindingItems(df, prefixes) {
|
|
9968
|
+
if (!df || !df.rule || !df.subst) return [];
|
|
9969
|
+
const ruleVars = varsInRule(df.rule);
|
|
9970
|
+
const visibleNames = Object.keys(df.subst)
|
|
9971
|
+
.filter((name) => ruleVars.has(name))
|
|
9972
|
+
.sort();
|
|
9973
|
+
if (!visibleNames.length) return [];
|
|
9974
|
+
const sourceNames = (df.rule && df.rule.__proofVarSourceNames) || null;
|
|
9975
|
+
return visibleNames.map((name) => {
|
|
9976
|
+
const value = applySubstTerm(new Var(name), df.subst);
|
|
9977
|
+
const displayName = sourceNames && sourceNames[name] ? sourceNames[name] : name;
|
|
9978
|
+
return `[ pe:var ${n3String(displayName)}; pe:value ${termToN3(value, prefixes)} ]`;
|
|
9979
|
+
});
|
|
9980
|
+
}
|
|
9981
|
+
|
|
9982
|
+
function withLastLineSuffix(text, suffix) {
|
|
9983
|
+
const lines = String(text).split(/\r?\n/);
|
|
9984
|
+
lines[lines.length - 1] += suffix;
|
|
9985
|
+
return lines.join('\n');
|
|
9986
|
+
}
|
|
9987
|
+
|
|
9988
|
+
function renderPredicateObjects(predicate, objects, isLast) {
|
|
9989
|
+
const values = (objects || []).filter((value) => value);
|
|
9990
|
+
if (!values.length) return [];
|
|
9991
|
+
const end = isLast ? '.' : ';';
|
|
9992
|
+
if (values.length === 1 && !values[0].includes('\n')) {
|
|
9993
|
+
return [` ${predicate} ${values[0]}${end}`];
|
|
9994
|
+
}
|
|
9995
|
+
const out = [` ${predicate}`];
|
|
9996
|
+
for (let i = 0; i < values.length; i++) {
|
|
9997
|
+
const suffix = i === values.length - 1 ? end : ',';
|
|
9998
|
+
out.push(lineIndent(withLastLineSuffix(values[i], suffix), ' '));
|
|
9999
|
+
}
|
|
10000
|
+
return out;
|
|
10001
|
+
}
|
|
10002
|
+
|
|
10003
|
+
function proofEntryKey(entry) {
|
|
10004
|
+
if (!entry) return '';
|
|
10005
|
+
if (entry.kind === 'rule') {
|
|
10006
|
+
const df = entry.df;
|
|
10007
|
+
const source = df && df.rule && df.rule.__source;
|
|
10008
|
+
const premiseKey = (df && df.premises ? df.premises : []).map(proofTripleKey).join('|');
|
|
10009
|
+
return `rule:${proofTripleKey(df && df.fact)}:${sourceKeyForProof(source)}:${premiseKey}`;
|
|
10010
|
+
}
|
|
10011
|
+
if (entry.kind === 'builtin') return `builtin:${proofTripleKey(entry.fact)}`;
|
|
10012
|
+
return `fact:${proofTripleKey(entry.fact)}:${sourceKeyForProof(entry.source)}`;
|
|
10013
|
+
}
|
|
10014
|
+
|
|
10015
|
+
function collectProofEntries(rootDf, derivedByKey, baseFactByKey, resolveBackwardProof) {
|
|
10016
|
+
const entries = [];
|
|
10017
|
+
const seen = new Set();
|
|
10018
|
+
|
|
10019
|
+
function remember(entry) {
|
|
10020
|
+
const key = proofEntryKey(entry);
|
|
10021
|
+
if (!key || seen.has(key)) return false;
|
|
10022
|
+
seen.add(key);
|
|
10023
|
+
entries.push(entry);
|
|
10024
|
+
return true;
|
|
10025
|
+
}
|
|
10026
|
+
|
|
10027
|
+
function derivedCandidatesForKey(key) {
|
|
10028
|
+
const found = derivedByKey.get(key);
|
|
10029
|
+
if (!found) return [];
|
|
10030
|
+
return Array.isArray(found) ? found : [found];
|
|
10031
|
+
}
|
|
10032
|
+
|
|
10033
|
+
function visitProofNode(proof, fallbackTriple, parentDf) {
|
|
10034
|
+
if (!proof) {
|
|
10035
|
+
visitFactTriple(fallbackTriple, parentDf);
|
|
10036
|
+
return;
|
|
10037
|
+
}
|
|
10038
|
+
if (proof.kind === 'rule' && proof.df) {
|
|
10039
|
+
visitDerivedFact(proof.df, proof.children || null);
|
|
10040
|
+
return;
|
|
10041
|
+
}
|
|
10042
|
+
if (proof.kind === 'builtin') {
|
|
10043
|
+
remember({ kind: 'builtin', fact: proof.fact || fallbackTriple, builtin: proof.builtin || (proof.fact && proof.fact.p) });
|
|
10044
|
+
return;
|
|
10045
|
+
}
|
|
10046
|
+
remember({ kind: 'fact', fact: proof.fact || fallbackTriple, source: proof.source });
|
|
10047
|
+
}
|
|
10048
|
+
|
|
10049
|
+
function visitFactTriple(tr, parentDf) {
|
|
10050
|
+
const key = proofTripleKey(tr);
|
|
10051
|
+
const base = baseFactByKey.get(key) || null;
|
|
10052
|
+
if (base) {
|
|
10053
|
+
remember({ kind: 'fact', fact: base, source: base.__source });
|
|
10054
|
+
return;
|
|
10055
|
+
}
|
|
10056
|
+
|
|
10057
|
+
const candidates = derivedCandidatesForKey(key);
|
|
10058
|
+
const df = candidates.find((candidate) => candidate !== parentDf) || null;
|
|
10059
|
+
if (df) {
|
|
10060
|
+
visitDerivedFact(df);
|
|
10061
|
+
return;
|
|
10062
|
+
}
|
|
10063
|
+
|
|
10064
|
+
if (tr && isBuiltinPred(tr.p)) {
|
|
10065
|
+
remember({ kind: 'builtin', fact: tr, builtin: tr.p });
|
|
10066
|
+
return;
|
|
10067
|
+
}
|
|
10068
|
+
|
|
10069
|
+
if (resolveBackwardProof) {
|
|
10070
|
+
const proof = resolveBackwardProof(tr);
|
|
10071
|
+
if (proof) {
|
|
10072
|
+
visitProofNode(proof, tr, parentDf);
|
|
10073
|
+
return;
|
|
10074
|
+
}
|
|
10075
|
+
}
|
|
10076
|
+
|
|
10077
|
+
remember({ kind: 'fact', fact: tr, source: null });
|
|
10078
|
+
}
|
|
10079
|
+
|
|
10080
|
+
function visitDerivedFact(df, children) {
|
|
10081
|
+
if (!df || !df.fact) return;
|
|
10082
|
+
const entry = { kind: 'rule', df };
|
|
10083
|
+
if (!remember(entry)) return;
|
|
10084
|
+
|
|
10085
|
+
if (Array.isArray(children) && children.length) {
|
|
10086
|
+
for (const child of children) visitProofNode(child, null, df);
|
|
10087
|
+
return;
|
|
10088
|
+
}
|
|
10089
|
+
for (const prem of df.premises || []) visitFactTriple(prem, df);
|
|
10090
|
+
}
|
|
10091
|
+
|
|
10092
|
+
visitDerivedFact(rootDf);
|
|
10093
|
+
return entries;
|
|
10094
|
+
}
|
|
10095
|
+
|
|
10096
|
+
function collectProofOutputTriples(outputDerived) {
|
|
10097
|
+
const out = [];
|
|
10098
|
+
const seen = new Set();
|
|
10099
|
+
for (const df of outputDerived || []) {
|
|
10100
|
+
if (!df || !df.fact) continue;
|
|
10101
|
+
const key = proofTripleKey(df.fact);
|
|
10102
|
+
if (seen.has(key)) continue;
|
|
10103
|
+
seen.add(key);
|
|
10104
|
+
out.push(df.fact);
|
|
10105
|
+
}
|
|
10106
|
+
return out;
|
|
10107
|
+
}
|
|
10108
|
+
|
|
10109
|
+
function renderProofEntry(entry, prefixes) {
|
|
10110
|
+
if (!entry) return '';
|
|
10111
|
+
if (entry.kind === 'fact') {
|
|
10112
|
+
return ` ${graphForTriple(entry.fact, prefixes)}\n pe:by ${byBlankNode('fact', entry.source)}.`;
|
|
10113
|
+
}
|
|
10114
|
+
if (entry.kind === 'builtin') {
|
|
10115
|
+
return ` ${graphForTriple(entry.fact, prefixes)}\n pe:by [ pe:builtin ${termToN3(entry.builtin, prefixes)} ].`;
|
|
10116
|
+
}
|
|
10117
|
+
|
|
10118
|
+
const df = entry.df;
|
|
10119
|
+
const bindingItems = renderBindingItems(df, prefixes);
|
|
10120
|
+
const useItems = (df.premises || []).map((prem) => graphForTriple(prem, prefixes));
|
|
10121
|
+
const propertyGroups = [
|
|
10122
|
+
{ predicate: 'pe:by', objects: [byBlankNode('rule', df.rule && df.rule.__source)] },
|
|
10123
|
+
{ predicate: 'pe:binding', objects: bindingItems },
|
|
10124
|
+
{ predicate: 'pe:uses', objects: useItems },
|
|
10125
|
+
].filter((group) => group.objects.length);
|
|
10126
|
+
|
|
10127
|
+
let out = ` ${graphForTriple(df.fact, prefixes)}\n`;
|
|
10128
|
+
for (let i = 0; i < propertyGroups.length; i++) {
|
|
10129
|
+
const group = propertyGroups[i];
|
|
10130
|
+
out += renderPredicateObjects(group.predicate, group.objects, i === propertyGroups.length - 1).join('\n') + '\n';
|
|
10131
|
+
}
|
|
10132
|
+
return out.trimEnd();
|
|
10133
|
+
}
|
|
10134
|
+
|
|
10135
|
+
function renderProofBlock(rootDf, derivedByKey, baseFactByKey, prefixes, resolveBackwardProof) {
|
|
10136
|
+
const entries = collectProofEntries(rootDf, derivedByKey, baseFactByKey, resolveBackwardProof);
|
|
10137
|
+
const rootGraph = graphForTriple(rootDf.fact, prefixes);
|
|
10138
|
+
const proofBody = entries.map((entry) => renderProofEntry(entry, prefixes)).join('\n\n');
|
|
10139
|
+
const proofGraph = proofBody ? `{
|
|
10140
|
+
${proofBody}
|
|
10141
|
+
}` : '{}';
|
|
10142
|
+
return `${rootGraph} pe:why ${proofGraph}.`;
|
|
10143
|
+
}
|
|
10144
|
+
|
|
10145
|
+
function renderProofDocument(outputDerived, allDerived, baseFacts, prefixes, backRules) {
|
|
10146
|
+
const selectedDerived = Array.isArray(outputDerived) ? outputDerived.filter((df) => df && df.fact) : [];
|
|
10147
|
+
if (!selectedDerived.length) return '';
|
|
10148
|
+
|
|
10149
|
+
const proofPrefixes = clonePrefixEnvWithProofVocabulary(prefixes);
|
|
10150
|
+
const derivedByKey = new Map();
|
|
10151
|
+
function addDerived(df) {
|
|
10152
|
+
if (!df || !df.fact) return;
|
|
10153
|
+
const key = proofTripleKey(df.fact);
|
|
10154
|
+
let bucket = derivedByKey.get(key);
|
|
10155
|
+
if (!bucket) {
|
|
10156
|
+
bucket = [];
|
|
10157
|
+
derivedByKey.set(key, bucket);
|
|
10158
|
+
}
|
|
10159
|
+
if (!bucket.includes(df)) bucket.push(df);
|
|
10160
|
+
}
|
|
10161
|
+
for (const df of allDerived || []) addDerived(df);
|
|
10162
|
+
for (const df of selectedDerived) addDerived(df);
|
|
10163
|
+
|
|
10164
|
+
const baseFactByKey = new Map();
|
|
10165
|
+
for (const tr of baseFacts || []) {
|
|
10166
|
+
if (!tr) continue;
|
|
10167
|
+
const key = proofTripleKey(tr);
|
|
10168
|
+
if (!baseFactByKey.has(key)) baseFactByKey.set(key, tr);
|
|
10169
|
+
}
|
|
10170
|
+
|
|
10171
|
+
const resolveBackwardProof = findBackwardProofForGoal
|
|
10172
|
+
? (tr) => findBackwardProofForGoal(tr, baseFacts || [], backRules || [], { maxDepth: 64 })
|
|
10173
|
+
: null;
|
|
10174
|
+
|
|
10175
|
+
const outputTriples = collectProofOutputTriples(selectedDerived);
|
|
10176
|
+
const proofRelationTriples = [];
|
|
10177
|
+
for (const df of selectedDerived) {
|
|
10178
|
+
proofRelationTriples.push({ s: new GraphTerm([df.fact]), p: new Iri(PE_NS + 'why'), o: new GraphTerm([]) });
|
|
10179
|
+
for (const entry of collectProofEntries(df, derivedByKey, baseFactByKey, resolveBackwardProof)) {
|
|
10180
|
+
const fact = entry.kind === 'rule' ? entry.df.fact : entry.fact;
|
|
10181
|
+
const byObject = entry.kind === 'builtin' && entry.builtin ? entry.builtin : new Iri(PE_NS + 'source');
|
|
10182
|
+
proofRelationTriples.push({ s: new GraphTerm([fact]), p: new Iri(PE_NS + 'by'), o: byObject });
|
|
10183
|
+
if (entry.kind === 'rule') {
|
|
10184
|
+
for (const prem of entry.df.premises || []) proofRelationTriples.push({ s: new GraphTerm([fact]), p: new Iri(PE_NS + 'uses'), o: new GraphTerm([prem]) });
|
|
10185
|
+
}
|
|
10186
|
+
}
|
|
10187
|
+
}
|
|
10188
|
+
|
|
10189
|
+
const usedPrefixes = proofPrefixes.prefixesUsedForOutput(outputTriples.concat(proofRelationTriples));
|
|
10190
|
+
if (!usedPrefixes.some(([pfx]) => pfx === 'pe')) usedPrefixes.push(['pe', PE_NS]);
|
|
10191
|
+
usedPrefixes.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
|
|
10192
|
+
|
|
10193
|
+
const parts = [];
|
|
10194
|
+
for (const [pfx, base] of usedPrefixes) {
|
|
10195
|
+
if (!base) continue;
|
|
10196
|
+
if (pfx === '') parts.push(`@prefix : <${base}> .`);
|
|
10197
|
+
else parts.push(`@prefix ${pfx}: <${base}> .`);
|
|
10198
|
+
}
|
|
10199
|
+
if (parts.length) parts.push('');
|
|
10200
|
+
|
|
10201
|
+
parts.push(...outputTriples.map((tr) => tripleToN3(tr, proofPrefixes)));
|
|
10202
|
+
parts.push('');
|
|
10203
|
+
for (let i = 0; i < selectedDerived.length; i++) {
|
|
10204
|
+
if (i > 0) parts.push('');
|
|
10205
|
+
parts.push(renderProofBlock(selectedDerived[i], derivedByKey, baseFactByKey, proofPrefixes, resolveBackwardProof));
|
|
10206
|
+
}
|
|
10207
|
+
|
|
10208
|
+
return parts.join('\n').replace(/[ \t]+$/gm, '').replace(/\s*$/g, '') + '\n';
|
|
10209
|
+
}
|
|
10210
|
+
|
|
9770
10211
|
// ===========================================================================
|
|
9771
10212
|
// CLI entry point
|
|
9772
10213
|
// ===========================================================================
|
|
@@ -9873,7 +10314,7 @@ function makeExplain(deps) {
|
|
|
9873
10314
|
return addMarkdownHardBreaks(pairs.map((p) => p.text).join(''));
|
|
9874
10315
|
}
|
|
9875
10316
|
|
|
9876
|
-
return { printExplanation, collectOutputStringsFromFacts };
|
|
10317
|
+
return { printExplanation, renderProofDocument, collectOutputStringsFromFacts };
|
|
9877
10318
|
}
|
|
9878
10319
|
|
|
9879
10320
|
module.exports = { makeExplain };
|
|
@@ -11665,6 +12106,67 @@ function emptyParsedDocument() {
|
|
|
11665
12106
|
};
|
|
11666
12107
|
}
|
|
11667
12108
|
|
|
12109
|
+
function lineStartsForText(text) {
|
|
12110
|
+
const starts = [0];
|
|
12111
|
+
const str = String(text);
|
|
12112
|
+
for (let i = 0; i < str.length; i++) {
|
|
12113
|
+
const c = str[i];
|
|
12114
|
+
if (c === '\n') starts.push(i + 1);
|
|
12115
|
+
else if (c === '\r') {
|
|
12116
|
+
starts.push(i + 1 < str.length && str[i + 1] === '\n' ? i + 2 : i + 1);
|
|
12117
|
+
if (i + 1 < str.length && str[i + 1] === '\n') i++;
|
|
12118
|
+
}
|
|
12119
|
+
}
|
|
12120
|
+
return starts;
|
|
12121
|
+
}
|
|
12122
|
+
|
|
12123
|
+
function offsetToLine(lineStarts, offset) {
|
|
12124
|
+
if (typeof offset !== 'number') return null;
|
|
12125
|
+
let lo = 0;
|
|
12126
|
+
let hi = lineStarts.length;
|
|
12127
|
+
while (lo + 1 < hi) {
|
|
12128
|
+
const mid = (lo + hi) >> 1;
|
|
12129
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
12130
|
+
else hi = mid;
|
|
12131
|
+
}
|
|
12132
|
+
return lo + 1;
|
|
12133
|
+
}
|
|
12134
|
+
|
|
12135
|
+
function annotateSourceLocation(obj, lineStarts, label) {
|
|
12136
|
+
if (!obj || typeof obj.__sourceOffset !== 'number') return obj;
|
|
12137
|
+
const line = offsetToLine(lineStarts, obj.__sourceOffset);
|
|
12138
|
+
Object.defineProperty(obj, '__source', {
|
|
12139
|
+
value: { label, line },
|
|
12140
|
+
enumerable: false,
|
|
12141
|
+
writable: false,
|
|
12142
|
+
configurable: true,
|
|
12143
|
+
});
|
|
12144
|
+
return obj;
|
|
12145
|
+
}
|
|
12146
|
+
|
|
12147
|
+
function annotateParsedSourceLocations(doc, text, label) {
|
|
12148
|
+
const lineStarts = lineStartsForText(text);
|
|
12149
|
+
for (const tr of doc.triples || []) annotateSourceLocation(tr, lineStarts, label);
|
|
12150
|
+
for (const r of doc.frules || []) annotateSourceLocation(r, lineStarts, label);
|
|
12151
|
+
for (const r of doc.brules || []) annotateSourceLocation(r, lineStarts, label);
|
|
12152
|
+
for (const r of doc.logQueryRules || []) annotateSourceLocation(r, lineStarts, label);
|
|
12153
|
+
}
|
|
12154
|
+
|
|
12155
|
+
function copySourceMetadata(from, to) {
|
|
12156
|
+
if (!from || !to) return to;
|
|
12157
|
+
for (const key of ['__sourceOffset', '__source']) {
|
|
12158
|
+
if (Object.prototype.hasOwnProperty.call(from, key)) {
|
|
12159
|
+
Object.defineProperty(to, key, {
|
|
12160
|
+
value: from[key],
|
|
12161
|
+
enumerable: false,
|
|
12162
|
+
writable: false,
|
|
12163
|
+
configurable: true,
|
|
12164
|
+
});
|
|
12165
|
+
}
|
|
12166
|
+
}
|
|
12167
|
+
return to;
|
|
12168
|
+
}
|
|
12169
|
+
|
|
11668
12170
|
function prefixesUsedInTokens(tokens, prefEnv) {
|
|
11669
12171
|
const used = new Set();
|
|
11670
12172
|
const toks = Array.isArray(tokens) ? tokens : [];
|
|
@@ -11742,6 +12244,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
11742
12244
|
label = '<input>',
|
|
11743
12245
|
keepSourceArtifacts = true,
|
|
11744
12246
|
collectUsedPrefixes = false,
|
|
12247
|
+
sourceLocations = false,
|
|
11745
12248
|
rdf = false,
|
|
11746
12249
|
} = opts || {};
|
|
11747
12250
|
const tokens = lex(text, { rdf });
|
|
@@ -11750,6 +12253,7 @@ function parseN3Text(text, opts = {}) {
|
|
|
11750
12253
|
const [prefixes, triples, frules, brules, logQueryRules] = parser.parseDocument();
|
|
11751
12254
|
|
|
11752
12255
|
const doc = { prefixes, triples, frules, brules, logQueryRules, label };
|
|
12256
|
+
if (sourceLocations) annotateParsedSourceLocations(doc, text, label);
|
|
11753
12257
|
|
|
11754
12258
|
if (collectUsedPrefixes) {
|
|
11755
12259
|
Object.defineProperty(doc, 'usedPrefixes', {
|
|
@@ -11795,7 +12299,7 @@ function scopeBlankNodesInDocument(doc, sourceIndex) {
|
|
|
11795
12299
|
}
|
|
11796
12300
|
|
|
11797
12301
|
function cloneTriple(triple) {
|
|
11798
|
-
return new Triple(cloneTerm(triple.s), cloneTerm(triple.p), cloneTerm(triple.o));
|
|
12302
|
+
return copySourceMetadata(triple, new Triple(cloneTerm(triple.s), cloneTerm(triple.p), cloneTerm(triple.o)));
|
|
11799
12303
|
}
|
|
11800
12304
|
|
|
11801
12305
|
function cloneRule(rule) {
|
|
@@ -11804,12 +12308,15 @@ function scopeBlankNodesInDocument(doc, sourceIndex) {
|
|
|
11804
12308
|
for (const label of rule.headBlankLabels) headBlankLabels.add(scopedBlankLabel(label, sourceIndex, mapping));
|
|
11805
12309
|
}
|
|
11806
12310
|
|
|
11807
|
-
const out =
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
12311
|
+
const out = copySourceMetadata(
|
|
12312
|
+
rule,
|
|
12313
|
+
new Rule(
|
|
12314
|
+
(rule.premise || []).map(cloneTriple),
|
|
12315
|
+
(rule.conclusion || []).map(cloneTriple),
|
|
12316
|
+
rule.isForward,
|
|
12317
|
+
rule.isFuse,
|
|
12318
|
+
headBlankLabels,
|
|
12319
|
+
),
|
|
11813
12320
|
);
|
|
11814
12321
|
|
|
11815
12322
|
if (rule && Object.prototype.hasOwnProperty.call(rule, '__dynamicConclusionTerm')) {
|
|
@@ -11938,6 +12445,7 @@ function parseN3SourceList(input, opts = {}) {
|
|
|
11938
12445
|
baseIri: source.baseIri || (sources.length === 1 ? defaultBaseIri : ''),
|
|
11939
12446
|
collectUsedPrefixes: true,
|
|
11940
12447
|
keepSourceArtifacts: !!opts.keepSourceArtifacts,
|
|
12448
|
+
sourceLocations: !!opts.sourceLocations,
|
|
11941
12449
|
rdf: !!opts.rdf,
|
|
11942
12450
|
}),
|
|
11943
12451
|
);
|
|
@@ -12003,6 +12511,17 @@ function failInvalidKeywordLikeIdent(fail, tok, name) {
|
|
|
12003
12511
|
fail(`invalid_keyword(${name})`, tok);
|
|
12004
12512
|
}
|
|
12005
12513
|
|
|
12514
|
+
function annotateSourceOffset(obj, offset) {
|
|
12515
|
+
if (!obj || typeof offset !== 'number') return obj;
|
|
12516
|
+
Object.defineProperty(obj, '__sourceOffset', {
|
|
12517
|
+
value: offset,
|
|
12518
|
+
enumerable: false,
|
|
12519
|
+
writable: false,
|
|
12520
|
+
configurable: true,
|
|
12521
|
+
});
|
|
12522
|
+
return obj;
|
|
12523
|
+
}
|
|
12524
|
+
|
|
12006
12525
|
class Parser {
|
|
12007
12526
|
constructor(tokens) {
|
|
12008
12527
|
this.toks = tokens;
|
|
@@ -12127,17 +12646,19 @@ class Parser {
|
|
|
12127
12646
|
continue;
|
|
12128
12647
|
}
|
|
12129
12648
|
|
|
12649
|
+
const statementToken = this.peek();
|
|
12650
|
+
const statementOffset = statementToken && typeof statementToken.offset === 'number' ? statementToken.offset : null;
|
|
12130
12651
|
const first = this.parseTerm();
|
|
12131
12652
|
if (this.peek().typ === 'OpImplies') {
|
|
12132
12653
|
this.next();
|
|
12133
12654
|
const second = this.parseTerm();
|
|
12134
12655
|
this.expectDot();
|
|
12135
|
-
forwardRules.push(this.makeRule(first, second, true));
|
|
12656
|
+
forwardRules.push(annotateSourceOffset(this.makeRule(first, second, true), statementOffset));
|
|
12136
12657
|
} else if (this.peek().typ === 'OpImpliedBy') {
|
|
12137
12658
|
this.next();
|
|
12138
12659
|
const second = this.parseTerm();
|
|
12139
12660
|
this.expectDot();
|
|
12140
|
-
backwardRules.push(this.makeRule(first, second, false));
|
|
12661
|
+
backwardRules.push(annotateSourceOffset(this.makeRule(first, second, false), statementOffset));
|
|
12141
12662
|
} else {
|
|
12142
12663
|
let more;
|
|
12143
12664
|
|
|
@@ -12155,16 +12676,17 @@ class Parser {
|
|
|
12155
12676
|
}
|
|
12156
12677
|
|
|
12157
12678
|
// normalize explicit log:implies / log:impliedBy at top-level
|
|
12158
|
-
for (const
|
|
12679
|
+
for (const tr0 of more) {
|
|
12680
|
+
const tr = annotateSourceOffset(tr0, statementOffset);
|
|
12159
12681
|
if (isLogImplies(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
12160
|
-
forwardRules.push(this.makeRule(tr.s, tr.o, true));
|
|
12682
|
+
forwardRules.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
12161
12683
|
} else if (isLogImpliedBy(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
12162
|
-
backwardRules.push(this.makeRule(tr.s, tr.o, false));
|
|
12684
|
+
backwardRules.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, false), statementOffset));
|
|
12163
12685
|
} else if (isLogQuery(tr.p) && tr.s instanceof GraphTerm && tr.o instanceof GraphTerm) {
|
|
12164
12686
|
// Output-selection directive: { premise } log:query { conclusion }.
|
|
12165
12687
|
// When present at top-level, eyeling prints only the instantiated conclusion
|
|
12166
12688
|
// triples (unique) instead of all newly derived facts.
|
|
12167
|
-
logQueries.push(this.makeRule(tr.s, tr.o, true));
|
|
12689
|
+
logQueries.push(annotateSourceOffset(this.makeRule(tr.s, tr.o, true), statementOffset));
|
|
12168
12690
|
} else {
|
|
12169
12691
|
triples.push(tr);
|
|
12170
12692
|
}
|
|
@@ -15105,6 +15627,7 @@ module.exports = {
|
|
|
15105
15627
|
if (typeof __entry.materializeRdfLists === "function") __outerSelf.materializeRdfLists = __entry.materializeRdfLists;
|
|
15106
15628
|
if (typeof __entry.isGroundTriple === "function") __outerSelf.isGroundTriple = __entry.isGroundTriple;
|
|
15107
15629
|
if (typeof __entry.printExplanation === "function") __outerSelf.printExplanation = __entry.printExplanation;
|
|
15630
|
+
if (typeof __entry.renderProofDocument === "function") __outerSelf.renderProofDocument = __entry.renderProofDocument;
|
|
15108
15631
|
if (typeof __entry.tripleToN3 === "function") __outerSelf.tripleToN3 = __entry.tripleToN3;
|
|
15109
15632
|
if (typeof __entry.collectOutputStringsFromFacts === "function") __outerSelf.collectOutputStringsFromFacts = __entry.collectOutputStringsFromFacts;
|
|
15110
15633
|
if (typeof __entry.prettyPrintQueryTriples === "function") __outerSelf.prettyPrintQueryTriples = __entry.prettyPrintQueryTriples;
|