eyeling 1.22.13 → 1.22.15

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/lib/builtins.js CHANGED
@@ -58,6 +58,19 @@ const MAX_NUMERIC_CACHE_KEY_LEN = 1024;
58
58
  // (Ackermann(4,2) is ~65k bits, so well below this.)
59
59
  const MAX_BIGINT_POW_RESULT_BITS = 2_000_000n;
60
60
 
61
+ function __emptySubst() {
62
+ return Object.create(null);
63
+ }
64
+
65
+ function __cloneSubst(subst) {
66
+ if (!subst) return __emptySubst();
67
+ const out = Object.create(null);
68
+ for (const k in subst) {
69
+ if (Object.prototype.hasOwnProperty.call(subst, k)) out[k] = subst[k];
70
+ }
71
+ return out;
72
+ }
73
+
61
74
  function __useNumericCacheKey(key) {
62
75
  return typeof key === 'string' && key.length <= MAX_NUMERIC_CACHE_KEY_LEN;
63
76
  }
@@ -1261,12 +1274,12 @@ function cmpNumericInfo(aInfo, bInfo, op) {
1261
1274
  function evalNumericComparisonBuiltin(g, subst, op) {
1262
1275
  const aInfo = parseNumericForCompareTerm(g.s);
1263
1276
  const bInfo = parseNumericForCompareTerm(g.o);
1264
- if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, op)) return [{ ...subst }];
1277
+ if (aInfo && bInfo && cmpNumericInfo(aInfo, bInfo, op)) return [__cloneSubst(subst)];
1265
1278
 
1266
1279
  if (g.s instanceof ListTerm && g.s.elems.length === 2) {
1267
1280
  const a2 = parseNumericForCompareTerm(g.s.elems[0]);
1268
1281
  const b2 = parseNumericForCompareTerm(g.s.elems[1]);
1269
- if (a2 && b2 && cmpNumericInfo(a2, b2, op)) return [{ ...subst }];
1282
+ if (a2 && b2 && cmpNumericInfo(a2, b2, op)) return [__cloneSubst(subst)];
1270
1283
  }
1271
1284
  return [];
1272
1285
  }
@@ -1482,12 +1495,12 @@ function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
1482
1495
  if (outDt === XSD_INTEGER_DT && !Number.isInteger(outVal)) outDt = XSD_DECIMAL_DT;
1483
1496
 
1484
1497
  if (g.o instanceof Var) {
1485
- const s2 = { ...subst };
1498
+ const s2 = __cloneSubst(subst);
1486
1499
  s2[g.o.name] = makeNumericOutputLiteral(outVal, outDt);
1487
1500
  return [s2];
1488
1501
  }
1489
- if (g.o instanceof Blank) return [{ ...subst }];
1490
- if (numEqualTerm(g.o, outVal)) return [{ ...subst }];
1502
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
1503
+ if (numEqualTerm(g.o, outVal)) return [__cloneSubst(subst)];
1491
1504
  return [];
1492
1505
  }
1493
1506
 
@@ -1500,12 +1513,12 @@ function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
1500
1513
  if (inDt === XSD_INTEGER_DT && !Number.isInteger(inVal)) inDt = XSD_DECIMAL_DT;
1501
1514
 
1502
1515
  if (g.s instanceof Var) {
1503
- const s2 = { ...subst };
1516
+ const s2 = __cloneSubst(subst);
1504
1517
  s2[g.s.name] = makeNumericOutputLiteral(inVal, inDt);
1505
1518
  return [s2];
1506
1519
  }
1507
- if (g.s instanceof Blank) return [{ ...subst }];
1508
- if (numEqualTerm(g.s, inVal)) return [{ ...subst }];
1520
+ if (g.s instanceof Blank) return [__cloneSubst(subst)];
1521
+ if (numEqualTerm(g.s, inVal)) return [__cloneSubst(subst)];
1509
1522
  return [];
1510
1523
  }
1511
1524
 
@@ -1525,7 +1538,7 @@ function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
1525
1538
 
1526
1539
  function listAppendSplit(parts, resElems, subst) {
1527
1540
  if (!parts.length) {
1528
- if (!resElems.length) return [{ ...subst }];
1541
+ if (!resElems.length) return [__cloneSubst(subst)];
1529
1542
  return [];
1530
1543
  }
1531
1544
  const out = [];
@@ -1853,7 +1866,7 @@ function evalCryptoHashBuiltin(g, subst, algo) {
1853
1866
  const lit = hashLiteralTerm(g.s, algo);
1854
1867
  if (!lit) return [];
1855
1868
  if (g.o instanceof Var) {
1856
- const s2 = { ...subst };
1869
+ const s2 = __cloneSubst(subst);
1857
1870
  s2[g.o.name] = lit;
1858
1871
  return [s2];
1859
1872
  }
@@ -1985,7 +1998,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
1985
1998
  const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
1986
1999
  const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
1987
2000
  if (g.o instanceof Var) {
1988
- const s2 = { ...subst };
2001
+ const s2 = __cloneSubst(subst);
1989
2002
  s2[g.o.name] = lit;
1990
2003
  return [s2];
1991
2004
  }
@@ -2001,7 +2014,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2001
2014
  const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
2002
2015
  const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
2003
2016
  if (g.o instanceof Var) {
2004
- const s2 = { ...subst };
2017
+ const s2 = __cloneSubst(subst);
2005
2018
  s2[g.o.name] = lit;
2006
2019
  return [s2];
2007
2020
  }
@@ -2023,17 +2036,17 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2023
2036
  }
2024
2037
 
2025
2038
  if (g.o instanceof Var) {
2026
- const s2 = { ...subst };
2039
+ const s2 = __cloneSubst(subst);
2027
2040
  s2[g.o.name] = makeNumericOutputLiteral(total, XSD_INTEGER_DT);
2028
2041
  return [s2];
2029
2042
  }
2030
- if (g.o instanceof Blank) return [{ ...subst }];
2043
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2031
2044
 
2032
2045
  const oi = parseIntLiteral(g.o);
2033
- if (oi !== null && oi === total) return [{ ...subst }];
2046
+ if (oi !== null && oi === total) return [__cloneSubst(subst)];
2034
2047
 
2035
2048
  // Fallback numeric compare
2036
- if (numEqualTerm(g.o, Number(total))) return [{ ...subst }];
2049
+ if (numEqualTerm(g.o, Number(total))) return [__cloneSubst(subst)];
2037
2050
  return [];
2038
2051
  }
