eyeling 1.24.1 → 1.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HANDBOOK.md +134 -0
- package/dist/browser/eyeling.browser.js +454 -22
- package/eyeling.js +454 -22
- package/index.js +2 -0
- package/lib/cli.js +27 -10
- package/lib/engine.js +17 -7
- package/lib/lexer.js +295 -2
- package/lib/multisource.js +9 -2
- package/lib/printing.js +106 -1
- package/package.json +1 -1
- package/see/README.md +4 -0
- package/see/examples/_see.js +33 -2
- package/see/examples/age.js +27 -1
- package/see/examples/annotation.js +27 -1
- package/see/examples/backward.js +27 -1
- package/see/examples/backward_recursion.js +27 -1
- package/see/examples/bayes_diagnosis.js +27 -1
- package/see/examples/bayes_therapy.js +27 -1
- package/see/examples/bmi.js +27 -1
- package/see/examples/builtin_coverage.js +27 -1
- package/see/examples/collection.js +27 -1
- package/see/examples/complex.js +27 -1
- package/see/examples/complex_matrix_stability.js +27 -1
- package/see/examples/composition_of_injective_functions_is_injective.js +27 -1
- package/see/examples/control_system.js +27 -1
- package/see/examples/crypto_builtins_tests.js +27 -1
- package/see/examples/delfour.js +27 -1
- package/see/examples/digital_product_passport.js +27 -1
- package/see/examples/dijkstra.js +27 -1
- package/see/examples/dijkstra_risk_path.js +27 -1
- package/see/examples/doc/rdf_dataset.md +26 -0
- package/see/examples/doc/triple_terms.md +26 -0
- package/see/examples/dog.js +27 -1
- package/see/examples/eco_route_insight.js +27 -1
- package/see/examples/equals.js +27 -1
- package/see/examples/equivalence_classes_overlap_implies_same_class.js +27 -1
- package/see/examples/euler_identity.js +27 -1
- package/see/examples/ev_roundtrip_planner.js +27 -1
- package/see/examples/existential_rule.js +27 -1
- package/see/examples/expression_eval.js +27 -1
- package/see/examples/family_cousins.js +27 -1
- package/see/examples/fastpow.js +27 -1
- package/see/examples/fibonacci.js +27 -1
- package/see/examples/french_cities.js +27 -1
- package/see/examples/fundamental_theorem_arithmetic.js +27 -1
- package/see/examples/genetic_knapsack_selection.js +27 -1
- package/see/examples/goldbach_1000.js +27 -1
- package/see/examples/good_cobbler.js +27 -1
- package/see/examples/gps.js +27 -1
- package/see/examples/gray_code_counter.js +27 -1
- package/see/examples/greatest_lower_bound_uniqueness.js +27 -1
- package/see/examples/group_inverse_uniqueness.js +27 -1
- package/see/examples/hadamard_approx.js +27 -1
- package/see/examples/hanoi.js +27 -1
- package/see/examples/input/rdf_dataset.trig +34 -0
- package/see/examples/input/triple_terms.trig +28 -0
- package/see/examples/n3/rdf_dataset.n3 +34 -0
- package/see/examples/n3/triple_terms.n3 +23 -0
- package/see/examples/odrl_dpv_risk_ranked.js +27 -1
- package/see/examples/output/rdf_dataset.md +54 -0
- package/see/examples/output/triple_terms.md +53 -0
- package/see/examples/path_discovery.js +27 -1
- package/see/examples/rc_discharge_envelope.js +27 -1
- package/see/examples/rdf_dataset.js +1512 -0
- package/see/examples/rdf_message_flow.js +27 -1
- package/see/examples/rdf_messages.js +27 -1
- package/see/examples/school_placement_audit.js +27 -1
- package/see/examples/smoke_arithmetic.js +27 -1
- package/see/examples/socrates.js +27 -1
- package/see/examples/triple_terms.js +1442 -0
- package/see/examples/wind_turbine.js +27 -1
- package/see/examples/witch.js +27 -1
- package/see/see.js +101 -4
- package/test/api.test.js +86 -0
- package/test/see.test.js +0 -0
- package/tools/bundle.js +0 -0
- package/tools/n3gen.js +0 -0
package/see/examples/_see.js
CHANGED
|
@@ -7,11 +7,31 @@ function lit(value) { return { kind: 'lit', value }; }
|
|
|
7
7
|
function blank(value) { return { kind: 'blank', value }; }
|
|
8
8
|
function list(items) { return { kind: 'list', items }; }
|
|
9
9
|
function formula(atoms) { return { kind: 'formula', atoms }; }
|
|
10
|
+
function triple(s, p, o) { return { kind: 'triple', s, p, o }; }
|
|
10
11
|
|
|
11
12
|
function readTermToken(text, start = 0) {
|
|
12
13
|
let i = start;
|
|
13
14
|
while (/\s/.test(text[i])) i += 1;
|
|
14
15
|
const begin = i;
|
|
16
|
+
if (text.startsWith('<<(', i)) {
|
|
17
|
+
let depth = 0;
|
|
18
|
+
while (i < text.length) {
|
|
19
|
+
if (text[i] === '"') {
|
|
20
|
+
const [, next] = readTermToken(text, i);
|
|
21
|
+
i = next;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (text.startsWith('<<(', i)) { depth += 1; i += 3; continue; }
|
|
25
|
+
if (text.startsWith(')>>', i)) {
|
|
26
|
+
depth -= 1;
|
|
27
|
+
i += 3;
|
|
28
|
+
if (depth === 0) break;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
i += 1;
|
|
32
|
+
}
|
|
33
|
+
return [text.slice(begin, i), i];
|
|
34
|
+
}
|
|
15
35
|
if (text[i] === '"') {
|
|
16
36
|
i += 1;
|
|
17
37
|
let escaped = false;
|
|
@@ -60,7 +80,10 @@ function splitListItems(text) {
|
|
|
60
80
|
while (/\s/.test(text[i])) i += 1;
|
|
61
81
|
if (i >= text.length) break;
|
|
62
82
|
const start = i;
|
|
63
|
-
if (text
|
|
83
|
+
if (text.startsWith('<<(', i)) {
|
|
84
|
+
const [, next] = readTermToken(text, i);
|
|
85
|
+
i = next;
|
|
86
|
+
} else if (text[i] === '"') {
|
|
64
87
|
i += 1;
|
|
65
88
|
let escaped = false;
|
|
66
89
|
while (i < text.length) {
|
|
@@ -83,9 +106,17 @@ function splitListItems(text) {
|
|
|
83
106
|
}
|
|
84
107
|
return out;
|
|
85
108
|
}
|
|
109
|
+
function parseTripleTermBody(text) {
|
|
110
|
+
const [s, i1] = readTermToken(text, 0);
|
|
111
|
+
const [p, i2] = readTermToken(text, i1);
|
|
112
|
+
const [o, i3] = readTermToken(text, i2);
|
|
113
|
+
if (!s || !p || !o || text.slice(i3).trim()) throw new Error('bad triple term: ' + text);
|
|
114
|
+
return triple(parseTerm(s), parseTerm(p), parseTerm(o));
|
|
115
|
+
}
|
|
86
116
|
function parseTerm(text) {
|
|
87
117
|
const t = String(text || '').trim();
|
|
88
118
|
if (!t) throw new Error('empty term');
|
|
119
|
+
if (t.startsWith('<<(') && t.endsWith(')>>')) return parseTripleTermBody(t.slice(3, -3).trim());
|
|
89
120
|
const first = t[0];
|
|
90
121
|
if (first === '"') return lit(JSON.parse(t));
|
|
91
122
|
if (first === '(' && t[t.length - 1] === ')') return list(splitListItems(t.slice(1, -1)).map(parseTerm));
|
|
@@ -112,7 +143,7 @@ function parseInputTrigFast(trig) {
|
|
|
112
143
|
const lines = String(trig || '').split(/\r?\n/);
|
|
113
144
|
for (let i = 0; i < lines.length; i += 1) {
|
|
114
145
|
const line = lines[i].trim();
|
|
115
|
-
if (!line || line.startsWith('#') || line.toLowerCase().startsWith('@prefix ')) continue;
|
|
146
|
+
if (!line || line.startsWith('#') || line.toLowerCase().startsWith('@prefix ') || /^(@version|version)\s+/i.test(line)) continue;
|
|
116
147
|
const graphStart = line.match(/^(\S+)\s*\{\s*$/);
|
|
117
148
|
if (graphStart) {
|
|
118
149
|
const atoms = [];
|
package/see/examples/age.js
CHANGED
|
@@ -8,6 +8,7 @@ const crypto = require('crypto');
|
|
|
8
8
|
|
|
9
9
|
function canonical(term) {
|
|
10
10
|
if (term.kind === 'list') return ['list', term.items.map(canonical)];
|
|
11
|
+
if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
|
|
11
12
|
if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
|
|
12
13
|
return [term.kind, term.value];
|
|
13
14
|
}
|
|
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
|
|
|
17
18
|
function termIsConcrete(t) {
|
|
18
19
|
if (!t || t.kind === 'var') return false;
|
|
19
20
|
if (t.kind === 'list') return t.items.every(termIsConcrete);
|
|
21
|
+
if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
|
|
20
22
|
if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
|
|
21
23
|
return true;
|
|
22
24
|
}
|
|
@@ -32,6 +34,7 @@ function primitive(t) {
|
|
|
32
34
|
if (t.kind === 'iri') return t.value.replace(/^:/, '');
|
|
33
35
|
if (t.kind === 'blank') return t.value;
|
|
34
36
|
if (t.kind === 'list') return t.items.map(primitive);
|
|
37
|
+
if (t.kind === 'triple') return termToN3(t);
|
|
35
38
|
if (t.kind === 'formula') return termToN3(t);
|
|
36
39
|
return undefined;
|
|
37
40
|
}
|
|
@@ -52,6 +55,7 @@ function termToN3(t) {
|
|
|
52
55
|
if (t.kind === 'var') return '?' + t.value;
|
|
53
56
|
if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
|
|
54
57
|
if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
|
|
58
|
+
if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
|
|
55
59
|
if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
|
|
56
60
|
return String(t.value ?? t);
|
|
57
61
|
}
|
|
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
|
|
|
74
78
|
return resolve(env[term.value], env, seen);
|
|
75
79
|
}
|
|
76
80
|
if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
|
|
81
|
+
if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
|
|
77
82
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
|
|
78
83
|
return term;
|
|
79
84
|
}
|
|
@@ -91,6 +96,14 @@ function unify(a, b, env) {
|
|
|
91
96
|
}
|
|
92
97
|
return out;
|
|
93
98
|
}
|
|
99
|
+
if (a.kind === 'triple' || b.kind === 'triple') {
|
|
100
|
+
if (a.kind !== 'triple' || b.kind !== 'triple') return null;
|
|
101
|
+
let out = unify(a.s, b.s, env);
|
|
102
|
+
if (!out) return null;
|
|
103
|
+
out = unify(a.p, b.p, out);
|
|
104
|
+
if (!out) return null;
|
|
105
|
+
return unify(a.o, b.o, out);
|
|
106
|
+
}
|
|
94
107
|
return deepEqual(a, b) ? env : null;
|
|
95
108
|
}
|
|
96
109
|
function bind(pattern, value, env) { return unify(pattern, value, env); }
|
|
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
|
|
|
106
119
|
const r = resolve(t, env);
|
|
107
120
|
if (r.kind === 'var') return false;
|
|
108
121
|
if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
|
|
122
|
+
if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
|
|
109
123
|
if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
|
|
110
124
|
return true;
|
|
111
125
|
}
|
|
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
|
|
|
665
679
|
}
|
|
666
680
|
if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
|
|
667
681
|
if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
|
|
682
|
+
if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
|
|
668
683
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
|
|
669
684
|
return cloneTerm(term);
|
|
670
685
|
}
|
|
@@ -1368,6 +1383,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1368
1383
|
}
|
|
1369
1384
|
return out;
|
|
1370
1385
|
}
|
|
1386
|
+
function termHasTripleTerm(term) {
|
|
1387
|
+
if (!term) return false;
|
|
1388
|
+
if (term.kind === 'triple') return true;
|
|
1389
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1390
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1394
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1395
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1371
1396
|
function trigGraphBlock(label, atoms) {
|
|
1372
1397
|
const lines = [label + ' {'];
|
|
1373
1398
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1415,7 +1440,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1415
1440
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1416
1441
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1417
1442
|
const nl = String.fromCharCode(10);
|
|
1418
|
-
|
|
1443
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1444
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1419
1445
|
}
|
|
1420
1446
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1421
1447
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
|
@@ -8,6 +8,7 @@ const crypto = require('crypto');
|
|
|
8
8
|
|
|
9
9
|
function canonical(term) {
|
|
10
10
|
if (term.kind === 'list') return ['list', term.items.map(canonical)];
|
|
11
|
+
if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
|
|
11
12
|
if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
|
|
12
13
|
return [term.kind, term.value];
|
|
13
14
|
}
|
|
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
|
|
|
17
18
|
function termIsConcrete(t) {
|
|
18
19
|
if (!t || t.kind === 'var') return false;
|
|
19
20
|
if (t.kind === 'list') return t.items.every(termIsConcrete);
|
|
21
|
+
if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
|
|
20
22
|
if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
|
|
21
23
|
return true;
|
|
22
24
|
}
|
|
@@ -32,6 +34,7 @@ function primitive(t) {
|
|
|
32
34
|
if (t.kind === 'iri') return t.value.replace(/^:/, '');
|
|
33
35
|
if (t.kind === 'blank') return t.value;
|
|
34
36
|
if (t.kind === 'list') return t.items.map(primitive);
|
|
37
|
+
if (t.kind === 'triple') return termToN3(t);
|
|
35
38
|
if (t.kind === 'formula') return termToN3(t);
|
|
36
39
|
return undefined;
|
|
37
40
|
}
|
|
@@ -52,6 +55,7 @@ function termToN3(t) {
|
|
|
52
55
|
if (t.kind === 'var') return '?' + t.value;
|
|
53
56
|
if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
|
|
54
57
|
if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
|
|
58
|
+
if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
|
|
55
59
|
if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
|
|
56
60
|
return String(t.value ?? t);
|
|
57
61
|
}
|
|
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
|
|
|
74
78
|
return resolve(env[term.value], env, seen);
|
|
75
79
|
}
|
|
76
80
|
if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
|
|
81
|
+
if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
|
|
77
82
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
|
|
78
83
|
return term;
|
|
79
84
|
}
|
|
@@ -91,6 +96,14 @@ function unify(a, b, env) {
|
|
|
91
96
|
}
|
|
92
97
|
return out;
|
|
93
98
|
}
|
|
99
|
+
if (a.kind === 'triple' || b.kind === 'triple') {
|
|
100
|
+
if (a.kind !== 'triple' || b.kind !== 'triple') return null;
|
|
101
|
+
let out = unify(a.s, b.s, env);
|
|
102
|
+
if (!out) return null;
|
|
103
|
+
out = unify(a.p, b.p, out);
|
|
104
|
+
if (!out) return null;
|
|
105
|
+
return unify(a.o, b.o, out);
|
|
106
|
+
}
|
|
94
107
|
return deepEqual(a, b) ? env : null;
|
|
95
108
|
}
|
|
96
109
|
function bind(pattern, value, env) { return unify(pattern, value, env); }
|
|
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
|
|
|
106
119
|
const r = resolve(t, env);
|
|
107
120
|
if (r.kind === 'var') return false;
|
|
108
121
|
if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
|
|
122
|
+
if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
|
|
109
123
|
if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
|
|
110
124
|
return true;
|
|
111
125
|
}
|
|
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
|
|
|
665
679
|
}
|
|
666
680
|
if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
|
|
667
681
|
if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
|
|
682
|
+
if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
|
|
668
683
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
|
|
669
684
|
return cloneTerm(term);
|
|
670
685
|
}
|
|
@@ -1229,6 +1244,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1229
1244
|
}
|
|
1230
1245
|
return out;
|
|
1231
1246
|
}
|
|
1247
|
+
function termHasTripleTerm(term) {
|
|
1248
|
+
if (!term) return false;
|
|
1249
|
+
if (term.kind === 'triple') return true;
|
|
1250
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1251
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1252
|
+
return false;
|
|
1253
|
+
}
|
|
1254
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1255
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1256
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1232
1257
|
function trigGraphBlock(label, atoms) {
|
|
1233
1258
|
const lines = [label + ' {'];
|
|
1234
1259
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1276,7 +1301,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1276
1301
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1277
1302
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1278
1303
|
const nl = String.fromCharCode(10);
|
|
1279
|
-
|
|
1304
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1305
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1280
1306
|
}
|
|
1281
1307
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1282
1308
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
package/see/examples/backward.js
CHANGED
|
@@ -8,6 +8,7 @@ const crypto = require('crypto');
|
|
|
8
8
|
|
|
9
9
|
function canonical(term) {
|
|
10
10
|
if (term.kind === 'list') return ['list', term.items.map(canonical)];
|
|
11
|
+
if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
|
|
11
12
|
if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
|
|
12
13
|
return [term.kind, term.value];
|
|
13
14
|
}
|
|
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
|
|
|
17
18
|
function termIsConcrete(t) {
|
|
18
19
|
if (!t || t.kind === 'var') return false;
|
|
19
20
|
if (t.kind === 'list') return t.items.every(termIsConcrete);
|
|
21
|
+
if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
|
|
20
22
|
if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
|
|
21
23
|
return true;
|
|
22
24
|
}
|
|
@@ -32,6 +34,7 @@ function primitive(t) {
|
|
|
32
34
|
if (t.kind === 'iri') return t.value.replace(/^:/, '');
|
|
33
35
|
if (t.kind === 'blank') return t.value;
|
|
34
36
|
if (t.kind === 'list') return t.items.map(primitive);
|
|
37
|
+
if (t.kind === 'triple') return termToN3(t);
|
|
35
38
|
if (t.kind === 'formula') return termToN3(t);
|
|
36
39
|
return undefined;
|
|
37
40
|
}
|
|
@@ -52,6 +55,7 @@ function termToN3(t) {
|
|
|
52
55
|
if (t.kind === 'var') return '?' + t.value;
|
|
53
56
|
if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
|
|
54
57
|
if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
|
|
58
|
+
if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
|
|
55
59
|
if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
|
|
56
60
|
return String(t.value ?? t);
|
|
57
61
|
}
|
|
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
|
|
|
74
78
|
return resolve(env[term.value], env, seen);
|
|
75
79
|
}
|
|
76
80
|
if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
|
|
81
|
+
if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
|
|
77
82
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
|
|
78
83
|
return term;
|
|
79
84
|
}
|
|
@@ -91,6 +96,14 @@ function unify(a, b, env) {
|
|
|
91
96
|
}
|
|
92
97
|
return out;
|
|
93
98
|
}
|
|
99
|
+
if (a.kind === 'triple' || b.kind === 'triple') {
|
|
100
|
+
if (a.kind !== 'triple' || b.kind !== 'triple') return null;
|
|
101
|
+
let out = unify(a.s, b.s, env);
|
|
102
|
+
if (!out) return null;
|
|
103
|
+
out = unify(a.p, b.p, out);
|
|
104
|
+
if (!out) return null;
|
|
105
|
+
return unify(a.o, b.o, out);
|
|
106
|
+
}
|
|
94
107
|
return deepEqual(a, b) ? env : null;
|
|
95
108
|
}
|
|
96
109
|
function bind(pattern, value, env) { return unify(pattern, value, env); }
|
|
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
|
|
|
106
119
|
const r = resolve(t, env);
|
|
107
120
|
if (r.kind === 'var') return false;
|
|
108
121
|
if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
|
|
122
|
+
if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
|
|
109
123
|
if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
|
|
110
124
|
return true;
|
|
111
125
|
}
|
|
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
|
|
|
665
679
|
}
|
|
666
680
|
if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
|
|
667
681
|
if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
|
|
682
|
+
if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
|
|
668
683
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
|
|
669
684
|
return cloneTerm(term);
|
|
670
685
|
}
|
|
@@ -1314,6 +1329,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1314
1329
|
}
|
|
1315
1330
|
return out;
|
|
1316
1331
|
}
|
|
1332
|
+
function termHasTripleTerm(term) {
|
|
1333
|
+
if (!term) return false;
|
|
1334
|
+
if (term.kind === 'triple') return true;
|
|
1335
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1336
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1340
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1341
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1317
1342
|
function trigGraphBlock(label, atoms) {
|
|
1318
1343
|
const lines = [label + ' {'];
|
|
1319
1344
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1361,7 +1386,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1361
1386
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1362
1387
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1363
1388
|
const nl = String.fromCharCode(10);
|
|
1364
|
-
|
|
1389
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1390
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1365
1391
|
}
|
|
1366
1392
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1367
1393
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
|
@@ -8,6 +8,7 @@ const crypto = require('crypto');
|
|
|
8
8
|
|
|
9
9
|
function canonical(term) {
|
|
10
10
|
if (term.kind === 'list') return ['list', term.items.map(canonical)];
|
|
11
|
+
if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
|
|
11
12
|
if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
|
|
12
13
|
return [term.kind, term.value];
|
|
13
14
|
}
|
|
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
|
|
|
17
18
|
function termIsConcrete(t) {
|
|
18
19
|
if (!t || t.kind === 'var') return false;
|
|
19
20
|
if (t.kind === 'list') return t.items.every(termIsConcrete);
|
|
21
|
+
if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
|
|
20
22
|
if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
|
|
21
23
|
return true;
|
|
22
24
|
}
|
|
@@ -32,6 +34,7 @@ function primitive(t) {
|
|
|
32
34
|
if (t.kind === 'iri') return t.value.replace(/^:/, '');
|
|
33
35
|
if (t.kind === 'blank') return t.value;
|
|
34
36
|
if (t.kind === 'list') return t.items.map(primitive);
|
|
37
|
+
if (t.kind === 'triple') return termToN3(t);
|
|
35
38
|
if (t.kind === 'formula') return termToN3(t);
|
|
36
39
|
return undefined;
|
|
37
40
|
}
|
|
@@ -52,6 +55,7 @@ function termToN3(t) {
|
|
|
52
55
|
if (t.kind === 'var') return '?' + t.value;
|
|
53
56
|
if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
|
|
54
57
|
if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
|
|
58
|
+
if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
|
|
55
59
|
if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
|
|
56
60
|
return String(t.value ?? t);
|
|
57
61
|
}
|
|
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
|
|
|
74
78
|
return resolve(env[term.value], env, seen);
|
|
75
79
|
}
|
|
76
80
|
if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
|
|
81
|
+
if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
|
|
77
82
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
|
|
78
83
|
return term;
|
|
79
84
|
}
|
|
@@ -91,6 +96,14 @@ function unify(a, b, env) {
|
|
|
91
96
|
}
|
|
92
97
|
return out;
|
|
93
98
|
}
|
|
99
|
+
if (a.kind === 'triple' || b.kind === 'triple') {
|
|
100
|
+
if (a.kind !== 'triple' || b.kind !== 'triple') return null;
|
|
101
|
+
let out = unify(a.s, b.s, env);
|
|
102
|
+
if (!out) return null;
|
|
103
|
+
out = unify(a.p, b.p, out);
|
|
104
|
+
if (!out) return null;
|
|
105
|
+
return unify(a.o, b.o, out);
|
|
106
|
+
}
|
|
94
107
|
return deepEqual(a, b) ? env : null;
|
|
95
108
|
}
|
|
96
109
|
function bind(pattern, value, env) { return unify(pattern, value, env); }
|
|
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
|
|
|
106
119
|
const r = resolve(t, env);
|
|
107
120
|
if (r.kind === 'var') return false;
|
|
108
121
|
if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
|
|
122
|
+
if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
|
|
109
123
|
if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
|
|
110
124
|
return true;
|
|
111
125
|
}
|
|
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
|
|
|
665
679
|
}
|
|
666
680
|
if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
|
|
667
681
|
if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
|
|
682
|
+
if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
|
|
668
683
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
|
|
669
684
|
return cloneTerm(term);
|
|
670
685
|
}
|
|
@@ -1413,6 +1428,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1413
1428
|
}
|
|
1414
1429
|
return out;
|
|
1415
1430
|
}
|
|
1431
|
+
function termHasTripleTerm(term) {
|
|
1432
|
+
if (!term) return false;
|
|
1433
|
+
if (term.kind === 'triple') return true;
|
|
1434
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1435
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1436
|
+
return false;
|
|
1437
|
+
}
|
|
1438
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1439
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1440
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1416
1441
|
function trigGraphBlock(label, atoms) {
|
|
1417
1442
|
const lines = [label + ' {'];
|
|
1418
1443
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1460,7 +1485,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1460
1485
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1461
1486
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1462
1487
|
const nl = String.fromCharCode(10);
|
|
1463
|
-
|
|
1488
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1489
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1464
1490
|
}
|
|
1465
1491
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1466
1492
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
|
@@ -8,6 +8,7 @@ const crypto = require('crypto');
|
|
|
8
8
|
|
|
9
9
|
function canonical(term) {
|
|
10
10
|
if (term.kind === 'list') return ['list', term.items.map(canonical)];
|
|
11
|
+
if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
|
|
11
12
|
if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
|
|
12
13
|
return [term.kind, term.value];
|
|
13
14
|
}
|
|
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
|
|
|
17
18
|
function termIsConcrete(t) {
|
|
18
19
|
if (!t || t.kind === 'var') return false;
|
|
19
20
|
if (t.kind === 'list') return t.items.every(termIsConcrete);
|
|
21
|
+
if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
|
|
20
22
|
if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
|
|
21
23
|
return true;
|
|
22
24
|
}
|
|
@@ -32,6 +34,7 @@ function primitive(t) {
|
|
|
32
34
|
if (t.kind === 'iri') return t.value.replace(/^:/, '');
|
|
33
35
|
if (t.kind === 'blank') return t.value;
|
|
34
36
|
if (t.kind === 'list') return t.items.map(primitive);
|
|
37
|
+
if (t.kind === 'triple') return termToN3(t);
|
|
35
38
|
if (t.kind === 'formula') return termToN3(t);
|
|
36
39
|
return undefined;
|
|
37
40
|
}
|
|
@@ -52,6 +55,7 @@ function termToN3(t) {
|
|
|
52
55
|
if (t.kind === 'var') return '?' + t.value;
|
|
53
56
|
if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
|
|
54
57
|
if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
|
|
58
|
+
if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
|
|
55
59
|
if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
|
|
56
60
|
return String(t.value ?? t);
|
|
57
61
|
}
|
|
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
|
|
|
74
78
|
return resolve(env[term.value], env, seen);
|
|
75
79
|
}
|
|
76
80
|
if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
|
|
81
|
+
if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
|
|
77
82
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
|
|
78
83
|
return term;
|
|
79
84
|
}
|
|
@@ -91,6 +96,14 @@ function unify(a, b, env) {
|
|
|
91
96
|
}
|
|
92
97
|
return out;
|
|
93
98
|
}
|
|
99
|
+
if (a.kind === 'triple' || b.kind === 'triple') {
|
|
100
|
+
if (a.kind !== 'triple' || b.kind !== 'triple') return null;
|
|
101
|
+
let out = unify(a.s, b.s, env);
|
|
102
|
+
if (!out) return null;
|
|
103
|
+
out = unify(a.p, b.p, out);
|
|
104
|
+
if (!out) return null;
|
|
105
|
+
return unify(a.o, b.o, out);
|
|
106
|
+
}
|
|
94
107
|
return deepEqual(a, b) ? env : null;
|
|
95
108
|
}
|
|
96
109
|
function bind(pattern, value, env) { return unify(pattern, value, env); }
|
|
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
|
|
|
106
119
|
const r = resolve(t, env);
|
|
107
120
|
if (r.kind === 'var') return false;
|
|
108
121
|
if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
|
|
122
|
+
if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
|
|
109
123
|
if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
|
|
110
124
|
return true;
|
|
111
125
|
}
|
|
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
|
|
|
665
679
|
}
|
|
666
680
|
if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
|
|
667
681
|
if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
|
|
682
|
+
if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
|
|
668
683
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
|
|
669
684
|
return cloneTerm(term);
|
|
670
685
|
}
|
|
@@ -2792,6 +2807,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
2792
2807
|
}
|
|
2793
2808
|
return out;
|
|
2794
2809
|
}
|
|
2810
|
+
function termHasTripleTerm(term) {
|
|
2811
|
+
if (!term) return false;
|
|
2812
|
+
if (term.kind === 'triple') return true;
|
|
2813
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
2814
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
2815
|
+
return false;
|
|
2816
|
+
}
|
|
2817
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
2818
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
2819
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
2795
2820
|
function trigGraphBlock(label, atoms) {
|
|
2796
2821
|
const lines = [label + ' {'];
|
|
2797
2822
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -2839,7 +2864,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
2839
2864
|
const prefixes = prefixLinesFromTrig(trig);
|
|
2840
2865
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
2841
2866
|
const nl = String.fromCharCode(10);
|
|
2842
|
-
|
|
2867
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
2868
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
2843
2869
|
}
|
|
2844
2870
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
2845
2871
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
|
@@ -8,6 +8,7 @@ const crypto = require('crypto');
|
|
|
8
8
|
|
|
9
9
|
function canonical(term) {
|
|
10
10
|
if (term.kind === 'list') return ['list', term.items.map(canonical)];
|
|
11
|
+
if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
|
|
11
12
|
if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
|
|
12
13
|
return [term.kind, term.value];
|
|
13
14
|
}
|
|
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
|
|
|
17
18
|
function termIsConcrete(t) {
|
|
18
19
|
if (!t || t.kind === 'var') return false;
|
|
19
20
|
if (t.kind === 'list') return t.items.every(termIsConcrete);
|
|
21
|
+
if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
|
|
20
22
|
if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
|
|
21
23
|
return true;
|
|
22
24
|
}
|
|
@@ -32,6 +34,7 @@ function primitive(t) {
|
|
|
32
34
|
if (t.kind === 'iri') return t.value.replace(/^:/, '');
|
|
33
35
|
if (t.kind === 'blank') return t.value;
|
|
34
36
|
if (t.kind === 'list') return t.items.map(primitive);
|
|
37
|
+
if (t.kind === 'triple') return termToN3(t);
|
|
35
38
|
if (t.kind === 'formula') return termToN3(t);
|
|
36
39
|
return undefined;
|
|
37
40
|
}
|
|
@@ -52,6 +55,7 @@ function termToN3(t) {
|
|
|
52
55
|
if (t.kind === 'var') return '?' + t.value;
|
|
53
56
|
if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
|
|
54
57
|
if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
|
|
58
|
+
if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
|
|
55
59
|
if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
|
|
56
60
|
return String(t.value ?? t);
|
|
57
61
|
}
|
|
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
|
|
|
74
78
|
return resolve(env[term.value], env, seen);
|
|
75
79
|
}
|
|
76
80
|
if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
|
|
81
|
+
if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
|
|
77
82
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
|
|
78
83
|
return term;
|
|
79
84
|
}
|
|
@@ -91,6 +96,14 @@ function unify(a, b, env) {
|
|
|
91
96
|
}
|
|
92
97
|
return out;
|
|
93
98
|
}
|
|
99
|
+
if (a.kind === 'triple' || b.kind === 'triple') {
|
|
100
|
+
if (a.kind !== 'triple' || b.kind !== 'triple') return null;
|
|
101
|
+
let out = unify(a.s, b.s, env);
|
|
102
|
+
if (!out) return null;
|
|
103
|
+
out = unify(a.p, b.p, out);
|
|
104
|
+
if (!out) return null;
|
|
105
|
+
return unify(a.o, b.o, out);
|
|
106
|
+
}
|
|
94
107
|
return deepEqual(a, b) ? env : null;
|
|
95
108
|
}
|
|
96
109
|
function bind(pattern, value, env) { return unify(pattern, value, env); }
|
|
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
|
|
|
106
119
|
const r = resolve(t, env);
|
|
107
120
|
if (r.kind === 'var') return false;
|
|
108
121
|
if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
|
|
122
|
+
if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
|
|
109
123
|
if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
|
|
110
124
|
return true;
|
|
111
125
|
}
|
|
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
|
|
|
665
679
|
}
|
|
666
680
|
if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
|
|
667
681
|
if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
|
|
682
|
+
if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
|
|
668
683
|
if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
|
|
669
684
|
return cloneTerm(term);
|
|
670
685
|
}
|
|
@@ -4061,6 +4076,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
4061
4076
|
}
|
|
4062
4077
|
return out;
|
|
4063
4078
|
}
|
|
4079
|
+
function termHasTripleTerm(term) {
|
|
4080
|
+
if (!term) return false;
|
|
4081
|
+
if (term.kind === 'triple') return true;
|
|
4082
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
4083
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
4084
|
+
return false;
|
|
4085
|
+
}
|
|
4086
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
4087
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
4088
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
4064
4089
|
function trigGraphBlock(label, atoms) {
|
|
4065
4090
|
const lines = [label + ' {'];
|
|
4066
4091
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -4108,7 +4133,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
4108
4133
|
const prefixes = prefixLinesFromTrig(trig);
|
|
4109
4134
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
4110
4135
|
const nl = String.fromCharCode(10);
|
|
4111
|
-
|
|
4136
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
4137
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
4112
4138
|
}
|
|
4113
4139
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
4114
4140
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|