eyeling 1.5.39 → 1.5.41
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/examples/cranberry-calculus.n3 +167 -0
- package/examples/output/cranberry-calculus.n3 +1334 -0
- package/eyeling.js +528 -840
- package/package.json +1 -1
package/eyeling.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
'use strict';
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* eyeling.js — a minimal Notation3 (N3) reasoner in JavaScript
|
|
@@ -16,29 +16,29 @@
|
|
|
16
16
|
* 5) Print only newly derived forward facts with explanations.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
const { version } = require(
|
|
20
|
-
const nodeCrypto = require(
|
|
19
|
+
const { version } = require('./package.json');
|
|
20
|
+
const nodeCrypto = require('crypto');
|
|
21
21
|
|
|
22
22
|
// ============================================================================
|
|
23
23
|
// Namespace constants
|
|
24
24
|
// ============================================================================
|
|
25
25
|
|
|
26
|
-
const RDF_NS =
|
|
27
|
-
const RDFS_NS =
|
|
28
|
-
const OWL_NS =
|
|
29
|
-
const XSD_NS =
|
|
30
|
-
const CRYPTO_NS =
|
|
31
|
-
const MATH_NS =
|
|
32
|
-
const TIME_NS =
|
|
33
|
-
const LIST_NS =
|
|
34
|
-
const LOG_NS =
|
|
35
|
-
const STRING_NS =
|
|
36
|
-
const SKOLEM_NS =
|
|
37
|
-
const RDF_JSON_DT = RDF_NS +
|
|
26
|
+
const RDF_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
27
|
+
const RDFS_NS = 'http://www.w3.org/2000/01/rdf-schema#';
|
|
28
|
+
const OWL_NS = 'http://www.w3.org/2002/07/owl#';
|
|
29
|
+
const XSD_NS = 'http://www.w3.org/2001/XMLSchema#';
|
|
30
|
+
const CRYPTO_NS = 'http://www.w3.org/2000/10/swap/crypto#';
|
|
31
|
+
const MATH_NS = 'http://www.w3.org/2000/10/swap/math#';
|
|
32
|
+
const TIME_NS = 'http://www.w3.org/2000/10/swap/time#';
|
|
33
|
+
const LIST_NS = 'http://www.w3.org/2000/10/swap/list#';
|
|
34
|
+
const LOG_NS = 'http://www.w3.org/2000/10/swap/log#';
|
|
35
|
+
const STRING_NS = 'http://www.w3.org/2000/10/swap/string#';
|
|
36
|
+
const SKOLEM_NS = 'https://eyereasoner.github.io/.well-known/genid/';
|
|
37
|
+
const RDF_JSON_DT = RDF_NS + 'JSON';
|
|
38
38
|
|
|
39
39
|
function isRdfJsonDatatype(dt) {
|
|
40
40
|
// dt comes from literalParts() and may be expanded or prefixed depending on parsing/printing.
|
|
41
|
-
return dt === null || dt === RDF_JSON_DT || dt ===
|
|
41
|
+
return dt === null || dt === RDF_JSON_DT || dt === 'rdf:JSON';
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function termToJsonText(t) {
|
|
@@ -52,9 +52,9 @@ function termToJsonText(t) {
|
|
|
52
52
|
function makeRdfJsonLiteral(jsonText) {
|
|
53
53
|
// Prefer a readable long literal when safe; fall back to short if needed.
|
|
54
54
|
if (!jsonText.includes('"""')) {
|
|
55
|
-
return new Literal('"""' + jsonText + '"""^^<' + RDF_JSON_DT +
|
|
55
|
+
return new Literal('"""' + jsonText + '"""^^<' + RDF_JSON_DT + '>');
|
|
56
56
|
}
|
|
57
|
-
return new Literal(JSON.stringify(jsonText) +
|
|
57
|
+
return new Literal(JSON.stringify(jsonText) + '^^<' + RDF_JSON_DT + '>');
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// For a single reasoning run, this maps a canonical representation
|
|
@@ -81,7 +81,7 @@ function normalizeDateTimeLex(s) {
|
|
|
81
81
|
// Accept: 2025-... , "2025-..." , "2025-..."^^xsd:dateTime , "..."^^<...>
|
|
82
82
|
if (s == null) return null;
|
|
83
83
|
let t = String(s).trim();
|
|
84
|
-
const caret = t.indexOf(
|
|
84
|
+
const caret = t.indexOf('^^');
|
|
85
85
|
if (caret >= 0) t = t.slice(0, caret).trim();
|
|
86
86
|
if (t.startsWith('"') && t.endsWith('"') && t.length >= 2) t = t.slice(1, -1);
|
|
87
87
|
return t.trim();
|
|
@@ -91,7 +91,7 @@ function utcIsoDateTimeStringFromEpochSeconds(sec) {
|
|
|
91
91
|
const ms = sec * 1000;
|
|
92
92
|
const d = new Date(ms);
|
|
93
93
|
function pad(n, w = 2) {
|
|
94
|
-
return String(n).padStart(w,
|
|
94
|
+
return String(n).padStart(w, '0');
|
|
95
95
|
}
|
|
96
96
|
const year = d.getUTCFullYear();
|
|
97
97
|
const month = d.getUTCMonth() + 1;
|
|
@@ -100,22 +100,8 @@ function utcIsoDateTimeStringFromEpochSeconds(sec) {
|
|
|
100
100
|
const min = d.getUTCMinutes();
|
|
101
101
|
const s2 = d.getUTCSeconds();
|
|
102
102
|
const ms2 = d.getUTCMilliseconds();
|
|
103
|
-
const msPart = ms2 ?
|
|
104
|
-
return (
|
|
105
|
-
pad(year, 4) +
|
|
106
|
-
"-" +
|
|
107
|
-
pad(month) +
|
|
108
|
-
"-" +
|
|
109
|
-
pad(day) +
|
|
110
|
-
"T" +
|
|
111
|
-
pad(hour) +
|
|
112
|
-
":" +
|
|
113
|
-
pad(min) +
|
|
114
|
-
":" +
|
|
115
|
-
pad(s2) +
|
|
116
|
-
msPart +
|
|
117
|
-
"+00:00"
|
|
118
|
-
);
|
|
103
|
+
const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
|
|
104
|
+
return pad(year, 4) + '-' + pad(month) + '-' + pad(day) + 'T' + pad(hour) + ':' + pad(min) + ':' + pad(s2) + msPart + '+00:00';
|
|
119
105
|
}
|
|
120
106
|
|
|
121
107
|
function getNowLex() {
|
|
@@ -150,22 +136,10 @@ function deterministicSkolemIdFromKey(key) {
|
|
|
150
136
|
h4 = (h4 * 0x01000193) >>> 0;
|
|
151
137
|
}
|
|
152
138
|
|
|
153
|
-
const hex = [h1, h2, h3, h4]
|
|
154
|
-
.map((h) => h.toString(16).padStart(8, "0"))
|
|
155
|
-
.join(""); // 32 hex chars
|
|
139
|
+
const hex = [h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, '0')).join(''); // 32 hex chars
|
|
156
140
|
|
|
157
141
|
// Format like a UUID: 8-4-4-4-12
|
|
158
|
-
return (
|
|
159
|
-
hex.slice(0, 8) +
|
|
160
|
-
"-" +
|
|
161
|
-
hex.slice(8, 12) +
|
|
162
|
-
"-" +
|
|
163
|
-
hex.slice(12, 16) +
|
|
164
|
-
"-" +
|
|
165
|
-
hex.slice(16, 20) +
|
|
166
|
-
"-" +
|
|
167
|
-
hex.slice(20)
|
|
168
|
-
);
|
|
142
|
+
return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
|
|
169
143
|
}
|
|
170
144
|
|
|
171
145
|
let runLocalTimeCache = null;
|
|
@@ -299,82 +273,82 @@ function lex(inputText) {
|
|
|
299
273
|
}
|
|
300
274
|
|
|
301
275
|
// 2) Comments starting with '#'
|
|
302
|
-
if (c ===
|
|
303
|
-
while (i < n && chars[i] !==
|
|
276
|
+
if (c === '#') {
|
|
277
|
+
while (i < n && chars[i] !== '\n' && chars[i] !== '\r') i++;
|
|
304
278
|
continue;
|
|
305
279
|
}
|
|
306
280
|
|
|
307
281
|
// 3) Two-character operators: => and <=
|
|
308
|
-
if (c ===
|
|
309
|
-
if (peek(1) ===
|
|
310
|
-
tokens.push(new Token(
|
|
282
|
+
if (c === '=') {
|
|
283
|
+
if (peek(1) === '>') {
|
|
284
|
+
tokens.push(new Token('OpImplies'));
|
|
311
285
|
i += 2;
|
|
312
286
|
continue;
|
|
313
287
|
} else {
|
|
314
288
|
// N3 syntactic sugar: '=' means owl:sameAs
|
|
315
|
-
tokens.push(new Token(
|
|
289
|
+
tokens.push(new Token('Equals'));
|
|
316
290
|
i += 1;
|
|
317
291
|
continue;
|
|
318
292
|
}
|
|
319
293
|
}
|
|
320
294
|
|
|
321
|
-
if (c ===
|
|
322
|
-
if (peek(1) ===
|
|
323
|
-
tokens.push(new Token(
|
|
295
|
+
if (c === '<') {
|
|
296
|
+
if (peek(1) === '=') {
|
|
297
|
+
tokens.push(new Token('OpImpliedBy'));
|
|
324
298
|
i += 2;
|
|
325
299
|
continue;
|
|
326
300
|
}
|
|
327
301
|
// N3 predicate inversion: "<-" (swap subject/object for this predicate)
|
|
328
|
-
if (peek(1) ===
|
|
329
|
-
tokens.push(new Token(
|
|
302
|
+
if (peek(1) === '-') {
|
|
303
|
+
tokens.push(new Token('OpPredInvert'));
|
|
330
304
|
i += 2;
|
|
331
305
|
continue;
|
|
332
306
|
}
|
|
333
307
|
// Otherwise IRIREF <...>
|
|
334
308
|
i++; // skip '<'
|
|
335
309
|
const iriChars = [];
|
|
336
|
-
while (i < n && chars[i] !==
|
|
310
|
+
while (i < n && chars[i] !== '>') {
|
|
337
311
|
iriChars.push(chars[i]);
|
|
338
312
|
i++;
|
|
339
313
|
}
|
|
340
|
-
if (i >= n || chars[i] !==
|
|
341
|
-
throw new Error(
|
|
314
|
+
if (i >= n || chars[i] !== '>') {
|
|
315
|
+
throw new Error('Unterminated IRI <...>');
|
|
342
316
|
}
|
|
343
317
|
i++; // skip '>'
|
|
344
|
-
const iri = iriChars.join(
|
|
345
|
-
tokens.push(new Token(
|
|
318
|
+
const iri = iriChars.join('');
|
|
319
|
+
tokens.push(new Token('IriRef', iri));
|
|
346
320
|
continue;
|
|
347
321
|
}
|
|
348
322
|
|
|
349
323
|
// 4) Path + datatype operators: !, ^, ^^
|
|
350
|
-
if (c ===
|
|
351
|
-
tokens.push(new Token(
|
|
324
|
+
if (c === '!') {
|
|
325
|
+
tokens.push(new Token('OpPathFwd'));
|
|
352
326
|
i += 1;
|
|
353
327
|
continue;
|
|
354
328
|
}
|
|
355
|
-
if (c ===
|
|
356
|
-
if (peek(1) ===
|
|
357
|
-
tokens.push(new Token(
|
|
329
|
+
if (c === '^') {
|
|
330
|
+
if (peek(1) === '^') {
|
|
331
|
+
tokens.push(new Token('HatHat'));
|
|
358
332
|
i += 2;
|
|
359
333
|
continue;
|
|
360
334
|
}
|
|
361
|
-
tokens.push(new Token(
|
|
335
|
+
tokens.push(new Token('OpPathRev'));
|
|
362
336
|
i += 1;
|
|
363
337
|
continue;
|
|
364
338
|
}
|
|
365
339
|
|
|
366
340
|
// 5) Single-character punctuation
|
|
367
|
-
if (
|
|
341
|
+
if ('{}()[];,.'.includes(c)) {
|
|
368
342
|
const mapping = {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
343
|
+
'{': 'LBrace',
|
|
344
|
+
'}': 'RBrace',
|
|
345
|
+
'(': 'LParen',
|
|
346
|
+
')': 'RParen',
|
|
347
|
+
'[': 'LBracket',
|
|
348
|
+
']': 'RBracket',
|
|
349
|
+
';': 'Semicolon',
|
|
350
|
+
',': 'Comma',
|
|
351
|
+
'.': 'Dot',
|
|
378
352
|
};
|
|
379
353
|
tokens.push(new Token(mapping[c]));
|
|
380
354
|
i++;
|
|
@@ -397,22 +371,21 @@ function lex(inputText) {
|
|
|
397
371
|
}
|
|
398
372
|
let cc = chars[i];
|
|
399
373
|
i++;
|
|
400
|
-
if (cc ===
|
|
374
|
+
if (cc === '\\') {
|
|
401
375
|
// Preserve escapes verbatim (same behavior as short strings)
|
|
402
376
|
if (i < n) {
|
|
403
377
|
const esc = chars[i];
|
|
404
378
|
i++;
|
|
405
|
-
sChars.push(
|
|
379
|
+
sChars.push('\\');
|
|
406
380
|
sChars.push(esc);
|
|
407
381
|
}
|
|
408
382
|
continue;
|
|
409
383
|
}
|
|
410
384
|
sChars.push(cc);
|
|
411
385
|
}
|
|
412
|
-
if (!closed)
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
tokens.push(new Token("Literal", s));
|
|
386
|
+
if (!closed) throw new Error('Unterminated long string literal """..."""');
|
|
387
|
+
const s = '"""' + sChars.join('') + '"""';
|
|
388
|
+
tokens.push(new Token('Literal', s));
|
|
416
389
|
continue;
|
|
417
390
|
}
|
|
418
391
|
|
|
@@ -422,11 +395,11 @@ function lex(inputText) {
|
|
|
422
395
|
while (i < n) {
|
|
423
396
|
let cc = chars[i];
|
|
424
397
|
i++;
|
|
425
|
-
if (cc ===
|
|
398
|
+
if (cc === '\\') {
|
|
426
399
|
if (i < n) {
|
|
427
400
|
const esc = chars[i];
|
|
428
401
|
i++;
|
|
429
|
-
sChars.push(
|
|
402
|
+
sChars.push('\\');
|
|
430
403
|
sChars.push(esc);
|
|
431
404
|
}
|
|
432
405
|
continue;
|
|
@@ -434,13 +407,13 @@ function lex(inputText) {
|
|
|
434
407
|
if (cc === '"') break;
|
|
435
408
|
sChars.push(cc);
|
|
436
409
|
}
|
|
437
|
-
const s = '"' + sChars.join(
|
|
438
|
-
tokens.push(new Token(
|
|
410
|
+
const s = '"' + sChars.join('') + '"';
|
|
411
|
+
tokens.push(new Token('Literal', s));
|
|
439
412
|
continue;
|
|
440
413
|
}
|
|
441
414
|
|
|
442
415
|
// Variable ?name
|
|
443
|
-
if (c ===
|
|
416
|
+
if (c === '?') {
|
|
444
417
|
i++;
|
|
445
418
|
const nameChars = [];
|
|
446
419
|
let cc;
|
|
@@ -448,19 +421,16 @@ function lex(inputText) {
|
|
|
448
421
|
nameChars.push(cc);
|
|
449
422
|
i++;
|
|
450
423
|
}
|
|
451
|
-
const name = nameChars.join(
|
|
452
|
-
tokens.push(new Token(
|
|
424
|
+
const name = nameChars.join('');
|
|
425
|
+
tokens.push(new Token('Var', name));
|
|
453
426
|
continue;
|
|
454
427
|
}
|
|
455
428
|
|
|
456
429
|
// Directives: @prefix, @base (and language tags after string literals)
|
|
457
|
-
if (c ===
|
|
430
|
+
if (c === '@') {
|
|
458
431
|
const prevTok = tokens.length ? tokens[tokens.length - 1] : null;
|
|
459
432
|
const prevWasQuotedLiteral =
|
|
460
|
-
prevTok &&
|
|
461
|
-
prevTok.typ === "Literal" &&
|
|
462
|
-
typeof prevTok.value === "string" &&
|
|
463
|
-
prevTok.value.startsWith('"');
|
|
433
|
+
prevTok && prevTok.typ === 'Literal' && typeof prevTok.value === 'string' && prevTok.value.startsWith('"');
|
|
464
434
|
|
|
465
435
|
i++; // consume '@'
|
|
466
436
|
|
|
@@ -476,8 +446,8 @@ function lex(inputText) {
|
|
|
476
446
|
tagChars.push(cc);
|
|
477
447
|
i++;
|
|
478
448
|
}
|
|
479
|
-
while (peek() ===
|
|
480
|
-
tagChars.push(
|
|
449
|
+
while (peek() === '-') {
|
|
450
|
+
tagChars.push('-');
|
|
481
451
|
i++; // consume '-'
|
|
482
452
|
const segChars = [];
|
|
483
453
|
while ((cc = peek()) !== null && /[A-Za-z0-9]/.test(cc)) {
|
|
@@ -485,13 +455,11 @@ function lex(inputText) {
|
|
|
485
455
|
i++;
|
|
486
456
|
}
|
|
487
457
|
if (!segChars.length) {
|
|
488
|
-
throw new Error(
|
|
489
|
-
"Invalid language tag (expected [A-Za-z0-9]+ after '-')",
|
|
490
|
-
);
|
|
458
|
+
throw new Error("Invalid language tag (expected [A-Za-z0-9]+ after '-')");
|
|
491
459
|
}
|
|
492
460
|
tagChars.push(...segChars);
|
|
493
461
|
}
|
|
494
|
-
tokens.push(new Token(
|
|
462
|
+
tokens.push(new Token('LangTag', tagChars.join('')));
|
|
495
463
|
continue;
|
|
496
464
|
}
|
|
497
465
|
|
|
@@ -502,18 +470,15 @@ function lex(inputText) {
|
|
|
502
470
|
wordChars.push(cc);
|
|
503
471
|
i++;
|
|
504
472
|
}
|
|
505
|
-
const word = wordChars.join(
|
|
506
|
-
if (word ===
|
|
507
|
-
else if (word ===
|
|
473
|
+
const word = wordChars.join('');
|
|
474
|
+
if (word === 'prefix') tokens.push(new Token('AtPrefix'));
|
|
475
|
+
else if (word === 'base') tokens.push(new Token('AtBase'));
|
|
508
476
|
else throw new Error(`Unknown directive @${word}`);
|
|
509
477
|
continue;
|
|
510
478
|
}
|
|
511
479
|
|
|
512
480
|
// 6) Numeric literal (integer or float)
|
|
513
|
-
if (
|
|
514
|
-
/[0-9]/.test(c) ||
|
|
515
|
-
(c === "-" && peek(1) !== null && /[0-9]/.test(peek(1)))
|
|
516
|
-
) {
|
|
481
|
+
if (/[0-9]/.test(c) || (c === '-' && peek(1) !== null && /[0-9]/.test(peek(1)))) {
|
|
517
482
|
const numChars = [c];
|
|
518
483
|
i++;
|
|
519
484
|
while (i < n) {
|
|
@@ -523,9 +488,9 @@ function lex(inputText) {
|
|
|
523
488
|
i++;
|
|
524
489
|
continue;
|
|
525
490
|
}
|
|
526
|
-
if (cc ===
|
|
491
|
+
if (cc === '.') {
|
|
527
492
|
if (i + 1 < n && /[0-9]/.test(chars[i + 1])) {
|
|
528
|
-
numChars.push(
|
|
493
|
+
numChars.push('.');
|
|
529
494
|
i++;
|
|
530
495
|
continue;
|
|
531
496
|
} else {
|
|
@@ -534,7 +499,7 @@ function lex(inputText) {
|
|
|
534
499
|
}
|
|
535
500
|
break;
|
|
536
501
|
}
|
|
537
|
-
tokens.push(new Token(
|
|
502
|
+
tokens.push(new Token('Literal', numChars.join('')));
|
|
538
503
|
continue;
|
|
539
504
|
}
|
|
540
505
|
|
|
@@ -548,17 +513,17 @@ function lex(inputText) {
|
|
|
548
513
|
if (!wordChars.length) {
|
|
549
514
|
throw new Error(`Unexpected char: ${JSON.stringify(c)}`);
|
|
550
515
|
}
|
|
551
|
-
const word = wordChars.join(
|
|
552
|
-
if (word ===
|
|
553
|
-
tokens.push(new Token(
|
|
516
|
+
const word = wordChars.join('');
|
|
517
|
+
if (word === 'true' || word === 'false') {
|
|
518
|
+
tokens.push(new Token('Literal', word));
|
|
554
519
|
} else if ([...word].every((ch) => /[0-9.\-]/.test(ch))) {
|
|
555
|
-
tokens.push(new Token(
|
|
520
|
+
tokens.push(new Token('Literal', word));
|
|
556
521
|
} else {
|
|
557
|
-
tokens.push(new Token(
|
|
522
|
+
tokens.push(new Token('Ident', word));
|
|
558
523
|
}
|
|
559
524
|
}
|
|
560
525
|
|
|
561
|
-
tokens.push(new Token(
|
|
526
|
+
tokens.push(new Token('EOF'));
|
|
562
527
|
return tokens;
|
|
563
528
|
}
|
|
564
529
|
|
|
@@ -573,16 +538,16 @@ class PrefixEnv {
|
|
|
573
538
|
|
|
574
539
|
static newDefault() {
|
|
575
540
|
const m = {};
|
|
576
|
-
m[
|
|
577
|
-
m[
|
|
578
|
-
m[
|
|
579
|
-
m[
|
|
580
|
-
m[
|
|
581
|
-
m[
|
|
582
|
-
m[
|
|
583
|
-
m[
|
|
584
|
-
m[
|
|
585
|
-
m[
|
|
541
|
+
m['rdf'] = RDF_NS;
|
|
542
|
+
m['rdfs'] = RDFS_NS;
|
|
543
|
+
m['xsd'] = XSD_NS;
|
|
544
|
+
m['log'] = LOG_NS;
|
|
545
|
+
m['math'] = MATH_NS;
|
|
546
|
+
m['string'] = STRING_NS;
|
|
547
|
+
m['list'] = LIST_NS;
|
|
548
|
+
m['time'] = TIME_NS;
|
|
549
|
+
m['genid'] = SKOLEM_NS;
|
|
550
|
+
m[''] = '';
|
|
586
551
|
return new PrefixEnv(m);
|
|
587
552
|
}
|
|
588
553
|
|
|
@@ -591,9 +556,9 @@ class PrefixEnv {
|
|
|
591
556
|
}
|
|
592
557
|
|
|
593
558
|
expandQName(q) {
|
|
594
|
-
if (q.includes(
|
|
595
|
-
const [p, local] = q.split(
|
|
596
|
-
const base = this.map[p] ||
|
|
559
|
+
if (q.includes(':')) {
|
|
560
|
+
const [p, local] = q.split(':', 2);
|
|
561
|
+
const base = this.map[p] || '';
|
|
597
562
|
if (base) return base + local;
|
|
598
563
|
return q;
|
|
599
564
|
}
|
|
@@ -613,7 +578,7 @@ class PrefixEnv {
|
|
|
613
578
|
}
|
|
614
579
|
if (best === null) return null;
|
|
615
580
|
const [p, local] = best;
|
|
616
|
-
if (p ===
|
|
581
|
+
if (p === '') return `:${local}`;
|
|
617
582
|
return `${p}:${local}`;
|
|
618
583
|
}
|
|
619
584
|
|
|
@@ -745,7 +710,7 @@ class Parser {
|
|
|
745
710
|
|
|
746
711
|
expectDot() {
|
|
747
712
|
const tok = this.next();
|
|
748
|
-
if (tok.typ !==
|
|
713
|
+
if (tok.typ !== 'Dot') {
|
|
749
714
|
throw new Error(`Expected '.', got ${tok.toString()}`);
|
|
750
715
|
}
|
|
751
716
|
}
|
|
@@ -755,21 +720,21 @@ class Parser {
|
|
|
755
720
|
const forwardRules = [];
|
|
756
721
|
const backwardRules = [];
|
|
757
722
|
|
|
758
|
-
while (this.peek().typ !==
|
|
759
|
-
if (this.peek().typ ===
|
|
723
|
+
while (this.peek().typ !== 'EOF') {
|
|
724
|
+
if (this.peek().typ === 'AtPrefix') {
|
|
760
725
|
this.next();
|
|
761
726
|
this.parsePrefixDirective();
|
|
762
|
-
} else if (this.peek().typ ===
|
|
727
|
+
} else if (this.peek().typ === 'AtBase') {
|
|
763
728
|
this.next();
|
|
764
729
|
this.parseBaseDirective();
|
|
765
730
|
} else {
|
|
766
731
|
const first = this.parseTerm();
|
|
767
|
-
if (this.peek().typ ===
|
|
732
|
+
if (this.peek().typ === 'OpImplies') {
|
|
768
733
|
this.next();
|
|
769
734
|
const second = this.parseTerm();
|
|
770
735
|
this.expectDot();
|
|
771
736
|
forwardRules.push(this.makeRule(first, second, true));
|
|
772
|
-
} else if (this.peek().typ ===
|
|
737
|
+
} else if (this.peek().typ === 'OpImpliedBy') {
|
|
773
738
|
this.next();
|
|
774
739
|
const second = this.parseTerm();
|
|
775
740
|
this.expectDot();
|
|
@@ -777,21 +742,15 @@ class Parser {
|
|
|
777
742
|
} else {
|
|
778
743
|
let more;
|
|
779
744
|
|
|
780
|
-
if (this.peek().typ ===
|
|
745
|
+
if (this.peek().typ === 'Dot') {
|
|
781
746
|
// Allow a bare blank-node property list statement, e.g. `[ a :Statement ].`
|
|
782
747
|
const lastTok = this.toks[this.pos - 1];
|
|
783
|
-
if (
|
|
784
|
-
this.pendingTriples.length > 0 &&
|
|
785
|
-
lastTok &&
|
|
786
|
-
lastTok.typ === "RBracket"
|
|
787
|
-
) {
|
|
748
|
+
if (this.pendingTriples.length > 0 && lastTok && lastTok.typ === 'RBracket') {
|
|
788
749
|
more = this.pendingTriples;
|
|
789
750
|
this.pendingTriples = [];
|
|
790
751
|
this.next(); // consume '.'
|
|
791
752
|
} else {
|
|
792
|
-
throw new Error(
|
|
793
|
-
`Unexpected '.' after term; missing predicate/object list`,
|
|
794
|
-
);
|
|
753
|
+
throw new Error(`Unexpected '.' after term; missing predicate/object list`);
|
|
795
754
|
}
|
|
796
755
|
} else {
|
|
797
756
|
more = this.parsePredicateObjectList(first);
|
|
@@ -800,17 +759,9 @@ class Parser {
|
|
|
800
759
|
|
|
801
760
|
// normalize explicit log:implies / log:impliedBy at top-level
|
|
802
761
|
for (const tr of more) {
|
|
803
|
-
if (
|
|
804
|
-
isLogImplies(tr.p) &&
|
|
805
|
-
tr.s instanceof FormulaTerm &&
|
|
806
|
-
tr.o instanceof FormulaTerm
|
|
807
|
-
) {
|
|
762
|
+
if (isLogImplies(tr.p) && tr.s instanceof FormulaTerm && tr.o instanceof FormulaTerm) {
|
|
808
763
|
forwardRules.push(this.makeRule(tr.s, tr.o, true));
|
|
809
|
-
} else if (
|
|
810
|
-
isLogImpliedBy(tr.p) &&
|
|
811
|
-
tr.s instanceof FormulaTerm &&
|
|
812
|
-
tr.o instanceof FormulaTerm
|
|
813
|
-
) {
|
|
764
|
+
} else if (isLogImpliedBy(tr.p) && tr.s instanceof FormulaTerm && tr.o instanceof FormulaTerm) {
|
|
814
765
|
backwardRules.push(this.makeRule(tr.s, tr.o, false));
|
|
815
766
|
} else {
|
|
816
767
|
triples.push(tr);
|
|
@@ -825,26 +776,26 @@ class Parser {
|
|
|
825
776
|
|
|
826
777
|
parsePrefixDirective() {
|
|
827
778
|
const tok = this.next();
|
|
828
|
-
if (tok.typ !==
|
|
779
|
+
if (tok.typ !== 'Ident') {
|
|
829
780
|
throw new Error(`Expected prefix name, got ${tok.toString()}`);
|
|
830
781
|
}
|
|
831
|
-
const pref = tok.value ||
|
|
832
|
-
const prefName = pref.endsWith(
|
|
782
|
+
const pref = tok.value || '';
|
|
783
|
+
const prefName = pref.endsWith(':') ? pref.slice(0, -1) : pref;
|
|
833
784
|
|
|
834
|
-
if (this.peek().typ ===
|
|
785
|
+
if (this.peek().typ === 'Dot') {
|
|
835
786
|
this.next();
|
|
836
787
|
if (!this.prefixes.map.hasOwnProperty(prefName)) {
|
|
837
|
-
this.prefixes.set(prefName,
|
|
788
|
+
this.prefixes.set(prefName, '');
|
|
838
789
|
}
|
|
839
790
|
return;
|
|
840
791
|
}
|
|
841
792
|
|
|
842
793
|
const tok2 = this.next();
|
|
843
794
|
let iri;
|
|
844
|
-
if (tok2.typ ===
|
|
845
|
-
iri = tok2.value ||
|
|
846
|
-
} else if (tok2.typ ===
|
|
847
|
-
iri = this.prefixes.expandQName(tok2.value ||
|
|
795
|
+
if (tok2.typ === 'IriRef') {
|
|
796
|
+
iri = tok2.value || '';
|
|
797
|
+
} else if (tok2.typ === 'Ident') {
|
|
798
|
+
iri = this.prefixes.expandQName(tok2.value || '');
|
|
848
799
|
} else {
|
|
849
800
|
throw new Error(`Expected IRI after @prefix, got ${tok2.toString()}`);
|
|
850
801
|
}
|
|
@@ -855,30 +806,28 @@ class Parser {
|
|
|
855
806
|
parseBaseDirective() {
|
|
856
807
|
const tok = this.next();
|
|
857
808
|
let iri;
|
|
858
|
-
if (tok.typ ===
|
|
859
|
-
iri = tok.value ||
|
|
860
|
-
} else if (tok.typ ===
|
|
861
|
-
iri = tok.value ||
|
|
809
|
+
if (tok.typ === 'IriRef') {
|
|
810
|
+
iri = tok.value || '';
|
|
811
|
+
} else if (tok.typ === 'Ident') {
|
|
812
|
+
iri = tok.value || '';
|
|
862
813
|
} else {
|
|
863
814
|
throw new Error(`Expected IRI after @base, got ${tok.toString()}`);
|
|
864
815
|
}
|
|
865
816
|
this.expectDot();
|
|
866
|
-
this.prefixes.set(
|
|
817
|
+
this.prefixes.set('', iri);
|
|
867
818
|
}
|
|
868
819
|
|
|
869
820
|
parseTerm() {
|
|
870
821
|
let t = this.parsePathItem();
|
|
871
822
|
|
|
872
|
-
while (this.peek().typ ===
|
|
823
|
+
while (this.peek().typ === 'OpPathFwd' || this.peek().typ === 'OpPathRev') {
|
|
873
824
|
const dir = this.next().typ; // OpPathFwd | OpPathRev
|
|
874
825
|
const pred = this.parsePathItem();
|
|
875
826
|
|
|
876
827
|
this.blankCounter += 1;
|
|
877
828
|
const bn = new Blank(`_:b${this.blankCounter}`);
|
|
878
829
|
|
|
879
|
-
this.pendingTriples.push(
|
|
880
|
-
dir === "OpPathFwd" ? new Triple(t, pred, bn) : new Triple(bn, pred, t),
|
|
881
|
-
);
|
|
830
|
+
this.pendingTriples.push(dir === 'OpPathFwd' ? new Triple(t, pred, bn) : new Triple(bn, pred, t));
|
|
882
831
|
|
|
883
832
|
t = bn;
|
|
884
833
|
}
|
|
@@ -891,81 +840,75 @@ class Parser {
|
|
|
891
840
|
const typ = tok.typ;
|
|
892
841
|
const val = tok.value;
|
|
893
842
|
|
|
894
|
-
if (typ ===
|
|
895
|
-
return new Iri(OWL_NS +
|
|
843
|
+
if (typ === 'Equals') {
|
|
844
|
+
return new Iri(OWL_NS + 'sameAs');
|
|
896
845
|
}
|
|
897
846
|
|
|
898
|
-
if (typ ===
|
|
899
|
-
return new Iri(val ||
|
|
847
|
+
if (typ === 'IriRef') {
|
|
848
|
+
return new Iri(val || '');
|
|
900
849
|
}
|
|
901
850
|
|
|
902
|
-
if (typ ===
|
|
903
|
-
const name = val ||
|
|
904
|
-
if (name ===
|
|
905
|
-
return new Iri(RDF_NS +
|
|
906
|
-
} else if (name.startsWith(
|
|
851
|
+
if (typ === 'Ident') {
|
|
852
|
+
const name = val || '';
|
|
853
|
+
if (name === 'a') {
|
|
854
|
+
return new Iri(RDF_NS + 'type');
|
|
855
|
+
} else if (name.startsWith('_:')) {
|
|
907
856
|
return new Blank(name);
|
|
908
|
-
} else if (name.includes(
|
|
857
|
+
} else if (name.includes(':')) {
|
|
909
858
|
return new Iri(this.prefixes.expandQName(name));
|
|
910
859
|
} else {
|
|
911
860
|
return new Iri(name);
|
|
912
861
|
}
|
|
913
862
|
}
|
|
914
863
|
|
|
915
|
-
if (typ ===
|
|
916
|
-
let s = val ||
|
|
864
|
+
if (typ === 'Literal') {
|
|
865
|
+
let s = val || '';
|
|
917
866
|
|
|
918
867
|
// Optional language tag: "..."@en, per N3 LANGTAG production.
|
|
919
|
-
if (this.peek().typ ===
|
|
868
|
+
if (this.peek().typ === 'LangTag') {
|
|
920
869
|
// Only quoted string literals can carry a language tag.
|
|
921
870
|
if (!(s.startsWith('"') && s.endsWith('"'))) {
|
|
922
|
-
throw new Error(
|
|
923
|
-
"Language tag is only allowed on quoted string literals",
|
|
924
|
-
);
|
|
871
|
+
throw new Error('Language tag is only allowed on quoted string literals');
|
|
925
872
|
}
|
|
926
873
|
const langTok = this.next();
|
|
927
|
-
const lang = langTok.value ||
|
|
874
|
+
const lang = langTok.value || '';
|
|
928
875
|
s = `${s}@${lang}`;
|
|
929
876
|
|
|
930
877
|
// N3/Turtle: language tags and datatypes are mutually exclusive.
|
|
931
|
-
if (this.peek().typ ===
|
|
932
|
-
throw new Error(
|
|
933
|
-
"A literal cannot have both a language tag (@...) and a datatype (^^...)",
|
|
934
|
-
);
|
|
878
|
+
if (this.peek().typ === 'HatHat') {
|
|
879
|
+
throw new Error('A literal cannot have both a language tag (@...) and a datatype (^^...)');
|
|
935
880
|
}
|
|
936
881
|
}
|
|
937
882
|
|
|
938
|
-
if (this.peek().typ ===
|
|
883
|
+
if (this.peek().typ === 'HatHat') {
|
|
939
884
|
this.next();
|
|
940
885
|
const dtTok = this.next();
|
|
941
886
|
let dtIri;
|
|
942
|
-
if (dtTok.typ ===
|
|
943
|
-
dtIri = dtTok.value ||
|
|
944
|
-
} else if (dtTok.typ ===
|
|
945
|
-
const qn = dtTok.value ||
|
|
946
|
-
if (qn.includes(
|
|
887
|
+
if (dtTok.typ === 'IriRef') {
|
|
888
|
+
dtIri = dtTok.value || '';
|
|
889
|
+
} else if (dtTok.typ === 'Ident') {
|
|
890
|
+
const qn = dtTok.value || '';
|
|
891
|
+
if (qn.includes(':')) dtIri = this.prefixes.expandQName(qn);
|
|
947
892
|
else dtIri = qn;
|
|
948
893
|
} else {
|
|
949
|
-
throw new Error(
|
|
950
|
-
`Expected datatype after ^^, got ${dtTok.toString()}`,
|
|
951
|
-
);
|
|
894
|
+
throw new Error(`Expected datatype after ^^, got ${dtTok.toString()}`);
|
|
952
895
|
}
|
|
953
896
|
s = `${s}^^<${dtIri}>`;
|
|
954
897
|
}
|
|
955
898
|
return new Literal(s);
|
|
956
899
|
}
|
|
957
900
|
|
|
958
|
-
if (typ ===
|
|
959
|
-
if (typ ===
|
|
960
|
-
if (typ ===
|
|
961
|
-
if (typ ===
|
|
901
|
+
if (typ === 'Var') return new Var(val || '');
|
|
902
|
+
if (typ === 'LParen') return this.parseList();
|
|
903
|
+
if (typ === 'LBracket') return this.parseBlank();
|
|
904
|
+
if (typ === 'LBrace') return this.parseFormula();
|
|
962
905
|
|
|
963
906
|
throw new Error(`Unexpected term token: ${tok.toString()}`);
|
|
964
907
|
}
|
|
965
908
|
|
|
966
909
|
parseList() {
|
|
967
910
|
const elems = [];
|
|
968
|
-
while (this.peek().typ !==
|
|
911
|
+
while (this.peek().typ !== 'RParen') {
|
|
969
912
|
elems.push(this.parseTerm());
|
|
970
913
|
}
|
|
971
914
|
this.next(); // consume ')'
|
|
@@ -974,7 +917,7 @@ class Parser {
|
|
|
974
917
|
|
|
975
918
|
parseBlank() {
|
|
976
919
|
// [] or [ ... ] property list
|
|
977
|
-
if (this.peek().typ ===
|
|
920
|
+
if (this.peek().typ === 'RBracket') {
|
|
978
921
|
this.next();
|
|
979
922
|
this.blankCounter += 1;
|
|
980
923
|
return new Blank(`_:b${this.blankCounter}`);
|
|
@@ -989,10 +932,10 @@ class Parser {
|
|
|
989
932
|
// Verb (can also be 'a')
|
|
990
933
|
let pred;
|
|
991
934
|
let invert = false;
|
|
992
|
-
if (this.peek().typ ===
|
|
935
|
+
if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
|
|
993
936
|
this.next();
|
|
994
|
-
pred = new Iri(RDF_NS +
|
|
995
|
-
} else if (this.peek().typ ===
|
|
937
|
+
pred = new Iri(RDF_NS + 'type');
|
|
938
|
+
} else if (this.peek().typ === 'OpPredInvert') {
|
|
996
939
|
this.next(); // consume "<-"
|
|
997
940
|
pred = this.parseTerm();
|
|
998
941
|
invert = true;
|
|
@@ -1002,33 +945,27 @@ class Parser {
|
|
|
1002
945
|
|
|
1003
946
|
// Object list: o1, o2, ...
|
|
1004
947
|
const objs = [this.parseTerm()];
|
|
1005
|
-
while (this.peek().typ ===
|
|
948
|
+
while (this.peek().typ === 'Comma') {
|
|
1006
949
|
this.next();
|
|
1007
950
|
objs.push(this.parseTerm());
|
|
1008
951
|
}
|
|
1009
952
|
|
|
1010
953
|
for (const o of objs) {
|
|
1011
|
-
this.pendingTriples.push(
|
|
1012
|
-
invert ? new Triple(o, pred, subj) : new Triple(subj, pred, o),
|
|
1013
|
-
);
|
|
954
|
+
this.pendingTriples.push(invert ? new Triple(o, pred, subj) : new Triple(subj, pred, o));
|
|
1014
955
|
}
|
|
1015
956
|
|
|
1016
|
-
if (this.peek().typ ===
|
|
957
|
+
if (this.peek().typ === 'Semicolon') {
|
|
1017
958
|
this.next();
|
|
1018
|
-
if (this.peek().typ ===
|
|
959
|
+
if (this.peek().typ === 'RBracket') break;
|
|
1019
960
|
continue;
|
|
1020
961
|
}
|
|
1021
962
|
break;
|
|
1022
963
|
}
|
|
1023
964
|
|
|
1024
|
-
if (this.peek().typ ===
|
|
965
|
+
if (this.peek().typ === 'RBracket') {
|
|
1025
966
|
this.next();
|
|
1026
967
|
} else {
|
|
1027
|
-
throw new Error(
|
|
1028
|
-
`Expected ']' at end of blank node property list, got ${JSON.stringify(
|
|
1029
|
-
this.peek(),
|
|
1030
|
-
)}`,
|
|
1031
|
-
);
|
|
968
|
+
throw new Error(`Expected ']' at end of blank node property list, got ${JSON.stringify(this.peek())}`);
|
|
1032
969
|
}
|
|
1033
970
|
|
|
1034
971
|
return new Blank(id);
|
|
@@ -1036,49 +973,45 @@ class Parser {
|
|
|
1036
973
|
|
|
1037
974
|
parseFormula() {
|
|
1038
975
|
const triples = [];
|
|
1039
|
-
while (this.peek().typ !==
|
|
976
|
+
while (this.peek().typ !== 'RBrace') {
|
|
1040
977
|
const left = this.parseTerm();
|
|
1041
|
-
if (this.peek().typ ===
|
|
978
|
+
if (this.peek().typ === 'OpImplies') {
|
|
1042
979
|
this.next();
|
|
1043
980
|
const right = this.parseTerm();
|
|
1044
|
-
const pred = new Iri(LOG_NS +
|
|
981
|
+
const pred = new Iri(LOG_NS + 'implies');
|
|
1045
982
|
triples.push(new Triple(left, pred, right));
|
|
1046
|
-
if (this.peek().typ ===
|
|
1047
|
-
else if (this.peek().typ ===
|
|
983
|
+
if (this.peek().typ === 'Dot') this.next();
|
|
984
|
+
else if (this.peek().typ === 'RBrace') {
|
|
1048
985
|
// ok
|
|
1049
986
|
} else {
|
|
1050
987
|
throw new Error(`Expected '.' or '}', got ${this.peek().toString()}`);
|
|
1051
988
|
}
|
|
1052
|
-
} else if (this.peek().typ ===
|
|
989
|
+
} else if (this.peek().typ === 'OpImpliedBy') {
|
|
1053
990
|
this.next();
|
|
1054
991
|
const right = this.parseTerm();
|
|
1055
|
-
const pred = new Iri(LOG_NS +
|
|
992
|
+
const pred = new Iri(LOG_NS + 'impliedBy');
|
|
1056
993
|
triples.push(new Triple(left, pred, right));
|
|
1057
|
-
if (this.peek().typ ===
|
|
1058
|
-
else if (this.peek().typ ===
|
|
994
|
+
if (this.peek().typ === 'Dot') this.next();
|
|
995
|
+
else if (this.peek().typ === 'RBrace') {
|
|
1059
996
|
// ok
|
|
1060
997
|
} else {
|
|
1061
998
|
throw new Error(`Expected '.' or '}', got ${this.peek().toString()}`);
|
|
1062
999
|
}
|
|
1063
1000
|
} else {
|
|
1064
1001
|
// Allow a bare blank-node property list statement inside a formula, e.g. `{ [ a :X ]. }`
|
|
1065
|
-
if (this.peek().typ ===
|
|
1002
|
+
if (this.peek().typ === 'Dot' || this.peek().typ === 'RBrace') {
|
|
1066
1003
|
const lastTok = this.toks[this.pos - 1];
|
|
1067
|
-
if (
|
|
1068
|
-
this.pendingTriples.length > 0 &&
|
|
1069
|
-
lastTok &&
|
|
1070
|
-
lastTok.typ === "RBracket"
|
|
1071
|
-
) {
|
|
1004
|
+
if (this.pendingTriples.length > 0 && lastTok && lastTok.typ === 'RBracket') {
|
|
1072
1005
|
triples.push(...this.pendingTriples);
|
|
1073
1006
|
this.pendingTriples = [];
|
|
1074
|
-
if (this.peek().typ ===
|
|
1007
|
+
if (this.peek().typ === 'Dot') this.next();
|
|
1075
1008
|
continue;
|
|
1076
1009
|
}
|
|
1077
1010
|
}
|
|
1078
1011
|
|
|
1079
1012
|
triples.push(...this.parsePredicateObjectList(left));
|
|
1080
|
-
if (this.peek().typ ===
|
|
1081
|
-
else if (this.peek().typ ===
|
|
1013
|
+
if (this.peek().typ === 'Dot') this.next();
|
|
1014
|
+
else if (this.peek().typ === 'RBrace') {
|
|
1082
1015
|
// ok
|
|
1083
1016
|
} else {
|
|
1084
1017
|
throw new Error(`Expected '.' or '}', got ${this.peek().toString()}`);
|
|
@@ -1102,10 +1035,10 @@ class Parser {
|
|
|
1102
1035
|
let verb;
|
|
1103
1036
|
let invert = false;
|
|
1104
1037
|
|
|
1105
|
-
if (this.peek().typ ===
|
|
1038
|
+
if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
|
|
1106
1039
|
this.next();
|
|
1107
|
-
verb = new Iri(RDF_NS +
|
|
1108
|
-
} else if (this.peek().typ ===
|
|
1040
|
+
verb = new Iri(RDF_NS + 'type');
|
|
1041
|
+
} else if (this.peek().typ === 'OpPredInvert') {
|
|
1109
1042
|
this.next(); // "<-"
|
|
1110
1043
|
verb = this.parseTerm();
|
|
1111
1044
|
invert = true;
|
|
@@ -1126,9 +1059,9 @@ class Parser {
|
|
|
1126
1059
|
out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
|
|
1127
1060
|
}
|
|
1128
1061
|
|
|
1129
|
-
if (this.peek().typ ===
|
|
1062
|
+
if (this.peek().typ === 'Semicolon') {
|
|
1130
1063
|
this.next();
|
|
1131
|
-
if (this.peek().typ ===
|
|
1064
|
+
if (this.peek().typ === 'Dot') break;
|
|
1132
1065
|
continue;
|
|
1133
1066
|
}
|
|
1134
1067
|
break;
|
|
@@ -1139,7 +1072,7 @@ class Parser {
|
|
|
1139
1072
|
|
|
1140
1073
|
parseObjectList() {
|
|
1141
1074
|
const objs = [this.parseTerm()];
|
|
1142
|
-
while (this.peek().typ ===
|
|
1075
|
+
while (this.peek().typ === 'Comma') {
|
|
1143
1076
|
this.next();
|
|
1144
1077
|
objs.push(this.parseTerm());
|
|
1145
1078
|
}
|
|
@@ -1159,7 +1092,7 @@ class Parser {
|
|
|
1159
1092
|
|
|
1160
1093
|
let isFuse = false;
|
|
1161
1094
|
if (isForward) {
|
|
1162
|
-
if (conclTerm instanceof Literal && conclTerm.value ===
|
|
1095
|
+
if (conclTerm instanceof Literal && conclTerm.value === 'false') {
|
|
1163
1096
|
isFuse = true;
|
|
1164
1097
|
}
|
|
1165
1098
|
}
|
|
@@ -1167,7 +1100,7 @@ class Parser {
|
|
|
1167
1100
|
let rawPremise;
|
|
1168
1101
|
if (premiseTerm instanceof FormulaTerm) {
|
|
1169
1102
|
rawPremise = premiseTerm.triples;
|
|
1170
|
-
} else if (premiseTerm instanceof Literal && premiseTerm.value ===
|
|
1103
|
+
} else if (premiseTerm instanceof Literal && premiseTerm.value === 'true') {
|
|
1171
1104
|
rawPremise = [];
|
|
1172
1105
|
} else {
|
|
1173
1106
|
rawPremise = [];
|
|
@@ -1176,7 +1109,7 @@ class Parser {
|
|
|
1176
1109
|
let rawConclusion;
|
|
1177
1110
|
if (conclTerm instanceof FormulaTerm) {
|
|
1178
1111
|
rawConclusion = conclTerm.triples;
|
|
1179
|
-
} else if (conclTerm instanceof Literal && conclTerm.value ===
|
|
1112
|
+
} else if (conclTerm instanceof Literal && conclTerm.value === 'false') {
|
|
1180
1113
|
rawConclusion = [];
|
|
1181
1114
|
} else {
|
|
1182
1115
|
rawConclusion = [];
|
|
@@ -1188,9 +1121,7 @@ class Parser {
|
|
|
1188
1121
|
const [premise0, conclusion] = liftBlankRuleVars(rawPremise, rawConclusion);
|
|
1189
1122
|
|
|
1190
1123
|
// Reorder constraints for *forward* rules.
|
|
1191
|
-
const premise = isForward
|
|
1192
|
-
? reorderPremiseForConstraints(premise0)
|
|
1193
|
-
: premise0;
|
|
1124
|
+
const premise = isForward ? reorderPremiseForConstraints(premise0) : premise0;
|
|
1194
1125
|
|
|
1195
1126
|
return new Rule(premise, conclusion, isForward, isFuse, headBlankLabels);
|
|
1196
1127
|
}
|
|
@@ -1221,12 +1152,7 @@ function liftBlankRuleVars(premise, conclusion) {
|
|
|
1221
1152
|
}
|
|
1222
1153
|
if (t instanceof FormulaTerm) {
|
|
1223
1154
|
const triples = t.triples.map(
|
|
1224
|
-
(tr) =>
|
|
1225
|
-
new Triple(
|
|
1226
|
-
convertTerm(tr.s, mapping, counter),
|
|
1227
|
-
convertTerm(tr.p, mapping, counter),
|
|
1228
|
-
convertTerm(tr.o, mapping, counter),
|
|
1229
|
-
),
|
|
1155
|
+
(tr) => new Triple(convertTerm(tr.s, mapping, counter), convertTerm(tr.p, mapping, counter), convertTerm(tr.o, mapping, counter)),
|
|
1230
1156
|
);
|
|
1231
1157
|
return new FormulaTerm(triples);
|
|
1232
1158
|
}
|
|
@@ -1234,11 +1160,7 @@ function liftBlankRuleVars(premise, conclusion) {
|
|
|
1234
1160
|
}
|
|
1235
1161
|
|
|
1236
1162
|
function convertTriple(tr, mapping, counter) {
|
|
1237
|
-
return new Triple(
|
|
1238
|
-
convertTerm(tr.s, mapping, counter),
|
|
1239
|
-
convertTerm(tr.p, mapping, counter),
|
|
1240
|
-
convertTerm(tr.o, mapping, counter),
|
|
1241
|
-
);
|
|
1163
|
+
return new Triple(convertTerm(tr.s, mapping, counter), convertTerm(tr.p, mapping, counter), convertTerm(tr.o, mapping, counter));
|
|
1242
1164
|
}
|
|
1243
1165
|
|
|
1244
1166
|
const mapping = {};
|
|
@@ -1263,28 +1185,18 @@ function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter) {
|
|
|
1263
1185
|
}
|
|
1264
1186
|
|
|
1265
1187
|
if (t instanceof ListTerm) {
|
|
1266
|
-
return new ListTerm(
|
|
1267
|
-
t.elems.map((e) =>
|
|
1268
|
-
skolemizeTermForHeadBlanks(e, headBlankLabels, mapping, skCounter),
|
|
1269
|
-
),
|
|
1270
|
-
);
|
|
1188
|
+
return new ListTerm(t.elems.map((e) => skolemizeTermForHeadBlanks(e, headBlankLabels, mapping, skCounter)));
|
|
1271
1189
|
}
|
|
1272
1190
|
|
|
1273
1191
|
if (t instanceof OpenListTerm) {
|
|
1274
1192
|
return new OpenListTerm(
|
|
1275
|
-
t.prefix.map((e) =>
|
|
1276
|
-
skolemizeTermForHeadBlanks(e, headBlankLabels, mapping, skCounter),
|
|
1277
|
-
),
|
|
1193
|
+
t.prefix.map((e) => skolemizeTermForHeadBlanks(e, headBlankLabels, mapping, skCounter)),
|
|
1278
1194
|
t.tailVar,
|
|
1279
1195
|
);
|
|
1280
1196
|
}
|
|
1281
1197
|
|
|
1282
1198
|
if (t instanceof FormulaTerm) {
|
|
1283
|
-
return new FormulaTerm(
|
|
1284
|
-
t.triples.map((tr) =>
|
|
1285
|
-
skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter),
|
|
1286
|
-
),
|
|
1287
|
-
);
|
|
1199
|
+
return new FormulaTerm(t.triples.map((tr) => skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter)));
|
|
1288
1200
|
}
|
|
1289
1201
|
|
|
1290
1202
|
return t;
|
|
@@ -1372,8 +1284,7 @@ function alphaEqTermInFormula(a, b, vmap, bmap) {
|
|
|
1372
1284
|
if (a instanceof ListTerm && b instanceof ListTerm) {
|
|
1373
1285
|
if (a.elems.length !== b.elems.length) return false;
|
|
1374
1286
|
for (let i = 0; i < a.elems.length; i++) {
|
|
1375
|
-
if (!alphaEqTermInFormula(a.elems[i], b.elems[i], vmap, bmap))
|
|
1376
|
-
return false;
|
|
1287
|
+
if (!alphaEqTermInFormula(a.elems[i], b.elems[i], vmap, bmap)) return false;
|
|
1377
1288
|
}
|
|
1378
1289
|
return true;
|
|
1379
1290
|
}
|
|
@@ -1381,8 +1292,7 @@ function alphaEqTermInFormula(a, b, vmap, bmap) {
|
|
|
1381
1292
|
if (a instanceof OpenListTerm && b instanceof OpenListTerm) {
|
|
1382
1293
|
if (a.prefix.length !== b.prefix.length) return false;
|
|
1383
1294
|
for (let i = 0; i < a.prefix.length; i++) {
|
|
1384
|
-
if (!alphaEqTermInFormula(a.prefix[i], b.prefix[i], vmap, bmap))
|
|
1385
|
-
return false;
|
|
1295
|
+
if (!alphaEqTermInFormula(a.prefix[i], b.prefix[i], vmap, bmap)) return false;
|
|
1386
1296
|
}
|
|
1387
1297
|
// tailVar is a var-name string, so treat it as renamable too
|
|
1388
1298
|
return alphaEqVarName(a.tailVar, b.tailVar, vmap);
|
|
@@ -1398,9 +1308,7 @@ function alphaEqTermInFormula(a, b, vmap, bmap) {
|
|
|
1398
1308
|
|
|
1399
1309
|
function alphaEqTripleInFormula(a, b, vmap, bmap) {
|
|
1400
1310
|
return (
|
|
1401
|
-
alphaEqTermInFormula(a.s, b.s, vmap, bmap) &&
|
|
1402
|
-
alphaEqTermInFormula(a.p, b.p, vmap, bmap) &&
|
|
1403
|
-
alphaEqTermInFormula(a.o, b.o, vmap, bmap)
|
|
1311
|
+
alphaEqTermInFormula(a.s, b.s, vmap, bmap) && alphaEqTermInFormula(a.p, b.p, vmap, bmap) && alphaEqTermInFormula(a.o, b.o, vmap, bmap)
|
|
1404
1312
|
);
|
|
1405
1313
|
}
|
|
1406
1314
|
|
|
@@ -1419,8 +1327,7 @@ function alphaEqFormulaTriples(xs, ys) {
|
|
|
1419
1327
|
if (used[j]) continue;
|
|
1420
1328
|
const y = ys[j];
|
|
1421
1329
|
// Cheap pruning when both predicates are IRIs.
|
|
1422
|
-
if (x.p instanceof Iri && y.p instanceof Iri && x.p.value !== y.p.value)
|
|
1423
|
-
continue;
|
|
1330
|
+
if (x.p instanceof Iri && y.p instanceof Iri && x.p.value !== y.p.value) continue;
|
|
1424
1331
|
|
|
1425
1332
|
const v2 = { ...vmap };
|
|
1426
1333
|
const b2 = { ...bmap };
|
|
@@ -1458,8 +1365,7 @@ function alphaEqTerm(a, b, bmap) {
|
|
|
1458
1365
|
return true;
|
|
1459
1366
|
}
|
|
1460
1367
|
if (a instanceof OpenListTerm && b instanceof OpenListTerm) {
|
|
1461
|
-
if (a.tailVar !== b.tailVar || a.prefix.length !== b.prefix.length)
|
|
1462
|
-
return false;
|
|
1368
|
+
if (a.tailVar !== b.tailVar || a.prefix.length !== b.prefix.length) return false;
|
|
1463
1369
|
for (let i = 0; i < a.prefix.length; i++) {
|
|
1464
1370
|
if (!alphaEqTerm(a.prefix[i], b.prefix[i], bmap)) return false;
|
|
1465
1371
|
}
|
|
@@ -1474,11 +1380,7 @@ function alphaEqTerm(a, b, bmap) {
|
|
|
1474
1380
|
|
|
1475
1381
|
function alphaEqTriple(a, b) {
|
|
1476
1382
|
const bmap = {};
|
|
1477
|
-
return (
|
|
1478
|
-
alphaEqTerm(a.s, b.s, bmap) &&
|
|
1479
|
-
alphaEqTerm(a.p, b.p, bmap) &&
|
|
1480
|
-
alphaEqTerm(a.o, b.o, bmap)
|
|
1481
|
-
);
|
|
1383
|
+
return alphaEqTerm(a.s, b.s, bmap) && alphaEqTerm(a.p, b.p, bmap) && alphaEqTerm(a.o, b.o, bmap);
|
|
1482
1384
|
}
|
|
1483
1385
|
|
|
1484
1386
|
function hasAlphaEquiv(triples, tr) {
|
|
@@ -1499,8 +1401,8 @@ function hasAlphaEquiv(triples, tr) {
|
|
|
1499
1401
|
// - __wildHeadPred: Rule[] (non-IRI head predicate)
|
|
1500
1402
|
|
|
1501
1403
|
function termFastKey(t) {
|
|
1502
|
-
if (t instanceof Iri) return
|
|
1503
|
-
if (t instanceof Literal) return
|
|
1404
|
+
if (t instanceof Iri) return 'I:' + t.value;
|
|
1405
|
+
if (t instanceof Literal) return 'L:' + t.value;
|
|
1504
1406
|
return null;
|
|
1505
1407
|
}
|
|
1506
1408
|
|
|
@@ -1509,23 +1411,23 @@ function tripleFastKey(tr) {
|
|
|
1509
1411
|
const kp = termFastKey(tr.p);
|
|
1510
1412
|
const ko = termFastKey(tr.o);
|
|
1511
1413
|
if (ks === null || kp === null || ko === null) return null;
|
|
1512
|
-
return ks +
|
|
1414
|
+
return ks + '\t' + kp + '\t' + ko;
|
|
1513
1415
|
}
|
|
1514
1416
|
|
|
1515
1417
|
function ensureFactIndexes(facts) {
|
|
1516
1418
|
if (facts.__byPred && facts.__byPO && facts.__keySet) return;
|
|
1517
1419
|
|
|
1518
|
-
Object.defineProperty(facts,
|
|
1420
|
+
Object.defineProperty(facts, '__byPred', {
|
|
1519
1421
|
value: new Map(),
|
|
1520
1422
|
enumerable: false,
|
|
1521
1423
|
writable: true,
|
|
1522
1424
|
});
|
|
1523
|
-
Object.defineProperty(facts,
|
|
1425
|
+
Object.defineProperty(facts, '__byPO', {
|
|
1524
1426
|
value: new Map(),
|
|
1525
1427
|
enumerable: false,
|
|
1526
1428
|
writable: true,
|
|
1527
1429
|
});
|
|
1528
|
-
Object.defineProperty(facts,
|
|
1430
|
+
Object.defineProperty(facts, '__keySet', {
|
|
1529
1431
|
value: new Set(),
|
|
1530
1432
|
enumerable: false,
|
|
1531
1433
|
writable: true,
|
|
@@ -1620,12 +1522,12 @@ function pushFactIndexed(facts, tr) {
|
|
|
1620
1522
|
function ensureBackRuleIndexes(backRules) {
|
|
1621
1523
|
if (backRules.__byHeadPred && backRules.__wildHeadPred) return;
|
|
1622
1524
|
|
|
1623
|
-
Object.defineProperty(backRules,
|
|
1525
|
+
Object.defineProperty(backRules, '__byHeadPred', {
|
|
1624
1526
|
value: new Map(),
|
|
1625
1527
|
enumerable: false,
|
|
1626
1528
|
writable: true,
|
|
1627
1529
|
});
|
|
1628
|
-
Object.defineProperty(backRules,
|
|
1530
|
+
Object.defineProperty(backRules, '__wildHeadPred', {
|
|
1629
1531
|
value: [],
|
|
1630
1532
|
enumerable: false,
|
|
1631
1533
|
writable: true,
|
|
@@ -1655,19 +1557,19 @@ function indexBackRule(backRules, r) {
|
|
|
1655
1557
|
// ============================================================================
|
|
1656
1558
|
|
|
1657
1559
|
function isRdfTypePred(p) {
|
|
1658
|
-
return p instanceof Iri && p.value === RDF_NS +
|
|
1560
|
+
return p instanceof Iri && p.value === RDF_NS + 'type';
|
|
1659
1561
|
}
|
|
1660
1562
|
|
|
1661
1563
|
function isOwlSameAsPred(t) {
|
|
1662
|
-
return t instanceof Iri && t.value === OWL_NS +
|
|
1564
|
+
return t instanceof Iri && t.value === OWL_NS + 'sameAs';
|
|
1663
1565
|
}
|
|
1664
1566
|
|
|
1665
1567
|
function isLogImplies(p) {
|
|
1666
|
-
return p instanceof Iri && p.value === LOG_NS +
|
|
1568
|
+
return p instanceof Iri && p.value === LOG_NS + 'implies';
|
|
1667
1569
|
}
|
|
1668
1570
|
|
|
1669
1571
|
function isLogImpliedBy(p) {
|
|
1670
|
-
return p instanceof Iri && p.value === LOG_NS +
|
|
1572
|
+
return p instanceof Iri && p.value === LOG_NS + 'impliedBy';
|
|
1671
1573
|
}
|
|
1672
1574
|
|
|
1673
1575
|
// ============================================================================
|
|
@@ -1680,44 +1582,40 @@ function isConstraintBuiltin(tr) {
|
|
|
1680
1582
|
|
|
1681
1583
|
// math: numeric comparisons (no new bindings, just tests)
|
|
1682
1584
|
if (
|
|
1683
|
-
v === MATH_NS +
|
|
1684
|
-
v === MATH_NS +
|
|
1685
|
-
v === MATH_NS +
|
|
1686
|
-
v === MATH_NS +
|
|
1687
|
-
v === MATH_NS +
|
|
1688
|
-
v === MATH_NS +
|
|
1585
|
+
v === MATH_NS + 'equalTo' ||
|
|
1586
|
+
v === MATH_NS + 'greaterThan' ||
|
|
1587
|
+
v === MATH_NS + 'lessThan' ||
|
|
1588
|
+
v === MATH_NS + 'notEqualTo' ||
|
|
1589
|
+
v === MATH_NS + 'notGreaterThan' ||
|
|
1590
|
+
v === MATH_NS + 'notLessThan'
|
|
1689
1591
|
) {
|
|
1690
1592
|
return true;
|
|
1691
1593
|
}
|
|
1692
1594
|
|
|
1693
1595
|
// list: membership test with no bindings
|
|
1694
|
-
if (v === LIST_NS +
|
|
1596
|
+
if (v === LIST_NS + 'notMember') {
|
|
1695
1597
|
return true;
|
|
1696
1598
|
}
|
|
1697
1599
|
|
|
1698
1600
|
// log: tests that are purely constraints (no new bindings)
|
|
1699
|
-
if (
|
|
1700
|
-
v === LOG_NS + "forAllIn" ||
|
|
1701
|
-
v === LOG_NS + "notEqualTo" ||
|
|
1702
|
-
v === LOG_NS + "notIncludes"
|
|
1703
|
-
) {
|
|
1601
|
+
if (v === LOG_NS + 'forAllIn' || v === LOG_NS + 'notEqualTo' || v === LOG_NS + 'notIncludes') {
|
|
1704
1602
|
return true;
|
|
1705
1603
|
}
|
|
1706
1604
|
|
|
1707
1605
|
// string: relational / membership style tests (no bindings)
|
|
1708
1606
|
if (
|
|
1709
|
-
v === STRING_NS +
|
|
1710
|
-
v === STRING_NS +
|
|
1711
|
-
v === STRING_NS +
|
|
1712
|
-
v === STRING_NS +
|
|
1713
|
-
v === STRING_NS +
|
|
1714
|
-
v === STRING_NS +
|
|
1715
|
-
v === STRING_NS +
|
|
1716
|
-
v === STRING_NS +
|
|
1717
|
-
v === STRING_NS +
|
|
1718
|
-
v === STRING_NS +
|
|
1719
|
-
v === STRING_NS +
|
|
1720
|
-
v === STRING_NS +
|
|
1607
|
+
v === STRING_NS + 'contains' ||
|
|
1608
|
+
v === STRING_NS + 'containsIgnoringCase' ||
|
|
1609
|
+
v === STRING_NS + 'endsWith' ||
|
|
1610
|
+
v === STRING_NS + 'equalIgnoringCase' ||
|
|
1611
|
+
v === STRING_NS + 'greaterThan' ||
|
|
1612
|
+
v === STRING_NS + 'lessThan' ||
|
|
1613
|
+
v === STRING_NS + 'matches' ||
|
|
1614
|
+
v === STRING_NS + 'notEqualIgnoringCase' ||
|
|
1615
|
+
v === STRING_NS + 'notGreaterThan' ||
|
|
1616
|
+
v === STRING_NS + 'notLessThan' ||
|
|
1617
|
+
v === STRING_NS + 'notMatches' ||
|
|
1618
|
+
v === STRING_NS + 'startsWith'
|
|
1721
1619
|
) {
|
|
1722
1620
|
return true;
|
|
1723
1621
|
}
|
|
@@ -1751,15 +1649,9 @@ function reorderPremiseForConstraints(premise) {
|
|
|
1751
1649
|
function containsVarTerm(t, v) {
|
|
1752
1650
|
if (t instanceof Var) return t.name === v;
|
|
1753
1651
|
if (t instanceof ListTerm) return t.elems.some((e) => containsVarTerm(e, v));
|
|
1754
|
-
if (t instanceof OpenListTerm)
|
|
1755
|
-
return t.prefix.some((e) => containsVarTerm(e, v)) || t.tailVar === v;
|
|
1652
|
+
if (t instanceof OpenListTerm) return t.prefix.some((e) => containsVarTerm(e, v)) || t.tailVar === v;
|
|
1756
1653
|
if (t instanceof FormulaTerm)
|
|
1757
|
-
return t.triples.some(
|
|
1758
|
-
(tr) =>
|
|
1759
|
-
containsVarTerm(tr.s, v) ||
|
|
1760
|
-
containsVarTerm(tr.p, v) ||
|
|
1761
|
-
containsVarTerm(tr.o, v),
|
|
1762
|
-
);
|
|
1654
|
+
return t.triples.some((tr) => containsVarTerm(tr.s, v) || containsVarTerm(tr.p, v) || containsVarTerm(tr.o, v));
|
|
1763
1655
|
return false;
|
|
1764
1656
|
}
|
|
1765
1657
|
|
|
@@ -1767,28 +1659,21 @@ function isGroundTermInFormula(t) {
|
|
|
1767
1659
|
// EYE-style: variables inside formula terms are treated as local placeholders,
|
|
1768
1660
|
// so they don't make the *surrounding triple* non-ground.
|
|
1769
1661
|
if (t instanceof OpenListTerm) return false;
|
|
1770
|
-
if (t instanceof ListTerm)
|
|
1771
|
-
|
|
1772
|
-
if (t instanceof FormulaTerm)
|
|
1773
|
-
return t.triples.every((tr) => isGroundTripleInFormula(tr));
|
|
1662
|
+
if (t instanceof ListTerm) return t.elems.every((e) => isGroundTermInFormula(e));
|
|
1663
|
+
if (t instanceof FormulaTerm) return t.triples.every((tr) => isGroundTripleInFormula(tr));
|
|
1774
1664
|
// Iri/Literal/Blank/Var are all OK inside formulas
|
|
1775
1665
|
return true;
|
|
1776
1666
|
}
|
|
1777
1667
|
|
|
1778
1668
|
function isGroundTripleInFormula(tr) {
|
|
1779
|
-
return (
|
|
1780
|
-
isGroundTermInFormula(tr.s) &&
|
|
1781
|
-
isGroundTermInFormula(tr.p) &&
|
|
1782
|
-
isGroundTermInFormula(tr.o)
|
|
1783
|
-
);
|
|
1669
|
+
return isGroundTermInFormula(tr.s) && isGroundTermInFormula(tr.p) && isGroundTermInFormula(tr.o);
|
|
1784
1670
|
}
|
|
1785
1671
|
|
|
1786
1672
|
function isGroundTerm(t) {
|
|
1787
1673
|
if (t instanceof Var) return false;
|
|
1788
1674
|
if (t instanceof ListTerm) return t.elems.every((e) => isGroundTerm(e));
|
|
1789
1675
|
if (t instanceof OpenListTerm) return false;
|
|
1790
|
-
if (t instanceof FormulaTerm)
|
|
1791
|
-
return t.triples.every((tr) => isGroundTripleInFormula(tr));
|
|
1676
|
+
if (t instanceof FormulaTerm) return t.triples.every((tr) => isGroundTripleInFormula(tr));
|
|
1792
1677
|
return true;
|
|
1793
1678
|
}
|
|
1794
1679
|
|
|
@@ -1801,19 +1686,14 @@ function isGroundTriple(tr) {
|
|
|
1801
1686
|
// robust to seeing vars/open lists anyway.
|
|
1802
1687
|
function skolemKeyFromTerm(t) {
|
|
1803
1688
|
function enc(u) {
|
|
1804
|
-
if (u instanceof Iri) return [
|
|
1805
|
-
if (u instanceof Literal) return [
|
|
1806
|
-
if (u instanceof Blank) return [
|
|
1807
|
-
if (u instanceof Var) return [
|
|
1808
|
-
if (u instanceof ListTerm) return [
|
|
1809
|
-
if (u instanceof OpenListTerm)
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
return [
|
|
1813
|
-
"Formula",
|
|
1814
|
-
u.triples.map((tr) => [enc(tr.s), enc(tr.p), enc(tr.o)]),
|
|
1815
|
-
];
|
|
1816
|
-
return ["Other", String(u)];
|
|
1689
|
+
if (u instanceof Iri) return ['I', u.value];
|
|
1690
|
+
if (u instanceof Literal) return ['L', u.value];
|
|
1691
|
+
if (u instanceof Blank) return ['B', u.label];
|
|
1692
|
+
if (u instanceof Var) return ['V', u.name];
|
|
1693
|
+
if (u instanceof ListTerm) return ['List', u.elems.map(enc)];
|
|
1694
|
+
if (u instanceof OpenListTerm) return ['OpenList', u.prefix.map(enc), u.tailVar];
|
|
1695
|
+
if (u instanceof FormulaTerm) return ['Formula', u.triples.map((tr) => [enc(tr.s), enc(tr.p), enc(tr.o)])];
|
|
1696
|
+
return ['Other', String(u)];
|
|
1817
1697
|
}
|
|
1818
1698
|
return JSON.stringify(enc(t));
|
|
1819
1699
|
}
|
|
@@ -1861,10 +1741,7 @@ function applySubstTerm(t, s) {
|
|
|
1861
1741
|
if (tailApplied instanceof ListTerm) {
|
|
1862
1742
|
return new ListTerm(newPrefix.concat(tailApplied.elems));
|
|
1863
1743
|
} else if (tailApplied instanceof OpenListTerm) {
|
|
1864
|
-
return new OpenListTerm(
|
|
1865
|
-
newPrefix.concat(tailApplied.prefix),
|
|
1866
|
-
tailApplied.tailVar,
|
|
1867
|
-
);
|
|
1744
|
+
return new OpenListTerm(newPrefix.concat(tailApplied.prefix), tailApplied.tailVar);
|
|
1868
1745
|
} else {
|
|
1869
1746
|
return new OpenListTerm(newPrefix, t.tailVar);
|
|
1870
1747
|
}
|
|
@@ -1881,11 +1758,7 @@ function applySubstTerm(t, s) {
|
|
|
1881
1758
|
}
|
|
1882
1759
|
|
|
1883
1760
|
function applySubstTriple(tr, s) {
|
|
1884
|
-
return new Triple(
|
|
1885
|
-
applySubstTerm(tr.s, s),
|
|
1886
|
-
applySubstTerm(tr.p, s),
|
|
1887
|
-
applySubstTerm(tr.o, s),
|
|
1888
|
-
);
|
|
1761
|
+
return new Triple(applySubstTerm(tr.s, s), applySubstTerm(tr.p, s), applySubstTerm(tr.o, s));
|
|
1889
1762
|
}
|
|
1890
1763
|
|
|
1891
1764
|
function unifyOpenWithList(prefix, tailv, ys, subst) {
|
|
@@ -1919,8 +1792,7 @@ function unifyFormulaTriples(xs, ys, subst) {
|
|
|
1919
1792
|
const y = ys[j];
|
|
1920
1793
|
|
|
1921
1794
|
// Cheap pruning when both predicates are IRIs.
|
|
1922
|
-
if (x.p instanceof Iri && y.p instanceof Iri && x.p.value !== y.p.value)
|
|
1923
|
-
continue;
|
|
1795
|
+
if (x.p instanceof Iri && y.p instanceof Iri && x.p.value !== y.p.value) continue;
|
|
1924
1796
|
|
|
1925
1797
|
const s2 = unifyTriple(x, y, s); // IMPORTANT: use `s`, not {}
|
|
1926
1798
|
if (s2 === null) continue;
|
|
@@ -1956,12 +1828,9 @@ function unifyTerm(a, b, subst) {
|
|
|
1956
1828
|
}
|
|
1957
1829
|
|
|
1958
1830
|
// Exact matches
|
|
1959
|
-
if (a instanceof Iri && b instanceof Iri && a.value === b.value)
|
|
1960
|
-
|
|
1961
|
-
if (a instanceof
|
|
1962
|
-
return { ...subst };
|
|
1963
|
-
if (a instanceof Blank && b instanceof Blank && a.label === b.label)
|
|
1964
|
-
return { ...subst };
|
|
1831
|
+
if (a instanceof Iri && b instanceof Iri && a.value === b.value) return { ...subst };
|
|
1832
|
+
if (a instanceof Literal && b instanceof Literal && a.value === b.value) return { ...subst };
|
|
1833
|
+
if (a instanceof Blank && b instanceof Blank && a.label === b.label) return { ...subst };
|
|
1965
1834
|
|
|
1966
1835
|
// Open list vs concrete list
|
|
1967
1836
|
if (a instanceof OpenListTerm && b instanceof ListTerm) {
|
|
@@ -1973,8 +1842,7 @@ function unifyTerm(a, b, subst) {
|
|
|
1973
1842
|
|
|
1974
1843
|
// Open list vs open list (same tail var)
|
|
1975
1844
|
if (a instanceof OpenListTerm && b instanceof OpenListTerm) {
|
|
1976
|
-
if (a.tailVar !== b.tailVar || a.prefix.length !== b.prefix.length)
|
|
1977
|
-
return null;
|
|
1845
|
+
if (a.tailVar !== b.tailVar || a.prefix.length !== b.prefix.length) return null;
|
|
1978
1846
|
let s2 = { ...subst };
|
|
1979
1847
|
for (let i = 0; i < a.prefix.length; i++) {
|
|
1980
1848
|
s2 = unifyTerm(a.prefix[i], b.prefix[i], s2);
|
|
@@ -2040,14 +1908,14 @@ function literalParts(lit) {
|
|
|
2040
1908
|
// Also strip an optional language tag from the lexical form:
|
|
2041
1909
|
// "\"hello\"@en" -> "\"hello\""
|
|
2042
1910
|
// "\"hello\"@en^^<...>" is rejected earlier in the parser.
|
|
2043
|
-
const idx = lit.indexOf(
|
|
1911
|
+
const idx = lit.indexOf('^^');
|
|
2044
1912
|
let lex = lit;
|
|
2045
1913
|
let dt = null;
|
|
2046
1914
|
|
|
2047
1915
|
if (idx >= 0) {
|
|
2048
1916
|
lex = lit.slice(0, idx);
|
|
2049
1917
|
dt = lit.slice(idx + 2).trim();
|
|
2050
|
-
if (dt.startsWith(
|
|
1918
|
+
if (dt.startsWith('<') && dt.endsWith('>')) {
|
|
2051
1919
|
dt = dt.slice(1, -1);
|
|
2052
1920
|
}
|
|
2053
1921
|
}
|
|
@@ -2055,11 +1923,7 @@ function literalParts(lit) {
|
|
|
2055
1923
|
// Strip LANGTAG from the lexical form when present.
|
|
2056
1924
|
if (lex.length >= 2 && lex[0] === '"') {
|
|
2057
1925
|
const lastQuote = lex.lastIndexOf('"');
|
|
2058
|
-
if (
|
|
2059
|
-
lastQuote > 0 &&
|
|
2060
|
-
lastQuote < lex.length - 1 &&
|
|
2061
|
-
lex[lastQuote + 1] === "@"
|
|
2062
|
-
) {
|
|
1926
|
+
if (lastQuote > 0 && lastQuote < lex.length - 1 && lex[lastQuote + 1] === '@') {
|
|
2063
1927
|
const lang = lex.slice(lastQuote + 2);
|
|
2064
1928
|
if (/^[A-Za-z]+(?:-[A-Za-z0-9]+)*$/.test(lang)) {
|
|
2065
1929
|
lex = lex.slice(0, lastQuote + 1);
|
|
@@ -2119,17 +1983,17 @@ function termToJsStringDecoded(t) {
|
|
|
2119
1983
|
|
|
2120
1984
|
function jsonPointerUnescape(seg) {
|
|
2121
1985
|
// RFC6901: ~1 -> '/', ~0 -> '~'
|
|
2122
|
-
let out =
|
|
1986
|
+
let out = '';
|
|
2123
1987
|
for (let i = 0; i < seg.length; i++) {
|
|
2124
1988
|
const c = seg[i];
|
|
2125
|
-
if (c !==
|
|
1989
|
+
if (c !== '~') {
|
|
2126
1990
|
out += c;
|
|
2127
1991
|
continue;
|
|
2128
1992
|
}
|
|
2129
1993
|
if (i + 1 >= seg.length) return null;
|
|
2130
1994
|
const n = seg[i + 1];
|
|
2131
|
-
if (n ===
|
|
2132
|
-
else if (n ===
|
|
1995
|
+
if (n === '0') out += '~';
|
|
1996
|
+
else if (n === '1') out += '/';
|
|
2133
1997
|
else return null;
|
|
2134
1998
|
i++;
|
|
2135
1999
|
}
|
|
@@ -2137,13 +2001,13 @@ function jsonPointerUnescape(seg) {
|
|
|
2137
2001
|
}
|
|
2138
2002
|
|
|
2139
2003
|
function jsonToTerm(v) {
|
|
2140
|
-
if (v === null) return makeStringLiteral(
|
|
2141
|
-
if (typeof v ===
|
|
2142
|
-
if (typeof v ===
|
|
2143
|
-
if (typeof v ===
|
|
2004
|
+
if (v === null) return makeStringLiteral('null');
|
|
2005
|
+
if (typeof v === 'string') return makeStringLiteral(v);
|
|
2006
|
+
if (typeof v === 'number') return new Literal(String(v));
|
|
2007
|
+
if (typeof v === 'boolean') return new Literal(v ? 'true' : 'false');
|
|
2144
2008
|
if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
|
|
2145
2009
|
|
|
2146
|
-
if (v && typeof v ===
|
|
2010
|
+
if (v && typeof v === 'object') {
|
|
2147
2011
|
return makeRdfJsonLiteral(JSON.stringify(v));
|
|
2148
2012
|
}
|
|
2149
2013
|
return null;
|
|
@@ -2153,7 +2017,7 @@ function jsonPointerLookup(jsonText, pointer) {
|
|
|
2153
2017
|
let ptr = pointer;
|
|
2154
2018
|
|
|
2155
2019
|
// Support URI fragment form "#/a/b"
|
|
2156
|
-
if (ptr.startsWith(
|
|
2020
|
+
if (ptr.startsWith('#')) {
|
|
2157
2021
|
try {
|
|
2158
2022
|
ptr = decodeURIComponent(ptr.slice(1));
|
|
2159
2023
|
} catch {
|
|
@@ -2178,17 +2042,17 @@ function jsonPointerLookup(jsonText, pointer) {
|
|
|
2178
2042
|
|
|
2179
2043
|
let cur = entry.parsed;
|
|
2180
2044
|
|
|
2181
|
-
if (ptr ===
|
|
2045
|
+
if (ptr === '') {
|
|
2182
2046
|
const t = jsonToTerm(cur);
|
|
2183
2047
|
entry.ptrCache.set(ptr, t);
|
|
2184
2048
|
return t;
|
|
2185
2049
|
}
|
|
2186
|
-
if (!ptr.startsWith(
|
|
2050
|
+
if (!ptr.startsWith('/')) {
|
|
2187
2051
|
entry.ptrCache.set(ptr, null);
|
|
2188
2052
|
return null;
|
|
2189
2053
|
}
|
|
2190
2054
|
|
|
2191
|
-
const parts = ptr.split(
|
|
2055
|
+
const parts = ptr.split('/').slice(1);
|
|
2192
2056
|
for (const raw of parts) {
|
|
2193
2057
|
const seg = jsonPointerUnescape(raw);
|
|
2194
2058
|
if (seg === null) {
|
|
@@ -2207,7 +2071,7 @@ function jsonPointerLookup(jsonText, pointer) {
|
|
|
2207
2071
|
return null;
|
|
2208
2072
|
}
|
|
2209
2073
|
cur = cur[idx];
|
|
2210
|
-
} else if (cur !== null && typeof cur ===
|
|
2074
|
+
} else if (cur !== null && typeof cur === 'object') {
|
|
2211
2075
|
if (!Object.prototype.hasOwnProperty.call(cur, seg)) {
|
|
2212
2076
|
entry.ptrCache.set(ptr, null);
|
|
2213
2077
|
return null;
|
|
@@ -2227,23 +2091,23 @@ function jsonPointerLookup(jsonText, pointer) {
|
|
|
2227
2091
|
// Tiny subset of sprintf: supports only %s and %%.
|
|
2228
2092
|
// Good enough for most N3 string:format use cases that just splice strings.
|
|
2229
2093
|
function simpleStringFormat(fmt, args) {
|
|
2230
|
-
let out =
|
|
2094
|
+
let out = '';
|
|
2231
2095
|
let argIndex = 0;
|
|
2232
2096
|
|
|
2233
2097
|
for (let i = 0; i < fmt.length; i++) {
|
|
2234
2098
|
const ch = fmt[i];
|
|
2235
|
-
if (ch ===
|
|
2099
|
+
if (ch === '%' && i + 1 < fmt.length) {
|
|
2236
2100
|
const spec = fmt[i + 1];
|
|
2237
2101
|
|
|
2238
|
-
if (spec ===
|
|
2239
|
-
const arg = argIndex < args.length ? args[argIndex++] :
|
|
2102
|
+
if (spec === 's') {
|
|
2103
|
+
const arg = argIndex < args.length ? args[argIndex++] : '';
|
|
2240
2104
|
out += arg;
|
|
2241
2105
|
i++;
|
|
2242
2106
|
continue;
|
|
2243
2107
|
}
|
|
2244
2108
|
|
|
2245
|
-
if (spec ===
|
|
2246
|
-
out +=
|
|
2109
|
+
if (spec === '%') {
|
|
2110
|
+
out += '%';
|
|
2247
2111
|
i++;
|
|
2248
2112
|
continue;
|
|
2249
2113
|
}
|
|
@@ -2260,44 +2124,38 @@ function simpleStringFormat(fmt, args) {
|
|
|
2260
2124
|
// -----------------------------------------------------------------------------
|
|
2261
2125
|
// Strict numeric literal parsing for math: builtins
|
|
2262
2126
|
// -----------------------------------------------------------------------------
|
|
2263
|
-
const XSD_DECIMAL_DT = XSD_NS +
|
|
2264
|
-
const XSD_DOUBLE_DT = XSD_NS +
|
|
2265
|
-
const XSD_FLOAT_DT = XSD_NS +
|
|
2266
|
-
const XSD_INTEGER_DT = XSD_NS +
|
|
2127
|
+
const XSD_DECIMAL_DT = XSD_NS + 'decimal';
|
|
2128
|
+
const XSD_DOUBLE_DT = XSD_NS + 'double';
|
|
2129
|
+
const XSD_FLOAT_DT = XSD_NS + 'float';
|
|
2130
|
+
const XSD_INTEGER_DT = XSD_NS + 'integer';
|
|
2267
2131
|
|
|
2268
2132
|
// Integer-derived datatypes from XML Schema Part 2 (and commonly used ones).
|
|
2269
2133
|
const XSD_INTEGER_DERIVED_DTS = new Set([
|
|
2270
2134
|
XSD_INTEGER_DT,
|
|
2271
|
-
XSD_NS +
|
|
2272
|
-
XSD_NS +
|
|
2273
|
-
XSD_NS +
|
|
2274
|
-
XSD_NS +
|
|
2275
|
-
XSD_NS +
|
|
2276
|
-
XSD_NS +
|
|
2277
|
-
XSD_NS +
|
|
2278
|
-
XSD_NS +
|
|
2279
|
-
XSD_NS +
|
|
2280
|
-
XSD_NS +
|
|
2281
|
-
XSD_NS +
|
|
2282
|
-
XSD_NS +
|
|
2135
|
+
XSD_NS + 'nonPositiveInteger',
|
|
2136
|
+
XSD_NS + 'negativeInteger',
|
|
2137
|
+
XSD_NS + 'long',
|
|
2138
|
+
XSD_NS + 'int',
|
|
2139
|
+
XSD_NS + 'short',
|
|
2140
|
+
XSD_NS + 'byte',
|
|
2141
|
+
XSD_NS + 'nonNegativeInteger',
|
|
2142
|
+
XSD_NS + 'unsignedLong',
|
|
2143
|
+
XSD_NS + 'unsignedInt',
|
|
2144
|
+
XSD_NS + 'unsignedShort',
|
|
2145
|
+
XSD_NS + 'unsignedByte',
|
|
2146
|
+
XSD_NS + 'positiveInteger',
|
|
2283
2147
|
]);
|
|
2284
2148
|
|
|
2285
2149
|
function isQuotedLexical(lex) {
|
|
2286
2150
|
// Note: the lexer stores long strings with literal delimiters: """..."""
|
|
2287
2151
|
return (
|
|
2288
|
-
(lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') ||
|
|
2289
|
-
(lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""'))
|
|
2152
|
+
(lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') || (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""'))
|
|
2290
2153
|
);
|
|
2291
2154
|
}
|
|
2292
2155
|
|
|
2293
2156
|
function isXsdNumericDatatype(dt) {
|
|
2294
2157
|
if (dt === null) return false;
|
|
2295
|
-
return (
|
|
2296
|
-
dt === XSD_DECIMAL_DT ||
|
|
2297
|
-
dt === XSD_DOUBLE_DT ||
|
|
2298
|
-
dt === XSD_FLOAT_DT ||
|
|
2299
|
-
XSD_INTEGER_DERIVED_DTS.has(dt)
|
|
2300
|
-
);
|
|
2158
|
+
return dt === XSD_DECIMAL_DT || dt === XSD_DOUBLE_DT || dt === XSD_FLOAT_DT || XSD_INTEGER_DERIVED_DTS.has(dt);
|
|
2301
2159
|
}
|
|
2302
2160
|
|
|
2303
2161
|
function isXsdIntegerDatatype(dt) {
|
|
@@ -2389,9 +2247,9 @@ function formatNum(n) {
|
|
|
2389
2247
|
function parseXsdDateTerm(t) {
|
|
2390
2248
|
if (!(t instanceof Literal)) return null;
|
|
2391
2249
|
const [lex, dt] = literalParts(t.value);
|
|
2392
|
-
if (dt !== XSD_NS +
|
|
2250
|
+
if (dt !== XSD_NS + 'date') return null;
|
|
2393
2251
|
const val = stripQuotes(lex);
|
|
2394
|
-
const d = new Date(val +
|
|
2252
|
+
const d = new Date(val + 'T00:00:00Z');
|
|
2395
2253
|
if (Number.isNaN(d.getTime())) return null;
|
|
2396
2254
|
return d;
|
|
2397
2255
|
}
|
|
@@ -2399,7 +2257,7 @@ function parseXsdDateTerm(t) {
|
|
|
2399
2257
|
function parseXsdDatetimeTerm(t) {
|
|
2400
2258
|
if (!(t instanceof Literal)) return null;
|
|
2401
2259
|
const [lex, dt] = literalParts(t.value);
|
|
2402
|
-
if (dt !== XSD_NS +
|
|
2260
|
+
if (dt !== XSD_NS + 'dateTime') return null;
|
|
2403
2261
|
const val = stripQuotes(lex);
|
|
2404
2262
|
const d = new Date(val);
|
|
2405
2263
|
if (Number.isNaN(d.getTime())) return null;
|
|
@@ -2414,9 +2272,9 @@ function parseDatetimeLike(t) {
|
|
|
2414
2272
|
|
|
2415
2273
|
function parseIso8601DurationToSeconds(s) {
|
|
2416
2274
|
if (!s) return null;
|
|
2417
|
-
if (s[0] !==
|
|
2275
|
+
if (s[0] !== 'P') return null;
|
|
2418
2276
|
const it = s.slice(1);
|
|
2419
|
-
let num =
|
|
2277
|
+
let num = '';
|
|
2420
2278
|
let inTime = false;
|
|
2421
2279
|
let years = 0,
|
|
2422
2280
|
months = 0,
|
|
@@ -2427,7 +2285,7 @@ function parseIso8601DurationToSeconds(s) {
|
|
|
2427
2285
|
seconds = 0;
|
|
2428
2286
|
|
|
2429
2287
|
for (const c of it) {
|
|
2430
|
-
if (c ===
|
|
2288
|
+
if (c === 'T') {
|
|
2431
2289
|
inTime = true;
|
|
2432
2290
|
continue;
|
|
2433
2291
|
}
|
|
@@ -2438,25 +2296,19 @@ function parseIso8601DurationToSeconds(s) {
|
|
|
2438
2296
|
if (!num) return null;
|
|
2439
2297
|
const val = Number(num);
|
|
2440
2298
|
if (Number.isNaN(val)) return null;
|
|
2441
|
-
num =
|
|
2442
|
-
if (!inTime && c ===
|
|
2443
|
-
else if (!inTime && c ===
|
|
2444
|
-
else if (!inTime && c ===
|
|
2445
|
-
else if (!inTime && c ===
|
|
2446
|
-
else if (inTime && c ===
|
|
2447
|
-
else if (inTime && c ===
|
|
2448
|
-
else if (inTime && c ===
|
|
2299
|
+
num = '';
|
|
2300
|
+
if (!inTime && c === 'Y') years += val;
|
|
2301
|
+
else if (!inTime && c === 'M') months += val;
|
|
2302
|
+
else if (!inTime && c === 'W') weeks += val;
|
|
2303
|
+
else if (!inTime && c === 'D') days += val;
|
|
2304
|
+
else if (inTime && c === 'H') hours += val;
|
|
2305
|
+
else if (inTime && c === 'M') minutes += val;
|
|
2306
|
+
else if (inTime && c === 'S') seconds += val;
|
|
2449
2307
|
else return null;
|
|
2450
2308
|
}
|
|
2451
2309
|
|
|
2452
2310
|
const totalDays =
|
|
2453
|
-
years * 365.2425 +
|
|
2454
|
-
months * 30.436875 +
|
|
2455
|
-
weeks * 7.0 +
|
|
2456
|
-
days +
|
|
2457
|
-
hours / 24.0 +
|
|
2458
|
-
minutes / (24.0 * 60.0) +
|
|
2459
|
-
seconds / (24.0 * 3600.0);
|
|
2311
|
+
years * 365.2425 + months * 30.436875 + weeks * 7.0 + days + hours / 24.0 + minutes / (24.0 * 60.0) + seconds / (24.0 * 3600.0);
|
|
2460
2312
|
|
|
2461
2313
|
return totalDays * 86400.0;
|
|
2462
2314
|
}
|
|
@@ -2465,10 +2317,10 @@ function parseNumericForCompareTerm(t) {
|
|
|
2465
2317
|
// Strict: only accept xsd numeric literals, xsd:duration, xsd:date, xsd:dateTime
|
|
2466
2318
|
// (or untyped numeric tokens).
|
|
2467
2319
|
const bi = parseIntLiteral(t);
|
|
2468
|
-
if (bi !== null) return { kind:
|
|
2320
|
+
if (bi !== null) return { kind: 'bigint', value: bi };
|
|
2469
2321
|
|
|
2470
2322
|
const nDur = parseNumOrDuration(t);
|
|
2471
|
-
if (nDur !== null) return { kind:
|
|
2323
|
+
if (nDur !== null) return { kind: 'number', value: nDur };
|
|
2472
2324
|
return null;
|
|
2473
2325
|
}
|
|
2474
2326
|
|
|
@@ -2476,25 +2328,25 @@ function cmpNumericInfo(aInfo, bInfo, op) {
|
|
|
2476
2328
|
// op is one of ">", "<", ">=", "<="
|
|
2477
2329
|
if (!aInfo || !bInfo) return false;
|
|
2478
2330
|
|
|
2479
|
-
if (aInfo.kind ===
|
|
2480
|
-
if (op ===
|
|
2481
|
-
if (op ===
|
|
2482
|
-
if (op ===
|
|
2483
|
-
if (op ===
|
|
2484
|
-
if (op ===
|
|
2485
|
-
if (op ===
|
|
2331
|
+
if (aInfo.kind === 'bigint' && bInfo.kind === 'bigint') {
|
|
2332
|
+
if (op === '>') return aInfo.value > bInfo.value;
|
|
2333
|
+
if (op === '<') return aInfo.value < bInfo.value;
|
|
2334
|
+
if (op === '>=') return aInfo.value >= bInfo.value;
|
|
2335
|
+
if (op === '<=') return aInfo.value <= bInfo.value;
|
|
2336
|
+
if (op === '==') return aInfo.value == bInfo.value;
|
|
2337
|
+
if (op === '!=') return aInfo.value != bInfo.value;
|
|
2486
2338
|
return false;
|
|
2487
2339
|
}
|
|
2488
2340
|
|
|
2489
|
-
const a = typeof aInfo.value ===
|
|
2490
|
-
const b = typeof bInfo.value ===
|
|
2341
|
+
const a = typeof aInfo.value === 'bigint' ? Number(aInfo.value) : aInfo.value;
|
|
2342
|
+
const b = typeof bInfo.value === 'bigint' ? Number(bInfo.value) : bInfo.value;
|
|
2491
2343
|
|
|
2492
|
-
if (op ===
|
|
2493
|
-
if (op ===
|
|
2494
|
-
if (op ===
|
|
2495
|
-
if (op ===
|
|
2496
|
-
if (op ===
|
|
2497
|
-
if (op ===
|
|
2344
|
+
if (op === '>') return a > b;
|
|
2345
|
+
if (op === '<') return a < b;
|
|
2346
|
+
if (op === '>=') return a >= b;
|
|
2347
|
+
if (op === '<=') return a <= b;
|
|
2348
|
+
if (op === '==') return a == b;
|
|
2349
|
+
if (op === '!=') return a != b;
|
|
2498
2350
|
return false;
|
|
2499
2351
|
}
|
|
2500
2352
|
|
|
@@ -2505,11 +2357,11 @@ function parseNumOrDuration(t) {
|
|
|
2505
2357
|
// xsd:duration
|
|
2506
2358
|
if (t instanceof Literal) {
|
|
2507
2359
|
const [lex, dt] = literalParts(t.value);
|
|
2508
|
-
if (dt === XSD_NS +
|
|
2360
|
+
if (dt === XSD_NS + 'duration') {
|
|
2509
2361
|
const val = stripQuotes(lex);
|
|
2510
|
-
const negative = val.startsWith(
|
|
2362
|
+
const negative = val.startsWith('-');
|
|
2511
2363
|
const core = negative ? val.slice(1) : val;
|
|
2512
|
-
if (!core.startsWith(
|
|
2364
|
+
if (!core.startsWith('P')) return null;
|
|
2513
2365
|
const secs = parseIso8601DurationToSeconds(core);
|
|
2514
2366
|
if (secs === null) return null;
|
|
2515
2367
|
return negative ? -secs : secs;
|
|
@@ -2568,10 +2420,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2568
2420
|
const [lex, _dt] = literalParts(t.value);
|
|
2569
2421
|
const input = stripQuotes(lex);
|
|
2570
2422
|
try {
|
|
2571
|
-
const digest = nodeCrypto
|
|
2572
|
-
.createHash(algo)
|
|
2573
|
-
.update(input, "utf8")
|
|
2574
|
-
.digest("hex");
|
|
2423
|
+
const digest = nodeCrypto.createHash(algo).update(input, 'utf8').digest('hex');
|
|
2575
2424
|
// plain string literal with the hex digest
|
|
2576
2425
|
return new Literal(JSON.stringify(digest));
|
|
2577
2426
|
} catch (e) {
|
|
@@ -2585,8 +2434,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2585
2434
|
|
|
2586
2435
|
// crypto:sha
|
|
2587
2436
|
// true iff ?o is the SHA-1 hash of the subject string.
|
|
2588
|
-
if (g.p instanceof Iri && g.p.value === CRYPTO_NS +
|
|
2589
|
-
const lit = hashLiteral(g.s,
|
|
2437
|
+
if (g.p instanceof Iri && g.p.value === CRYPTO_NS + 'sha') {
|
|
2438
|
+
const lit = hashLiteral(g.s, 'sha1');
|
|
2590
2439
|
if (!lit) return [];
|
|
2591
2440
|
if (g.o instanceof Var) {
|
|
2592
2441
|
const s2 = { ...subst };
|
|
@@ -2598,8 +2447,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2598
2447
|
}
|
|
2599
2448
|
|
|
2600
2449
|
// crypto:md5
|
|
2601
|
-
if (g.p instanceof Iri && g.p.value === CRYPTO_NS +
|
|
2602
|
-
const lit = hashLiteral(g.s,
|
|
2450
|
+
if (g.p instanceof Iri && g.p.value === CRYPTO_NS + 'md5') {
|
|
2451
|
+
const lit = hashLiteral(g.s, 'md5');
|
|
2603
2452
|
if (!lit) return [];
|
|
2604
2453
|
if (g.o instanceof Var) {
|
|
2605
2454
|
const s2 = { ...subst };
|
|
@@ -2611,8 +2460,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2611
2460
|
}
|
|
2612
2461
|
|
|
2613
2462
|
// crypto:sha256
|
|
2614
|
-
if (g.p instanceof Iri && g.p.value === CRYPTO_NS +
|
|
2615
|
-
const lit = hashLiteral(g.s,
|
|
2463
|
+
if (g.p instanceof Iri && g.p.value === CRYPTO_NS + 'sha256') {
|
|
2464
|
+
const lit = hashLiteral(g.s, 'sha256');
|
|
2616
2465
|
if (!lit) return [];
|
|
2617
2466
|
if (g.o instanceof Var) {
|
|
2618
2467
|
const s2 = { ...subst };
|
|
@@ -2624,8 +2473,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2624
2473
|
}
|
|
2625
2474
|
|
|
2626
2475
|
// crypto:sha512
|
|
2627
|
-
if (g.p instanceof Iri && g.p.value === CRYPTO_NS +
|
|
2628
|
-
const lit = hashLiteral(g.s,
|
|
2476
|
+
if (g.p instanceof Iri && g.p.value === CRYPTO_NS + 'sha512') {
|
|
2477
|
+
const lit = hashLiteral(g.s, 'sha512');
|
|
2629
2478
|
if (!lit) return [];
|
|
2630
2479
|
if (g.o instanceof Var) {
|
|
2631
2480
|
const s2 = { ...subst };
|
|
@@ -2641,97 +2490,91 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2641
2490
|
// -----------------------------------------------------------------
|
|
2642
2491
|
|
|
2643
2492
|
// math:greaterThan
|
|
2644
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2493
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'greaterThan') {
|
|
2645
2494
|
const aInfo = parseNumericForCompareTerm(g.s);
|
|
2646
2495
|
const bInfo = parseNumericForCompareTerm(g.o);
|
|
2647
|
-
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo,
|
|
2648
|
-
return [{ ...subst }];
|
|
2496
|
+
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, '>')) return [{ ...subst }];
|
|
2649
2497
|
|
|
2650
2498
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2651
2499
|
const a2 = parseNumericForCompareTerm(g.s.elems[0]);
|
|
2652
2500
|
const b2 = parseNumericForCompareTerm(g.s.elems[1]);
|
|
2653
|
-
if (a2 && b2 && cmpNumericInfo(a2, b2,
|
|
2501
|
+
if (a2 && b2 && cmpNumericInfo(a2, b2, '>')) return [{ ...subst }];
|
|
2654
2502
|
}
|
|
2655
2503
|
return [];
|
|
2656
2504
|
}
|
|
2657
2505
|
|
|
2658
2506
|
// math:lessThan
|
|
2659
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2507
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'lessThan') {
|
|
2660
2508
|
const aInfo = parseNumericForCompareTerm(g.s);
|
|
2661
2509
|
const bInfo = parseNumericForCompareTerm(g.o);
|
|
2662
|
-
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo,
|
|
2663
|
-
return [{ ...subst }];
|
|
2510
|
+
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, '<')) return [{ ...subst }];
|
|
2664
2511
|
|
|
2665
2512
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2666
2513
|
const a2 = parseNumericForCompareTerm(g.s.elems[0]);
|
|
2667
2514
|
const b2 = parseNumericForCompareTerm(g.s.elems[1]);
|
|
2668
|
-
if (a2 && b2 && cmpNumericInfo(a2, b2,
|
|
2515
|
+
if (a2 && b2 && cmpNumericInfo(a2, b2, '<')) return [{ ...subst }];
|
|
2669
2516
|
}
|
|
2670
2517
|
return [];
|
|
2671
2518
|
}
|
|
2672
2519
|
|
|
2673
2520
|
// math:notLessThan
|
|
2674
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2521
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'notLessThan') {
|
|
2675
2522
|
const aInfo = parseNumericForCompareTerm(g.s);
|
|
2676
2523
|
const bInfo = parseNumericForCompareTerm(g.o);
|
|
2677
|
-
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo,
|
|
2678
|
-
return [{ ...subst }];
|
|
2524
|
+
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, '>=')) return [{ ...subst }];
|
|
2679
2525
|
|
|
2680
2526
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2681
2527
|
const a2 = parseNumericForCompareTerm(g.s.elems[0]);
|
|
2682
2528
|
const b2 = parseNumericForCompareTerm(g.s.elems[1]);
|
|
2683
|
-
if (a2 && b2 && cmpNumericInfo(a2, b2,
|
|
2529
|
+
if (a2 && b2 && cmpNumericInfo(a2, b2, '>=')) return [{ ...subst }];
|
|
2684
2530
|
}
|
|
2685
2531
|
return [];
|
|
2686
2532
|
}
|
|
2687
2533
|
|
|
2688
2534
|
// math:notGreaterThan
|
|
2689
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2535
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'notGreaterThan') {
|
|
2690
2536
|
const aInfo = parseNumericForCompareTerm(g.s);
|
|
2691
2537
|
const bInfo = parseNumericForCompareTerm(g.o);
|
|
2692
|
-
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo,
|
|
2693
|
-
return [{ ...subst }];
|
|
2538
|
+
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, '<=')) return [{ ...subst }];
|
|
2694
2539
|
|
|
2695
2540
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2696
2541
|
const a2 = parseNumericForCompareTerm(g.s.elems[0]);
|
|
2697
2542
|
const b2 = parseNumericForCompareTerm(g.s.elems[1]);
|
|
2698
|
-
if (a2 && b2 && cmpNumericInfo(a2, b2,
|
|
2543
|
+
if (a2 && b2 && cmpNumericInfo(a2, b2, '<=')) return [{ ...subst }];
|
|
2699
2544
|
}
|
|
2700
2545
|
return [];
|
|
2701
2546
|
}
|
|
2702
2547
|
|
|
2703
2548
|
// math:equalTo
|
|
2704
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2549
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'equalTo') {
|
|
2705
2550
|
const aInfo = parseNumericForCompareTerm(g.s);
|
|
2706
2551
|
const bInfo = parseNumericForCompareTerm(g.o);
|
|
2707
|
-
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo,
|
|
2708
|
-
return [{ ...subst }];
|
|
2552
|
+
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, '==')) return [{ ...subst }];
|
|
2709
2553
|
|
|
2710
2554
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2711
2555
|
const a2 = parseNumericForCompareTerm(g.s.elems[0]);
|
|
2712
2556
|
const b2 = parseNumericForCompareTerm(g.s.elems[1]);
|
|
2713
|
-
if (a2 && b2 && cmpNumericInfo(a2, b2,
|
|
2557
|
+
if (a2 && b2 && cmpNumericInfo(a2, b2, '==')) return [{ ...subst }];
|
|
2714
2558
|
}
|
|
2715
2559
|
return [];
|
|
2716
2560
|
}
|
|
2717
2561
|
|
|
2718
2562
|
// math:notEqualTo
|
|
2719
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2563
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'notEqualTo') {
|
|
2720
2564
|
const aInfo = parseNumericForCompareTerm(g.s);
|
|
2721
2565
|
const bInfo = parseNumericForCompareTerm(g.o);
|
|
2722
|
-
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo,
|
|
2723
|
-
return [{ ...subst }];
|
|
2566
|
+
if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, '!=')) return [{ ...subst }];
|
|
2724
2567
|
|
|
2725
2568
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2726
2569
|
const a2 = parseNumericForCompareTerm(g.s.elems[0]);
|
|
2727
2570
|
const b2 = parseNumericForCompareTerm(g.s.elems[1]);
|
|
2728
|
-
if (a2 && b2 && cmpNumericInfo(a2, b2,
|
|
2571
|
+
if (a2 && b2 && cmpNumericInfo(a2, b2, '!=')) return [{ ...subst }];
|
|
2729
2572
|
}
|
|
2730
2573
|
return [];
|
|
2731
2574
|
}
|
|
2732
2575
|
|
|
2733
2576
|
// math:sum
|
|
2734
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2577
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'sum') {
|
|
2735
2578
|
if (g.s instanceof ListTerm && g.s.elems.length >= 2) {
|
|
2736
2579
|
const xs = g.s.elems;
|
|
2737
2580
|
const values = [];
|
|
@@ -2742,7 +2585,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2742
2585
|
}
|
|
2743
2586
|
|
|
2744
2587
|
let lit;
|
|
2745
|
-
const allBig = values.every((v) => typeof v ===
|
|
2588
|
+
const allBig = values.every((v) => typeof v === 'bigint');
|
|
2746
2589
|
if (allBig) {
|
|
2747
2590
|
let total = 0n;
|
|
2748
2591
|
for (const v of values) total += v;
|
|
@@ -2750,7 +2593,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2750
2593
|
} else {
|
|
2751
2594
|
let total = 0.0;
|
|
2752
2595
|
for (const v of values) {
|
|
2753
|
-
total += typeof v ===
|
|
2596
|
+
total += typeof v === 'bigint' ? Number(v) : v;
|
|
2754
2597
|
}
|
|
2755
2598
|
lit = new Literal(formatNum(total));
|
|
2756
2599
|
}
|
|
@@ -2767,7 +2610,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2767
2610
|
}
|
|
2768
2611
|
|
|
2769
2612
|
// math:product
|
|
2770
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2613
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'product') {
|
|
2771
2614
|
if (g.s instanceof ListTerm && g.s.elems.length >= 2) {
|
|
2772
2615
|
const xs = g.s.elems;
|
|
2773
2616
|
const values = [];
|
|
@@ -2778,7 +2621,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2778
2621
|
}
|
|
2779
2622
|
|
|
2780
2623
|
let lit;
|
|
2781
|
-
const allBig = values.every((v) => typeof v ===
|
|
2624
|
+
const allBig = values.every((v) => typeof v === 'bigint');
|
|
2782
2625
|
if (allBig) {
|
|
2783
2626
|
let prod = 1n;
|
|
2784
2627
|
for (const v of values) prod *= v;
|
|
@@ -2786,7 +2629,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2786
2629
|
} else {
|
|
2787
2630
|
let prod = 1.0;
|
|
2788
2631
|
for (const v of values) {
|
|
2789
|
-
prod *= typeof v ===
|
|
2632
|
+
prod *= typeof v === 'bigint' ? Number(v) : v;
|
|
2790
2633
|
}
|
|
2791
2634
|
lit = new Literal(formatNum(prod));
|
|
2792
2635
|
}
|
|
@@ -2804,7 +2647,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2804
2647
|
}
|
|
2805
2648
|
|
|
2806
2649
|
// math:difference
|
|
2807
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2650
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'difference') {
|
|
2808
2651
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2809
2652
|
const [a0, b0] = g.s.elems;
|
|
2810
2653
|
|
|
@@ -2859,7 +2702,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2859
2702
|
}
|
|
2860
2703
|
|
|
2861
2704
|
// math:quotient
|
|
2862
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2705
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'quotient') {
|
|
2863
2706
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2864
2707
|
const a = parseNum(g.s.elems[0]);
|
|
2865
2708
|
const b = parseNum(g.s.elems[1]);
|
|
@@ -2881,7 +2724,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2881
2724
|
// math:integerQuotient
|
|
2882
2725
|
// Schema: ( $a $b ) math:integerQuotient $q
|
|
2883
2726
|
// Cwm: divide first integer by second integer, ignoring remainder. :contentReference[oaicite:1]{index=1}
|
|
2884
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2727
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'integerQuotient') {
|
|
2885
2728
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
2886
2729
|
const [a0, b0] = g.s.elems;
|
|
2887
2730
|
|
|
@@ -2920,7 +2763,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2920
2763
|
}
|
|
2921
2764
|
|
|
2922
2765
|
// math:exponentiation
|
|
2923
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2766
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'exponentiation') {
|
|
2924
2767
|
if (g.s instanceof ListTerm && g.s.elems.length === 2) {
|
|
2925
2768
|
const a = parseNum(g.s.elems[0]);
|
|
2926
2769
|
const b0 = g.s.elems[1];
|
|
@@ -2954,7 +2797,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2954
2797
|
}
|
|
2955
2798
|
|
|
2956
2799
|
// math:negation
|
|
2957
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2800
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'negation') {
|
|
2958
2801
|
const a = parseNum(g.s);
|
|
2959
2802
|
if (a !== null && g.o instanceof Var) {
|
|
2960
2803
|
const s2 = { ...subst };
|
|
@@ -2976,7 +2819,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2976
2819
|
}
|
|
2977
2820
|
|
|
2978
2821
|
// math:absoluteValue
|
|
2979
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2822
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'absoluteValue') {
|
|
2980
2823
|
const a = parseNum(g.s);
|
|
2981
2824
|
if (a !== null && g.o instanceof Var) {
|
|
2982
2825
|
const s2 = { ...subst };
|
|
@@ -2991,7 +2834,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2991
2834
|
}
|
|
2992
2835
|
|
|
2993
2836
|
// math:cos
|
|
2994
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2837
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'cos') {
|
|
2995
2838
|
const a = parseNum(g.s);
|
|
2996
2839
|
if (a !== null) {
|
|
2997
2840
|
const cVal = Math.cos(a);
|
|
@@ -3008,7 +2851,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3008
2851
|
}
|
|
3009
2852
|
|
|
3010
2853
|
// math:sin
|
|
3011
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2854
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'sin') {
|
|
3012
2855
|
const a = parseNum(g.s);
|
|
3013
2856
|
if (a !== null) {
|
|
3014
2857
|
const cVal = Math.sin(a);
|
|
@@ -3025,7 +2868,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3025
2868
|
}
|
|
3026
2869
|
|
|
3027
2870
|
// math:acos
|
|
3028
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2871
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'acos') {
|
|
3029
2872
|
const a = parseNum(g.s);
|
|
3030
2873
|
if (a !== null) {
|
|
3031
2874
|
const cVal = Math.acos(a);
|
|
@@ -3044,7 +2887,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3044
2887
|
}
|
|
3045
2888
|
|
|
3046
2889
|
// math:asin
|
|
3047
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2890
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'asin') {
|
|
3048
2891
|
const a = parseNum(g.s);
|
|
3049
2892
|
if (a !== null) {
|
|
3050
2893
|
const cVal = Math.asin(a);
|
|
@@ -3063,7 +2906,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3063
2906
|
}
|
|
3064
2907
|
|
|
3065
2908
|
// math:atan
|
|
3066
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2909
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'atan') {
|
|
3067
2910
|
const a = parseNum(g.s);
|
|
3068
2911
|
if (a !== null) {
|
|
3069
2912
|
const cVal = Math.atan(a);
|
|
@@ -3083,9 +2926,9 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3083
2926
|
|
|
3084
2927
|
// math:cosh
|
|
3085
2928
|
// Hyperbolic cosine
|
|
3086
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2929
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'cosh') {
|
|
3087
2930
|
const a = parseNum(g.s);
|
|
3088
|
-
if (a !== null && typeof Math.cosh ===
|
|
2931
|
+
if (a !== null && typeof Math.cosh === 'function') {
|
|
3089
2932
|
const cVal = Math.cosh(a);
|
|
3090
2933
|
if (Number.isFinite(cVal)) {
|
|
3091
2934
|
if (g.o instanceof Var) {
|
|
@@ -3103,7 +2946,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3103
2946
|
|
|
3104
2947
|
// math:degrees
|
|
3105
2948
|
// Convert radians -> degrees
|
|
3106
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2949
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'degrees') {
|
|
3107
2950
|
const a = parseNum(g.s);
|
|
3108
2951
|
if (a !== null) {
|
|
3109
2952
|
const cVal = (a * 180.0) / Math.PI;
|
|
@@ -3124,7 +2967,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3124
2967
|
// math:remainder
|
|
3125
2968
|
// Subject is a list (dividend divisor); object is the remainder.
|
|
3126
2969
|
// Schema: ( $a $b ) math:remainder $r
|
|
3127
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2970
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'remainder') {
|
|
3128
2971
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3129
2972
|
const a = parseNum(g.s.elems[0]);
|
|
3130
2973
|
const b = parseNum(g.s.elems[1]);
|
|
@@ -3146,7 +2989,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3146
2989
|
// Round to nearest integer.
|
|
3147
2990
|
// If there are two such numbers, then the one closest to positive infinity is returned.
|
|
3148
2991
|
// Schema: $s math:rounded $o
|
|
3149
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
2992
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'rounded') {
|
|
3150
2993
|
const a = parseNum(g.s);
|
|
3151
2994
|
if (a === null) return [];
|
|
3152
2995
|
const rVal = Math.round(a);
|
|
@@ -3162,9 +3005,9 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3162
3005
|
}
|
|
3163
3006
|
|
|
3164
3007
|
// math:sinh
|
|
3165
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
3008
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'sinh') {
|
|
3166
3009
|
const a = parseNum(g.s);
|
|
3167
|
-
if (a !== null && typeof Math.sinh ===
|
|
3010
|
+
if (a !== null && typeof Math.sinh === 'function') {
|
|
3168
3011
|
const cVal = Math.sinh(a);
|
|
3169
3012
|
if (Number.isFinite(cVal)) {
|
|
3170
3013
|
if (g.o instanceof Var) {
|
|
@@ -3181,7 +3024,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3181
3024
|
}
|
|
3182
3025
|
|
|
3183
3026
|
// math:tan
|
|
3184
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
3027
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'tan') {
|
|
3185
3028
|
const a = parseNum(g.s);
|
|
3186
3029
|
if (a !== null) {
|
|
3187
3030
|
const cVal = Math.tan(a);
|
|
@@ -3200,9 +3043,9 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3200
3043
|
}
|
|
3201
3044
|
|
|
3202
3045
|
// math:tanh
|
|
3203
|
-
if (g.p instanceof Iri && g.p.value === MATH_NS +
|
|
3046
|
+
if (g.p instanceof Iri && g.p.value === MATH_NS + 'tanh') {
|
|
3204
3047
|
const a = parseNum(g.s);
|
|
3205
|
-
if (a !== null && typeof Math.tanh ===
|
|
3048
|
+
if (a !== null && typeof Math.tanh === 'function') {
|
|
3206
3049
|
const cVal = Math.tanh(a);
|
|
3207
3050
|
if (Number.isFinite(cVal)) {
|
|
3208
3051
|
if (g.o instanceof Var) {
|
|
@@ -3224,7 +3067,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3224
3067
|
|
|
3225
3068
|
// time:localTime
|
|
3226
3069
|
// "" time:localTime ?D. binds ?D to “now” as xsd:dateTime.
|
|
3227
|
-
if (g.p instanceof Iri && g.p.value === TIME_NS +
|
|
3070
|
+
if (g.p instanceof Iri && g.p.value === TIME_NS + 'localTime') {
|
|
3228
3071
|
const now = getNowLex();
|
|
3229
3072
|
|
|
3230
3073
|
if (g.o instanceof Var) {
|
|
@@ -3246,7 +3089,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3246
3089
|
// list:append
|
|
3247
3090
|
// true if and only if $o is the concatenation of all lists $s.i.
|
|
3248
3091
|
// Schema: ( $s.i?[*] )+ list:append $o?
|
|
3249
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3092
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'append') {
|
|
3250
3093
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3251
3094
|
const parts = g.s.elems;
|
|
3252
3095
|
if (g.o instanceof ListTerm) {
|
|
@@ -3270,7 +3113,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3270
3113
|
// list:first
|
|
3271
3114
|
// true iff $s is a list and $o is the first member of that list.
|
|
3272
3115
|
// Schema: $s+ list:first $o-
|
|
3273
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3116
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'first') {
|
|
3274
3117
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3275
3118
|
if (!g.s.elems.length) return [];
|
|
3276
3119
|
const first = g.s.elems[0];
|
|
@@ -3281,7 +3124,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3281
3124
|
// list:rest
|
|
3282
3125
|
// true iff $s is a (non-empty) list and $o is the rest (tail) of that list.
|
|
3283
3126
|
// Schema: $s+ list:rest $o-
|
|
3284
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3127
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'rest') {
|
|
3285
3128
|
// Closed list: (a b c) -> (b c)
|
|
3286
3129
|
if (g.s instanceof ListTerm) {
|
|
3287
3130
|
if (!g.s.elems.length) return [];
|
|
@@ -3310,7 +3153,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3310
3153
|
|
|
3311
3154
|
// rdf:first (alias of list:first)
|
|
3312
3155
|
// Schema: $s+ rdf:first $o-
|
|
3313
|
-
if (g.p instanceof Iri && g.p.value === RDF_NS +
|
|
3156
|
+
if (g.p instanceof Iri && g.p.value === RDF_NS + 'first') {
|
|
3314
3157
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3315
3158
|
if (!g.s.elems.length) return [];
|
|
3316
3159
|
const first = g.s.elems[0];
|
|
@@ -3320,7 +3163,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3320
3163
|
|
|
3321
3164
|
// rdf:rest (alias of list:rest)
|
|
3322
3165
|
// Schema: $s+ rdf:rest $o-
|
|
3323
|
-
if (g.p instanceof Iri && g.p.value === RDF_NS +
|
|
3166
|
+
if (g.p instanceof Iri && g.p.value === RDF_NS + 'rest') {
|
|
3324
3167
|
// Closed list: (a b c) -> (b c)
|
|
3325
3168
|
if (g.s instanceof ListTerm) {
|
|
3326
3169
|
if (!g.s.elems.length) return [];
|
|
@@ -3346,7 +3189,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3346
3189
|
// Multi-solution builtin:
|
|
3347
3190
|
// For a list subject $s, generate solutions by unifying $o with (index value).
|
|
3348
3191
|
// This allows $o to be a variable (e.g., ?Y) or a pattern (e.g., (?i "Dewey")).
|
|
3349
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3192
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'iterate') {
|
|
3350
3193
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3351
3194
|
const xs = g.s.elems;
|
|
3352
3195
|
const outs = [];
|
|
@@ -3362,7 +3205,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3362
3205
|
// list:last
|
|
3363
3206
|
// true iff $s is a list and $o is the last member of that list.
|
|
3364
3207
|
// Schema: $s+ list:last $o-
|
|
3365
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3208
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'last') {
|
|
3366
3209
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3367
3210
|
const xs = g.s.elems;
|
|
3368
3211
|
if (!xs.length) return [];
|
|
@@ -3374,7 +3217,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3374
3217
|
// list:memberAt
|
|
3375
3218
|
// true iff $s.1 is a list, $s.2 is a valid index, and $o is the member at that index.
|
|
3376
3219
|
// Schema: ( $s.1+ $s.2?[*] )+ list:memberAt $o?[*]
|
|
3377
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3220
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'memberAt') {
|
|
3378
3221
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3379
3222
|
const [listTerm, indexTerm] = g.s.elems;
|
|
3380
3223
|
if (!(listTerm instanceof ListTerm)) return [];
|
|
@@ -3395,7 +3238,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3395
3238
|
// list:remove
|
|
3396
3239
|
// true iff $s.1 is a list and $o is that list with all occurrences of $s.2 removed.
|
|
3397
3240
|
// Schema: ( $s.1+ $s.2+ )+ list:remove $o-
|
|
3398
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3241
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'remove') {
|
|
3399
3242
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3400
3243
|
const [listTerm, itemTerm] = g.s.elems;
|
|
3401
3244
|
if (!(listTerm instanceof ListTerm)) return [];
|
|
@@ -3410,7 +3253,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3410
3253
|
}
|
|
3411
3254
|
|
|
3412
3255
|
// list:member
|
|
3413
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3256
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'member') {
|
|
3414
3257
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3415
3258
|
const outs = [];
|
|
3416
3259
|
for (const x of g.s.elems) {
|
|
@@ -3421,7 +3264,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3421
3264
|
}
|
|
3422
3265
|
|
|
3423
3266
|
// list:in
|
|
3424
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3267
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'in') {
|
|
3425
3268
|
if (!(g.o instanceof ListTerm)) return [];
|
|
3426
3269
|
const outs = [];
|
|
3427
3270
|
for (const x of g.o.elems) {
|
|
@@ -3432,7 +3275,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3432
3275
|
}
|
|
3433
3276
|
|
|
3434
3277
|
// list:length
|
|
3435
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3278
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'length') {
|
|
3436
3279
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3437
3280
|
const nTerm = new Literal(String(g.s.elems.length));
|
|
3438
3281
|
const s2 = unifyTerm(g.o, nTerm, subst);
|
|
@@ -3440,7 +3283,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3440
3283
|
}
|
|
3441
3284
|
|
|
3442
3285
|
// list:notMember
|
|
3443
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3286
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'notMember') {
|
|
3444
3287
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3445
3288
|
for (const el of g.s.elems) {
|
|
3446
3289
|
if (unifyTerm(g.o, el, subst) !== null) return [];
|
|
@@ -3449,7 +3292,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3449
3292
|
}
|
|
3450
3293
|
|
|
3451
3294
|
// list:reverse
|
|
3452
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3295
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'reverse') {
|
|
3453
3296
|
if (g.s instanceof ListTerm) {
|
|
3454
3297
|
const rev = [...g.s.elems].reverse();
|
|
3455
3298
|
const rterm = new ListTerm(rev);
|
|
@@ -3466,7 +3309,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3466
3309
|
}
|
|
3467
3310
|
|
|
3468
3311
|
// list:sort
|
|
3469
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3312
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'sort') {
|
|
3470
3313
|
function cmpTermForSort(a, b) {
|
|
3471
3314
|
if (a instanceof Literal && b instanceof Literal) {
|
|
3472
3315
|
const [lexA] = literalParts(a.value);
|
|
@@ -3534,7 +3377,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3534
3377
|
}
|
|
3535
3378
|
|
|
3536
3379
|
// list:map
|
|
3537
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3380
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'map') {
|
|
3538
3381
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3539
3382
|
const [inputTerm, predTerm] = g.s.elems;
|
|
3540
3383
|
if (!(inputTerm instanceof ListTerm)) return [];
|
|
@@ -3546,16 +3389,9 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3546
3389
|
|
|
3547
3390
|
const results = [];
|
|
3548
3391
|
for (const el of inputList) {
|
|
3549
|
-
const yvar = new Var(
|
|
3392
|
+
const yvar = new Var('_mapY');
|
|
3550
3393
|
const goal2 = new Triple(el, pred, yvar);
|
|
3551
|
-
const sols = evalBuiltin(
|
|
3552
|
-
goal2,
|
|
3553
|
-
subst,
|
|
3554
|
-
facts,
|
|
3555
|
-
backRules,
|
|
3556
|
-
depth + 1,
|
|
3557
|
-
varGen,
|
|
3558
|
-
);
|
|
3394
|
+
const sols = evalBuiltin(goal2, subst, facts, backRules, depth + 1, varGen);
|
|
3559
3395
|
if (!sols.length) return [];
|
|
3560
3396
|
const yval = applySubstTerm(yvar, sols[0]);
|
|
3561
3397
|
if (yval instanceof Var) return [];
|
|
@@ -3567,7 +3403,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3567
3403
|
}
|
|
3568
3404
|
|
|
3569
3405
|
// list:firstRest
|
|
3570
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS +
|
|
3406
|
+
if (g.p instanceof Iri && g.p.value === LIST_NS + 'firstRest') {
|
|
3571
3407
|
if (g.s instanceof ListTerm) {
|
|
3572
3408
|
if (!g.s.elems.length) return [];
|
|
3573
3409
|
const first = g.s.elems[0];
|
|
@@ -3605,20 +3441,20 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3605
3441
|
// -----------------------------------------------------------------
|
|
3606
3442
|
|
|
3607
3443
|
// log:equalTo
|
|
3608
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3444
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'equalTo') {
|
|
3609
3445
|
const s2 = unifyTerm(goal.s, goal.o, subst);
|
|
3610
3446
|
return s2 !== null ? [s2] : [];
|
|
3611
3447
|
}
|
|
3612
3448
|
|
|
3613
3449
|
// log:notEqualTo
|
|
3614
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3450
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'notEqualTo') {
|
|
3615
3451
|
const s2 = unifyTerm(goal.s, goal.o, subst);
|
|
3616
3452
|
if (s2 !== null) return [];
|
|
3617
3453
|
return [{ ...subst }];
|
|
3618
3454
|
}
|
|
3619
3455
|
|
|
3620
3456
|
// log:implies — expose internal forward rules as data
|
|
3621
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3457
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'implies') {
|
|
3622
3458
|
const allFw = backRules.__allForwardRules || [];
|
|
3623
3459
|
const results = [];
|
|
3624
3460
|
|
|
@@ -3629,9 +3465,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3629
3465
|
const r = standardizeRule(r0, varGen);
|
|
3630
3466
|
|
|
3631
3467
|
const premF = new FormulaTerm(r.premise);
|
|
3632
|
-
const concTerm = r0.isFuse
|
|
3633
|
-
? new Literal("false")
|
|
3634
|
-
: new FormulaTerm(r.conclusion);
|
|
3468
|
+
const concTerm = r0.isFuse ? new Literal('false') : new FormulaTerm(r.conclusion);
|
|
3635
3469
|
|
|
3636
3470
|
// unify subject with the premise formula
|
|
3637
3471
|
let s2 = unifyTerm(goal.s, premF, subst);
|
|
@@ -3648,7 +3482,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3648
3482
|
}
|
|
3649
3483
|
|
|
3650
3484
|
// log:impliedBy — expose internal backward rules as data
|
|
3651
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3485
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'impliedBy') {
|
|
3652
3486
|
const allBw = backRules.__allBackwardRules || backRules;
|
|
3653
3487
|
const results = [];
|
|
3654
3488
|
|
|
@@ -3677,39 +3511,23 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3677
3511
|
}
|
|
3678
3512
|
|
|
3679
3513
|
// log:notIncludes
|
|
3680
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3514
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'notIncludes') {
|
|
3681
3515
|
if (!(g.o instanceof FormulaTerm)) return [];
|
|
3682
3516
|
const body = g.o.triples;
|
|
3683
3517
|
const visited2 = [];
|
|
3684
|
-
const sols = proveGoals(
|
|
3685
|
-
Array.from(body),
|
|
3686
|
-
{},
|
|
3687
|
-
facts,
|
|
3688
|
-
backRules,
|
|
3689
|
-
depth + 1,
|
|
3690
|
-
visited2,
|
|
3691
|
-
varGen,
|
|
3692
|
-
);
|
|
3518
|
+
const sols = proveGoals(Array.from(body), {}, facts, backRules, depth + 1, visited2, varGen);
|
|
3693
3519
|
if (!sols.length) return [{ ...subst }];
|
|
3694
3520
|
return [];
|
|
3695
3521
|
}
|
|
3696
3522
|
|
|
3697
3523
|
// log:collectAllIn
|
|
3698
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3524
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'collectAllIn') {
|
|
3699
3525
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 3) return [];
|
|
3700
3526
|
const [valueTempl, clauseTerm, listTerm] = g.s.elems;
|
|
3701
3527
|
if (!(clauseTerm instanceof FormulaTerm)) return [];
|
|
3702
3528
|
const body = clauseTerm.triples;
|
|
3703
3529
|
const visited2 = [];
|
|
3704
|
-
const sols = proveGoals(
|
|
3705
|
-
Array.from(body),
|
|
3706
|
-
{},
|
|
3707
|
-
facts,
|
|
3708
|
-
backRules,
|
|
3709
|
-
depth + 1,
|
|
3710
|
-
visited2,
|
|
3711
|
-
varGen,
|
|
3712
|
-
);
|
|
3530
|
+
const sols = proveGoals(Array.from(body), {}, facts, backRules, depth + 1, visited2, varGen);
|
|
3713
3531
|
|
|
3714
3532
|
// Collect one value per *solution*, duplicates allowed
|
|
3715
3533
|
const collected = [];
|
|
@@ -3724,7 +3542,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3724
3542
|
}
|
|
3725
3543
|
|
|
3726
3544
|
// log:forAllIn
|
|
3727
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3545
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'forAllIn') {
|
|
3728
3546
|
// Subject: list with two clauses (where-clause, then-clause)
|
|
3729
3547
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3730
3548
|
const [whereClause, thenClause] = g.s.elems;
|
|
@@ -3733,29 +3551,13 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3733
3551
|
|
|
3734
3552
|
// 1. Find all substitutions that make the first clause true
|
|
3735
3553
|
const visited1 = [];
|
|
3736
|
-
const sols1 = proveGoals(
|
|
3737
|
-
Array.from(whereClause.triples),
|
|
3738
|
-
{},
|
|
3739
|
-
facts,
|
|
3740
|
-
backRules,
|
|
3741
|
-
depth + 1,
|
|
3742
|
-
visited1,
|
|
3743
|
-
varGen,
|
|
3744
|
-
);
|
|
3554
|
+
const sols1 = proveGoals(Array.from(whereClause.triples), {}, facts, backRules, depth + 1, visited1, varGen);
|
|
3745
3555
|
|
|
3746
3556
|
// 2. For every such substitution, check that the second clause holds too.
|
|
3747
3557
|
// If there are no matches for the first clause, this is vacuously true.
|
|
3748
3558
|
for (const s1 of sols1) {
|
|
3749
3559
|
const visited2 = [];
|
|
3750
|
-
const sols2 = proveGoals(
|
|
3751
|
-
Array.from(thenClause.triples),
|
|
3752
|
-
s1,
|
|
3753
|
-
facts,
|
|
3754
|
-
backRules,
|
|
3755
|
-
depth + 1,
|
|
3756
|
-
visited2,
|
|
3757
|
-
varGen,
|
|
3758
|
-
);
|
|
3560
|
+
const sols2 = proveGoals(Array.from(thenClause.triples), s1, facts, backRules, depth + 1, visited2, varGen);
|
|
3759
3561
|
// Found a counterexample: whereClause holds but thenClause does not
|
|
3760
3562
|
if (!sols2.length) return [];
|
|
3761
3563
|
}
|
|
@@ -3765,7 +3567,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3765
3567
|
}
|
|
3766
3568
|
|
|
3767
3569
|
// log:skolem
|
|
3768
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3570
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'skolem') {
|
|
3769
3571
|
// Subject must be ground; commonly a list, but we allow any ground term.
|
|
3770
3572
|
if (!isGroundTerm(g.s)) return [];
|
|
3771
3573
|
|
|
@@ -3782,7 +3584,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3782
3584
|
}
|
|
3783
3585
|
|
|
3784
3586
|
// log:uri
|
|
3785
|
-
if (g.p instanceof Iri && g.p.value === LOG_NS +
|
|
3587
|
+
if (g.p instanceof Iri && g.p.value === LOG_NS + 'uri') {
|
|
3786
3588
|
// Direction 1: subject is an IRI -> object is its string representation
|
|
3787
3589
|
if (g.s instanceof Iri) {
|
|
3788
3590
|
const uriStr = g.s.value; // raw IRI string, e.g. "https://www.w3.org"
|
|
@@ -3810,7 +3612,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3810
3612
|
// -----------------------------------------------------------------
|
|
3811
3613
|
|
|
3812
3614
|
// string:concatenation
|
|
3813
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3615
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'concatenation') {
|
|
3814
3616
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3815
3617
|
const parts = [];
|
|
3816
3618
|
for (const t of g.s.elems) {
|
|
@@ -3818,7 +3620,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3818
3620
|
if (sStr === null) return [];
|
|
3819
3621
|
parts.push(sStr);
|
|
3820
3622
|
}
|
|
3821
|
-
const lit = makeStringLiteral(parts.join(
|
|
3623
|
+
const lit = makeStringLiteral(parts.join(''));
|
|
3822
3624
|
|
|
3823
3625
|
if (g.o instanceof Var) {
|
|
3824
3626
|
const s2 = { ...subst };
|
|
@@ -3830,7 +3632,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3830
3632
|
}
|
|
3831
3633
|
|
|
3832
3634
|
// string:contains
|
|
3833
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3635
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'contains') {
|
|
3834
3636
|
const sStr = termToJsString(g.s);
|
|
3835
3637
|
const oStr = termToJsString(g.o);
|
|
3836
3638
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3838,17 +3640,15 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3838
3640
|
}
|
|
3839
3641
|
|
|
3840
3642
|
// string:containsIgnoringCase
|
|
3841
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3643
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'containsIgnoringCase') {
|
|
3842
3644
|
const sStr = termToJsString(g.s);
|
|
3843
3645
|
const oStr = termToJsString(g.o);
|
|
3844
3646
|
if (sStr === null || oStr === null) return [];
|
|
3845
|
-
return sStr.toLowerCase().includes(oStr.toLowerCase())
|
|
3846
|
-
? [{ ...subst }]
|
|
3847
|
-
: [];
|
|
3647
|
+
return sStr.toLowerCase().includes(oStr.toLowerCase()) ? [{ ...subst }] : [];
|
|
3848
3648
|
}
|
|
3849
3649
|
|
|
3850
3650
|
// string:endsWith
|
|
3851
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3651
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'endsWith') {
|
|
3852
3652
|
const sStr = termToJsString(g.s);
|
|
3853
3653
|
const oStr = termToJsString(g.o);
|
|
3854
3654
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3856,7 +3656,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3856
3656
|
}
|
|
3857
3657
|
|
|
3858
3658
|
// string:equalIgnoringCase
|
|
3859
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3659
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'equalIgnoringCase') {
|
|
3860
3660
|
const sStr = termToJsString(g.s);
|
|
3861
3661
|
const oStr = termToJsString(g.o);
|
|
3862
3662
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3865,7 +3665,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3865
3665
|
|
|
3866
3666
|
// string:format
|
|
3867
3667
|
// (limited: only %s and %% are supported, anything else ⇒ builtin fails)
|
|
3868
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3668
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'format') {
|
|
3869
3669
|
if (!(g.s instanceof ListTerm) || g.s.elems.length < 1) return [];
|
|
3870
3670
|
const fmtStr = termToJsString(g.s.elems[0]);
|
|
3871
3671
|
if (fmtStr === null) return [];
|
|
@@ -3892,7 +3692,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3892
3692
|
|
|
3893
3693
|
// string:jsonPointer
|
|
3894
3694
|
// Schema: ( $jsonText $pointer ) string:jsonPointer $value
|
|
3895
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3695
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'jsonPointer') {
|
|
3896
3696
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
3897
3697
|
|
|
3898
3698
|
const jsonText = termToJsonText(g.s.elems[0]); // <-- changed
|
|
@@ -3907,7 +3707,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3907
3707
|
}
|
|
3908
3708
|
|
|
3909
3709
|
// string:greaterThan
|
|
3910
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3710
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'greaterThan') {
|
|
3911
3711
|
const sStr = termToJsString(g.s);
|
|
3912
3712
|
const oStr = termToJsString(g.o);
|
|
3913
3713
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3915,7 +3715,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3915
3715
|
}
|
|
3916
3716
|
|
|
3917
3717
|
// string:lessThan
|
|
3918
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3718
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'lessThan') {
|
|
3919
3719
|
const sStr = termToJsString(g.s);
|
|
3920
3720
|
const oStr = termToJsString(g.o);
|
|
3921
3721
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3923,7 +3723,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3923
3723
|
}
|
|
3924
3724
|
|
|
3925
3725
|
// string:matches
|
|
3926
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3726
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'matches') {
|
|
3927
3727
|
const sStr = termToJsString(g.s);
|
|
3928
3728
|
const pattern = termToJsString(g.o);
|
|
3929
3729
|
if (sStr === null || pattern === null) return [];
|
|
@@ -3938,7 +3738,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3938
3738
|
}
|
|
3939
3739
|
|
|
3940
3740
|
// string:notEqualIgnoringCase
|
|
3941
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3741
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'notEqualIgnoringCase') {
|
|
3942
3742
|
const sStr = termToJsString(g.s);
|
|
3943
3743
|
const oStr = termToJsString(g.o);
|
|
3944
3744
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3946,7 +3746,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3946
3746
|
}
|
|
3947
3747
|
|
|
3948
3748
|
// string:notGreaterThan (≤ in Unicode code order)
|
|
3949
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3749
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'notGreaterThan') {
|
|
3950
3750
|
const sStr = termToJsString(g.s);
|
|
3951
3751
|
const oStr = termToJsString(g.o);
|
|
3952
3752
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3954,7 +3754,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3954
3754
|
}
|
|
3955
3755
|
|
|
3956
3756
|
// string:notLessThan (≥ in Unicode code order)
|
|
3957
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3757
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'notLessThan') {
|
|
3958
3758
|
const sStr = termToJsString(g.s);
|
|
3959
3759
|
const oStr = termToJsString(g.o);
|
|
3960
3760
|
if (sStr === null || oStr === null) return [];
|
|
@@ -3962,7 +3762,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3962
3762
|
}
|
|
3963
3763
|
|
|
3964
3764
|
// string:notMatches
|
|
3965
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3765
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'notMatches') {
|
|
3966
3766
|
const sStr = termToJsString(g.s);
|
|
3967
3767
|
const pattern = termToJsString(g.o);
|
|
3968
3768
|
if (sStr === null || pattern === null) return [];
|
|
@@ -3976,7 +3776,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3976
3776
|
}
|
|
3977
3777
|
|
|
3978
3778
|
// string:replace
|
|
3979
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3779
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'replace') {
|
|
3980
3780
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 3) return [];
|
|
3981
3781
|
const dataStr = termToJsString(g.s.elems[0]);
|
|
3982
3782
|
const searchStr = termToJsString(g.s.elems[1]);
|
|
@@ -3986,7 +3786,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3986
3786
|
let re;
|
|
3987
3787
|
try {
|
|
3988
3788
|
// Global replacement
|
|
3989
|
-
re = new RegExp(searchStr,
|
|
3789
|
+
re = new RegExp(searchStr, 'g');
|
|
3990
3790
|
} catch (e) {
|
|
3991
3791
|
return [];
|
|
3992
3792
|
}
|
|
@@ -4004,7 +3804,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4004
3804
|
}
|
|
4005
3805
|
|
|
4006
3806
|
// string:scrape
|
|
4007
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3807
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'scrape') {
|
|
4008
3808
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 2) return [];
|
|
4009
3809
|
const dataStr = termToJsString(g.s.elems[0]);
|
|
4010
3810
|
const pattern = termToJsString(g.s.elems[1]);
|
|
@@ -4033,7 +3833,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4033
3833
|
}
|
|
4034
3834
|
|
|
4035
3835
|
// string:startsWith
|
|
4036
|
-
if (g.p instanceof Iri && g.p.value === STRING_NS +
|
|
3836
|
+
if (g.p instanceof Iri && g.p.value === STRING_NS + 'startsWith') {
|
|
4037
3837
|
const sStr = termToJsString(g.s);
|
|
4038
3838
|
const oStr = termToJsString(g.o);
|
|
4039
3839
|
if (sStr === null || oStr === null) return [];
|
|
@@ -4049,7 +3849,7 @@ function isBuiltinPred(p) {
|
|
|
4049
3849
|
const v = p.value;
|
|
4050
3850
|
|
|
4051
3851
|
// Treat RDF Collections as list-term builtins too.
|
|
4052
|
-
if (v === RDF_NS +
|
|
3852
|
+
if (v === RDF_NS + 'first' || v === RDF_NS + 'rest') {
|
|
4053
3853
|
return true;
|
|
4054
3854
|
}
|
|
4055
3855
|
|
|
@@ -4092,14 +3892,7 @@ function standardizeRule(rule, gen) {
|
|
|
4092
3892
|
}
|
|
4093
3893
|
if (t instanceof FormulaTerm) {
|
|
4094
3894
|
return new FormulaTerm(
|
|
4095
|
-
t.triples.map(
|
|
4096
|
-
(tr) =>
|
|
4097
|
-
new Triple(
|
|
4098
|
-
renameTerm(tr.s, vmap, genArr),
|
|
4099
|
-
renameTerm(tr.p, vmap, genArr),
|
|
4100
|
-
renameTerm(tr.o, vmap, genArr),
|
|
4101
|
-
),
|
|
4102
|
-
),
|
|
3895
|
+
t.triples.map((tr) => new Triple(renameTerm(tr.s, vmap, genArr), renameTerm(tr.p, vmap, genArr), renameTerm(tr.o, vmap, genArr))),
|
|
4103
3896
|
);
|
|
4104
3897
|
}
|
|
4105
3898
|
return t;
|
|
@@ -4107,28 +3900,12 @@ function standardizeRule(rule, gen) {
|
|
|
4107
3900
|
|
|
4108
3901
|
const vmap2 = {};
|
|
4109
3902
|
const premise = rule.premise.map(
|
|
4110
|
-
(tr) =>
|
|
4111
|
-
new Triple(
|
|
4112
|
-
renameTerm(tr.s, vmap2, gen),
|
|
4113
|
-
renameTerm(tr.p, vmap2, gen),
|
|
4114
|
-
renameTerm(tr.o, vmap2, gen),
|
|
4115
|
-
),
|
|
3903
|
+
(tr) => new Triple(renameTerm(tr.s, vmap2, gen), renameTerm(tr.p, vmap2, gen), renameTerm(tr.o, vmap2, gen)),
|
|
4116
3904
|
);
|
|
4117
3905
|
const conclusion = rule.conclusion.map(
|
|
4118
|
-
(tr) =>
|
|
4119
|
-
new Triple(
|
|
4120
|
-
renameTerm(tr.s, vmap2, gen),
|
|
4121
|
-
renameTerm(tr.p, vmap2, gen),
|
|
4122
|
-
renameTerm(tr.o, vmap2, gen),
|
|
4123
|
-
),
|
|
4124
|
-
);
|
|
4125
|
-
return new Rule(
|
|
4126
|
-
premise,
|
|
4127
|
-
conclusion,
|
|
4128
|
-
rule.isForward,
|
|
4129
|
-
rule.isFuse,
|
|
4130
|
-
rule.headBlankLabels,
|
|
3906
|
+
(tr) => new Triple(renameTerm(tr.s, vmap2, gen), renameTerm(tr.p, vmap2, gen), renameTerm(tr.o, vmap2, gen)),
|
|
4131
3907
|
);
|
|
3908
|
+
return new Rule(premise, conclusion, rule.isForward, rule.isFuse, rule.headBlankLabels);
|
|
4132
3909
|
}
|
|
4133
3910
|
|
|
4134
3911
|
function listHasTriple(list, tr) {
|
|
@@ -4268,14 +4045,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
4268
4045
|
|
|
4269
4046
|
// 1) Builtins
|
|
4270
4047
|
if (isBuiltinPred(goal0.p)) {
|
|
4271
|
-
const deltas = evalBuiltin(
|
|
4272
|
-
goal0,
|
|
4273
|
-
{},
|
|
4274
|
-
facts,
|
|
4275
|
-
backRules,
|
|
4276
|
-
state.depth,
|
|
4277
|
-
varGen,
|
|
4278
|
-
);
|
|
4048
|
+
const deltas = evalBuiltin(goal0, {}, facts, backRules, state.depth, varGen);
|
|
4279
4049
|
for (const delta of deltas) {
|
|
4280
4050
|
const composed = composeSubst(state.subst, delta);
|
|
4281
4051
|
if (composed === null) continue;
|
|
@@ -4283,12 +4053,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
4283
4053
|
if (!restGoals.length) {
|
|
4284
4054
|
results.push(gcCompactForGoals(composed, [], answerVars));
|
|
4285
4055
|
} else {
|
|
4286
|
-
const nextSubst = maybeCompactSubst(
|
|
4287
|
-
composed,
|
|
4288
|
-
restGoals,
|
|
4289
|
-
answerVars,
|
|
4290
|
-
state.depth + 1,
|
|
4291
|
-
);
|
|
4056
|
+
const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
|
|
4292
4057
|
stack.push({
|
|
4293
4058
|
goals: restGoals,
|
|
4294
4059
|
subst: nextSubst,
|
|
@@ -4317,12 +4082,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
4317
4082
|
if (!restGoals.length) {
|
|
4318
4083
|
results.push(gcCompactForGoals(composed, [], answerVars));
|
|
4319
4084
|
} else {
|
|
4320
|
-
const nextSubst = maybeCompactSubst(
|
|
4321
|
-
composed,
|
|
4322
|
-
restGoals,
|
|
4323
|
-
answerVars,
|
|
4324
|
-
state.depth + 1,
|
|
4325
|
-
);
|
|
4085
|
+
const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
|
|
4326
4086
|
stack.push({
|
|
4327
4087
|
goals: restGoals,
|
|
4328
4088
|
subst: nextSubst,
|
|
@@ -4343,12 +4103,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
4343
4103
|
if (!restGoals.length) {
|
|
4344
4104
|
results.push(gcCompactForGoals(composed, [], answerVars));
|
|
4345
4105
|
} else {
|
|
4346
|
-
const nextSubst = maybeCompactSubst(
|
|
4347
|
-
composed,
|
|
4348
|
-
restGoals,
|
|
4349
|
-
answerVars,
|
|
4350
|
-
state.depth + 1,
|
|
4351
|
-
);
|
|
4106
|
+
const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
|
|
4352
4107
|
stack.push({
|
|
4353
4108
|
goals: restGoals,
|
|
4354
4109
|
subst: nextSubst,
|
|
@@ -4362,16 +4117,13 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
4362
4117
|
// 4) Backward rules (indexed by head predicate)
|
|
4363
4118
|
if (goal0.p instanceof Iri) {
|
|
4364
4119
|
ensureBackRuleIndexes(backRules);
|
|
4365
|
-
const candRules = (
|
|
4366
|
-
backRules.__byHeadPred.get(goal0.p.value) || []
|
|
4367
|
-
).concat(backRules.__wildHeadPred);
|
|
4120
|
+
const candRules = (backRules.__byHeadPred.get(goal0.p.value) || []).concat(backRules.__wildHeadPred);
|
|
4368
4121
|
|
|
4369
4122
|
for (const r of candRules) {
|
|
4370
4123
|
if (r.conclusion.length !== 1) continue;
|
|
4371
4124
|
|
|
4372
4125
|
const rawHead = r.conclusion[0];
|
|
4373
|
-
if (rawHead.p instanceof Iri && rawHead.p.value !== goal0.p.value)
|
|
4374
|
-
continue;
|
|
4126
|
+
if (rawHead.p instanceof Iri && rawHead.p.value !== goal0.p.value) continue;
|
|
4375
4127
|
|
|
4376
4128
|
const rStd = standardizeRule(r, varGen);
|
|
4377
4129
|
const head = rStd.conclusion[0];
|
|
@@ -4383,12 +4135,7 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
4383
4135
|
if (composed === null) continue;
|
|
4384
4136
|
|
|
4385
4137
|
const newGoals = body.concat(restGoals);
|
|
4386
|
-
const nextSubst = maybeCompactSubst(
|
|
4387
|
-
composed,
|
|
4388
|
-
newGoals,
|
|
4389
|
-
answerVars,
|
|
4390
|
-
state.depth + 1,
|
|
4391
|
-
);
|
|
4138
|
+
const nextSubst = maybeCompactSubst(composed, newGoals, answerVars, state.depth + 1);
|
|
4392
4139
|
stack.push({
|
|
4393
4140
|
goals: newGoals,
|
|
4394
4141
|
subst: nextSubst,
|
|
@@ -4427,53 +4174,34 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
4427
4174
|
const empty = {};
|
|
4428
4175
|
const visited = [];
|
|
4429
4176
|
|
|
4430
|
-
const sols = proveGoals(
|
|
4431
|
-
r.premise.slice(),
|
|
4432
|
-
empty,
|
|
4433
|
-
facts,
|
|
4434
|
-
backRules,
|
|
4435
|
-
0,
|
|
4436
|
-
visited,
|
|
4437
|
-
varGen,
|
|
4438
|
-
);
|
|
4177
|
+
const sols = proveGoals(r.premise.slice(), empty, facts, backRules, 0, visited, varGen);
|
|
4439
4178
|
|
|
4440
4179
|
// Inference fuse
|
|
4441
4180
|
if (r.isFuse && sols.length) {
|
|
4442
|
-
console.log(
|
|
4443
|
-
"# Inference fuse triggered: a { ... } => false. rule fired.",
|
|
4444
|
-
);
|
|
4181
|
+
console.log('# Inference fuse triggered: a { ... } => false. rule fired.');
|
|
4445
4182
|
process.exit(2);
|
|
4446
4183
|
}
|
|
4447
4184
|
|
|
4448
4185
|
for (const s of sols) {
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4186
|
+
// IMPORTANT: one skolem map per *rule firing* so head blank nodes
|
|
4187
|
+
// (e.g., from [ :p ... ; :q ... ]) stay connected across all head triples.
|
|
4188
|
+
const skMap = {};
|
|
4189
|
+
const instantiatedPremises = r.premise.map((b) => applySubstTriple(b, s));
|
|
4452
4190
|
|
|
4453
4191
|
for (const cpat of r.conclusion) {
|
|
4454
4192
|
const instantiated = applySubstTriple(cpat, s);
|
|
4455
4193
|
|
|
4456
4194
|
const isFwRuleTriple =
|
|
4457
4195
|
isLogImplies(instantiated.p) &&
|
|
4458
|
-
((instantiated.s instanceof FormulaTerm &&
|
|
4459
|
-
instantiated.o instanceof FormulaTerm) ||
|
|
4460
|
-
(instantiated.s instanceof Literal &&
|
|
4461
|
-
instantiated.s.value === "true" &&
|
|
4462
|
-
instantiated.o instanceof FormulaTerm) ||
|
|
4463
|
-
(instantiated.s instanceof FormulaTerm &&
|
|
4464
|
-
instantiated.o instanceof Literal &&
|
|
4465
|
-
instantiated.o.value === "true"));
|
|
4196
|
+
((instantiated.s instanceof FormulaTerm && instantiated.o instanceof FormulaTerm) ||
|
|
4197
|
+
(instantiated.s instanceof Literal && instantiated.s.value === 'true' && instantiated.o instanceof FormulaTerm) ||
|
|
4198
|
+
(instantiated.s instanceof FormulaTerm && instantiated.o instanceof Literal && instantiated.o.value === 'true'));
|
|
4466
4199
|
|
|
4467
4200
|
const isBwRuleTriple =
|
|
4468
4201
|
isLogImpliedBy(instantiated.p) &&
|
|
4469
|
-
((instantiated.s instanceof FormulaTerm &&
|
|
4470
|
-
instantiated.o instanceof
|
|
4471
|
-
(instantiated.s instanceof
|
|
4472
|
-
instantiated.o instanceof Literal &&
|
|
4473
|
-
instantiated.o.value === "true") ||
|
|
4474
|
-
(instantiated.s instanceof Literal &&
|
|
4475
|
-
instantiated.s.value === "true" &&
|
|
4476
|
-
instantiated.o instanceof FormulaTerm));
|
|
4202
|
+
((instantiated.s instanceof FormulaTerm && instantiated.o instanceof FormulaTerm) ||
|
|
4203
|
+
(instantiated.s instanceof FormulaTerm && instantiated.o instanceof Literal && instantiated.o.value === 'true') ||
|
|
4204
|
+
(instantiated.s instanceof Literal && instantiated.s.value === 'true' && instantiated.o instanceof FormulaTerm));
|
|
4477
4205
|
|
|
4478
4206
|
if (isFwRuleTriple || isBwRuleTriple) {
|
|
4479
4207
|
if (!hasFactIndexed(facts, instantiated)) {
|
|
@@ -4491,16 +4219,14 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
4491
4219
|
const left =
|
|
4492
4220
|
instantiated.s instanceof FormulaTerm
|
|
4493
4221
|
? instantiated.s.triples
|
|
4494
|
-
: instantiated.s instanceof Literal &&
|
|
4495
|
-
instantiated.s.value === "true"
|
|
4222
|
+
: instantiated.s instanceof Literal && instantiated.s.value === 'true'
|
|
4496
4223
|
? []
|
|
4497
4224
|
: null;
|
|
4498
4225
|
|
|
4499
4226
|
const right =
|
|
4500
4227
|
instantiated.o instanceof FormulaTerm
|
|
4501
4228
|
? instantiated.o.triples
|
|
4502
|
-
: instantiated.o instanceof Literal &&
|
|
4503
|
-
instantiated.o.value === "true"
|
|
4229
|
+
: instantiated.o instanceof Literal && instantiated.o.value === 'true'
|
|
4504
4230
|
? []
|
|
4505
4231
|
: null;
|
|
4506
4232
|
|
|
@@ -4510,13 +4236,7 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
4510
4236
|
const premise = reorderPremiseForConstraints(premise0);
|
|
4511
4237
|
|
|
4512
4238
|
const headBlankLabels = collectBlankLabelsInTriples(conclusion);
|
|
4513
|
-
const newRule = new Rule(
|
|
4514
|
-
premise,
|
|
4515
|
-
conclusion,
|
|
4516
|
-
true,
|
|
4517
|
-
false,
|
|
4518
|
-
headBlankLabels,
|
|
4519
|
-
);
|
|
4239
|
+
const newRule = new Rule(premise, conclusion, true, false, headBlankLabels);
|
|
4520
4240
|
|
|
4521
4241
|
const already = forwardRules.some(
|
|
4522
4242
|
(rr) =>
|
|
@@ -4530,13 +4250,7 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
4530
4250
|
const [premise, conclusion] = liftBlankRuleVars(right, left);
|
|
4531
4251
|
|
|
4532
4252
|
const headBlankLabels = collectBlankLabelsInTriples(conclusion);
|
|
4533
|
-
const newRule = new Rule(
|
|
4534
|
-
premise,
|
|
4535
|
-
conclusion,
|
|
4536
|
-
false,
|
|
4537
|
-
false,
|
|
4538
|
-
headBlankLabels,
|
|
4539
|
-
);
|
|
4253
|
+
const newRule = new Rule(premise, conclusion, false, false, headBlankLabels);
|
|
4540
4254
|
|
|
4541
4255
|
const already = backRules.some(
|
|
4542
4256
|
(rr) =>
|
|
@@ -4556,13 +4270,7 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
4556
4270
|
}
|
|
4557
4271
|
|
|
4558
4272
|
// Only skolemize blank nodes that occur explicitly in the rule head
|
|
4559
|
-
const
|
|
4560
|
-
const inst = skolemizeTripleForHeadBlanks(
|
|
4561
|
-
instantiated,
|
|
4562
|
-
r.headBlankLabels,
|
|
4563
|
-
skMap,
|
|
4564
|
-
skCounter,
|
|
4565
|
-
);
|
|
4273
|
+
const inst = skolemizeTripleForHeadBlanks(instantiated, r.headBlankLabels, skMap, skCounter);
|
|
4566
4274
|
|
|
4567
4275
|
if (!isGroundTriple(inst)) continue;
|
|
4568
4276
|
if (hasFactIndexed(facts, inst)) continue;
|
|
@@ -4570,9 +4278,7 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
4570
4278
|
factList.push(inst);
|
|
4571
4279
|
pushFactIndexed(facts, inst);
|
|
4572
4280
|
|
|
4573
|
-
derivedForward.push(
|
|
4574
|
-
new DerivedFact(inst, r, instantiatedPremises.slice(), { ...s }),
|
|
4575
|
-
);
|
|
4281
|
+
derivedForward.push(new DerivedFact(inst, r, instantiatedPremises.slice(), { ...s }));
|
|
4576
4282
|
changed = true;
|
|
4577
4283
|
}
|
|
4578
4284
|
}
|
|
@@ -4593,19 +4299,19 @@ function termToN3(t, pref) {
|
|
|
4593
4299
|
const i = t.value;
|
|
4594
4300
|
const q = pref.shrinkIri(i);
|
|
4595
4301
|
if (q !== null) return q;
|
|
4596
|
-
if (i.startsWith(
|
|
4302
|
+
if (i.startsWith('_:')) return i;
|
|
4597
4303
|
return `<${i}>`;
|
|
4598
4304
|
}
|
|
4599
4305
|
if (t instanceof Literal) {
|
|
4600
4306
|
const [lex, dt] = literalParts(t.value);
|
|
4601
4307
|
|
|
4602
4308
|
// Pretty-print xsd:boolean as bare true/false
|
|
4603
|
-
if (dt === XSD_NS +
|
|
4309
|
+
if (dt === XSD_NS + 'boolean') {
|
|
4604
4310
|
const v = stripQuotes(lex);
|
|
4605
|
-
if (v ===
|
|
4311
|
+
if (v === 'true' || v === 'false') return v;
|
|
4606
4312
|
// optional: normalize 1/0 too
|
|
4607
|
-
if (v ===
|
|
4608
|
-
if (v ===
|
|
4313
|
+
if (v === '1') return 'true';
|
|
4314
|
+
if (v === '0') return 'false';
|
|
4609
4315
|
}
|
|
4610
4316
|
|
|
4611
4317
|
if (!dt) return t.value; // keep numbers, booleans, lang-tagged strings, etc.
|
|
@@ -4617,20 +4323,20 @@ function termToN3(t, pref) {
|
|
|
4617
4323
|
if (t instanceof Blank) return t.label;
|
|
4618
4324
|
if (t instanceof ListTerm) {
|
|
4619
4325
|
const inside = t.elems.map((e) => termToN3(e, pref));
|
|
4620
|
-
return
|
|
4326
|
+
return '(' + inside.join(' ') + ')';
|
|
4621
4327
|
}
|
|
4622
4328
|
if (t instanceof OpenListTerm) {
|
|
4623
4329
|
const inside = t.prefix.map((e) => termToN3(e, pref));
|
|
4624
|
-
inside.push(
|
|
4625
|
-
return
|
|
4330
|
+
inside.push('?' + t.tailVar);
|
|
4331
|
+
return '(' + inside.join(' ') + ')';
|
|
4626
4332
|
}
|
|
4627
4333
|
if (t instanceof FormulaTerm) {
|
|
4628
|
-
let s =
|
|
4334
|
+
let s = '{\n';
|
|
4629
4335
|
for (const tr of t.triples) {
|
|
4630
4336
|
let line = tripleToN3(tr, pref).trimEnd();
|
|
4631
|
-
if (line) s +=
|
|
4337
|
+
if (line) s += ' ' + line + '\n';
|
|
4632
4338
|
}
|
|
4633
|
-
s +=
|
|
4339
|
+
s += '}';
|
|
4634
4340
|
return s;
|
|
4635
4341
|
}
|
|
4636
4342
|
return JSON.stringify(t);
|
|
@@ -4651,74 +4357,62 @@ function tripleToN3(tr, prefixes) {
|
|
|
4651
4357
|
}
|
|
4652
4358
|
|
|
4653
4359
|
const s = termToN3(tr.s, prefixes);
|
|
4654
|
-
const p = isRdfTypePred(tr.p)
|
|
4655
|
-
? "a"
|
|
4656
|
-
: isOwlSameAsPred(tr.p)
|
|
4657
|
-
? "="
|
|
4658
|
-
: termToN3(tr.p, prefixes);
|
|
4360
|
+
const p = isRdfTypePred(tr.p) ? 'a' : isOwlSameAsPred(tr.p) ? '=' : termToN3(tr.p, prefixes);
|
|
4659
4361
|
const o = termToN3(tr.o, prefixes);
|
|
4660
4362
|
|
|
4661
4363
|
return `${s} ${p} ${o} .`;
|
|
4662
4364
|
}
|
|
4663
4365
|
|
|
4664
4366
|
function printExplanation(df, prefixes) {
|
|
4665
|
-
console.log(
|
|
4666
|
-
|
|
4667
|
-
);
|
|
4668
|
-
console.log("# Proof for derived triple:");
|
|
4367
|
+
console.log('# ----------------------------------------------------------------------');
|
|
4368
|
+
console.log('# Proof for derived triple:');
|
|
4669
4369
|
|
|
4670
4370
|
// Fact line(s), indented 2 spaces after '# '
|
|
4671
4371
|
for (const line of tripleToN3(df.fact, prefixes).split(/\r?\n/)) {
|
|
4672
|
-
const stripped = line.replace(/\s+$/,
|
|
4372
|
+
const stripped = line.replace(/\s+$/, '');
|
|
4673
4373
|
if (stripped) {
|
|
4674
|
-
console.log(
|
|
4374
|
+
console.log('# ' + stripped);
|
|
4675
4375
|
}
|
|
4676
4376
|
}
|
|
4677
4377
|
|
|
4678
4378
|
if (!df.premises.length) {
|
|
4679
|
-
console.log(
|
|
4680
|
-
|
|
4681
|
-
);
|
|
4682
|
-
console.log(
|
|
4683
|
-
"# so it holds unconditionally whenever the program is loaded.",
|
|
4684
|
-
);
|
|
4379
|
+
console.log('# This triple is the head of a forward rule with an empty premise,');
|
|
4380
|
+
console.log('# so it holds unconditionally whenever the program is loaded.');
|
|
4685
4381
|
} else {
|
|
4686
|
-
console.log(
|
|
4687
|
-
"# It holds because the following instance of the rule body is provable:",
|
|
4688
|
-
);
|
|
4382
|
+
console.log('# It holds because the following instance of the rule body is provable:');
|
|
4689
4383
|
|
|
4690
4384
|
// Premises, also indented 2 spaces after '# '
|
|
4691
4385
|
for (const prem of df.premises) {
|
|
4692
4386
|
for (const line of tripleToN3(prem, prefixes).split(/\r?\n/)) {
|
|
4693
|
-
const stripped = line.replace(/\s+$/,
|
|
4387
|
+
const stripped = line.replace(/\s+$/, '');
|
|
4694
4388
|
if (stripped) {
|
|
4695
|
-
console.log(
|
|
4389
|
+
console.log('# ' + stripped);
|
|
4696
4390
|
}
|
|
4697
4391
|
}
|
|
4698
4392
|
}
|
|
4699
4393
|
|
|
4700
|
-
console.log(
|
|
4394
|
+
console.log('# via the schematic forward rule:');
|
|
4701
4395
|
|
|
4702
4396
|
// Rule pretty-printed
|
|
4703
|
-
console.log(
|
|
4397
|
+
console.log('# {');
|
|
4704
4398
|
for (const tr of df.rule.premise) {
|
|
4705
4399
|
for (const line of tripleToN3(tr, prefixes).split(/\r?\n/)) {
|
|
4706
|
-
const stripped = line.replace(/\s+$/,
|
|
4400
|
+
const stripped = line.replace(/\s+$/, '');
|
|
4707
4401
|
if (stripped) {
|
|
4708
|
-
console.log(
|
|
4402
|
+
console.log('# ' + stripped);
|
|
4709
4403
|
}
|
|
4710
4404
|
}
|
|
4711
4405
|
}
|
|
4712
|
-
console.log(
|
|
4406
|
+
console.log('# } => {');
|
|
4713
4407
|
for (const tr of df.rule.conclusion) {
|
|
4714
4408
|
for (const line of tripleToN3(tr, prefixes).split(/\r?\n/)) {
|
|
4715
|
-
const stripped = line.replace(/\s+$/,
|
|
4409
|
+
const stripped = line.replace(/\s+$/, '');
|
|
4716
4410
|
if (stripped) {
|
|
4717
|
-
console.log(
|
|
4411
|
+
console.log('# ' + stripped);
|
|
4718
4412
|
}
|
|
4719
4413
|
}
|
|
4720
4414
|
}
|
|
4721
|
-
console.log(
|
|
4415
|
+
console.log('# } .');
|
|
4722
4416
|
}
|
|
4723
4417
|
|
|
4724
4418
|
// Substitution block
|
|
@@ -4728,7 +4422,7 @@ function printExplanation(df, prefixes) {
|
|
|
4728
4422
|
.sort();
|
|
4729
4423
|
|
|
4730
4424
|
if (visibleNames.length) {
|
|
4731
|
-
console.log(
|
|
4425
|
+
console.log('# with substitution (on rule variables):');
|
|
4732
4426
|
for (const v of visibleNames) {
|
|
4733
4427
|
const fullTerm = applySubstTerm(new Var(v), df.subst);
|
|
4734
4428
|
const rendered = termToN3(fullTerm, prefixes);
|
|
@@ -4736,37 +4430,33 @@ function printExplanation(df, prefixes) {
|
|
|
4736
4430
|
|
|
4737
4431
|
if (lines.length === 1) {
|
|
4738
4432
|
// single-line term
|
|
4739
|
-
const stripped = lines[0].replace(/\s+$/,
|
|
4433
|
+
const stripped = lines[0].replace(/\s+$/, '');
|
|
4740
4434
|
if (stripped) {
|
|
4741
|
-
console.log(
|
|
4435
|
+
console.log('# ?' + v + ' = ' + stripped);
|
|
4742
4436
|
}
|
|
4743
4437
|
} else {
|
|
4744
4438
|
// multi-line term (e.g. a formula)
|
|
4745
4439
|
const first = lines[0].trimEnd(); // usually "{"
|
|
4746
4440
|
if (first) {
|
|
4747
|
-
console.log(
|
|
4441
|
+
console.log('# ?' + v + ' = ' + first);
|
|
4748
4442
|
}
|
|
4749
4443
|
for (let i = 1; i < lines.length; i++) {
|
|
4750
4444
|
const stripped = lines[i].trim();
|
|
4751
4445
|
if (!stripped) continue;
|
|
4752
4446
|
if (i === lines.length - 1) {
|
|
4753
4447
|
// closing brace
|
|
4754
|
-
console.log(
|
|
4448
|
+
console.log('# ' + stripped);
|
|
4755
4449
|
} else {
|
|
4756
4450
|
// inner triple lines
|
|
4757
|
-
console.log(
|
|
4451
|
+
console.log('# ' + stripped);
|
|
4758
4452
|
}
|
|
4759
4453
|
}
|
|
4760
4454
|
}
|
|
4761
4455
|
}
|
|
4762
4456
|
}
|
|
4763
4457
|
|
|
4764
|
-
console.log(
|
|
4765
|
-
|
|
4766
|
-
);
|
|
4767
|
-
console.log(
|
|
4768
|
-
"# ----------------------------------------------------------------------\n",
|
|
4769
|
-
);
|
|
4458
|
+
console.log('# Therefore the derived triple above is entailed by the rules and facts.');
|
|
4459
|
+
console.log('# ----------------------------------------------------------------------\n');
|
|
4770
4460
|
}
|
|
4771
4461
|
|
|
4772
4462
|
// ============================================================================
|
|
@@ -4776,13 +4466,13 @@ function printExplanation(df, prefixes) {
|
|
|
4776
4466
|
// Turn RDF Collections described with rdf:first/rdf:rest (+ rdf:nil) into ListTerm terms.
|
|
4777
4467
|
// This mutates triples/rules in-place so list:* builtins work on RDF-serialized lists too.
|
|
4778
4468
|
function materializeRdfLists(triples, forwardRules, backwardRules) {
|
|
4779
|
-
const RDF_FIRST = RDF_NS +
|
|
4780
|
-
const RDF_REST = RDF_NS +
|
|
4781
|
-
const RDF_NIL = RDF_NS +
|
|
4469
|
+
const RDF_FIRST = RDF_NS + 'first';
|
|
4470
|
+
const RDF_REST = RDF_NS + 'rest';
|
|
4471
|
+
const RDF_NIL = RDF_NS + 'nil';
|
|
4782
4472
|
|
|
4783
4473
|
function nodeKey(t) {
|
|
4784
|
-
if (t instanceof Blank) return
|
|
4785
|
-
if (t instanceof Iri) return
|
|
4474
|
+
if (t instanceof Blank) return 'B:' + t.label;
|
|
4475
|
+
if (t instanceof Iri) return 'I:' + t.value;
|
|
4786
4476
|
return null;
|
|
4787
4477
|
}
|
|
4788
4478
|
|
|
@@ -4807,7 +4497,7 @@ function materializeRdfLists(triples, forwardRules, backwardRules) {
|
|
|
4807
4497
|
visiting.add(k);
|
|
4808
4498
|
|
|
4809
4499
|
// rdf:nil => ()
|
|
4810
|
-
if (k ===
|
|
4500
|
+
if (k === 'I:' + RDF_NIL) {
|
|
4811
4501
|
const empty = new ListTerm([]);
|
|
4812
4502
|
cache.set(k, empty);
|
|
4813
4503
|
visiting.delete(k);
|
|
@@ -4904,7 +4594,7 @@ function materializeRdfLists(triples, forwardRules, backwardRules) {
|
|
|
4904
4594
|
|
|
4905
4595
|
function localIsoDateTimeString(d) {
|
|
4906
4596
|
function pad(n, width = 2) {
|
|
4907
|
-
return String(n).padStart(width,
|
|
4597
|
+
return String(n).padStart(width, '0');
|
|
4908
4598
|
}
|
|
4909
4599
|
const year = d.getFullYear();
|
|
4910
4600
|
const month = d.getMonth() + 1;
|
|
@@ -4914,27 +4604,27 @@ function localIsoDateTimeString(d) {
|
|
|
4914
4604
|
const sec = d.getSeconds();
|
|
4915
4605
|
const ms = d.getMilliseconds();
|
|
4916
4606
|
const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
|
|
4917
|
-
const sign = offsetMin >= 0 ?
|
|
4607
|
+
const sign = offsetMin >= 0 ? '+' : '-';
|
|
4918
4608
|
const abs = Math.abs(offsetMin);
|
|
4919
4609
|
const oh = Math.floor(abs / 60);
|
|
4920
4610
|
const om = abs % 60;
|
|
4921
|
-
const msPart = ms ?
|
|
4611
|
+
const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
|
|
4922
4612
|
return (
|
|
4923
4613
|
pad(year, 4) +
|
|
4924
|
-
|
|
4614
|
+
'-' +
|
|
4925
4615
|
pad(month) +
|
|
4926
|
-
|
|
4616
|
+
'-' +
|
|
4927
4617
|
pad(day) +
|
|
4928
|
-
|
|
4618
|
+
'T' +
|
|
4929
4619
|
pad(hour) +
|
|
4930
|
-
|
|
4620
|
+
':' +
|
|
4931
4621
|
pad(min) +
|
|
4932
|
-
|
|
4622
|
+
':' +
|
|
4933
4623
|
pad(sec) +
|
|
4934
4624
|
msPart +
|
|
4935
4625
|
sign +
|
|
4936
4626
|
pad(oh) +
|
|
4937
|
-
|
|
4627
|
+
':' +
|
|
4938
4628
|
pad(om)
|
|
4939
4629
|
);
|
|
4940
4630
|
}
|
|
@@ -4952,33 +4642,31 @@ function main() {
|
|
|
4952
4642
|
// --------------------------------------------------------------------------
|
|
4953
4643
|
|
|
4954
4644
|
// --version / -v: print version and exit
|
|
4955
|
-
if (argv.includes(
|
|
4645
|
+
if (argv.includes('--version') || argv.includes('-v')) {
|
|
4956
4646
|
console.log(`eyeling v${version}`);
|
|
4957
4647
|
process.exit(0);
|
|
4958
4648
|
}
|
|
4959
4649
|
|
|
4960
4650
|
// --no-proof-comments / -n: disable proof explanations
|
|
4961
|
-
if (argv.includes(
|
|
4651
|
+
if (argv.includes('--no-proof-comments') || argv.includes('-n')) {
|
|
4962
4652
|
proofCommentsEnabled = false;
|
|
4963
4653
|
}
|
|
4964
4654
|
|
|
4965
4655
|
// --------------------------------------------------------------------------
|
|
4966
4656
|
// Positional args (the N3 file)
|
|
4967
4657
|
// --------------------------------------------------------------------------
|
|
4968
|
-
const positional = argv.filter((a) => !a.startsWith(
|
|
4658
|
+
const positional = argv.filter((a) => !a.startsWith('-'));
|
|
4969
4659
|
|
|
4970
4660
|
if (positional.length !== 1) {
|
|
4971
|
-
console.error(
|
|
4972
|
-
"Usage: eyeling.js [--version|-v] [--no-proof-comments|-n] <file.n3>",
|
|
4973
|
-
);
|
|
4661
|
+
console.error('Usage: eyeling.js [--version|-v] [--no-proof-comments|-n] <file.n3>');
|
|
4974
4662
|
process.exit(1);
|
|
4975
4663
|
}
|
|
4976
4664
|
|
|
4977
4665
|
const path = positional[0];
|
|
4978
4666
|
let text;
|
|
4979
4667
|
try {
|
|
4980
|
-
const fs = require(
|
|
4981
|
-
text = fs.readFileSync(path, { encoding:
|
|
4668
|
+
const fs = require('fs');
|
|
4669
|
+
text = fs.readFileSync(path, { encoding: 'utf8' });
|
|
4982
4670
|
} catch (e) {
|
|
4983
4671
|
console.error(`Error reading file ${JSON.stringify(path)}: ${e.message}`);
|
|
4984
4672
|
process.exit(1);
|
|
@@ -4999,7 +4687,7 @@ function main() {
|
|
|
4999
4687
|
const usedPrefixes = prefixes.prefixesUsedForOutput(derivedTriples);
|
|
5000
4688
|
|
|
5001
4689
|
for (const [pfx, base] of usedPrefixes) {
|
|
5002
|
-
if (pfx ===
|
|
4690
|
+
if (pfx === '') console.log(`@prefix : <${base}> .`);
|
|
5003
4691
|
else console.log(`@prefix ${pfx}: <${base}> .`);
|
|
5004
4692
|
}
|
|
5005
4693
|
if (derived.length && usedPrefixes.length) console.log();
|