2039
2052
 
@@ -2050,12 +2063,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2050
2063
  const lit = makeNumericOutputLiteral(total, dtOut);
2051
2064
 
2052
2065
  if (g.o instanceof Var) {
2053
- const s2 = { ...subst };
2066
+ const s2 = __cloneSubst(subst);
2054
2067
  s2[g.o.name] = lit;
2055
2068
  return [s2];
2056
2069
  }
2057
- if (g.o instanceof Blank) return [{ ...subst }];
2058
- if (numEqualTerm(g.o, total)) return [{ ...subst }];
2070
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2071
+ if (numEqualTerm(g.o, total)) return [__cloneSubst(subst)];
2059
2072
  return [];
2060
2073
  }
2061
2074
 
@@ -2078,15 +2091,15 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2078
2091
  }
2079
2092
 
2080
2093
  if (g.o instanceof Var) {
2081
- const s2 = { ...subst };
2094
+ const s2 = __cloneSubst(subst);
2082
2095
  s2[g.o.name] = makeNumericOutputLiteral(prod, XSD_INTEGER_DT);
2083
2096
  return [s2];
2084
2097
  }
2085
- if (g.o instanceof Blank) return [{ ...subst }];
2098
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2086
2099
 
2087
2100
  const oi = parseIntLiteral(g.o);
2088
- if (oi !== null && oi === prod) return [{ ...subst }];
2089
- if (numEqualTerm(g.o, Number(prod))) return [{ ...subst }];
2101
+ if (oi !== null && oi === prod) return [__cloneSubst(subst)];
2102
+ if (numEqualTerm(g.o, Number(prod))) return [__cloneSubst(subst)];
2090
2103
  return [];
2091
2104
  }
2092
2105
 
@@ -2103,12 +2116,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2103
2116
  const lit = makeNumericOutputLiteral(prod, dtOut);
2104
2117
 
2105
2118
  if (g.o instanceof Var) {
2106
- const s2 = { ...subst };
2119
+ const s2 = __cloneSubst(subst);
2107
2120
  s2[g.o.name] = lit;
2108
2121
  return [s2];
2109
2122
  }
2110
- if (g.o instanceof Blank) return [{ ...subst }];
2111
- if (numEqualTerm(g.o, prod)) return [{ ...subst }];
2123
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2124
+ if (numEqualTerm(g.o, prod)) return [__cloneSubst(subst)];
2112
2125
  return [];
2113
2126
  }
2114
2127
 
@@ -2132,7 +2145,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2132
2145
  const lit = formatDurationLiteralFromSeconds(diffSecs);
2133
2146
 
2134
2147
  if (g.o instanceof Var) {
2135
- const s2 = { ...subst };
2148
+ const s2 = __cloneSubst(subst);
2136
2149
  s2[g.o.name] = lit;
2137
2150
  return [s2];
2138
2151
  }
@@ -2148,7 +2161,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2148
2161
  const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
2149
2162
  const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
2150
2163
  if (g.o instanceof Var) {
2151
- const s2 = { ...subst };
2164
+ const s2 = __cloneSubst(subst);
2152
2165
  s2[g.o.name] = lit;
2153
2166
  return [s2];
2154
2167
  }
@@ -2164,7 +2177,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2164
2177
  const ci = ai - bi;
2165
2178
  const lit = internLiteral(ci.toString());
2166
2179
  if (g.o instanceof Var) {
2167
- const s2 = { ...subst };
2180
+ const s2 = __cloneSubst(subst);
2168
2181
  s2[g.o.name] = lit;
2169
2182
  return [s2];
2170
2183
  }
@@ -2187,19 +2200,19 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2187
2200
  const lit = makeNumericOutputLiteral(c, dtOut);
2188
2201
 
2189
2202
  if (g.o instanceof Var) {
2190
- const s2 = { ...subst };
2203
+ const s2 = __cloneSubst(subst);
2191
2204
  s2[g.o.name] = lit;
2192
2205
  return [s2];
2193
2206
  }
2194
- if (g.o instanceof Blank) return [{ ...subst }];
2195
- if (numEqualTerm(g.o, c)) return [{ ...subst }];
2207
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2208
+ if (numEqualTerm(g.o, c)) return [__cloneSubst(subst)];
2196
2209
  return [];
2197
2210
  }
2198
2211
 
2199
2212
  // Fallback (if you *don’t* have those helpers yet):
2200
2213
  const lit = internLiteral(formatNum(c));
2201
2214
  if (g.o instanceof Var) {
2202
- const s2 = { ...subst };
2215
+ const s2 = __cloneSubst(subst);
2203
2216
  s2[g.o.name] = lit;
2204
2217
  return [s2];
2205
2218
  }
@@ -2226,12 +2239,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2226
2239
  const lit = makeNumericOutputLiteral(c, dtOut);
2227
2240
 
2228
2241
  if (g.o instanceof Var) {
2229
- const s2 = { ...subst };
2242
+ const s2 = __cloneSubst(subst);
2230
2243
  s2[g.o.name] = lit;
2231
2244
  return [s2];
2232
2245
  }
2233
- if (g.o instanceof Blank) return [{ ...subst }];
2234
- if (numEqualTerm(g.o, c)) return [{ ...subst }];
2246
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2247
+ if (numEqualTerm(g.o, c)) return [__cloneSubst(subst)];
2235
2248
  return [];
2236
2249
  }
2237
2250
 
@@ -2250,19 +2263,19 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2250
2263
  const q = ai / bi; // BigInt division truncates toward zero
2251
2264
  const lit = internLiteral(q.toString());
2252
2265
  if (g.o instanceof Var) {
2253
- const s2 = { ...subst };
2266
+ const s2 = __cloneSubst(subst);
2254
2267
  s2[g.o.name] = lit;
2255
2268
  return [s2];
2256
2269
  }
2257
- if (g.o instanceof Blank) return [{ ...subst }];
2270
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2258
2271
 
2259
2272
  const oi = parseIntLiteral(g.o);
2260
- if (oi !== null && oi === q) return [{ ...subst }];
2273
+ if (oi !== null && oi === q) return [__cloneSubst(subst)];
2261
2274
 
2262
2275
  // Only do numeric compare when safe enough to convert
2263
2276
  const qNum = Number(q);
2264
2277
  if (Number.isFinite(qNum) && Math.abs(qNum) <= Number.MAX_SAFE_INTEGER) {
2265
- if (numEqualTerm(g.o, qNum)) return [{ ...subst }];
2278
+ if (numEqualTerm(g.o, qNum)) return [__cloneSubst(subst)];
2266
2279
  }
