eyeling 1.30.6 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -161
- package/dist/browser/eyeling.browser.js +54 -638
- package/eyeling.js +54 -638
- package/index.d.ts +9 -49
- package/index.js +1 -2
- package/lib/cli.js +4 -11
- package/lib/engine.js +6 -14
- package/lib/lexer.js +2 -6
- package/lib/multisource.js +3 -5
- package/lib/rdfjs.js +39 -1
- package/package.json +4 -2
- package/test/examples.test.js +5 -37
- package/test/run.js +0 -1
- package/examples/input/rdf-surfaces-all-values-from-reverse.trig +0 -18
- package/examples/input/rdf-surfaces-all-values-from.trig +0 -14
- package/examples/input/rdf-surfaces-ancestor.trig +0 -21
- package/examples/input/rdf-surfaces-city.trig +0 -12
- package/examples/input/rdf-surfaces-disjunction-elimination.trig +0 -17
- package/examples/input/rdf-surfaces-disjunction-route-filter.trig +0 -12
- package/examples/input/rdf-surfaces-domain.trig +0 -12
- package/examples/input/rdf-surfaces-explicit-disjunction.trig +0 -23
- package/examples/input/rdf-surfaces-multi-premise.trig +0 -14
- package/examples/input/rdf-surfaces-owl-all-values-from-codex.trig +0 -36
- package/examples/input/rdf-surfaces-property-chain.trig +0 -14
- package/examples/input/rdf-surfaces-range.trig +0 -12
- package/examples/input/rdf-surfaces-rdf12-graph-triple-term.trig +0 -15
- package/examples/input/rdf-surfaces-rdf12-named-graph.trig +0 -14
- package/examples/input/rdf-surfaces-rdf12-triple-term.trig +0 -13
- package/examples/input/rdf-surfaces-rdfs-range-codex.trig +0 -19
- package/examples/input/rdf-surfaces-rdfs-subclass-codex.trig +0 -19
- package/examples/input/rdf-surfaces-strong-negation-access.trig +0 -15
- package/examples/output/rdf-surfaces-all-values-from-reverse.n3 +0 -3
- package/examples/output/rdf-surfaces-all-values-from.n3 +0 -3
- package/examples/output/rdf-surfaces-ancestor.n3 +0 -5
- package/examples/output/rdf-surfaces-city.n3 +0 -3
- package/examples/output/rdf-surfaces-disjunction-elimination.n3 +0 -3
- package/examples/output/rdf-surfaces-disjunction-route-filter.n3 +0 -3
- package/examples/output/rdf-surfaces-domain.n3 +0 -3
- package/examples/output/rdf-surfaces-explicit-disjunction.n3 +0 -3
- package/examples/output/rdf-surfaces-multi-premise.n3 +0 -3
- package/examples/output/rdf-surfaces-owl-all-values-from-codex.n3 +0 -6
- package/examples/output/rdf-surfaces-property-chain.n3 +0 -3
- package/examples/output/rdf-surfaces-range.n3 +0 -3
- package/examples/output/rdf-surfaces-rdf12-graph-triple-term.n3 +0 -3
- package/examples/output/rdf-surfaces-rdf12-named-graph.n3 +0 -3
- package/examples/output/rdf-surfaces-rdf12-triple-term.n3 +0 -3
- package/examples/output/rdf-surfaces-rdfs-range-codex.n3 +0 -3
- package/examples/output/rdf-surfaces-rdfs-subclass-codex.n3 +0 -3
- package/examples/output/rdf-surfaces-strong-negation-access.n3 +0 -4
- package/examples/rdf-surfaces-all-values-from-reverse.n3 +0 -6
- package/examples/rdf-surfaces-all-values-from.n3 +0 -6
- package/examples/rdf-surfaces-ancestor.n3 +0 -6
- package/examples/rdf-surfaces-city.n3 +0 -6
- package/examples/rdf-surfaces-disjunction-elimination.n3 +0 -13
- package/examples/rdf-surfaces-disjunction-route-filter.n3 +0 -24
- package/examples/rdf-surfaces-domain.n3 +0 -6
- package/examples/rdf-surfaces-explicit-disjunction.n3 +0 -16
- package/examples/rdf-surfaces-multi-premise.n3 +0 -6
- package/examples/rdf-surfaces-owl-all-values-from-codex.n3 +0 -10
- package/examples/rdf-surfaces-property-chain.n3 +0 -6
- package/examples/rdf-surfaces-range.n3 +0 -6
- package/examples/rdf-surfaces-rdf12-graph-triple-term.n3 +0 -6
- package/examples/rdf-surfaces-rdf12-named-graph.n3 +0 -6
- package/examples/rdf-surfaces-rdf12-triple-term.n3 +0 -6
- package/examples/rdf-surfaces-rdfs-range-codex.n3 +0 -6
- package/examples/rdf-surfaces-rdfs-subclass-codex.n3 +0 -6
- package/examples/rdf-surfaces-strong-negation-access.n3 +0 -20
- package/lib/rdf_surfaces.js +0 -598
- package/test/rdf_surfaces.test.js +0 -227
package/lib/rdf_surfaces.js
DELETED
|
@@ -1,598 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Eyeling Reasoner — RDF Surfaces syntax normalizer
|
|
3
|
-
*
|
|
4
|
-
* Implements a small RDF Surfaces text convention inspired by Hayes' BLOGIC
|
|
5
|
-
* slides: `%not[ ... %]` surface parentheses with explicit blank mark binders
|
|
6
|
-
* such as `_:x _:y` at the beginning of a surface. The supported fragment
|
|
7
|
-
* covers slide 32, the slide 33 range shape, both slide 33 allValuesFrom
|
|
8
|
-
* shapes, and top-level fuse surfaces.
|
|
9
|
-
*
|
|
10
|
-
* The normalizer rewrites the supported fragment into ordinary Eyeling N3:
|
|
11
|
-
* %not[ _:x P(?x) . %not[ Q(?x) . %] %]
|
|
12
|
-
* becomes:
|
|
13
|
-
* { P(?x) . } => { Q(?x) . } .
|
|
14
|
-
*
|
|
15
|
-
* A top-level negative surface without an inner negative surface becomes an
|
|
16
|
-
* inference fuse:
|
|
17
|
-
* %not[ _:x P(?x) . %]
|
|
18
|
-
* becomes:
|
|
19
|
-
* { P(?x) . } => false .
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
'use strict';
|
|
23
|
-
|
|
24
|
-
function syntaxError(message, offset = null) {
|
|
25
|
-
const e = new Error(message);
|
|
26
|
-
e.name = 'N3SyntaxError';
|
|
27
|
-
if (typeof offset === 'number') e.offset = offset;
|
|
28
|
-
return e;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function isWs(ch) {
|
|
32
|
-
return ch != null && /\s/.test(ch);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
function readStringAt(s, at) {
|
|
37
|
-
const quote = s[at];
|
|
38
|
-
let i = at;
|
|
39
|
-
let out = quote;
|
|
40
|
-
const long = s.startsWith(quote.repeat(3), i);
|
|
41
|
-
if (long) {
|
|
42
|
-
out = quote.repeat(3);
|
|
43
|
-
i += 3;
|
|
44
|
-
while (i < s.length) {
|
|
45
|
-
if (s.startsWith(quote.repeat(3), i)) {
|
|
46
|
-
out += quote.repeat(3);
|
|
47
|
-
i += 3;
|
|
48
|
-
return { text: out, end: i };
|
|
49
|
-
}
|
|
50
|
-
if (s[i] === '\\' && i + 1 < s.length) {
|
|
51
|
-
out += s.slice(i, i + 2);
|
|
52
|
-
i += 2;
|
|
53
|
-
} else {
|
|
54
|
-
out += s[i++];
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
throw syntaxError('Unterminated string literal inside RDF Surface', at);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
i += 1;
|
|
61
|
-
let escaped = false;
|
|
62
|
-
while (i < s.length) {
|
|
63
|
-
const ch = s[i++];
|
|
64
|
-
out += ch;
|
|
65
|
-
if (escaped) escaped = false;
|
|
66
|
-
else if (ch === '\\') escaped = true;
|
|
67
|
-
else if (ch === quote) return { text: out, end: i };
|
|
68
|
-
}
|
|
69
|
-
throw syntaxError('Unterminated string literal inside RDF Surface', at);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function readIriAt(s, at) {
|
|
73
|
-
let i = at + 1;
|
|
74
|
-
let out = '<';
|
|
75
|
-
while (i < s.length) {
|
|
76
|
-
const ch = s[i++];
|
|
77
|
-
out += ch;
|
|
78
|
-
if (ch === '>') return { text: out, end: i };
|
|
79
|
-
}
|
|
80
|
-
throw syntaxError('Unterminated IRI inside RDF Surface', at);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function skipWsAndComments(s, at) {
|
|
84
|
-
let i = at;
|
|
85
|
-
while (i < s.length) {
|
|
86
|
-
if (isWs(s[i])) {
|
|
87
|
-
i += 1;
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
if (s[i] === '#') {
|
|
91
|
-
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
return i;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function readBareTokenAt(s, at) {
|
|
100
|
-
const i0 = skipWsAndComments(s, at);
|
|
101
|
-
if (i0 >= s.length) return null;
|
|
102
|
-
if (s[i0] === '<') return readIriAt(s, i0);
|
|
103
|
-
if (s[i0] === '"' || s[i0] === "'") return readStringAt(s, i0);
|
|
104
|
-
let i = i0;
|
|
105
|
-
while (i < s.length && !isWs(s[i]) && !'{}[](),;.'.includes(s[i])) i += 1;
|
|
106
|
-
if (i === i0) return null;
|
|
107
|
-
return { text: s.slice(i0, i), start: i0, end: i };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function readStatementSegment(s) {
|
|
111
|
-
let i = 0;
|
|
112
|
-
let depthBrace = 0;
|
|
113
|
-
let depthBracket = 0;
|
|
114
|
-
let depthParen = 0;
|
|
115
|
-
while (i < s.length) {
|
|
116
|
-
if (s.startsWith('%not[', i) && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
|
|
117
|
-
return s.slice(0, i);
|
|
118
|
-
}
|
|
119
|
-
const ch = s[i];
|
|
120
|
-
if (ch === '"' || ch === "'") {
|
|
121
|
-
i = readStringAt(s, i).end;
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
if (ch === '<') {
|
|
125
|
-
i = readIriAt(s, i).end;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (ch === '#') {
|
|
129
|
-
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
if (ch === '{') depthBrace += 1;
|
|
133
|
-
else if (ch === '}' && depthBrace > 0) depthBrace -= 1;
|
|
134
|
-
else if (ch === '[') depthBracket += 1;
|
|
135
|
-
else if (ch === ']' && depthBracket > 0) depthBracket -= 1;
|
|
136
|
-
else if (ch === '(') depthParen += 1;
|
|
137
|
-
else if (ch === ')' && depthParen > 0) depthParen -= 1;
|
|
138
|
-
else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) return s.slice(0, i);
|
|
139
|
-
i += 1;
|
|
140
|
-
}
|
|
141
|
-
return s;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function tokenizeLeadingSegment(segment) {
|
|
145
|
-
const toks = [];
|
|
146
|
-
let pos = 0;
|
|
147
|
-
while (pos < segment.length) {
|
|
148
|
-
const tok = readBareTokenAt(segment, pos);
|
|
149
|
-
if (!tok) break;
|
|
150
|
-
toks.push(tok);
|
|
151
|
-
pos = tok.end;
|
|
152
|
-
}
|
|
153
|
-
return toks;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function extractLeadingBinders(raw) {
|
|
157
|
-
const text = String(raw || '');
|
|
158
|
-
const contentStart = skipWsAndComments(text, 0);
|
|
159
|
-
if (contentStart >= text.length) return { binders: [], text };
|
|
160
|
-
|
|
161
|
-
// Preferred BLOGIC graffiti style: put newly bound marks on the `%not[`
|
|
162
|
-
// line and put triples on following non-indented lines, e.g.
|
|
163
|
-
// `%not[ _:x _:y\n_:x :p _:y .`. Reading that first line directly
|
|
164
|
-
// avoids guessing from the first triple shape, which matters for RDF 1.2
|
|
165
|
-
// formula objects and TriG named graph blocks.
|
|
166
|
-
let lineEnd = text.indexOf('\n', contentStart);
|
|
167
|
-
if (lineEnd < 0) lineEnd = text.length;
|
|
168
|
-
let lineText = text.slice(contentStart, lineEnd);
|
|
169
|
-
let newlineEnd = lineEnd < text.length ? lineEnd + 1 : lineEnd;
|
|
170
|
-
if (lineText.endsWith('\r')) {
|
|
171
|
-
lineText = lineText.slice(0, -1);
|
|
172
|
-
}
|
|
173
|
-
const lineTrim = lineText.trim();
|
|
174
|
-
if (/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(lineTrim)) {
|
|
175
|
-
const binders = lineTrim.split(/\s+/).map((tok) => tok.slice(2));
|
|
176
|
-
return { binders, text: text.slice(0, contentStart) + text.slice(newlineEnd) };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const segment = readStatementSegment(text.slice(contentStart));
|
|
180
|
-
const toks = tokenizeLeadingSegment(segment);
|
|
181
|
-
let leadingBlankCount = 0;
|
|
182
|
-
while (leadingBlankCount < toks.length && /^_:[A-Za-z_][A-Za-z0-9._-]*$/.test(toks[leadingBlankCount].text)) {
|
|
183
|
-
leadingBlankCount += 1;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (leadingBlankCount === 0) return { binders: [], text };
|
|
187
|
-
|
|
188
|
-
let binderCount = 0;
|
|
189
|
-
if (toks.length >= 3) {
|
|
190
|
-
// Prefer the longest explicit binder prefix that still leaves at least a
|
|
191
|
-
// subject, predicate, and object for the first statement. This matches the
|
|
192
|
-
// BLOGIC slide convention, e.g. `%not[ _:x _:x a :C . ... %]`.
|
|
193
|
-
binderCount = Math.min(leadingBlankCount, Math.max(0, toks.length - 3));
|
|
194
|
-
} else {
|
|
195
|
-
// No own triple before a nested surface: treat the leading marks as binders.
|
|
196
|
-
binderCount = leadingBlankCount;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (binderCount <= 0) return { binders: [], text };
|
|
200
|
-
|
|
201
|
-
const binders = toks.slice(0, binderCount).map((t) => t.text.slice(2));
|
|
202
|
-
const cut = toks[binderCount - 1].end;
|
|
203
|
-
return { binders, text: text.slice(0, contentStart) + text.slice(contentStart + cut) };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
function readBalancedCurlyAt(s, at) {
|
|
208
|
-
if (s[at] !== '{') return null;
|
|
209
|
-
let i = at;
|
|
210
|
-
let depth = 0;
|
|
211
|
-
while (i < s.length) {
|
|
212
|
-
const ch = s[i];
|
|
213
|
-
if (ch === '"' || ch === "'") {
|
|
214
|
-
i = readStringAt(s, i).end;
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
if (ch === '<') {
|
|
218
|
-
i = readIriAt(s, i).end;
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
if (ch === '#') {
|
|
222
|
-
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
if (ch === '{') depth += 1;
|
|
226
|
-
else if (ch === '}') {
|
|
227
|
-
depth -= 1;
|
|
228
|
-
if (depth === 0) return { text: s.slice(at, i + 1), end: i + 1 };
|
|
229
|
-
}
|
|
230
|
-
i += 1;
|
|
231
|
-
}
|
|
232
|
-
throw syntaxError('Unterminated named graph block inside RDF Surface', at);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function normalizeSurfaceStatement(statement) {
|
|
236
|
-
const raw = String(statement || '').trim();
|
|
237
|
-
if (!raw) return raw;
|
|
238
|
-
|
|
239
|
-
let i = 0;
|
|
240
|
-
const first = readBareTokenAt(raw, i);
|
|
241
|
-
if (first && /^GRAPH$/i.test(first.text)) {
|
|
242
|
-
i = first.end;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const term = readBareTokenAt(raw, i);
|
|
246
|
-
if (!term) return raw;
|
|
247
|
-
const afterTerm = skipWsAndComments(raw, term.end);
|
|
248
|
-
if (raw[afterTerm] !== '{') return raw;
|
|
249
|
-
|
|
250
|
-
const block = readBalancedCurlyAt(raw, afterTerm);
|
|
251
|
-
const afterBlock = skipWsAndComments(raw, block.end);
|
|
252
|
-
if (afterBlock !== raw.length) return raw;
|
|
253
|
-
|
|
254
|
-
return `${term.text} ${LOG_NAME_OF_IRI} ${block.text}`;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function splitTopLevelStatements(raw, surfaceOffset = null) {
|
|
258
|
-
const text = String(raw || '');
|
|
259
|
-
const out = [];
|
|
260
|
-
let start = 0;
|
|
261
|
-
let i = 0;
|
|
262
|
-
let depthBrace = 0;
|
|
263
|
-
let depthBracket = 0;
|
|
264
|
-
let depthParen = 0;
|
|
265
|
-
|
|
266
|
-
while (i < text.length) {
|
|
267
|
-
const ch = text[i];
|
|
268
|
-
if (ch === '"' || ch === "'") {
|
|
269
|
-
i = readStringAt(text, i).end;
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
if (ch === '<') {
|
|
273
|
-
i = readIriAt(text, i).end;
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
if (ch === '#') {
|
|
277
|
-
while (i < text.length && text[i] !== '\n' && text[i] !== '\r') i += 1;
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
if (ch === '{') depthBrace += 1;
|
|
281
|
-
else if (ch === '}' && depthBrace > 0) depthBrace -= 1;
|
|
282
|
-
else if (ch === '[') depthBracket += 1;
|
|
283
|
-
else if (ch === ']' && depthBracket > 0) depthBracket -= 1;
|
|
284
|
-
else if (ch === '(') depthParen += 1;
|
|
285
|
-
else if (ch === ')' && depthParen > 0) depthParen -= 1;
|
|
286
|
-
else if (ch === '.' && depthBrace === 0 && depthBracket === 0 && depthParen === 0) {
|
|
287
|
-
const stmt = text.slice(start, i).trim();
|
|
288
|
-
if (stmt) out.push(normalizeSurfaceStatement(stmt));
|
|
289
|
-
start = i + 1;
|
|
290
|
-
}
|
|
291
|
-
i += 1;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const tail = text.slice(start).trim();
|
|
295
|
-
if (tail) {
|
|
296
|
-
// A raw binder-only segment is OK; RDF 1.2 TriG named graph blocks are
|
|
297
|
-
// also OK without a trailing dot. Any other dangling text is most likely a
|
|
298
|
-
// missing dot in the surface body.
|
|
299
|
-
const normalizedTail = normalizeSurfaceStatement(tail);
|
|
300
|
-
if (normalizedTail !== tail) {
|
|
301
|
-
out.push(normalizedTail);
|
|
302
|
-
} else if (!/^_:[A-Za-z_][A-Za-z0-9._-]*(?:\s+_:[A-Za-z_][A-Za-z0-9._-]*)*$/.test(tail)) {
|
|
303
|
-
throw syntaxError('RDF Surface statement is missing a terminating dot', surfaceOffset);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return out;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function readSurfaceAt(s, at) {
|
|
311
|
-
if (!s.startsWith('%not[', at)) return null;
|
|
312
|
-
let i = at + '%not['.length;
|
|
313
|
-
let current = '';
|
|
314
|
-
const segments = [];
|
|
315
|
-
const children = [];
|
|
316
|
-
|
|
317
|
-
while (i < s.length) {
|
|
318
|
-
if (s.startsWith('%]', i)) {
|
|
319
|
-
segments.push(current);
|
|
320
|
-
i += 2;
|
|
321
|
-
const raw = segments.join('\n');
|
|
322
|
-
const stripped = extractLeadingBinders(raw);
|
|
323
|
-
return {
|
|
324
|
-
type: 'not',
|
|
325
|
-
start: at,
|
|
326
|
-
end: i,
|
|
327
|
-
binders: stripped.binders,
|
|
328
|
-
statements: splitTopLevelStatements(stripped.text, at),
|
|
329
|
-
children,
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (s.startsWith('%not[', i)) {
|
|
334
|
-
segments.push(current);
|
|
335
|
-
current = '';
|
|
336
|
-
const child = readSurfaceAt(s, i);
|
|
337
|
-
children.push(child);
|
|
338
|
-
i = child.end;
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const ch = s[i];
|
|
343
|
-
if (ch === '"' || ch === "'") {
|
|
344
|
-
const str = readStringAt(s, i);
|
|
345
|
-
current += str.text;
|
|
346
|
-
i = str.end;
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
if (ch === '<') {
|
|
350
|
-
const iri = readIriAt(s, i);
|
|
351
|
-
current += iri.text;
|
|
352
|
-
i = iri.end;
|
|
353
|
-
continue;
|
|
354
|
-
}
|
|
355
|
-
if (ch === '#') {
|
|
356
|
-
while (i < s.length) {
|
|
357
|
-
const c = s[i++];
|
|
358
|
-
current += c;
|
|
359
|
-
if (c === '\n' || c === '\r') break;
|
|
360
|
-
}
|
|
361
|
-
continue;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
current += ch;
|
|
365
|
-
i += 1;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
throw syntaxError('Unterminated RDF Surface, expected %]', at);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const LOG_FOR_ALL_IN_IRI = '<http://www.w3.org/2000/10/swap/log#forAllIn>';
|
|
372
|
-
const LOG_NAME_OF_IRI = '<http://www.w3.org/2000/10/swap/log#nameOf>';
|
|
373
|
-
|
|
374
|
-
function rewriteBlankMarksWithMap(statement, labelToVarName) {
|
|
375
|
-
const map = labelToVarName instanceof Map ? labelToVarName : new Map();
|
|
376
|
-
let out = '';
|
|
377
|
-
let i = 0;
|
|
378
|
-
while (i < statement.length) {
|
|
379
|
-
const ch = statement[i];
|
|
380
|
-
if (ch === '"' || ch === "'") {
|
|
381
|
-
const str = readStringAt(statement, i);
|
|
382
|
-
out += str.text;
|
|
383
|
-
i = str.end;
|
|
384
|
-
continue;
|
|
385
|
-
}
|
|
386
|
-
if (ch === '<') {
|
|
387
|
-
const iri = readIriAt(statement, i);
|
|
388
|
-
out += iri.text;
|
|
389
|
-
i = iri.end;
|
|
390
|
-
continue;
|
|
391
|
-
}
|
|
392
|
-
if (ch === '#') {
|
|
393
|
-
while (i < statement.length) {
|
|
394
|
-
const c = statement[i++];
|
|
395
|
-
out += c;
|
|
396
|
-
if (c === '\n' || c === '\r') break;
|
|
397
|
-
}
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
if (statement.startsWith('_:', i)) {
|
|
401
|
-
let j = i + 2;
|
|
402
|
-
while (j < statement.length && !isWs(statement[j]) && !'{}[](),;.'.includes(statement[j])) j += 1;
|
|
403
|
-
const label = statement.slice(i + 2, j);
|
|
404
|
-
const mapped = label ? map.get(label) : null;
|
|
405
|
-
if (mapped) {
|
|
406
|
-
out += `?${mapped}`;
|
|
407
|
-
i = j;
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
out += ch;
|
|
412
|
-
i += 1;
|
|
413
|
-
}
|
|
414
|
-
return out.trim();
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function formatGraphWithMap(statements, labelMap) {
|
|
418
|
-
const body = (statements || [])
|
|
419
|
-
.map((st) => rewriteBlankMarksWithMap(st, labelMap))
|
|
420
|
-
.filter(Boolean)
|
|
421
|
-
.map((st) => ` ${st} .`)
|
|
422
|
-
.join('\n');
|
|
423
|
-
return body ? `{
|
|
424
|
-
${body}\n}` : '{ }';
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
function formatGraphFromRewritten(statements) {
|
|
428
|
-
const body = (statements || [])
|
|
429
|
-
.map((st) => String(st || '').trim())
|
|
430
|
-
.filter(Boolean)
|
|
431
|
-
.map((st) => ` ${st} .`)
|
|
432
|
-
.join('\n');
|
|
433
|
-
return body ? `{
|
|
434
|
-
${body}\n}` : '{ }';
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
function makeVarMap(labels, prefix = '') {
|
|
438
|
-
const map = new Map();
|
|
439
|
-
for (const label of labels || []) map.set(label, `${prefix}${label}`);
|
|
440
|
-
return map;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
function mergeVarMaps(...maps) {
|
|
444
|
-
const out = new Map();
|
|
445
|
-
for (const m of maps) {
|
|
446
|
-
for (const [k, v] of m.entries()) out.set(k, v);
|
|
447
|
-
}
|
|
448
|
-
return out;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function slide33ReverseAllValuesFromRule(node, inheritedMap = new Map(), extraPremises = []) {
|
|
452
|
-
const outerBinders = node.binders || [];
|
|
453
|
-
const own = node.statements || [];
|
|
454
|
-
const children = node.children || [];
|
|
455
|
-
|
|
456
|
-
if (own.length !== 0 || outerBinders.length === 0 || children.length !== 2) return null;
|
|
457
|
-
|
|
458
|
-
let bodyChild = null;
|
|
459
|
-
let headChild = null;
|
|
460
|
-
for (const child of children) {
|
|
461
|
-
const childChildren = child && child.children ? child.children : [];
|
|
462
|
-
if (childChildren.length === 1) bodyChild = child;
|
|
463
|
-
else if (childChildren.length === 0) headChild = child;
|
|
464
|
-
else return null;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
if (!bodyChild || !headChild) return null;
|
|
468
|
-
if (!bodyChild.statements || bodyChild.statements.length === 0) return null;
|
|
469
|
-
if (!headChild.statements || headChild.statements.length === 0) return null;
|
|
470
|
-
|
|
471
|
-
const thenChild = bodyChild.children[0];
|
|
472
|
-
if (!thenChild || (thenChild.children && thenChild.children.length)) return null;
|
|
473
|
-
if (!thenChild.statements || thenChild.statements.length === 0) return null;
|
|
474
|
-
|
|
475
|
-
const outerMap = mergeVarMaps(inheritedMap, makeVarMap(outerBinders));
|
|
476
|
-
const witnessMap = makeVarMap(bodyChild.binders || [], '__rs_witness_');
|
|
477
|
-
const localMap = makeVarMap(bodyChild.binders || [], '__rs_');
|
|
478
|
-
|
|
479
|
-
const mappedExtra = (extraPremises || [])
|
|
480
|
-
.map((st) => rewriteBlankMarksWithMap(st, outerMap))
|
|
481
|
-
.filter(Boolean);
|
|
482
|
-
const premiseStmts = bodyChild.statements
|
|
483
|
-
.map((st) => rewriteBlankMarksWithMap(st, mergeVarMaps(outerMap, witnessMap)))
|
|
484
|
-
.filter(Boolean);
|
|
485
|
-
|
|
486
|
-
const whereGraph = formatGraphWithMap(bodyChild.statements, mergeVarMaps(outerMap, localMap));
|
|
487
|
-
const thenGraph = formatGraphWithMap(thenChild.statements, mergeVarMaps(outerMap, localMap));
|
|
488
|
-
const forAllLine = `( ${whereGraph} ${thenGraph} ) ${LOG_FOR_ALL_IN_IRI} 1`;
|
|
489
|
-
|
|
490
|
-
const premise = formatGraphFromRewritten([...mappedExtra, ...premiseStmts, forAllLine]);
|
|
491
|
-
const conclusion = formatGraphWithMap(headChild.statements, outerMap);
|
|
492
|
-
return `${premise} => ${conclusion} .`;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
function translateHeadSurface(node, extraPremises, inheritedMap = new Map()) {
|
|
497
|
-
const rules = [];
|
|
498
|
-
const map = inheritedMap instanceof Map ? inheritedMap : new Map();
|
|
499
|
-
const own = node.statements || [];
|
|
500
|
-
if (own.length) {
|
|
501
|
-
rules.push(`${formatGraphWithMap(extraPremises, map)} => ${formatGraphWithMap(own, map)} .`);
|
|
502
|
-
}
|
|
503
|
-
for (const child of node.children || []) {
|
|
504
|
-
rules.push(...translateRuleSurface(child, extraPremises, map));
|
|
505
|
-
}
|
|
506
|
-
return rules;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
function translateRuleSurface(node, extraPremises = [], inheritedMap = new Map()) {
|
|
510
|
-
const slide33Reverse = slide33ReverseAllValuesFromRule(node, inheritedMap, extraPremises);
|
|
511
|
-
if (slide33Reverse) return [slide33Reverse];
|
|
512
|
-
|
|
513
|
-
const map = mergeVarMaps(inheritedMap, makeVarMap(node.binders || []));
|
|
514
|
-
const own = node.statements || [];
|
|
515
|
-
const premise = [...(extraPremises || []), ...own];
|
|
516
|
-
const children = node.children || [];
|
|
517
|
-
|
|
518
|
-
if (children.length === 0) {
|
|
519
|
-
return own.length ? [`${formatGraphWithMap(premise, map)} => false .`] : [];
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
return children.flatMap((child) => translateHeadSurface(child, premise, map));
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
function translateTopLevelSurface(node) {
|
|
526
|
-
const map = makeVarMap(node.binders || []);
|
|
527
|
-
const own = node.statements || [];
|
|
528
|
-
|
|
529
|
-
if (!node.children || node.children.length === 0) {
|
|
530
|
-
return own.length ? [`${formatGraphWithMap(own, map)} => false .`] : [];
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const slide33Reverse = slide33ReverseAllValuesFromRule(node);
|
|
534
|
-
if (slide33Reverse) return [slide33Reverse];
|
|
535
|
-
|
|
536
|
-
return node.children.flatMap((child) => translateHeadSurface(child, own, map));
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
function normalizeRdfSurfaces(inputText) {
|
|
540
|
-
const s = String(inputText ?? '');
|
|
541
|
-
if (!s.includes('%not[')) return s;
|
|
542
|
-
|
|
543
|
-
let out = '';
|
|
544
|
-
const generated = [];
|
|
545
|
-
let i = 0;
|
|
546
|
-
let braceDepth = 0;
|
|
547
|
-
let bracketDepth = 0;
|
|
548
|
-
let parenDepth = 0;
|
|
549
|
-
|
|
550
|
-
while (i < s.length) {
|
|
551
|
-
if (s.startsWith('%not[', i) && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
552
|
-
const surface = readSurfaceAt(s, i);
|
|
553
|
-
generated.push(...translateTopLevelSurface(surface));
|
|
554
|
-
i = surface.end;
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const ch = s[i];
|
|
559
|
-
if (ch === '"' || ch === "'") {
|
|
560
|
-
const str = readStringAt(s, i);
|
|
561
|
-
out += str.text;
|
|
562
|
-
i = str.end;
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
if (ch === '<') {
|
|
566
|
-
const iri = readIriAt(s, i);
|
|
567
|
-
out += iri.text;
|
|
568
|
-
i = iri.end;
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
if (ch === '#') {
|
|
572
|
-
while (i < s.length) {
|
|
573
|
-
const c = s[i++];
|
|
574
|
-
out += c;
|
|
575
|
-
if (c === '\n' || c === '\r') break;
|
|
576
|
-
}
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
if (ch === '{') braceDepth += 1;
|
|
581
|
-
else if (ch === '}' && braceDepth > 0) braceDepth -= 1;
|
|
582
|
-
else if (ch === '[') bracketDepth += 1;
|
|
583
|
-
else if (ch === ']' && bracketDepth > 0) bracketDepth -= 1;
|
|
584
|
-
else if (ch === '(') parenDepth += 1;
|
|
585
|
-
else if (ch === ')' && parenDepth > 0) parenDepth -= 1;
|
|
586
|
-
|
|
587
|
-
out += ch;
|
|
588
|
-
i += 1;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
if (generated.length === 0) return out;
|
|
592
|
-
const sep = out.trim() ? (out.endsWith('\n') ? '\n' : '\n\n') : '';
|
|
593
|
-
return out + sep + generated.join('\n\n') + '\n';
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
module.exports = {
|
|
597
|
-
normalizeRdfSurfaces,
|
|
598
|
-
};
|