eyeling 1.6.18 → 1.6.20

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.
Files changed (2) hide show
  1. package/eyeling.js +113 -75
  2. 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 new Literal('"""' + jsonText + '"""^^<' + RDF_JSON_DT + '>');
65
+ return internLiteral('"""' + jsonText + '"""^^<' + RDF_JSON_DT + '>');
66
66
  }
67
- return new Literal(JSON.stringify(jsonText) + '^^<' + RDF_JSON_DT + '>');
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
@@ -87,16 +87,6 @@ let fixedNowLex = null;
87
87
  // If not fixed, we still memoize one value per run to avoid re-firing rules.
88
88
  let runNowLex = null;
89
89
 
90
- function normalizeDateTimeLex(s) {
91
- // Accept: 2025-... , "2025-..." , "2025-..."^^xsd:dateTime , "..."^^<...>
92
- if (s == null) return null;
93
- let t = String(s).trim();
94
- const caret = t.indexOf('^^');
95
- if (caret >= 0) t = t.slice(0, caret).trim();
96
- if (t.startsWith('"') && t.endsWith('"') && t.length >= 2) t = t.slice(1, -1);
97
- return t.trim();
98
- }
99
-
100
90
  // ===========================================================================
101
91
  // Run-level time helpers
102
92
  // ===========================================================================
@@ -222,6 +212,37 @@ class Var extends Term {
222
212
  }
223
213
  }
