eyeling 1.6.19 → 1.6.21
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/eyeling.js +191 -54
- package/package.json +1 -1
package/eyeling.js
CHANGED
|
@@ -62,9 +62,9 @@ function termToJsonText(t) {
|
|
|
62
62
|
function makeRdfJsonLiteral(jsonText) {
|
|
63
63
|
// Prefer a readable long literal when safe; fall back to short if needed.
|
|
64
64
|
if (!jsonText.includes('"""')) {
|
|
65
|
-
return
|
|
65
|
+
return internLiteral('"""' + jsonText + '"""^^<' + RDF_JSON_DT + '>');
|
|
66
66
|
}
|
|
67
|
-
return
|
|
67
|
+
return internLiteral(JSON.stringify(jsonText) + '^^<' + RDF_JSON_DT + '>');
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// For a single reasoning run, this maps a canonical representation
|
|
@@ -212,6 +212,37 @@ class Var extends Term {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
// ===========================================================================
|
|
216
|
+
// Term interning
|
|
217
|
+
// ===========================================================================
|
|
218
|
+
|
|
219
|
+
// Intern IRIs and literals by their raw lexical string.
|
|
220
|
+
// This reduces allocations when the same terms repeat and can improve performance.
|
|
221
|
+
//
|
|
222
|
+
// NOTE: Terms are treated as immutable. Do NOT mutate .value on interned objects.
|
|
223
|
+
const __iriIntern = new Map();
|
|
224
|
+
const __literalIntern = new Map();
|
|
225
|
+
|
|
226
|
+
/** @param {string} value */
|
|
227
|
+
function internIri(value) {
|
|
228
|
+
let t = __iriIntern.get(value);
|
|
229
|
+
if (!t) {
|
|
230
|
+
t = new Iri(value);
|
|
231
|
+
__iriIntern.set(value, t);
|
|
232
|
+
}
|
|
233
|
+
return t;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** @param {string} value */
|
|
237
|
+
function internLiteral(value) {
|
|
238
|
+
let t = __literalIntern.get(value);
|
|
239
|
+
if (!t) {
|
|
240
|
+
t = new Literal(value);
|
|
241
|
+
__literalIntern.set(value, t);
|
|
242
|
+
}
|
|
243
|
+
return t;
|
|
244
|
+
}
|
|
245
|
+
|
|
215
246
|
class Blank extends Term {
|
|
216
247
|
constructor(label) {
|
|
217
248
|
super();
|
|
@@ -528,6 +559,67 @@ function lex(inputText) {
|
|
|
528
559
|
continue;
|
|
529
560
|
}
|
|
530
561
|
|
|
562
|
+
// String literal: short '...' or long '''...'''
|
|
563
|
+
if (c === "'") {
|
|
564
|
+
// Long string literal ''' ... '''
|
|
565
|
+
if (peek(1) === "'" && peek(2) === "'") {
|
|
566
|
+
i += 3; // consume opening '''
|
|
567
|
+
const sChars = [];
|
|
568
|
+
let closed = false;
|
|
569
|
+
while (i < n) {
|
|
570
|
+
// closing delimiter?
|
|
571
|
+
if (peek() === "'" && peek(1) === "'" && peek(2) === "'") {
|
|
572
|
+
i += 3; // consume closing '''
|
|
573
|
+
closed = true;
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
let cc = chars[i];
|
|
577
|
+
i++;
|
|
578
|
+
if (cc === '\\') {
|
|
579
|
+
// Preserve escapes verbatim (same behavior as short strings)
|
|
580
|
+
if (i < n) {
|
|
581
|
+
const esc = chars[i];
|
|
582
|
+
i++;
|
|
583
|
+
sChars.push('\\');
|
|
584
|
+
sChars.push(esc);
|
|
585
|
+
}
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
sChars.push(cc);
|
|
589
|
+
}
|
|
590
|
+
if (!closed) throw new Error("Unterminated long string literal '''...'''");
|
|
591
|
+
const raw = "'''" + sChars.join('') + "'''";
|
|
592
|
+
const decoded = decodeN3StringEscapes(stripQuotes(raw));
|
|
593
|
+
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
594
|
+
tokens.push(new Token('Literal', s));
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Short string literal ' ... '
|
|
599
|
+
i++; // consume opening '
|
|
600
|
+
const sChars = [];
|
|
601
|
+
while (i < n) {
|
|
602
|
+
let cc = chars[i];
|
|
603
|
+
i++;
|
|
604
|
+
if (cc === '\\') {
|
|
605
|
+
if (i < n) {
|
|
606
|
+
const esc = chars[i];
|
|
607
|
+
i++;
|
|
608
|
+
sChars.push('\\');
|
|
609
|
+
sChars.push(esc);
|
|
610
|
+
}
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
if (cc === "'") break;
|
|
614
|
+
sChars.push(cc);
|
|
615
|
+
}
|
|
616
|
+
const raw = "'" + sChars.join('') + "'";
|
|
617
|
+
const decoded = decodeN3StringEscapes(stripQuotes(raw));
|
|
618
|
+
const s = JSON.stringify(decoded); // canonical short quoted form
|
|
619
|
+
tokens.push(new Token('Literal', s));
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
|
|
531
623
|
// Variable ?name
|
|
532
624
|
if (c === '?') {
|
|
533
625
|
i++;
|
|
@@ -976,23 +1068,23 @@ class Parser {
|
|
|
976
1068
|
const val = tok.value;
|
|
977
1069
|
|
|
978
1070
|
if (typ === 'Equals') {
|
|
979
|
-
return
|
|
1071
|
+
return internIri(OWL_NS + 'sameAs');
|
|
980
1072
|
}
|
|
981
1073
|
|
|
982
1074
|
if (typ === 'IriRef') {
|
|
983
1075
|
const base = this.prefixes.map[''] || '';
|
|
984
|
-
return
|
|
1076
|
+
return internIri(resolveIriRef(val || '', base));
|
|
985
1077
|
}
|
|
986
1078
|
if (typ === 'Ident') {
|
|
987
1079
|
const name = val || '';
|
|
988
1080
|
if (name === 'a') {
|
|
989
|
-
return
|
|
1081
|
+
return internIri(RDF_NS + 'type');
|
|
990
1082
|
} else if (name.startsWith('_:')) {
|
|
991
1083
|
return new Blank(name);
|
|
992
1084
|
} else if (name.includes(':')) {
|
|
993
|
-
return
|
|
1085
|
+
return internIri(this.prefixes.expandQName(name));
|
|
994
1086
|
} else {
|
|
995
|
-
return
|
|
1087
|
+
return internIri(name);
|
|
996
1088
|
}
|
|
997
1089
|
}
|
|
998
1090
|
|
|
@@ -1030,7 +1122,7 @@ class Parser {
|
|
|
1030
1122
|
}
|
|
1031
1123
|
s = `${s}^^<${dtIri}>`;
|
|
1032
1124
|
}
|
|
1033
|
-
return
|
|
1125
|
+
return internLiteral(s);
|
|
1034
1126
|
}
|
|
1035
1127
|
|
|
1036
1128
|
if (typ === 'Var') return new Var(val || '');
|
|
@@ -1069,7 +1161,7 @@ class Parser {
|
|
|
1069
1161
|
let invert = false;
|
|
1070
1162
|
if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
|
|
1071
1163
|
this.next();
|
|
1072
|
-
pred =
|
|
1164
|
+
pred = internIri(RDF_NS + 'type');
|
|
1073
1165
|
} else if (this.peek().typ === 'OpPredInvert') {
|
|
1074
1166
|
this.next(); // consume "<-"
|
|
1075
1167
|
pred = this.parseTerm();
|
|
@@ -1113,7 +1205,7 @@ class Parser {
|
|
|
1113
1205
|
if (this.peek().typ === 'OpImplies') {
|
|
1114
1206
|
this.next();
|
|
1115
1207
|
const right = this.parseTerm();
|
|
1116
|
-
const pred =
|
|
1208
|
+
const pred = internIri(LOG_NS + 'implies');
|
|
1117
1209
|
triples.push(new Triple(left, pred, right));
|
|
1118
1210
|
if (this.peek().typ === 'Dot') this.next();
|
|
1119
1211
|
else if (this.peek().typ === 'RBrace') {
|
|
@@ -1124,7 +1216,7 @@ class Parser {
|
|
|
1124
1216
|
} else if (this.peek().typ === 'OpImpliedBy') {
|
|
1125
1217
|
this.next();
|
|
1126
1218
|
const right = this.parseTerm();
|
|
1127
|
-
const pred =
|
|
1219
|
+
const pred = internIri(LOG_NS + 'impliedBy');
|
|
1128
1220
|
triples.push(new Triple(left, pred, right));
|
|
1129
1221
|
if (this.peek().typ === 'Dot') this.next();
|
|
1130
1222
|
else if (this.peek().typ === 'RBrace') {
|
|
@@ -1172,7 +1264,7 @@ class Parser {
|
|
|
1172
1264
|
|
|
1173
1265
|
if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
|
|
1174
1266
|
this.next();
|
|
1175
|
-
verb =
|
|
1267
|
+
verb = internIri(RDF_NS + 'type');
|
|
1176
1268
|
} else if (this.peek().typ === 'OpPredInvert') {
|
|
1177
1269
|
this.next(); // "<-"
|
|
1178
1270
|
verb = this.parseTerm();
|
|
@@ -1669,13 +1761,18 @@ function tripleFastKey(tr) {
|
|
|
1669
1761
|
}
|
|
1670
1762
|
|
|
1671
1763
|
function ensureFactIndexes(facts) {
|
|
1672
|
-
if (facts.__byPred && facts.__byPO && facts.__keySet) return;
|
|
1764
|
+
if (facts.__byPred && facts.__byPS && facts.__byPO && facts.__keySet) return;
|
|
1673
1765
|
|
|
1674
1766
|
Object.defineProperty(facts, '__byPred', {
|
|
1675
1767
|
value: new Map(),
|
|
1676
1768
|
enumerable: false,
|
|
1677
1769
|
writable: true,
|
|
1678
1770
|
});
|
|
1771
|
+
Object.defineProperty(facts, '__byPS', {
|
|
1772
|
+
value: new Map(),
|
|
1773
|
+
enumerable: false,
|
|
1774
|
+
writable: true,
|
|
1775
|
+
});
|
|
1679
1776
|
Object.defineProperty(facts, '__byPO', {
|
|
1680
1777
|
value: new Map(),
|
|
1681
1778
|
enumerable: false,
|
|
@@ -1701,6 +1798,21 @@ function indexFact(facts, tr) {
|
|
|
1701
1798
|
}
|
|
1702
1799
|
pb.push(tr);
|
|
1703
1800
|
|
|
1801
|
+
const sk = termFastKey(tr.s);
|
|
1802
|
+
if (sk !== null) {
|
|
1803
|
+
let ps = facts.__byPS.get(pk);
|
|
1804
|
+
if (!ps) {
|
|
1805
|
+
ps = new Map();
|
|
1806
|
+
facts.__byPS.set(pk, ps);
|
|
1807
|
+
}
|
|
1808
|
+
let psb = ps.get(sk);
|
|
1809
|
+
if (!psb) {
|
|
1810
|
+
psb = [];
|
|
1811
|
+
ps.set(sk, psb);
|
|
1812
|
+
}
|
|
1813
|
+
psb.push(tr);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1704
1816
|
const ok = termFastKey(tr.o);
|
|
1705
1817
|
if (ok !== null) {
|
|
1706
1818
|
let po = facts.__byPO.get(pk);
|
|
@@ -1727,15 +1839,27 @@ function candidateFacts(facts, goal) {
|
|
|
1727
1839
|
if (goal.p instanceof Iri) {
|
|
1728
1840
|
const pk = goal.p.value;
|
|
1729
1841
|
|
|
1842
|
+
const sk = termFastKey(goal.s);
|
|
1730
1843
|
const ok = termFastKey(goal.o);
|
|
1844
|
+
|
|
1845
|
+
/** @type {Triple[] | null} */
|
|
1846
|
+
let byPS = null;
|
|
1847
|
+
if (sk !== null) {
|
|
1848
|
+
const ps = facts.__byPS.get(pk);
|
|
1849
|
+
if (ps) byPS = ps.get(sk) || null;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
/** @type {Triple[] | null} */
|
|
1853
|
+
let byPO = null;
|
|
1731
1854
|
if (ok !== null) {
|
|
1732
1855
|
const po = facts.__byPO.get(pk);
|
|
1733
|
-
if (po)
|
|
1734
|
-
const pob = po.get(ok);
|
|
1735
|
-
if (pob) return pob;
|
|
1736
|
-
}
|
|
1856
|
+
if (po) byPO = po.get(ok) || null;
|
|
1737
1857
|
}
|
|
1738
1858
|
|
|
1859
|
+
if (byPS && byPO) return byPS.length <= byPO.length ? byPS : byPO;
|
|
1860
|
+
if (byPS) return byPS;
|
|
1861
|
+
if (byPO) return byPO;
|
|
1862
|
+
|
|
1739
1863
|
return facts.__byPred.get(pk) || [];
|
|
1740
1864
|
}
|
|
1741
1865
|
|
|
@@ -2308,11 +2432,16 @@ function normalizeLiteralForFastKey(lit) {
|
|
|
2308
2432
|
}
|
|
2309
2433
|
|
|
2310
2434
|
function stripQuotes(lex) {
|
|
2311
|
-
if (lex
|
|
2312
|
-
|
|
2435
|
+
if (typeof lex !== 'string') return lex;
|
|
2436
|
+
// Handle both short ('...' / "...") and long ('''...''' / """...""") forms.
|
|
2437
|
+
if (lex.length >= 6) {
|
|
2438
|
+
if (lex.startsWith('"""') && lex.endsWith('"""')) return lex.slice(3, -3);
|
|
2439
|
+
if (lex.startsWith("'''") && lex.endsWith("'''")) return lex.slice(3, -3);
|
|
2313
2440
|
}
|
|
2314
|
-
if (lex.length >= 2
|
|
2315
|
-
|
|
2441
|
+
if (lex.length >= 2) {
|
|
2442
|
+
const a = lex[0];
|
|
2443
|
+
const b = lex[lex.length - 1];
|
|
2444
|
+
if ((a === '"' && b === '"') || (a === "'" && b === "'")) return lex.slice(1, -1);
|
|
2316
2445
|
}
|
|
2317
2446
|
return lex;
|
|
2318
2447
|
}
|
|
@@ -2332,7 +2461,7 @@ function termToJsString(t) {
|
|
|
2332
2461
|
function makeStringLiteral(str) {
|
|
2333
2462
|
// JSON.stringify gives us a valid N3/Turtle-style quoted string
|
|
2334
2463
|
// (with proper escaping for quotes, backslashes, newlines, …).
|
|
2335
|
-
return
|
|
2464
|
+
return internLiteral(JSON.stringify(str));
|
|
2336
2465
|
}
|
|
2337
2466
|
|
|
2338
2467
|
function termToJsStringDecoded(t) {
|
|
@@ -2381,8 +2510,8 @@ function jsonPointerUnescape(seg) {
|
|
|
2381
2510
|
function jsonToTerm(v) {
|
|
2382
2511
|
if (v === null) return makeStringLiteral('null');
|
|
2383
2512
|
if (typeof v === 'string') return makeStringLiteral(v);
|
|
2384
|
-
if (typeof v === 'number') return
|
|
2385
|
-
if (typeof v === 'boolean') return
|
|
2513
|
+
if (typeof v === 'number') return internLiteral(String(v));
|
|
2514
|
+
if (typeof v === 'boolean') return internLiteral(v ? 'true' : 'false');
|
|
2386
2515
|
if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
|
|
2387
2516
|
|
|
2388
2517
|
if (v && typeof v === 'object') {
|
|
@@ -2565,10 +2694,18 @@ function formatXsdFloatSpecialLex(n) {
|
|
|
2565
2694
|
}
|
|
2566
2695
|
|
|
2567
2696
|
function isQuotedLexical(lex) {
|
|
2568
|
-
//
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
);
|
|
2697
|
+
// Accept both Turtle/N3 quoting styles:
|
|
2698
|
+
// short: "..." or '...'
|
|
2699
|
+
// long: """...""" or '''...'''
|
|
2700
|
+
if (typeof lex !== 'string') return false;
|
|
2701
|
+
const n = lex.length;
|
|
2702
|
+
if (n >= 6 && ((lex.startsWith('"""') && lex.endsWith('"""')) || (lex.startsWith("'''") && lex.endsWith("'''")))) return true;
|
|
2703
|
+
if (n >= 2) {
|
|
2704
|
+
const a = lex[0];
|
|
2705
|
+
const b = lex[n - 1];
|
|
2706
|
+
return (a === '"' && b === '"') || (a === "'" && b === "'");
|
|
2707
|
+
}
|
|
2708
|
+
return false;
|
|
2572
2709
|
}
|
|
2573
2710
|
|
|
2574
2711
|
function isXsdNumericDatatype(dt) {
|
|
@@ -2855,7 +2992,7 @@ function formatDurationLiteralFromSeconds(secs) {
|
|
|
2855
2992
|
const neg = secs < 0;
|
|
2856
2993
|
const days = Math.round(Math.abs(secs) / 86400.0);
|
|
2857
2994
|
const literalLex = neg ? `"-P${days}D"` : `"P${days}D"`;
|
|
2858
|
-
return
|
|
2995
|
+
return internLiteral(`${literalLex}^^<${XSD_NS}duration>`);
|
|
2859
2996
|
}
|
|
2860
2997
|
function numEqualTerm(t, n, eps = 1e-9) {
|
|
2861
2998
|
const v = parseNum(t);
|
|
@@ -2967,21 +3104,21 @@ function commonNumericDatatype(terms, outTerm) {
|
|
|
2967
3104
|
|
|
2968
3105
|
function makeNumericOutputLiteral(val, dt) {
|
|
2969
3106
|
if (dt === XSD_INTEGER_DT) {
|
|
2970
|
-
if (typeof val === 'bigint') return
|
|
2971
|
-
if (Number.isInteger(val)) return
|
|
3107
|
+
if (typeof val === 'bigint') return internLiteral(val.toString());
|
|
3108
|
+
if (Number.isInteger(val)) return internLiteral(String(val));
|
|
2972
3109
|
// If a non-integer sneaks in, promote to decimal.
|
|
2973
|
-
return
|
|
3110
|
+
return internLiteral(`"${formatNum(val)}"^^<${XSD_DECIMAL_DT}>`);
|
|
2974
3111
|
}
|
|
2975
3112
|
|
|
2976
3113
|
if (dt === XSD_FLOAT_DT || dt === XSD_DOUBLE_DT) {
|
|
2977
3114
|
const sp = formatXsdFloatSpecialLex(val);
|
|
2978
3115
|
const lex = sp !== null ? sp : formatNum(val);
|
|
2979
|
-
return
|
|
3116
|
+
return internLiteral(`"${lex}"^^<${dt}>`);
|
|
2980
3117
|
}
|
|
2981
3118
|
|
|
2982
3119
|
// decimal
|
|
2983
3120
|
const lex = typeof val === 'bigint' ? val.toString() : formatNum(val);
|
|
2984
|
-
return
|
|
3121
|
+
return internLiteral(`"${lex}"^^<${dt}>`);
|
|
2985
3122
|
}
|
|
2986
3123
|
|
|
2987
3124
|
function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
|
|
@@ -3229,7 +3366,7 @@ function hashLiteralTerm(t, algo) {
|
|
|
3229
3366
|
const input = stripQuotes(lex);
|
|
3230
3367
|
try {
|
|
3231
3368
|
const digest = nodeCrypto.createHash(algo).update(input, 'utf8').digest('hex');
|
|
3232
|
-
return
|
|
3369
|
+
return internLiteral(JSON.stringify(digest));
|
|
3233
3370
|
} catch (e) {
|
|
3234
3371
|
return null;
|
|
3235
3372
|
}
|
|
@@ -3429,7 +3566,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3429
3566
|
if (secs !== null) {
|
|
3430
3567
|
const outSecs = aDt.getTime() / 1000.0 - secs;
|
|
3431
3568
|
const lex = utcIsoDateTimeStringFromEpochSeconds(outSecs);
|
|
3432
|
-
const lit =
|
|
3569
|
+
const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
|
|
3433
3570
|
if (g.o instanceof Var) {
|
|
3434
3571
|
const s2 = { ...subst };
|
|
3435
3572
|
s2[g.o.name] = lit;
|
|
@@ -3445,7 +3582,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3445
3582
|
const bi = parseIntLiteral(b0);
|
|
3446
3583
|
if (ai !== null && bi !== null) {
|
|
3447
3584
|
const ci = ai - bi;
|
|
3448
|
-
const lit =
|
|
3585
|
+
const lit = internLiteral(ci.toString());
|
|
3449
3586
|
if (g.o instanceof Var) {
|
|
3450
3587
|
const s2 = { ...subst };
|
|
3451
3588
|
s2[g.o.name] = lit;
|
|
@@ -3480,7 +3617,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3480
3617
|
}
|
|
3481
3618
|
|
|
3482
3619
|
// Fallback (if you *don’t* have those helpers yet):
|
|
3483
|
-
const lit =
|
|
3620
|
+
const lit = internLiteral(formatNum(c));
|
|
3484
3621
|
if (g.o instanceof Var) {
|
|
3485
3622
|
const s2 = { ...subst };
|
|
3486
3623
|
s2[g.o.name] = lit;
|
|
@@ -3531,7 +3668,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3531
3668
|
if (ai !== null && bi !== null) {
|
|
3532
3669
|
if (bi === 0n) return [];
|
|
3533
3670
|
const q = ai / bi; // BigInt division truncates toward zero
|
|
3534
|
-
const lit =
|
|
3671
|
+
const lit = internLiteral(q.toString());
|
|
3535
3672
|
if (g.o instanceof Var) {
|
|
3536
3673
|
const s2 = { ...subst };
|
|
3537
3674
|
s2[g.o.name] = lit;
|
|
@@ -3560,7 +3697,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3560
3697
|
if (!Number.isInteger(a) || !Number.isInteger(b)) return [];
|
|
3561
3698
|
|
|
3562
3699
|
const q = Math.trunc(a / b);
|
|
3563
|
-
const lit =
|
|
3700
|
+
const lit = internLiteral(String(q));
|
|
3564
3701
|
if (g.o instanceof Var) {
|
|
3565
3702
|
const s2 = { ...subst };
|
|
3566
3703
|
s2[g.o.name] = lit;
|
|
@@ -3758,7 +3895,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3758
3895
|
if (Number.isNaN(a)) return [];
|
|
3759
3896
|
|
|
3760
3897
|
const rVal = Math.round(a); // ties go toward +∞ in JS (e.g., -1.5 -> -1)
|
|
3761
|
-
const lit =
|
|
3898
|
+
const lit = internLiteral(String(rVal)); // integer token
|
|
3762
3899
|
|
|
3763
3900
|
if (g.o instanceof Var) {
|
|
3764
3901
|
const s2 = { ...subst };
|
|
@@ -3786,7 +3923,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3786
3923
|
|
|
3787
3924
|
if (g.o instanceof Var) {
|
|
3788
3925
|
const s2 = { ...subst };
|
|
3789
|
-
s2[g.o.name] =
|
|
3926
|
+
s2[g.o.name] = internLiteral(`"${now}"^^<${XSD_NS}dateTime>`);
|
|
3790
3927
|
return [s2];
|
|
3791
3928
|
}
|
|
3792
3929
|
if (g.o instanceof Literal) {
|
|
@@ -3848,7 +3985,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3848
3985
|
const outs = [];
|
|
3849
3986
|
|
|
3850
3987
|
for (let i = 0; i < xs.length; i++) {
|
|
3851
|
-
const idxLit =
|
|
3988
|
+
const idxLit = internLiteral(String(i)); // 0-based
|
|
3852
3989
|
const val = xs[i];
|
|
3853
3990
|
|
|
3854
3991
|
// Fast path: object is exactly a 2-element list (idx, value)
|
|
@@ -3904,7 +4041,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3904
4041
|
const outs = [];
|
|
3905
4042
|
|
|
3906
4043
|
for (let i = 0; i < xs.length; i++) {
|
|
3907
|
-
const idxLit =
|
|
4044
|
+
const idxLit = internLiteral(String(i)); // index starts at 0
|
|
3908
4045
|
|
|
3909
4046
|
// --- index side: strict if ground, otherwise unify/bind
|
|
3910
4047
|
let s1 = null;
|
|
@@ -3980,7 +4117,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3980
4117
|
// list:length (strict: do not accept integer<->decimal matches for a ground object)
|
|
3981
4118
|
if (pv === LIST_NS + 'length') {
|
|
3982
4119
|
if (!(g.s instanceof ListTerm)) return [];
|
|
3983
|
-
const nTerm =
|
|
4120
|
+
const nTerm = internLiteral(String(g.s.elems.length));
|
|
3984
4121
|
|
|
3985
4122
|
const o2 = applySubstTerm(g.o, subst);
|
|
3986
4123
|
if (isGroundTerm(o2)) {
|
|
@@ -4092,7 +4229,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4092
4229
|
if (!(inputTerm instanceof ListTerm)) return [];
|
|
4093
4230
|
const inputList = inputTerm.elems;
|
|
4094
4231
|
if (!(predTerm instanceof Iri)) return [];
|
|
4095
|
-
const pred =
|
|
4232
|
+
const pred = internIri(predTerm.value);
|
|
4096
4233
|
if (!isBuiltinPred(pred)) return [];
|
|
4097
4234
|
if (!inputList.every((e) => isGroundTerm(e))) return [];
|
|
4098
4235
|
|
|
@@ -4185,8 +4322,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4185
4322
|
}
|
|
4186
4323
|
|
|
4187
4324
|
if (oDt !== null) {
|
|
4188
|
-
const strLit = isQuotedLexical(oLex) ?
|
|
4189
|
-
const subjList = new ListTerm([strLit,
|
|
4325
|
+
const strLit = isQuotedLexical(oLex) ? internLiteral(oLex) : makeStringLiteral(String(oLex));
|
|
4326
|
+
const subjList = new ListTerm([strLit, internIri(oDt)]);
|
|
4190
4327
|
const s2 = unifyTerm(goal.s, subjList, subst);
|
|
4191
4328
|
if (s2 !== null) results.push(s2);
|
|
4192
4329
|
}
|
|
@@ -4205,7 +4342,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4205
4342
|
if (okString) {
|
|
4206
4343
|
const dtIri = b.value;
|
|
4207
4344
|
// For xsd:string, prefer the plain string literal form.
|
|
4208
|
-
const outLit = dtIri === XSD_NS + 'string' ?
|
|
4345
|
+
const outLit = dtIri === XSD_NS + 'string' ? internLiteral(sLex) : internLiteral(`${sLex}^^<${dtIri}>`);
|
|
4209
4346
|
const s2 = unifyTerm(goal.o, outLit, subst);
|
|
4210
4347
|
if (s2 !== null) results.push(s2);
|
|
4211
4348
|
}
|
|
@@ -4241,7 +4378,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4241
4378
|
const tag = extractLangTag(g.o.value);
|
|
4242
4379
|
if (tag !== null) {
|
|
4243
4380
|
const [oLex] = literalParts(g.o.value); // strips @lang into lexical part
|
|
4244
|
-
const strLit = isQuotedLexical(oLex) ?
|
|
4381
|
+
const strLit = isQuotedLexical(oLex) ? internLiteral(oLex) : makeStringLiteral(String(oLex));
|
|
4245
4382
|
const langLit = makeStringLiteral(tag);
|
|
4246
4383
|
const subjList = new ListTerm([strLit, langLit]);
|
|
4247
4384
|
const s2 = unifyTerm(goal.s, subjList, subst);
|
|
@@ -4261,7 +4398,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4261
4398
|
if (okString && okLang) {
|
|
4262
4399
|
const tag = stripQuotes(langLex);
|
|
4263
4400
|
if (LANG_RE.test(tag)) {
|
|
4264
|
-
const outLit =
|
|
4401
|
+
const outLit = internLiteral(`${sLex}@${tag}`);
|
|
4265
4402
|
const s2 = unifyTerm(goal.o, outLit, subst);
|
|
4266
4403
|
if (s2 !== null) results.push(s2);
|
|
4267
4404
|
}
|
|
@@ -4283,7 +4420,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4283
4420
|
const r = standardizeRule(r0, varGen);
|
|
4284
4421
|
|
|
4285
4422
|
const premF = new FormulaTerm(r.premise);
|
|
4286
|
-
const concTerm = r0.isFuse ?
|
|
4423
|
+
const concTerm = r0.isFuse ? internLiteral('false') : new FormulaTerm(r.conclusion);
|
|
4287
4424
|
|
|
4288
4425
|
// unify subject with the premise formula
|
|
4289
4426
|
let s2 = unifyTerm(goal.s, premF, subst);
|
|
@@ -4420,7 +4557,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4420
4557
|
let iri = skolemCache.get(key);
|
|
4421
4558
|
if (!iri) {
|
|
4422
4559
|
const id = deterministicSkolemIdFromKey(key);
|
|
4423
|
-
iri =
|
|
4560
|
+
iri = internIri(SKOLEM_NS + id);
|
|
4424
4561
|
skolemCache.set(key, iri);
|
|
4425
4562
|
}
|
|
4426
4563
|
|
|
@@ -4442,7 +4579,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
4442
4579
|
if (g.o instanceof Literal) {
|
|
4443
4580
|
const uriStr = termToJsString(g.o); // JS string from the literal
|
|
4444
4581
|
if (uriStr === null) return [];
|
|
4445
|
-
const iri =
|
|
4582
|
+
const iri = internIri(uriStr);
|
|
4446
4583
|
const s2 = unifyTerm(goal.s, iri, subst);
|
|
4447
4584
|
return s2 !== null ? [s2] : [];
|
|
4448
4585
|
}
|