2267
2280
 
2268
2281
  const s2 = unifyTerm(g.o, lit, subst);
@@ -2279,13 +2292,13 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2279
2292
  const q = Math.trunc(a / b);
2280
2293
  const lit = internLiteral(String(q));
2281
2294
  if (g.o instanceof Var) {
2282
- const s2 = { ...subst };
2295
+ const s2 = __cloneSubst(subst);
2283
2296
  s2[g.o.name] = lit;
2284
2297
  return [s2];
2285
2298
  }
2286
- if (g.o instanceof Blank) return [{ ...subst }];
2299
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2287
2300
 
2288
- if (numEqualTerm(g.o, q)) return [{ ...subst }];
2301
+ if (numEqualTerm(g.o, q)) return [__cloneSubst(subst)];
2289
2302
 
2290
2303
  const s2 = unifyTerm(g.o, lit, subst);
2291
2304
  return s2 !== null ? [s2] : [];
@@ -2318,14 +2331,14 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2318
2331
  const lit = makeNumericOutputLiteral(out, XSD_INTEGER_DT);
2319
2332
 
2320
2333
  if (g.o instanceof Var) {
2321
- const s2 = { ...subst };
2334
+ const s2 = __cloneSubst(subst);
2322
2335
  s2[g.o.name] = lit;
2323
2336
  return [s2];
2324
2337
  }
2325
- if (g.o instanceof Blank) return [{ ...subst }];
2338
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2326
2339
 
2327
2340
  const oi = parseIntLiteral(g.o);
2328
- if (oi !== null && oi === out) return [{ ...subst }];
2341
+ if (oi !== null && oi === out) return [__cloneSubst(subst)];
2329
2342
 
2330
2343
  const s2 = unifyTerm(g.o, lit, subst);
2331
2344
  return s2 !== null ? [s2] : [];
@@ -2345,12 +2358,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2345
2358
  const lit = makeNumericOutputLiteral(cVal, dtOut);
2346
2359
 
2347
2360
  if (g.o instanceof Var) {
2348
- const s2 = { ...subst };
2361
+ const s2 = __cloneSubst(subst);
2349
2362
  s2[g.o.name] = lit;
2350
2363
  return [s2];
2351
2364
  }
2352
- if (g.o instanceof Blank) return [{ ...subst }];
2353
- if (numEqualTerm(g.o, cVal)) return [{ ...subst }];
2365
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2366
+ if (numEqualTerm(g.o, cVal)) return [__cloneSubst(subst)];
2354
2367
  }
2355
2368
 
2356
2369
  // Inverse: solve exponent using logs (Number mode only)
@@ -2363,7 +2376,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2363
2376
  let dtB = commonNumericDatatype([baseTerm, g.o], expTerm);
2364
2377
  if (dtB === XSD_INTEGER_DT && !Number.isInteger(bVal)) dtB = XSD_DECIMAL_DT;
2365
2378
 
2366
- const s2 = { ...subst };
2379
+ const s2 = __cloneSubst(subst);
2367
2380
  s2[expTerm.name] = makeNumericOutputLiteral(bVal, dtB);
2368
2381
  return [s2];
2369
2382
  }
@@ -2379,15 +2392,15 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2379
2392
  const lit = makeNumericOutputLiteral(outVal, XSD_INTEGER_DT);
2380
2393
 
2381
2394
  if (g.o instanceof Var) {
2382
- const s2 = { ...subst };
2395
+ const s2 = __cloneSubst(subst);
2383
2396
  s2[g.o.name] = lit;
2384
2397
  return [s2];
2385
2398
  }
2386
- if (g.o instanceof Blank) return [{ ...subst }];
2399
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2387
2400
 
2388
2401
  const oi = parseIntLiteral(g.o);
2389
- if (oi !== null && oi === outVal) return [{ ...subst }];
2390
- if (numEqualTerm(g.o, Number(outVal))) return [{ ...subst }];
2402
+ if (oi !== null && oi === outVal) return [__cloneSubst(subst)];
2403
+ if (numEqualTerm(g.o, Number(outVal))) return [__cloneSubst(subst)];
2391
2404
  return [];
2392
2405
  }
2393
2406
 
@@ -2401,12 +2414,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2401
2414
  if (dtOut === XSD_INTEGER_DT && !Number.isInteger(outVal)) dtOut = XSD_DECIMAL_DT;
2402
2415
 
2403
2416
  if (g.o instanceof Var) {
2404
- const s2 = { ...subst };
2417
+ const s2 = __cloneSubst(subst);
2405
2418
  s2[g.o.name] = makeNumericOutputLiteral(outVal, dtOut);
2406
2419
  return [s2];
2407
2420
  }
2408
- if (g.o instanceof Blank) return [{ ...subst }];
2409
- if (numEqualTerm(g.o, outVal)) return [{ ...subst }];
2421
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2422
+ if (numEqualTerm(g.o, outVal)) return [__cloneSubst(subst)];
2410
2423
  return [];
2411
2424
  }
2412
2425
 
@@ -2468,14 +2481,14 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2468
2481
  const outVal = -si;
2469
2482
  const lit = makeNumericOutputLiteral(outVal, XSD_INTEGER_DT);
2470
2483
  if (g.o instanceof Var) {
2471
- const s2 = { ...subst };
2484
+ const s2 = __cloneSubst(subst);
2472
2485
  s2[g.o.name] = lit;
2473
2486
  return [s2];
2474
2487
  }
2475
- if (g.o instanceof Blank) return [{ ...subst }];
2488
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2476
2489
  const oi = parseIntLiteral(g.o);
2477
- if (oi !== null && oi === outVal) return [{ ...subst }];
2478
- if (numEqualTerm(g.o, Number(outVal))) return [{ ...subst }];
2490
+ if (oi !== null && oi === outVal) return [__cloneSubst(subst)];
2491
+ if (numEqualTerm(g.o, Number(outVal))) return [__cloneSubst(subst)];
2479
2492
  return [];
2480
2493
  }
2481
2494
 
@@ -2484,14 +2497,14 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2484
2497
  const inVal = -oi;
2485
2498
  const lit = makeNumericOutputLiteral(inVal, XSD_INTEGER_DT);
2486
2499
  if (g.s instanceof Var) {
2487
- const s2 = { ...subst };
2500
+ const s2 = __cloneSubst(subst);
2488
2501
  s2[g.s.name] = lit;
2489
2502
  return [s2];
2490
2503
  }
2491
- if (g.s instanceof Blank) return [{ ...subst }];
2504
+ if (g.s instanceof Blank) return [__cloneSubst(subst)];
2492
2505
  const si2 = parseIntLiteral(g.s);
2493
- if (si2 !== null && si2 === inVal) return [{ ...subst }];
2494
- if (numEqualTerm(g.s, Number(inVal))) return [{ ...subst }];
2506
+ if (si2 !== null && si2 === inVal) return [__cloneSubst(subst)];
2507
+ if (numEqualTerm(g.s, Number(inVal))) return [__cloneSubst(subst)];
2495
2508
  return [];
2496
2509
  }
2497
2510
 
@@ -2515,15 +2528,15 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2515
2528
  const lit = makeNumericOutputLiteral(r, XSD_INTEGER_DT);
2516
2529
 
2517
2530
  if (g.o instanceof Var) {
2518
- const s2 = { ...subst };
2531
+ const s2 = __cloneSubst(subst);
2519
2532
  s2[g.o.name] = lit;
2520
2533
  return [s2];
2521
2534
  }
2522
- if (g.o instanceof Blank) return [{ ...subst }];
2535
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2523
2536
 
2524
2537
  const oi = parseIntLiteral(g.o);
2525
- if (oi !== null && oi === r) return [{ ...subst }];
2526
- if (numEqualTerm(g.o, Number(r))) return [{ ...subst }];
2538
+ if (oi !== null && oi === r) return [__cloneSubst(subst)];
2539
+ if (numEqualTerm(g.o, Number(r))) return [__cloneSubst(subst)];
2527
2540
  return [];
2528
2541
  }
2529
2542
 
@@ -2538,12 +2551,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2538
2551
  const lit = makeNumericOutputLiteral(rVal, XSD_INTEGER_DT);
2539
2552
 
2540
2553
  if (g.o instanceof Var) {
2541
- const s2 = { ...subst };
2554
+ const s2 = __cloneSubst(subst);
2542
2555
  s2[g.o.name] = lit;
2543
2556
  return [s2];
2544
2557
  }
2545
- if (g.o instanceof Blank) return [{ ...subst }];
2546
- if (numEqualTerm(g.o, rVal)) return [{ ...subst }];
2558
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2559
+ if (numEqualTerm(g.o, rVal)) return [__cloneSubst(subst)];
2547
2560
  return [];
2548
2561
  }
2549
2562
 
@@ -2558,15 +2571,15 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2558
2571
  const lit = makeNumericOutputLiteral(ai, XSD_INTEGER_DT);
2559
2572
 
2560
2573
  if (g.o instanceof Var) {
2561
- const s2 = { ...subst };
2574
+ const s2 = __cloneSubst(subst);
2562
2575
  s2[g.o.name] = lit;
2563
2576
  return [s2];
2564
2577
  }
2565
- if (g.o instanceof Blank) return [{ ...subst }];
2578
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2566
2579
 
2567
2580
  const oi = parseIntLiteral(g.o);
2568
- if (oi !== null && oi === ai) return [{ ...subst }];
2569
- if (numEqualTerm(g.o, Number(ai))) return [{ ...subst }];
2581
+ if (oi !== null && oi === ai) return [__cloneSubst(subst)];
2582
+ if (numEqualTerm(g.o, Number(ai))) return [__cloneSubst(subst)];
2570
2583
 
2571
2584
  const s2 = unifyTerm(g.o, lit, subst);
2572
2585
  return s2 !== null ? [s2] : [];
@@ -2580,14 +2593,14 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2580
2593
  const lit = internLiteral(String(rVal)); // integer token
2581
2594
 
2582
2595
  if (g.o instanceof Var) {
2583
- const s2 = { ...subst };
2596
+ const s2 = __cloneSubst(subst);
2584
2597
  s2[g.o.name] = lit;
2585
2598
  return [s2];
2586
2599
  }
2587
- if (g.o instanceof Blank) return [{ ...subst }];
2600
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2588
2601
 
2589
2602
  // Accept typed numeric literals too (e.g., "3"^^xsd:float) if numerically equal.
2590
- if (numEqualTerm(g.o, rVal)) return [{ ...subst }];
2603
+ if (numEqualTerm(g.o, rVal)) return [__cloneSubst(subst)];
2591
2604
 
2592
2605
  // Fallback to strict unification
2593
2606
  const s2 = unifyTerm(g.o, lit, subst);
@@ -2607,16 +2620,16 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2607
2620
  const out = internLiteral(String(parts.day));
2608
2621
 
2609
2622
  if (g.o instanceof Var) {
2610
- const s2 = { ...subst };
2623
+ const s2 = __cloneSubst(subst);
2611
2624
  s2[g.o.name] = out;
2612
2625
  return [s2];
2613
2626
  }
2614
- if (g.o instanceof Blank) return [{ ...subst }];
2627
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2615
2628
 
2616
2629
  const oi = parseIntLiteral(g.o);
2617
2630
  if (oi !== null) {
2618
2631
  try {
2619
- if (oi === BigInt(parts.day)) return [{ ...subst }];
2632
+ if (oi === BigInt(parts.day)) return [__cloneSubst(subst)];
2620
2633
  } catch {}
2621
2634
  }
2622
2635
 
@@ -2633,16 +2646,16 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2633
2646
  const out = internLiteral(String(parts.hour));
2634
2647
 
2635
2648
  if (g.o instanceof Var) {
2636
- const s2 = { ...subst };
2649
+ const s2 = __cloneSubst(subst);
2637
2650
  s2[g.o.name] = out;
2638
2651
  return [s2];
2639
2652
  }
2640
- if (g.o instanceof Blank) return [{ ...subst }];
2653
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2641
2654
 
2642
2655
  const oi = parseIntLiteral(g.o);
2643
2656
  if (oi !== null) {
2644
2657
  try {
2645
- if (oi === BigInt(parts.hour)) return [{ ...subst }];
2658
+ if (oi === BigInt(parts.hour)) return [__cloneSubst(subst)];
2646
2659
  } catch {}
2647
2660
  }
2648
2661
 
@@ -2659,16 +2672,16 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2659
2672
  const out = internLiteral(String(parts.minute));
2660
2673
 
2661
2674
  if (g.o instanceof Var) {
2662
- const s2 = { ...subst };
2675
+ const s2 = __cloneSubst(subst);
2663
2676
  s2[g.o.name] = out;
2664
2677
  return [s2];
2665
2678
  }
2666
- if (g.o instanceof Blank) return [{ ...subst }];
2679
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2667
2680
 
2668
2681
  const oi = parseIntLiteral(g.o);
2669
2682
  if (oi !== null) {
2670
2683
  try {
2671
- if (oi === BigInt(parts.minute)) return [{ ...subst }];
2684
+ if (oi === BigInt(parts.minute)) return [__cloneSubst(subst)];
2672
2685
  } catch {}
2673
2686
  }
2674
2687
 
@@ -2685,16 +2698,16 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2685
2698
  const out = internLiteral(String(parts.month));
2686
2699
 
2687
2700
  if (g.o instanceof Var) {
2688
- const s2 = { ...subst };
2701
+ const s2 = __cloneSubst(subst);
2689
2702
  s2[g.o.name] = out;
2690
2703
  return [s2];
2691
2704
  }
2692
- if (g.o instanceof Blank) return [{ ...subst }];
2705
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2693
2706
 
2694
2707
  const oi = parseIntLiteral(g.o);
2695
2708
  if (oi !== null) {
2696
2709
  try {
2697
- if (oi === BigInt(parts.month)) return [{ ...subst }];
2710
+ if (oi === BigInt(parts.month)) return [__cloneSubst(subst)];
2698
2711
  } catch {}
2699
2712
  }
2700
2713
 
@@ -2711,16 +2724,16 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2711
2724
  const out = internLiteral(String(parts.second));
2712
2725
 
2713
2726
  if (g.o instanceof Var) {
2714
- const s2 = { ...subst };
2727
+ const s2 = __cloneSubst(subst);
2715
2728
  s2[g.o.name] = out;
2716
2729
  return [s2];
2717
2730
  }
2718
- if (g.o instanceof Blank) return [{ ...subst }];
2731
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2719
2732
 
2720
2733
  const oi = parseIntLiteral(g.o);
2721
2734
  if (oi !== null) {
2722
2735
  try {
2723
- if (oi === BigInt(parts.second)) return [{ ...subst }];
2736
+ if (oi === BigInt(parts.second)) return [__cloneSubst(subst)];
2724
2737
  } catch {}
2725
2738
  }
2726
2739
 
@@ -2738,18 +2751,18 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2738
2751
  const out = internLiteral(`"${parts.tz}"`);
2739
2752
 
2740
2753
  if (g.o instanceof Var) {
2741
- const s2 = { ...subst };
2754
+ const s2 = __cloneSubst(subst);
2742
2755
  s2[g.o.name] = out;
2743
2756
  return [s2];
2744
2757
  }
2745
- if (g.o instanceof Blank) return [{ ...subst }];
2758
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2746
2759
 
2747
- if (termsEqual(g.o, out)) return [{ ...subst }];
2760
+ if (termsEqual(g.o, out)) return [__cloneSubst(subst)];
2748
2761
 
2749
2762
  // Also accept explicitly typed xsd:string literals.
2750
2763
  if (g.o instanceof Literal) {
2751
2764
  const [lexO, dtO] = literalParts(g.o.value);
2752
- if (dtO === XSD_NS + 'string' && stripQuotes(lexO) === parts.tz) return [{ ...subst }];
2765
+ if (dtO === XSD_NS + 'string' && stripQuotes(lexO) === parts.tz) return [__cloneSubst(subst)];
2753
2766
  }
2754
2767
  return [];
2755
2768
  }
@@ -2763,16 +2776,16 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2763
2776
  const out = internLiteral(String(parts.yearStr));
2764
2777
 
2765
2778
  if (g.o instanceof Var) {
2766
- const s2 = { ...subst };
2779
+ const s2 = __cloneSubst(subst);
2767
2780
  s2[g.o.name] = out;
2768
2781
  return [s2];
2769
2782
  }
2770
- if (g.o instanceof Blank) return [{ ...subst }];
2783
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
2771
2784
 
2772
2785
  const oi = parseIntLiteral(g.o);
2773
2786
  if (oi !== null) {
2774
2787
  try {
2775
- if (oi === BigInt(parts.yearStr)) return [{ ...subst }];
2788
+ if (oi === BigInt(parts.yearStr)) return [__cloneSubst(subst)];
2776
2789
  } catch {}
2777
2790
  }
2778
2791
 
@@ -2786,13 +2799,13 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2786
2799
  const now = time.getNowLex();
2787
2800
 
2788
2801
  if (g.o instanceof Var) {
2789
- const s2 = { ...subst };
2802
+ const s2 = __cloneSubst(subst);
2790
2803
  s2[g.o.name] = internLiteral(`"${now}"^^<${XSD_NS}dateTime>`);
2791
2804
  return [s2];
2792
2805
  }
2793
2806
  if (g.o instanceof Literal) {
2794
2807
  const [lexO] = literalParts(g.o.value);
2795
- if (stripQuotes(lexO) === now) return [{ ...subst }];
2808
+ if (stripQuotes(lexO) === now) return [__cloneSubst(subst)];
2796
2809
  }
2797
2810
  return [];
2798
2811
  }
@@ -2817,11 +2830,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2817
2830
  }
2818
2831
  const result = new ListTerm(outElems);
2819
2832
  if (g.o instanceof Var) {
2820
- const s2 = { ...subst };
2833
+ const s2 = __cloneSubst(subst);
2821
2834
  s2[g.o.name] = result;
2822
2835
  return [s2];
2823
2836
  }
2824
- if (termsEqual(g.o, result)) return [{ ...subst }];
2837
+ if (termsEqual(g.o, result)) return [__cloneSubst(subst)];
2825
2838
  return [];
2826
2839
  }
2827
2840
 
@@ -2925,7 +2938,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2925
2938
  const idxPat2 = applySubstTerm(indexTerm, subst);
2926
2939
  if (isGroundTerm(idxPat2)) {
2927
2940
  if (!termsEqualNoIntDecimal(idxPat2, idxLit)) continue;
2928
- s1 = { ...subst };
2941
+ s1 = __cloneSubst(subst);
2929
2942
  } else {
2930
2943
  s1 = unifyTerm(indexTerm, idxLit, subst);
2931
2944
  if (s1 === null) continue;
@@ -3000,7 +3013,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3000
3013
 
3001
3014
  const o2 = applySubstTerm(g.o, subst);
3002
3015
  if (isGroundTerm(o2)) {
3003
- return termsEqualNoIntDecimal(o2, nTerm) ? [{ ...subst }] : [];
3016
+ return termsEqualNoIntDecimal(o2, nTerm) ? [__cloneSubst(subst)] : [];
3004
3017
  }
3005
3018
 
3006
3019
  const s2 = unifyTerm(g.o, nTerm, subst);
@@ -3014,7 +3027,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3014
3027
  for (const el of xs) {
3015
3028
  if (unifyTerm(g.o, el, subst) !== null) return [];
3016
3029
  }
3017
- return [{ ...subst }];
3030
+ return [__cloneSubst(subst)];
3018
3031
  }
3019
3032
 
3020
3033
  // list:reverse
@@ -3200,7 +3213,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3200
3213
  if (pv === LOG_NS + 'notEqualTo') {
3201
3214
  const s2 = unifyTerm(goal.s, goal.o, subst);
3202
3215
  if (s2 !== null) return [];
3203
- return [{ ...subst }];
3216
+ return [__cloneSubst(subst)];
3204
3217
  }
3205
3218
 
3206
3219
  // log:conjunction
@@ -3249,7 +3262,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3249
3262
  const outFormula = new GraphTerm(merged);
3250
3263
 
3251
3264
  // Allow blank nodes as a don't-care output (common in builtin schemas).
3252
- if (g.o instanceof Blank) return [{ ...subst }];
3265
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3253
3266
 
3254
3267
  const s2 = unifyTerm(g.o, outFormula, subst);
3255
3268
  return s2 !== null ? [s2] : [];
@@ -3269,11 +3282,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3269
3282
  if (!(conclusion instanceof GraphTerm)) return [];
3270
3283
 
3271
3284
  if (g.o instanceof Var) {
3272
- const s2 = { ...subst };
3285
+ const s2 = __cloneSubst(subst);
3273
3286
  s2[g.o.name] = conclusion;
3274
3287
  return [s2];
3275
3288
  }
3276
- if (g.o instanceof Blank) return [{ ...subst }];
3289
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3277
3290
 
3278
3291
  const s2 = unifyTerm(g.o, conclusion, subst);
3279
3292
  return s2 !== null ? [s2] : [];
@@ -3293,11 +3306,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3293
3306
  const lit = internLiteral(`${JSON.stringify(text)}^^<${XSD_NS}string>`);
3294
3307
 
3295
3308
  if (g.o instanceof Var) {
3296
- const s2 = { ...subst };
3309
+ const s2 = __cloneSubst(subst);
3297
3310
  s2[g.o.name] = lit;
3298
3311
  return [s2];
3299
3312
  }
3300
- if (g.o instanceof Blank) return [{ ...subst }];
3313
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3301
3314
 
3302
3315
  const s2 = unifyTerm(g.o, lit, subst);
3303
3316
  return s2 !== null ? [s2] : [];
@@ -3317,7 +3330,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3317
3330
  // Avoid variable capture between the returned quoted formula and the
3318
3331
  // surrounding proof environment.
3319
3332
  const formulaStd = standardizeTermApart(formula, varGen);
3320
- if (g.o instanceof Blank) return [{ ...subst }];
3333
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3321
3334
 
3322
3335
  const s2 = unifyTerm(g.o, formulaStd, subst);
3323
3336
  return s2 !== null ? [s2] : [];
@@ -3337,7 +3350,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3337
3350
  // surrounding proof environment.
3338
3351
  if (term instanceof GraphTerm) term = standardizeTermApart(term, varGen);
3339
3352
 
3340
- if (g.o instanceof Blank) return [{ ...subst }];
3353
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3341
3354
 
3342
3355
  const s2 = unifyTerm(g.o, term, subst);
3343
3356
  return s2 !== null ? [s2] : [];
@@ -3363,7 +3376,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3363
3376
  // surrounding proof environment.
3364
3377
  formula = standardizeTermApart(formula, varGen);
3365
3378
 
3366
- if (g.o instanceof Blank) return [{ ...subst }];
3379
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3367
3380
 
3368
3381
  const s2 = unifyTerm(g.o, formula, subst);
3369
3382
  return s2 !== null ? [s2] : [];
@@ -3382,11 +3395,11 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3382
3395
  else ty = internIri(LOG_NS + 'Other');
3383
3396
 
3384
3397
  if (g.o instanceof Var) {
3385
- const s2 = { ...subst };
3398
+ const s2 = __cloneSubst(subst);
3386
3399
  s2[g.o.name] = ty;
3387
3400
  return [s2];
3388
3401
  }
3389
- if (g.o instanceof Blank) return [{ ...subst }];
3402
+ if (g.o instanceof Blank) return [__cloneSubst(subst)];
3390
3403
 
3391
3404
  const s2 = unifyTerm(g.o, ty, subst);
3392
3405
  return s2 !== null ? [s2] : [];
@@ -3398,7 +3411,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3398
3411
  if (pv === LOG_NS + 'dtlit') {
3399
3412
  // Fully unbound (both arguments '?'-mode): treat as satisfiable, succeed once.
3400
3413
  // Required by notation3tests "success-fullUnbound-*".
3401
- if (g.s instanceof Var && g.o instanceof Var) return [{ ...subst }];
3414
+ if (g.s instanceof Var && g.o instanceof Var) return [__cloneSubst(subst)];
3402
3415
 
3403
3416
  const results = [];
3404
3417
 
@@ -3451,7 +3464,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3451
3464
  // true iff $o is a language-tagged literal with string value $s.1 and language tag $s.2
3452
3465
  if (pv === LOG_NS + 'langlit') {
3453
3466
  // Fully unbound (both arguments '?'-mode): treat as satisfiable, succeed once.
3454
- if (g.s instanceof Var && g.o instanceof Var) return [{ ...subst }];
3467
+ if (g.s instanceof Var && g.o instanceof Var) return [__cloneSubst(subst)];
3455
3468
  const results = [];
3456
3469
  const LANG_RE = /^[A-Za-z]+(?:-[A-Za-z0-9]+)*$/; // (same notion as literalParts/literalHasLangTag)
3457
3470
 
@@ -3641,7 +3654,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3641
3654
  }
3642
3655
 
3643
3656
  // Empty formula is always included (but may be priority-gated above).
3644
- if (g.o instanceof Literal && g.o.value === 'true') return [{ ...subst }];
3657
+ if (g.o instanceof Literal && g.o.value === 'true') return [__cloneSubst(subst)];
3645
3658
  if (!(g.o instanceof GraphTerm)) return [];
3646
3659
 
3647
3660
  const visited2 = [];
@@ -3654,7 +3667,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3654
3667
  for (const variant of goalVariants) {
3655
3668
  const sols = proveGoals(
3656
3669
  variant.goals,
3657
- { ...subst },
3670
+ __cloneSubst(subst),
3658
3671
  scopeFacts,
3659
3672
  scopeBackRules,
3660
3673
  depth + 1,
@@ -3732,7 +3745,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3732
3745
  const visited2 = [];
3733
3746
  const sols = proveGoals(
3734
3747
  __prepareQuotedPatternTriples(goal.o, subst, varGen),
3735
- { ...subst },
3748
+ __cloneSubst(subst),
3736
3749
  scopeFacts,
3737
3750
  scopeBackRules,
3738
3751
  depth + 1,
@@ -3740,7 +3753,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3740
3753
  varGen,
3741
3754
  1,
3742
3755
  );
3743
- return sols.length ? [] : [{ ...subst }];
3756
+ return sols.length ? [] : [__cloneSubst(subst)];
3744
3757
  }
3745
3758
 
3746
3759
  // log:trace
@@ -3754,7 +3767,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3754
3767
  const yStr = termToN3(g.o, pref);
3755
3768
 
3756
3769
  trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
3757
- return [{ ...subst }];
3770
+ return [__cloneSubst(subst)];
3758
3771
  }
3759
3772
 
3760
3773
  // log:outputString
@@ -3768,7 +3781,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3768
3781
  if (g.o instanceof Var) return [];
3769
3782
  const s = termToJsString(g.o);
3770
3783
  if (s === null) return [];
3771
- return [{ ...subst }];
3784
+ return [__cloneSubst(subst)];
3772
3785
  }
3773
3786
 
3774
3787
  // log:collectAllIn (scoped)
@@ -3783,7 +3796,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3783
3796
  // - object = Var: treat as priority 1 (do not bind)
3784
3797
  // - any other object: backward-compatible default priority 1
3785
3798
 
3786
- const outSubst = { ...subst };
3799
+ const outSubst = __cloneSubst(subst);
3787
3800
  let scopeFacts = null;
3788
3801
  let scopeBackRules = backRules;
3789
3802
 
@@ -3830,7 +3843,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3830
3843
  rawClauseTerm instanceof GraphTerm
3831
3844
  ? __prepareQuotedPatternTriples(rawClauseTerm, subst, varGen)
3832
3845
  : __prepareQuotedPatternTriples(clauseTerm, subst, varGen);
3833
- const sols = proveGoals(clauseGoals, {}, scopeFacts, scopeBackRules, depth + 1, visited2, varGen);
3846
+ const sols = proveGoals(clauseGoals, __emptySubst(), scopeFacts, scopeBackRules, depth + 1, visited2, varGen);
3834
3847
 
3835
3848
  const collected = sols.map((sBody) => applySubstTerm(valueTempl, sBody));
3836
3849
  const collectedList = new ListTerm(collected);
@@ -3847,7 +3860,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3847
3860
 
3848
3861
  // See log:collectAllIn above for the priority / closure semantics.
3849
3862
 
3850
- const outSubst = { ...subst };
3863
+ const outSubst = __cloneSubst(subst);
3851
3864
  let scopeFacts = null;
3852
3865
  let scopeBackRules = backRules;
3853
3866
 
@@ -3895,7 +3908,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3895
3908
  : __prepareQuotedPatternTriples(thenClause, subst, varGen);
3896
3909
 
3897
3910
  const visited1 = [];
3898
- const sols1 = proveGoals(whereGoals, {}, scopeFacts, scopeBackRules, depth + 1, visited1, varGen);
3911
+ const sols1 = proveGoals(whereGoals, __emptySubst(), scopeFacts, scopeBackRules, depth + 1, visited1, varGen);
3899
3912
 
3900
3913
  for (const s1 of sols1) {
3901
3914
  const visited2 = [];
@@ -3947,7 +3960,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3947
3960
  const sOk = g.s instanceof Var || g.s instanceof Blank || g.s instanceof Iri;
3948
3961
  const oOk = g.o instanceof Var || g.o instanceof Blank || g.o instanceof Literal;
3949
3962
  if (!sOk || !oOk) return [];
3950
- return [{ ...subst }];
3963
+ return [__cloneSubst(subst)];
3951
3964
  }
3952
3965
 
3953
3966
  // -----------------------------------------------------------------
@@ -3966,7 +3979,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3966
3979
  const lit = makeStringLiteral(parts.join(''));
3967
3980
 
3968
3981
  if (g.o instanceof Var) {
3969
- const s2 = { ...subst };
3982
+ const s2 = __cloneSubst(subst);
3970
3983
  s2[g.o.name] = lit;
3971
3984
  return [s2];
3972
3985
  }
@@ -3979,7 +3992,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3979
3992
  const sStr = termToJsString(g.s);
3980
3993
  const oStr = termToJsString(g.o);
3981
3994
  if (sStr === null || oStr === null) return [];
3982
- return sStr.includes(oStr) ? [{ ...subst }] : [];
3995
+ return sStr.includes(oStr) ? [__cloneSubst(subst)] : [];
3983
3996
  }
3984
3997
 
3985
3998
  // string:containsIgnoringCase
@@ -3987,7 +4000,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3987
4000
  const sStr = termToJsString(g.s);
3988
4001
  const oStr = termToJsString(g.o);
3989
4002
  if (sStr === null || oStr === null) return [];
3990
- return sStr.toLowerCase().includes(oStr.toLowerCase()) ? [{ ...subst }] : [];
4003
+ return sStr.toLowerCase().includes(oStr.toLowerCase()) ? [__cloneSubst(subst)] : [];
3991
4004
  }
3992
4005
 
3993
4006
  // string:endsWith
@@ -3995,7 +4008,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3995
4008
  const sStr = termToJsString(g.s);
3996
4009
  const oStr = termToJsString(g.o);
3997
4010
  if (sStr === null || oStr === null) return [];
3998
- return sStr.endsWith(oStr) ? [{ ...subst }] : [];
4011
+ return sStr.endsWith(oStr) ? [__cloneSubst(subst)] : [];
3999
4012
  }
4000
4013
 
4001
4014
  // string:equalIgnoringCase
@@ -4003,7 +4016,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4003
4016
  const sStr = termToJsString(g.s);
4004
4017
  const oStr = termToJsString(g.o);
4005
4018
  if (sStr === null || oStr === null) return [];
4006
- return sStr.toLowerCase() === oStr.toLowerCase() ? [{ ...subst }] : [];
4019
+ return sStr.toLowerCase() === oStr.toLowerCase() ? [__cloneSubst(subst)] : [];
4007
4020
  }
4008
4021
 
4009
4022
  // string:format
@@ -4023,7 +4036,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4023
4036
 
4024
4037
  const lit = makeStringLiteral(formatted);
4025
4038
  if (g.o instanceof Var) {
4026
- const s2 = { ...subst };
4039
+ const s2 = __cloneSubst(subst);
4027
4040
  s2[g.o.name] = lit;
4028
4041
  return [s2];
4029
4042
  }
@@ -4036,7 +4049,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4036
4049
  const sStr = termToJsString(g.s);
4037
4050
  const oStr = termToJsString(g.o);
4038
4051
  if (sStr === null || oStr === null) return [];
4039
- return sStr > oStr ? [{ ...subst }] : [];
4052
+ return sStr > oStr ? [__cloneSubst(subst)] : [];
4040
4053
  }
4041
4054
 
4042
4055
  // string:lessThan
@@ -4044,7 +4057,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4044
4057
  const sStr = termToJsString(g.s);
4045
4058
  const oStr = termToJsString(g.o);
4046
4059
  if (sStr === null || oStr === null) return [];
4047
- return sStr < oStr ? [{ ...subst }] : [];
4060
+ return sStr < oStr ? [__cloneSubst(subst)] : [];
4048
4061
  }
4049
4062
 
4050
4063
  // string:matches
@@ -4054,7 +4067,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4054
4067
  if (sStr === null || pattern === null) return [];
4055
4068
  const re = compileSwapRegex(pattern, '');
4056
4069
  if (!re) return [];
4057
- return re.test(sStr) ? [{ ...subst }] : [];
4070
+ return re.test(sStr) ? [__cloneSubst(subst)] : [];
4058
4071
  }
4059
4072
 
4060
4073
  // string:notEqualIgnoringCase
@@ -4062,7 +4075,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4062
4075
  const sStr = termToJsString(g.s);
4063
4076
  const oStr = termToJsString(g.o);
4064
4077
  if (sStr === null || oStr === null) return [];
4065
- return sStr.toLowerCase() !== oStr.toLowerCase() ? [{ ...subst }] : [];
4078
+ return sStr.toLowerCase() !== oStr.toLowerCase() ? [__cloneSubst(subst)] : [];
4066
4079
  }
4067
4080
 
4068
4081
  // string:notGreaterThan (≤ in Unicode code order)
@@ -4070,7 +4083,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4070
4083
  const sStr = termToJsString(g.s);
4071
4084
  const oStr = termToJsString(g.o);
4072
4085
  if (sStr === null || oStr === null) return [];
4073
- return sStr <= oStr ? [{ ...subst }] : [];
4086
+ return sStr <= oStr ? [__cloneSubst(subst)] : [];
4074
4087
  }
4075
4088
 
4076
4089
  // string:notLessThan (≥ in Unicode code order)
@@ -4078,7 +4091,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4078
4091
  const sStr = termToJsString(g.s);
4079
4092
  const oStr = termToJsString(g.o);
4080
4093
  if (sStr === null || oStr === null) return [];
4081
- return sStr >= oStr ? [{ ...subst }] : [];
4094
+ return sStr >= oStr ? [__cloneSubst(subst)] : [];
4082
4095
  }
4083
4096
 
4084
4097
  // string:notMatches
@@ -4088,7 +4101,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4088
4101
  if (sStr === null || pattern === null) return [];
4089
4102
  const re = compileSwapRegex(pattern, '');
4090
4103
  if (!re) return [];
4091
- return re.test(sStr) ? [] : [{ ...subst }];
4104
+ return re.test(sStr) ? [] : [__cloneSubst(subst)];
4092
4105
  }
4093
4106
 
4094
4107
  // string:replace
@@ -4106,7 +4119,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4106
4119
  const lit = makeStringLiteral(outStr);
4107
4120
 
4108
4121
  if (g.o instanceof Var) {
4109
- const s2 = { ...subst };
4122
+ const s2 = __cloneSubst(subst);
4110
4123
  s2[g.o.name] = lit;
4111
4124
  return [s2];
4112
4125
  }
@@ -4131,7 +4144,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4131
4144
  const lit = makeStringLiteral(group);
4132
4145
 
4133
4146
  if (g.o instanceof Var) {
4134
- const s2 = { ...subst };
4147
+ const s2 = __cloneSubst(subst);
4135
4148
  s2[g.o.name] = lit;
4136
4149
  return [s2];
4137
4150
  }
@@ -4144,7 +4157,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4144
4157
  const sStr = termToJsString(g.s);
4145
4158
  const oStr = termToJsString(g.o);
4146
4159
  if (sStr === null || oStr === null) return [];
4147
- return sStr.startsWith(oStr) ? [{ ...subst }] : [];
4160
+ return sStr.startsWith(oStr) ? [__cloneSubst(subst)] : [];
4148
4161
  }
4149
4162
 
4150
4163
  // -----------------------------------------------------------------
@@ -4159,7 +4172,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4159
4172
  if (sStr === null) return [];
4160
4173
  const lit = internLiteral(String(sStr.length));
4161
4174
  if (g.o instanceof Var) {
4162
- const s2 = { ...subst };
4175
+ const s2 = __cloneSubst(subst);
4163
4176
  s2[g.o.name] = lit;
4164
4177
  return [s2];
4165
4178
  }
@@ -4179,7 +4192,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4179
4192
  const ch = idx < 0 || idx >= sStr.length ? '' : sStr.charAt(idx);
4180
4193
  const lit = makeStringLiteral(ch);
4181
4194
  if (g.o instanceof Var) {
4182
- const s2 = { ...subst };
4195
+ const s2 = __cloneSubst(subst);
4183
4196
  s2[g.o.name] = lit;
4184
4197
  return [s2];
4185
4198
  }
@@ -4202,7 +4215,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
4202
4215
  if (idx >= 0 && idx < sStr.length) out = sStr.slice(0, idx) + rep + sStr.slice(idx + 1);
4203
4216
  const lit = makeStringLiteral(out);
4204
4217
  if (g.o instanceof Var) {
4205
- const s2 = { ...subst };
4218
+ const s2 = __cloneSubst(subst);
4206
4219
  s2[g.o.name] = lit;
4207
4220
  return [s2];
4208
4221
  }