224
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
+
225
246
  class Blank extends Term {
226
247
  constructor(label) {
227
248
  super();
@@ -986,23 +1007,23 @@ class Parser {
986
1007
  const val = tok.value;
987
1008
 
988
1009
  if (typ === 'Equals') {
989
- return new Iri(OWL_NS + 'sameAs');
1010
+ return internIri(OWL_NS + 'sameAs');
990
1011
  }
991
1012
 
992
1013
  if (typ === 'IriRef') {
993
1014
  const base = this.prefixes.map[''] || '';
994
- return new Iri(resolveIriRef(val || '', base));
1015
+ return internIri(resolveIriRef(val || '', base));
995
1016
  }
996
1017
  if (typ === 'Ident') {
997
1018
  const name = val || '';
998
1019
  if (name === 'a') {
999
- return new Iri(RDF_NS + 'type');
1020
+ return internIri(RDF_NS + 'type');
1000
1021
  } else if (name.startsWith('_:')) {
1001
1022
  return new Blank(name);
1002
1023
  } else if (name.includes(':')) {
1003
- return new Iri(this.prefixes.expandQName(name));
1024
+ return internIri(this.prefixes.expandQName(name));
1004
1025
  } else {
1005
- return new Iri(name);
1026
+ return internIri(name);
1006
1027
  }
1007
1028
  }
1008
1029
 
@@ -1040,7 +1061,7 @@ class Parser {
1040
1061
  }
1041
1062
  s = `${s}^^<${dtIri}>`;
1042
1063
  }
1043
- return new Literal(s);
1064
+ return internLiteral(s);
1044
1065
  }
1045
1066
 
1046
1067
  if (typ === 'Var') return new Var(val || '');
@@ -1079,7 +1100,7 @@ class Parser {
1079
1100
  let invert = false;
1080
1101
  if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
1081
1102
  this.next();
1082
- pred = new Iri(RDF_NS + 'type');
1103
+ pred = internIri(RDF_NS + 'type');
1083
1104
  } else if (this.peek().typ === 'OpPredInvert') {
1084
1105
  this.next(); // consume "<-"
1085
1106
  pred = this.parseTerm();
@@ -1123,7 +1144,7 @@ class Parser {
1123
1144
  if (this.peek().typ === 'OpImplies') {
1124
1145
  this.next();
1125
1146
  const right = this.parseTerm();
1126
- const pred = new Iri(LOG_NS + 'implies');
1147
+ const pred = internIri(LOG_NS + 'implies');
1127
1148
  triples.push(new Triple(left, pred, right));
1128
1149
  if (this.peek().typ === 'Dot') this.next();
1129
1150
  else if (this.peek().typ === 'RBrace') {
@@ -1134,7 +1155,7 @@ class Parser {
1134
1155
  } else if (this.peek().typ === 'OpImpliedBy') {
1135
1156
  this.next();
1136
1157
  const right = this.parseTerm();
1137
- const pred = new Iri(LOG_NS + 'impliedBy');
1158
+ const pred = internIri(LOG_NS + 'impliedBy');
1138
1159
  triples.push(new Triple(left, pred, right));
1139
1160
  if (this.peek().typ === 'Dot') this.next();
1140
1161
  else if (this.peek().typ === 'RBrace') {
@@ -1182,7 +1203,7 @@ class Parser {
1182
1203
 
1183
1204
  if (this.peek().typ === 'Ident' && (this.peek().value || '') === 'a') {
1184
1205
  this.next();
1185
- verb = new Iri(RDF_NS + 'type');
1206
+ verb = internIri(RDF_NS + 'type');
1186
1207
  } else if (this.peek().typ === 'OpPredInvert') {
1187
1208
  this.next(); // "<-"
1188
1209
  verb = this.parseTerm();
@@ -1651,10 +1672,6 @@ function alphaEqTriple(a, b) {
1651
1672
  return alphaEqTerm(a.s, b.s, bmap) && alphaEqTerm(a.p, b.p, bmap) && alphaEqTerm(a.o, b.o, bmap);
1652
1673
  }
1653
1674
 
1654
- function hasAlphaEquiv(triples, tr) {
1655
- return triples.some((t) => alphaEqTriple(t, tr));
1656
- }
1657
-
1658
1675
  // ===========================================================================
1659
1676
  // Indexes (facts + backward rules)
1660
1677
  // ===========================================================================
@@ -1683,13 +1700,18 @@ function tripleFastKey(tr) {
1683
1700
  }
1684
1701
 
1685
1702
  function ensureFactIndexes(facts) {
1686
- if (facts.__byPred && facts.__byPO && facts.__keySet) return;
1703
+ if (facts.__byPred && facts.__byPS && facts.__byPO && facts.__keySet) return;
1687
1704
 
1688
1705
  Object.defineProperty(facts, '__byPred', {
1689
1706
  value: new Map(),
1690
1707
  enumerable: false,
1691
1708
  writable: true,
1692
1709
  });
1710
+ Object.defineProperty(facts, '__byPS', {
1711
+ value: new Map(),
1712
+ enumerable: false,
1713
+ writable: true,
1714
+ });
1693
1715
  Object.defineProperty(facts, '__byPO', {
1694
1716
  value: new Map(),
1695
1717
  enumerable: false,
@@ -1715,6 +1737,21 @@ function indexFact(facts, tr) {
1715
1737
  }
1716
1738
  pb.push(tr);
1717
1739
 
1740
+ const sk = termFastKey(tr.s);
1741
+ if (sk !== null) {
1742
+ let ps = facts.__byPS.get(pk);
1743
+ if (!ps) {
1744
+ ps = new Map();
1745
+ facts.__byPS.set(pk, ps);
1746
+ }
1747
+ let psb = ps.get(sk);
1748
+ if (!psb) {
1749
+ psb = [];
1750
+ ps.set(sk, psb);
1751
+ }
1752
+ psb.push(tr);
1753
+ }
1754
+
1718
1755
  const ok = termFastKey(tr.o);
1719
1756
  if (ok !== null) {
1720
1757
  let po = facts.__byPO.get(pk);
@@ -1741,15 +1778,27 @@ function candidateFacts(facts, goal) {
1741
1778
  if (goal.p instanceof Iri) {
1742
1779
  const pk = goal.p.value;
1743
1780
 
1781
+ const sk = termFastKey(goal.s);
1744
1782
  const ok = termFastKey(goal.o);
1783
+
1784
+ /** @type {Triple[] | null} */
1785
+ let byPS = null;
1786
+ if (sk !== null) {
1787
+ const ps = facts.__byPS.get(pk);
1788
+ if (ps) byPS = ps.get(sk) || null;
1789
+ }
1790
+
1791
+ /** @type {Triple[] | null} */
1792
+ let byPO = null;
1745
1793
  if (ok !== null) {
1746
1794
  const po = facts.__byPO.get(pk);
1747
- if (po) {
1748
- const pob = po.get(ok);
1749
- if (pob) return pob;
1750
- }
1795
+ if (po) byPO = po.get(ok) || null;
1751
1796
  }
1752
1797
 
1798
+ if (byPS && byPO) return byPS.length <= byPO.length ? byPS : byPO;
1799
+ if (byPS) return byPS;
1800
+ if (byPO) return byPO;
1801
+
1753
1802
  return facts.__byPred.get(pk) || [];
1754
1803
  }
1755
1804
 
@@ -1896,12 +1945,10 @@ function isConstraintBuiltin(tr) {
1896
1945
  return false;
1897
1946
  }
1898
1947
 
1899
- /**
1900
- * Move constraint builtins to the end of the rule premise.
1901
- * This is a simple "delaying" strategy similar in spirit to Prolog's when/2:
1902
- * - normal goals first (can bind variables),
1903
- * - pure test / constraint builtins last (checked once bindings are in place).
1904
- */
1948
+ // Move constraint builtins to the end of the rule premise.
1949
+ // This is a simple "delaying" strategy similar in spirit to Prolog's when/2:
1950
+ // - normal goals first (can bind variables),
1951
+ // - pure test / constraint builtins last (checked once bindings are in place).
1905
1952
  function reorderPremiseForConstraints(premise) {
1906
1953
  if (!premise || premise.length === 0) return premise;
1907
1954
 
@@ -2348,7 +2395,7 @@ function termToJsString(t) {
2348
2395
  function makeStringLiteral(str) {
2349
2396
  // JSON.stringify gives us a valid N3/Turtle-style quoted string
2350
2397
  // (with proper escaping for quotes, backslashes, newlines, …).
2351
- return new Literal(JSON.stringify(str));
2398
+ return internLiteral(JSON.stringify(str));
2352
2399
  }
2353
2400
 
2354
2401
  function termToJsStringDecoded(t) {
@@ -2397,8 +2444,8 @@ function jsonPointerUnescape(seg) {
2397
2444
  function jsonToTerm(v) {
2398
2445
  if (v === null) return makeStringLiteral('null');
2399
2446
  if (typeof v === 'string') return makeStringLiteral(v);
2400
- if (typeof v === 'number') return new Literal(String(v));
2401
- if (typeof v === 'boolean') return new Literal(v ? 'true' : 'false');
2447
+ if (typeof v === 'number') return internLiteral(String(v));
2448
+ if (typeof v === 'boolean') return internLiteral(v ? 'true' : 'false');
2402
2449
  if (Array.isArray(v)) return new ListTerm(v.map(jsonToTerm));
2403
2450
 
2404
2451
  if (v && typeof v === 'object') {
@@ -2676,15 +2723,6 @@ function parseIntLiteral(t) {
2676
2723
  }
2677
2724
  }
2678
2725
 
2679
- function parseNumberLiteral(t) {
2680
- // Prefer BigInt for integers, fall back to Number for other numeric literals.
2681
- const bi = parseIntLiteral(t);
2682
- if (bi !== null) return bi;
2683
- const n = parseNum(t);
2684
- if (n !== null) return n;
2685
- return null;
2686
- }
2687
-
2688
2726
  function formatNum(n) {
2689
2727
  return String(n);
2690
2728
  }
@@ -2880,7 +2918,7 @@ function formatDurationLiteralFromSeconds(secs) {
2880
2918
  const neg = secs < 0;
2881
2919
  const days = Math.round(Math.abs(secs) / 86400.0);
2882
2920
  const literalLex = neg ? `"-P${days}D"` : `"P${days}D"`;
2883
- return new Literal(`${literalLex}^^<${XSD_NS}duration>`);
2921
+ return internLiteral(`${literalLex}^^<${XSD_NS}duration>`);
2884
2922
  }
2885
2923
  function numEqualTerm(t, n, eps = 1e-9) {
2886
2924
  const v = parseNum(t);
@@ -2992,21 +3030,21 @@ function commonNumericDatatype(terms, outTerm) {
2992
3030
 
2993
3031
  function makeNumericOutputLiteral(val, dt) {
2994
3032
  if (dt === XSD_INTEGER_DT) {
2995
- if (typeof val === 'bigint') return new Literal(val.toString());
2996
- if (Number.isInteger(val)) return new Literal(String(val));
3033
+ if (typeof val === 'bigint') return internLiteral(val.toString());
3034
+ if (Number.isInteger(val)) return internLiteral(String(val));
2997
3035
  // If a non-integer sneaks in, promote to decimal.
2998
- return new Literal(`"${formatNum(val)}"^^<${XSD_DECIMAL_DT}>`);
3036
+ return internLiteral(`"${formatNum(val)}"^^<${XSD_DECIMAL_DT}>`);
2999
3037
  }
3000
3038
 
3001
3039
  if (dt === XSD_FLOAT_DT || dt === XSD_DOUBLE_DT) {
3002
3040
  const sp = formatXsdFloatSpecialLex(val);
3003
3041
  const lex = sp !== null ? sp : formatNum(val);
3004
- return new Literal(`"${lex}"^^<${dt}>`);
3042
+ return internLiteral(`"${lex}"^^<${dt}>`);
3005
3043
  }
3006
3044
 
3007
3045
  // decimal
3008
3046
  const lex = typeof val === 'bigint' ? val.toString() : formatNum(val);
3009
- return new Literal(`"${lex}"^^<${dt}>`);
3047
+ return internLiteral(`"${lex}"^^<${dt}>`);
3010
3048
  }
3011
3049
 
3012
3050
  function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
@@ -3254,7 +3292,7 @@ function hashLiteralTerm(t, algo) {
3254
3292
  const input = stripQuotes(lex);
3255
3293
  try {
3256
3294
  const digest = nodeCrypto.createHash(algo).update(input, 'utf8').digest('hex');
3257
- return new Literal(JSON.stringify(digest));
3295
+ return internLiteral(JSON.stringify(digest));
3258
3296
  } catch (e) {
3259
3297
  return null;
3260
3298
  }
@@ -3454,7 +3492,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3454
3492
  if (secs !== null) {
3455
3493
  const outSecs = aDt.getTime() / 1000.0 - secs;
3456
3494
  const lex = utcIsoDateTimeStringFromEpochSeconds(outSecs);
3457
- const lit = new Literal(`"${lex}"^^<${XSD_NS}dateTime>`);
3495
+ const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
3458
3496
  if (g.o instanceof Var) {
3459
3497
  const s2 = { ...subst };
3460
3498
  s2[g.o.name] = lit;
@@ -3470,7 +3508,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3470
3508
  const bi = parseIntLiteral(b0);
3471
3509
  if (ai !== null && bi !== null) {
3472
3510
  const ci = ai - bi;
3473
- const lit = new Literal(ci.toString());
3511
+ const lit = internLiteral(ci.toString());
3474
3512
  if (g.o instanceof Var) {
3475
3513
  const s2 = { ...subst };
3476
3514
  s2[g.o.name] = lit;
@@ -3505,7 +3543,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3505
3543
  }
3506
3544
 
3507
3545
  // Fallback (if you *don’t* have those helpers yet):
3508
- const lit = new Literal(formatNum(c));
3546
+ const lit = internLiteral(formatNum(c));
3509
3547
  if (g.o instanceof Var) {
3510
3548
  const s2 = { ...subst };
3511
3549
  s2[g.o.name] = lit;
@@ -3556,7 +3594,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3556
3594
  if (ai !== null && bi !== null) {
3557
3595
  if (bi === 0n) return [];
3558
3596
  const q = ai / bi; // BigInt division truncates toward zero
3559
- const lit = new Literal(q.toString());
3597
+ const lit = internLiteral(q.toString());
3560
3598
  if (g.o instanceof Var) {
3561
3599
  const s2 = { ...subst };
3562
3600
  s2[g.o.name] = lit;
@@ -3585,7 +3623,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3585
3623
  if (!Number.isInteger(a) || !Number.isInteger(b)) return [];
3586
3624
 
3587
3625
  const q = Math.trunc(a / b);
3588
- const lit = new Literal(String(q));
3626
+ const lit = internLiteral(String(q));
3589
3627
  if (g.o instanceof Var) {
3590
3628
  const s2 = { ...subst };
3591
3629
  s2[g.o.name] = lit;
@@ -3783,7 +3821,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3783
3821
  if (Number.isNaN(a)) return [];
3784
3822
 
3785
3823
  const rVal = Math.round(a); // ties go toward +∞ in JS (e.g., -1.5 -> -1)
3786
- const lit = new Literal(String(rVal)); // integer token
3824
+ const lit = internLiteral(String(rVal)); // integer token
3787
3825
 
3788
3826
  if (g.o instanceof Var) {
3789
3827
  const s2 = { ...subst };
@@ -3811,7 +3849,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3811
3849
 
3812
3850
  if (g.o instanceof Var) {
3813
3851
  const s2 = { ...subst };
3814
- s2[g.o.name] = new Literal(`"${now}"^^<${XSD_NS}dateTime>`);
3852
+ s2[g.o.name] = internLiteral(`"${now}"^^<${XSD_NS}dateTime>`);
3815
3853
  return [s2];
3816
3854
  }
3817
3855
  if (g.o instanceof Literal) {
@@ -3873,7 +3911,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3873
3911
  const outs = [];
3874
3912
 
3875
3913
  for (let i = 0; i < xs.length; i++) {
3876
- const idxLit = new Literal(String(i)); // 0-based
3914
+ const idxLit = internLiteral(String(i)); // 0-based
3877
3915
  const val = xs[i];
3878
3916
 
3879
3917
  // Fast path: object is exactly a 2-element list (idx, value)
@@ -3929,7 +3967,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3929
3967
  const outs = [];
3930
3968
 
3931
3969
  for (let i = 0; i < xs.length; i++) {
3932
- const idxLit = new Literal(String(i)); // index starts at 0
3970
+ const idxLit = internLiteral(String(i)); // index starts at 0
3933
3971
 
3934
3972
  // --- index side: strict if ground, otherwise unify/bind
3935
3973
  let s1 = null;
@@ -4005,7 +4043,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4005
4043
  // list:length (strict: do not accept integer<->decimal matches for a ground object)
4006
4044
  if (pv === LIST_NS + 'length') {
4007
4045
  if (!(g.s instanceof ListTerm)) return [];
4008
- const nTerm = new Literal(String(g.s.elems.length));
4046
+ const nTerm = internLiteral(String(g.s.elems.length));
4009
4047
 
4010
4048
  const o2 = applySubstTerm(g.o, subst);
4011
4049
  if (isGroundTerm(o2)) {
@@ -4117,7 +4155,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4117
4155
  if (!(inputTerm instanceof ListTerm)) return [];
4118
4156
  const inputList = inputTerm.elems;
4119
4157
  if (!(predTerm instanceof Iri)) return [];
4120
- const pred = new Iri(predTerm.value);
4158
+ const pred = internIri(predTerm.value);
4121
4159
  if (!isBuiltinPred(pred)) return [];
4122
4160
  if (!inputList.every((e) => isGroundTerm(e))) return [];
4123
4161
 
@@ -4210,8 +4248,8 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4210
4248
  }
4211
4249
 
4212
4250
  if (oDt !== null) {
4213
- const strLit = isQuotedLexical(oLex) ? new Literal(oLex) : makeStringLiteral(String(oLex));
4214
- const subjList = new ListTerm([strLit, new Iri(oDt)]);
4251
+ const strLit = isQuotedLexical(oLex) ? internLiteral(oLex) : makeStringLiteral(String(oLex));
4252
+ const subjList = new ListTerm([strLit, internIri(oDt)]);
4215
4253
  const s2 = unifyTerm(goal.s, subjList, subst);
4216
4254
  if (s2 !== null) results.push(s2);
4217
4255
  }
@@ -4230,7 +4268,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4230
4268
  if (okString) {
4231
4269
  const dtIri = b.value;
4232
4270
  // For xsd:string, prefer the plain string literal form.
4233
- const outLit = dtIri === XSD_NS + 'string' ? new Literal(sLex) : new Literal(`${sLex}^^<${dtIri}>`);
4271
+ const outLit = dtIri === XSD_NS + 'string' ? internLiteral(sLex) : internLiteral(`${sLex}^^<${dtIri}>`);
4234
4272
  const s2 = unifyTerm(goal.o, outLit, subst);
4235
4273
  if (s2 !== null) results.push(s2);
4236
4274
  }
@@ -4266,7 +4304,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4266
4304
  const tag = extractLangTag(g.o.value);
4267
4305
  if (tag !== null) {
4268
4306
  const [oLex] = literalParts(g.o.value); // strips @lang into lexical part
4269
- const strLit = isQuotedLexical(oLex) ? new Literal(oLex) : makeStringLiteral(String(oLex));
4307
+ const strLit = isQuotedLexical(oLex) ? internLiteral(oLex) : makeStringLiteral(String(oLex));
4270
4308
  const langLit = makeStringLiteral(tag);
4271
4309
  const subjList = new ListTerm([strLit, langLit]);
4272
4310
  const s2 = unifyTerm(goal.s, subjList, subst);
@@ -4286,7 +4324,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4286
4324
  if (okString && okLang) {
4287
4325
  const tag = stripQuotes(langLex);
4288
4326
  if (LANG_RE.test(tag)) {
4289
- const outLit = new Literal(`${sLex}@${tag}`);
4327
+ const outLit = internLiteral(`${sLex}@${tag}`);
4290
4328
  const s2 = unifyTerm(goal.o, outLit, subst);
4291
4329
  if (s2 !== null) results.push(s2);
4292
4330
  }
@@ -4308,7 +4346,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4308
4346
  const r = standardizeRule(r0, varGen);
4309
4347
 
4310
4348
  const premF = new FormulaTerm(r.premise);
4311
- const concTerm = r0.isFuse ? new Literal('false') : new FormulaTerm(r.conclusion);
4349
+ const concTerm = r0.isFuse ? internLiteral('false') : new FormulaTerm(r.conclusion);
4312
4350
 
4313
4351
  // unify subject with the premise formula
4314
4352
  let s2 = unifyTerm(goal.s, premF, subst);
@@ -4445,7 +4483,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4445
4483
  let iri = skolemCache.get(key);
4446
4484
  if (!iri) {
4447
4485
  const id = deterministicSkolemIdFromKey(key);
4448
- iri = new Iri(SKOLEM_NS + id);
4486
+ iri = internIri(SKOLEM_NS + id);
4449
4487
  skolemCache.set(key, iri);
4450
4488
  }
4451
4489
 
@@ -4467,7 +4505,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4467
4505
  if (g.o instanceof Literal) {
4468
4506
  const uriStr = termToJsString(g.o); // JS string from the literal
4469
4507
  if (uriStr === null) return [];
4470
- const iri = new Iri(uriStr);
4508
+ const iri = internIri(uriStr);
4471
4509
  const s2 = unifyTerm(goal.s, iri, subst);
4472
4510
  return s2 !== null ? [s2] : [];
4473
4511
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.6.18",
3
+ "version": "1.6.20",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [