eyeling 1.26.2 → 1.26.4

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/engine.js CHANGED
@@ -40,6 +40,27 @@ const INFERENCE_FUSE_EXIT_CODE = 65;
40
40
  const RDF_NIL_IRI = RDF_NS + 'nil';
41
41
  const EMPTY_LIST_TERM = new ListTerm([]);
42
42
 
43
+ const LOG_COLLECT_ALL_IN_IRI = LOG_NS + 'collectAllIn';
44
+ const LOG_FOR_ALL_IN_IRI = LOG_NS + 'forAllIn';
45
+ const LOG_INCLUDES_IRI = LOG_NS + 'includes';
46
+ const LOG_NOT_INCLUDES_IRI = LOG_NS + 'notIncludes';
47
+ const LOG_IMPLIES_IRI = LOG_NS + 'implies';
48
+ const LOG_IMPLIED_BY_IRI = LOG_NS + 'impliedBy';
49
+
50
+ const MATH_BUILTINS_SATISFIABLE_WHEN_FULLY_UNBOUND = new Set([
51
+ MATH_NS + 'sin',
52
+ MATH_NS + 'cos',
53
+ MATH_NS + 'tan',
54
+ MATH_NS + 'asin',
55
+ MATH_NS + 'acos',
56
+ MATH_NS + 'atan',
57
+ MATH_NS + 'sinh',
58
+ MATH_NS + 'cosh',
59
+ MATH_NS + 'tanh',
60
+ MATH_NS + 'degrees',
61
+ MATH_NS + 'negation',
62
+ ]);
63
+
43
64
  const { lex, N3SyntaxError } = require('./lexer');
44
65
  const { Parser } = require('./parser');
45
66
  const { liftBlankRuleVars } = require('./rules');
@@ -100,6 +121,29 @@ function __cloneSubst(subst) {
100
121
  return out;
101
122
  }
102
123
 
124
+ function __defineHidden(obj, name, value, writable) {
125
+ Object.defineProperty(obj, name, { value, enumerable: false, writable, configurable: true });
126
+ }
127
+
128
+ function __defineHiddenValue(obj, name, value) {
129
+ __defineHidden(obj, name, value, false);
130
+ }
131
+
132
+ function __defineHiddenWritable(obj, name, value) {
133
+ __defineHidden(obj, name, value, true);
134
+ }
135
+
136
+ function __setHiddenWritable(obj, name, value) {
137
+ if (hasOwn.call(obj, name)) obj[name] = value;
138
+ else __defineHiddenWritable(obj, name, value);
139
+ }
140
+
141
+ const FACT_INDEX_ARRAY_FIELDS = ['__varPred', '__varPredNonFastS', '__varPredNonFastO'];
142
+ const FACT_INDEX_ARRAY_MAP_FIELDS = ['__byPred', '__byPNonFastS', '__byPNonFastO', '__varPredPS', '__varPredPO'];
143
+ const FACT_INDEX_NESTED_ARRAY_MAP_FIELDS = ['__byPS', '__byPO'];
144
+ const FACT_INDEX_MAP_FIELDS = FACT_INDEX_ARRAY_MAP_FIELDS.concat(FACT_INDEX_NESTED_ARRAY_MAP_FIELDS);
145
+ const FACT_INDEX_REQUIRED_FIELDS = FACT_INDEX_ARRAY_FIELDS.concat(FACT_INDEX_MAP_FIELDS, ['__keySet']);
146
+
103
147
  let version = 'dev';
104
148
  try {
105
149
  // Node: keep package.json version if available
@@ -323,14 +367,13 @@ function __firingKey(ruleIndex, instantiatedPremises) {
323
367
  // -----------------------------------------------------------------------------
324
368
  function __ensureRuleKeySet(rules) {
325
369
  if (!hasOwn.call(rules, '__ruleKeySet')) {
326
- Object.defineProperty(rules, '__ruleKeySet', {
327
- value: new Set(
370
+ __defineHiddenValue(
371
+ rules,
372
+ '__ruleKeySet',
373
+ new Set(
328
374
  rules.map((r) => __ruleKey(r.isForward, r.isFuse, r.premise, r.conclusion, r.__dynamicConclusionTerm || null)),
329
375
  ),
330
- enumerable: false,
331
- writable: false,
332
- configurable: true,
333
- });
376
+ );
334
377
  }
335
378
  return rules.__ruleKeySet;
336
379
  }
@@ -348,28 +391,13 @@ function __computeHeadIsStrictGround(r) {
348
391
  function __prepareForwardRule(r) {
349
392
  if (!hasOwn.call(r, '__scopedSkipInfo')) {
350
393
  const info = __computeForwardRuleScopedSkipInfo(r);
351
- Object.defineProperty(r, '__scopedSkipInfo', {
352
- value: info,
353
- enumerable: false,
354
- writable: false,
355
- configurable: true,
356
- });
394
+ __defineHiddenValue(r, '__scopedSkipInfo', info);
357
395
  }
358
396
  if (!hasOwn.call(r, '__headIsStrictGround')) {
359
- Object.defineProperty(r, '__headIsStrictGround', {
360
- value: __computeHeadIsStrictGround(r),
361
- enumerable: false,
362
- writable: false,
363
- configurable: true,
364
- });
397
+ __defineHiddenValue(r, '__headIsStrictGround', __computeHeadIsStrictGround(r));
365
398
  }
366
399
  if (!hasOwn.call(r, '__needsForwardSkipCheck')) {
367
- Object.defineProperty(r, '__needsForwardSkipCheck', {
368
- value: !!(r.__headIsStrictGround || (r.__scopedSkipInfo && r.__scopedSkipInfo.needsSnap)),
369
- enumerable: false,
370
- writable: false,
371
- configurable: true,
372
- });
400
+ __defineHiddenValue(r, '__needsForwardSkipCheck', !!(r.__headIsStrictGround || (r.__scopedSkipInfo && r.__scopedSkipInfo.needsSnap)));
373
401
  }
374
402
  }
375
403
 
@@ -411,44 +439,29 @@ function __logNaturalPriorityFromTerm(t) {
411
439
  function __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules) {
412
440
  let maxP = 0;
413
441
 
442
+ function bumpMaxPriority(term) {
443
+ if (term instanceof GraphTerm) return;
444
+ if (term instanceof Var) {
445
+ if (maxP < 1) maxP = 1;
446
+ return;
447
+ }
448
+ const p0 = __logNaturalPriorityFromTerm(term);
449
+ const priority = p0 !== null ? p0 : 1;
450
+ if (priority > maxP) maxP = priority;
451
+ }
452
+
414
453
  function scanTriple(tr) {
415
454
  if (!(tr && tr.p instanceof Iri)) return;
416
455
  const pv = tr.p.value;
417
456
 
418
457
  // log:collectAllIn / log:forAllIn use the object position for the priority.
419
- if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
420
- // Explicit scope graphs are immediate and do not require a closure.
421
- if (tr.o instanceof GraphTerm) return;
422
- // Variable or non-numeric object => default priority 1 (if used).
423
- if (tr.o instanceof Var) {
424
- if (maxP < 1) maxP = 1;
425
- return;
426
- }
427
- const p0 = __logNaturalPriorityFromTerm(tr.o);
428
- if (p0 !== null) {
429
- if (p0 > maxP) maxP = p0;
430
- } else {
431
- if (maxP < 1) maxP = 1;
432
- }
458
+ if (pv === LOG_COLLECT_ALL_IN_IRI || pv === LOG_FOR_ALL_IN_IRI) {
459
+ bumpMaxPriority(tr.o);
433
460
  return;
434
461
  }
435
462
 
436
463
  // log:includes / log:notIncludes use the subject position for the priority.
437
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
438
- // Explicit scope graphs are immediate and do not require a closure.
439
- if (tr.s instanceof GraphTerm) return;
440
- // Variable or non-numeric subject => default priority 1 (if used).
441
- if (tr.s instanceof Var) {
442
- if (maxP < 1) maxP = 1;
443
- return;
444
- }
445
- const p0 = __logNaturalPriorityFromTerm(tr.s);
446
- if (p0 !== null) {
447
- if (p0 > maxP) maxP = p0;
448
- } else {
449
- if (maxP < 1) maxP = 1;
450
- }
451
- }
464
+ if (pv === LOG_INCLUDES_IRI || pv === LOG_NOT_INCLUDES_IRI) bumpMaxPriority(tr.s);
452
465
  }
453
466
 
454
467
  for (const r of forwardRules) {
@@ -460,17 +473,6 @@ function __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules) {
460
473
  return maxP;
461
474
  }
462
475
 
463
- function __termContainsVarName(t, name) {
464
- if (t instanceof Var) return t.name === name;
465
- if (t instanceof ListTerm) return t.elems.some((e) => __termContainsVarName(e, name));
466
- if (t instanceof OpenListTerm) return t.tailVar === name || t.prefix.some((e) => __termContainsVarName(e, name));
467
- if (t instanceof GraphTerm)
468
- return t.triples.some(
469
- (tr) =>
470
- __termContainsVarName(tr.s, name) || __termContainsVarName(tr.p, name) || __termContainsVarName(tr.o, name),
471
- );
472
- return false;
473
- }
474
476
 
475
477
  function __varOccursElsewhereInPremise(premise, name, idx, field) {
476
478
  for (let i = 0; i < premise.length; i++) {
@@ -478,14 +480,13 @@ function __varOccursElsewhereInPremise(premise, name, idx, field) {
478
480
  if (!(tr && tr.s && tr.p && tr.o)) continue;
479
481
 
480
482
  // Skip the specific scope/priority occurrence we are analyzing.
481
- if (!(i === idx && field === 's') && __termContainsVarName(tr.s, name)) return true;
482
- if (!(i === idx && field === 'p') && __termContainsVarName(tr.p, name)) return true;
483
- if (!(i === idx && field === 'o') && __termContainsVarName(tr.o, name)) return true;
483
+ if (!(i === idx && field === 's') && containsVarTerm(tr.s, name)) return true;
484
+ if (!(i === idx && field === 'p') && containsVarTerm(tr.p, name)) return true;
485
+ if (!(i === idx && field === 'o') && containsVarTerm(tr.o, name)) return true;
484
486
  }
485
487
  return false;
486
488
  }
487
489
 
488
-
489
490
  function __scopedPriorityForTerm(t) {
490
491
  if (t instanceof GraphTerm) return 0;
491
492
  const p0 = __logNaturalPriorityFromTerm(t);
@@ -512,7 +513,7 @@ function __analyzeForwardRuleScopedUse(rule) {
512
513
  if (!(tr && tr.p instanceof Iri)) continue;
513
514
  const pv = tr.p.value;
514
515
 
515
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
516
+ if (pv === LOG_INCLUDES_IRI || pv === LOG_NOT_INCLUDES_IRI) {
516
517
  // Explicit quoted scopes are local formulas, not snapshots of the global closure.
517
518
  if (tr.s instanceof GraphTerm) continue;
518
519
 
@@ -526,7 +527,7 @@ function __analyzeForwardRuleScopedUse(rule) {
526
527
  continue;
527
528
  }
528
529
 
529
- if (pv === LOG_NS + 'collectAllIn') {
530
+ if (pv === LOG_COLLECT_ALL_IN_IRI) {
530
531
  if (tr.o instanceof GraphTerm) continue;
531
532
 
532
533
  out.needsSnap = true;
@@ -538,7 +539,7 @@ function __analyzeForwardRuleScopedUse(rule) {
538
539
  continue;
539
540
  }
540
541
 
541
- if (pv === LOG_NS + 'forAllIn') {
542
+ if (pv === LOG_FOR_ALL_IN_IRI) {
542
543
  if (tr.o instanceof GraphTerm) continue;
543
544
 
544
545
  out.needsSnap = true;
@@ -580,16 +581,7 @@ function __setForwardRuleScopedStratumInfo(rule, level) {
580
581
  ? { needsSnap: true, requiredLevel: level, exactLevel: true }
581
582
  : { needsSnap: false, requiredLevel: 0, exactLevel: false };
582
583
 
583
- if (!hasOwn.call(rule, '__scopedStratumInfo')) {
584
- Object.defineProperty(rule, '__scopedStratumInfo', {
585
- value,
586
- enumerable: false,
587
- writable: true,
588
- configurable: true,
589
- });
590
- } else {
591
- rule.__scopedStratumInfo = value;
592
- }
584
+ __setHiddenWritable(rule, '__scopedStratumInfo', value);
593
585
  }
594
586
 
595
587
  function __computeForwardRuleScopedStrata(forwardRules) {
@@ -627,7 +619,6 @@ function __computeForwardRuleScopedStrata(forwardRules) {
627
619
  if (!changed) break;
628
620
  }
629
621
 
630
-
631
622
  maxLevel = 0;
632
623
  for (let i = 0; i < forwardRules.length; i++) {
633
624
  __setForwardRuleScopedStratumInfo(forwardRules[i], levels[i]);
@@ -641,42 +632,33 @@ function __computeForwardRuleScopedSkipInfo(rule) {
641
632
  let needsSnap = false;
642
633
  let requiredLevel = 0;
643
634
 
635
+ function addScopedUse(scopeTerm, idx, field) {
636
+ if (scopeTerm instanceof GraphTerm) return true; // explicit scope
637
+
638
+ // If scope term is a Var that appears elsewhere, it might be bound to a GraphTerm.
639
+ // Be conservative and do not skip in that case.
640
+ if (scopeTerm instanceof Var) {
641
+ if (__varOccursElsewhereInPremise(rule.premise, scopeTerm.name, idx, field)) return false;
642
+ needsSnap = true;
643
+ requiredLevel = Math.max(requiredLevel, 1);
644
+ return true;
645
+ }
646
+
647
+ needsSnap = true;
648
+ const p0 = __logNaturalPriorityFromTerm(scopeTerm);
649
+ requiredLevel = Math.max(requiredLevel, p0 !== null ? p0 : 1);
650
+ return true;
651
+ }
652
+
644
653
  for (let i = 0; i < rule.premise.length; i++) {
645
654
  const tr = rule.premise[i];
646
655
  if (!(tr && tr.p instanceof Iri)) continue;
647
656
  const pv = tr.p.value;
648
657
 
649
- if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
650
- if (tr.o instanceof GraphTerm) continue; // explicit scope
651
- // If scope term is a Var that appears elsewhere, it might be bound to a GraphTerm.
652
- // Be conservative and do not skip in that case.
653
- if (tr.o instanceof Var) {
654
- if (__varOccursElsewhereInPremise(rule.premise, tr.o.name, i, 'o')) return null;
655
- needsSnap = true;
656
- requiredLevel = Math.max(requiredLevel, 1);
657
- } else {
658
- needsSnap = true;
659
- let prio = 1;
660
- const p0 = __logNaturalPriorityFromTerm(tr.o);
661
- if (p0 !== null) prio = p0;
662
- requiredLevel = Math.max(requiredLevel, prio);
663
- }
664
- continue;
665
- }
666
-
667
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
668
- if (tr.s instanceof GraphTerm) continue; // explicit scope
669
- if (tr.s instanceof Var) {
670
- if (__varOccursElsewhereInPremise(rule.premise, tr.s.name, i, 's')) return null;
671
- needsSnap = true;
672
- requiredLevel = Math.max(requiredLevel, 1);
673
- } else {
674
- needsSnap = true;
675
- let prio = 1;
676
- const p0 = __logNaturalPriorityFromTerm(tr.s);
677
- if (p0 !== null) prio = p0;
678
- requiredLevel = Math.max(requiredLevel, prio);
679
- }
658
+ if (pv === LOG_COLLECT_ALL_IN_IRI || pv === LOG_FOR_ALL_IN_IRI) {
659
+ if (!addScopedUse(tr.o, i, 'o')) return null;
660
+ } else if (pv === LOG_INCLUDES_IRI || pv === LOG_NOT_INCLUDES_IRI) {
661
+ if (!addScopedUse(tr.s, i, 's')) return null;
680
662
  }
681
663
  }
682
664
 
@@ -859,140 +841,70 @@ function skolemizeTripleForHeadBlanks(tr, headBlankLabels, mapping, skCounter, f
859
841
  // Alpha equivalence helpers
860
842
  // ===========================================================================
861
843
 
862
- function termsEqual(a, b) {
863
- if (a === b) return true;
864
- if (!a || !b) return false;
865
- if (a.__tid && b.__tid && a.__tid === b.__tid) return true;
866
-
867
- // rdf:nil is equivalent to the empty list ()
868
- if (a instanceof Iri && a.value === RDF_NIL_IRI && b instanceof ListTerm && b.elems.length === 0) return true;
869
- if (b instanceof Iri && b.value === RDF_NIL_IRI && a instanceof ListTerm && a.elems.length === 0) return true;
870
- if (a.constructor !== b.constructor) return false;
871
-
872
- if (a instanceof Iri) return a.value === b.value;
873
-
874
- if (a instanceof Literal) {
875
- if (a.value === b.value) return true;
876
-
877
- // Plain "abc" == "abc"^^xsd:string (but not language-tagged strings)
878
- if (literalsEquivalentAsXsdString(a.value, b.value)) return true;
879
-
880
- // Keep in sync with unifyTerm(): numeric-value equality, datatype-aware.
881
- const ai = parseNumericLiteralInfo(a);
882
- const bi = parseNumericLiteralInfo(b);
844
+ function __isRdfNilEmptyListPair(a, b) {
845
+ return a instanceof Iri && a.value === RDF_NIL_IRI && b instanceof ListTerm && b.elems.length === 0;
846
+ }
883
847
 
884
- if (ai && bi) {
885
- // Same datatype => compare values
886
- if (ai.dt === bi.dt) {
887
- if (ai.kind === 'bigint' && bi.kind === 'bigint') return ai.value === bi.value;
848
+ function __numericInfosSameDatatypeEqual(ai, bi, exactDecimal) {
849
+ if (!ai || !bi || ai.dt !== bi.dt) return false;
850
+ if (ai.kind === 'bigint' && bi.kind === 'bigint') return ai.value === bi.value;
888
851
 
889
- const an = ai.kind === 'bigint' ? Number(ai.value) : ai.value;
890
- const bn = bi.kind === 'bigint' ? Number(bi.value) : bi.value;
891
- return !Number.isNaN(an) && !Number.isNaN(bn) && an === bn;
892
- }
852
+ if (exactDecimal && ai.dt === XSD_NS + 'decimal') {
853
+ const da = parseXsdDecimalToBigIntScale(ai.lexStr);
854
+ const db = parseXsdDecimalToBigIntScale(bi.lexStr);
855
+ if (da && db) {
856
+ const scale = Math.max(da.scale, db.scale);
857
+ return da.num * pow10n(scale - da.scale) === db.num * pow10n(scale - db.scale);
893
858
  }
894
-
895
- return false;
896
859
  }
897
860
 
898
- if (a instanceof Var) return a.name === b.name;
899
- if (a instanceof Blank) return a.label === b.label;
900
-
901
- if (a instanceof ListTerm) {
902
- if (a.elems.length !== b.elems.length) return false;
903
- for (let i = 0; i < a.elems.length; i++) {
904
- if (!termsEqual(a.elems[i], b.elems[i])) return false;
905
- }
906
- return true;
907
- }
861
+ const an = ai.kind === 'bigint' ? Number(ai.value) : ai.value;
862
+ const bn = bi.kind === 'bigint' ? Number(bi.value) : bi.value;
863
+ return !Number.isNaN(an) && !Number.isNaN(bn) && an === bn;
864
+ }
908
865
 
909
- if (a instanceof OpenListTerm) {
910
- if (a.tailVar !== b.tailVar) return false;
911
- if (a.prefix.length !== b.prefix.length) return false;
912
- for (let i = 0; i < a.prefix.length; i++) {
913
- if (!termsEqual(a.prefix[i], b.prefix[i])) return false;
914
- }
915
- return true;
916
- }
866
+ function __literalsEqual(a, b, exactDecimal) {
867
+ if (a.value === b.value) return true;
868
+ if (literalsEquivalentAsXsdString(a.value, b.value)) return true;
869
+ return __numericInfosSameDatatypeEqual(parseNumericLiteralInfo(a), parseNumericLiteralInfo(b), exactDecimal);
870
+ }
917
871
 
918
- if (a instanceof GraphTerm) {
919
- return alphaEqGraphTriples(a.triples, b.triples);
872
+ function __termArraysEqual(xs, ys, eq) {
873
+ if (xs.length !== ys.length) return false;
874
+ for (let i = 0; i < xs.length; i++) {
875
+ if (!eq(xs[i], ys[i])) return false;
920
876
  }
921
-
922
- return false;
877
+ return true;
923
878
  }
924
879
 
925
- function termsEqualNoIntDecimal(a, b) {
880
+ function __termsEqual(a, b, exactDecimal) {
926
881
  if (a === b) return true;
927
882
  if (!a || !b) return false;
928
883
  if (a.__tid && b.__tid && a.__tid === b.__tid) return true;
929
884
 
930
885
  // rdf:nil is equivalent to the empty list ()
931
- if (a instanceof Iri && a.value === RDF_NIL_IRI && b instanceof ListTerm && b.elems.length === 0) return true;
932
- if (b instanceof Iri && b.value === RDF_NIL_IRI && a instanceof ListTerm && a.elems.length === 0) return true;
886
+ if (__isRdfNilEmptyListPair(a, b) || __isRdfNilEmptyListPair(b, a)) return true;
933
887
  if (a.constructor !== b.constructor) return false;
934
888
 
935
889
  if (a instanceof Iri) return a.value === b.value;
936
-
937
- if (a instanceof Literal) {
938
- if (a.value === b.value) return true;
939
-
940
- // Plain "abc" == "abc"^^xsd:string (but not language-tagged)
941
- if (literalsEquivalentAsXsdString(a.value, b.value)) return true;
942
-
943
- // Numeric equality ONLY when datatypes agree (no integer<->decimal here)
944
- const ai = parseNumericLiteralInfo(a);
945
- const bi = parseNumericLiteralInfo(b);
946
- if (ai && bi && ai.dt === bi.dt) {
947
- // integer: exact bigint
948
- if (ai.kind === 'bigint' && bi.kind === 'bigint') return ai.value === bi.value;
949
-
950
- // decimal: compare exactly via num/scale if possible
951
- if (ai.dt === XSD_NS + 'decimal') {
952
- const da = parseXsdDecimalToBigIntScale(ai.lexStr);
953
- const db = parseXsdDecimalToBigIntScale(bi.lexStr);
954
- if (da && db) {
955
- const scale = Math.max(da.scale, db.scale);
956
- const na = da.num * pow10n(scale - da.scale);
957
- const nb = db.num * pow10n(scale - db.scale);
958
- return na === nb;
959
- }
960
- }
961
-
962
- // double/float-ish: JS number (same as your normal same-dt path)
963
- const an = ai.kind === 'bigint' ? Number(ai.value) : ai.value;
964
- const bn = bi.kind === 'bigint' ? Number(bi.value) : bi.value;
965
- return !Number.isNaN(an) && !Number.isNaN(bn) && an === bn;
966
- }
967
-
968
- return false;
969
- }
970
-
890
+ if (a instanceof Literal) return __literalsEqual(a, b, exactDecimal);
971
891
  if (a instanceof Var) return a.name === b.name;
972
892
  if (a instanceof Blank) return a.label === b.label;
893
+ if (a instanceof ListTerm) return __termArraysEqual(a.elems, b.elems, (x, y) => __termsEqual(x, y, exactDecimal));
894
+ if (a instanceof OpenListTerm)
895
+ return a.tailVar === b.tailVar && __termArraysEqual(a.prefix, b.prefix, (x, y) => __termsEqual(x, y, exactDecimal));
896
+ if (a instanceof GraphTerm) return alphaEqGraphTriples(a.triples, b.triples);
897
+ return false;
898
+ }
973
899
 
974
- if (a instanceof ListTerm) {
975
- if (a.elems.length !== b.elems.length) return false;
976
- for (let i = 0; i < a.elems.length; i++) {
977
- if (!termsEqualNoIntDecimal(a.elems[i], b.elems[i])) return false;
978
- }
979
- return true;
980
- }
981
-
982
- if (a instanceof OpenListTerm) {
983
- if (a.tailVar !== b.tailVar) return false;
984
- if (a.prefix.length !== b.prefix.length) return false;
985
- for (let i = 0; i < a.prefix.length; i++) {
986
- if (!termsEqualNoIntDecimal(a.prefix[i], b.prefix[i])) return false;
987
- }
988
- return true;
989
- }
990
-
991
- if (a instanceof GraphTerm) {
992
- return alphaEqGraphTriples(a.triples, b.triples);
993
- }
900
+ function termsEqual(a, b) {
901
+ // Keep in sync with unifyTerm(): numeric-value equality, datatype-aware.
902
+ return __termsEqual(a, b, false);
903
+ }
994
904
 
995
- return false;
905
+ function termsEqualNoIntDecimal(a, b) {
906
+ // Numeric equality ONLY when datatypes agree; decimals are compared exactly.
907
+ return __termsEqual(a, b, true);
996
908
  }
997
909
 
998
910
  function triplesEqual(a, b) {
@@ -1337,81 +1249,12 @@ function tripleFastKey(tr) {
1337
1249
  }
1338
1250
 
1339
1251
  function ensureFactIndexes(facts) {
1340
- if (
1341
- facts.__byPred &&
1342
- facts.__byPS &&
1343
- facts.__byPO &&
1344
- facts.__byPNonFastS &&
1345
- facts.__byPNonFastO &&
1346
- facts.__varPred &&
1347
- facts.__varPredPS &&
1348
- facts.__varPredPO &&
1349
- facts.__varPredNonFastS &&
1350
- facts.__varPredNonFastO &&
1351
- facts.__keySet
1352
- )
1353
- return;
1252
+ if (FACT_INDEX_REQUIRED_FIELDS.every((name) => facts[name])) return;
1354
1253
 
1355
- Object.defineProperty(facts, '__byPred', {
1356
- value: new Map(),
1357
- enumerable: false,
1358
- writable: true,
1359
- });
1360
- Object.defineProperty(facts, '__byPS', {
1361
- value: new Map(),
1362
- enumerable: false,
1363
- writable: true,
1364
- });
1365
- Object.defineProperty(facts, '__byPO', {
1366
- value: new Map(),
1367
- enumerable: false,
1368
- writable: true,
1369
- });
1370
- Object.defineProperty(facts, '__byPNonFastS', {
1371
- value: new Map(),
1372
- enumerable: false,
1373
- writable: true,
1374
- });
1375
- Object.defineProperty(facts, '__byPNonFastO', {
1376
- value: new Map(),
1377
- enumerable: false,
1378
- writable: true,
1379
- });
1380
- Object.defineProperty(facts, '__varPred', {
1381
- value: [],
1382
- enumerable: false,
1383
- writable: true,
1384
- });
1385
- Object.defineProperty(facts, '__varPredPS', {
1386
- value: new Map(),
1387
- enumerable: false,
1388
- writable: true,
1389
- });
1390
- Object.defineProperty(facts, '__varPredPO', {
1391
- value: new Map(),
1392
- enumerable: false,
1393
- writable: true,
1394
- });
1395
- Object.defineProperty(facts, '__varPredNonFastS', {
1396
- value: [],
1397
- enumerable: false,
1398
- writable: true,
1399
- });
1400
- Object.defineProperty(facts, '__varPredNonFastO', {
1401
- value: [],
1402
- enumerable: false,
1403
- writable: true,
1404
- });
1405
- Object.defineProperty(facts, '__keySet', {
1406
- value: new Set(),
1407
- enumerable: false,
1408
- writable: true,
1409
- });
1410
- Object.defineProperty(facts, '__keySetComplete', {
1411
- value: false,
1412
- enumerable: false,
1413
- writable: true,
1414
- });
1254
+ for (const name of FACT_INDEX_MAP_FIELDS) __defineHiddenWritable(facts, name, new Map());
1255
+ for (const name of FACT_INDEX_ARRAY_FIELDS) __defineHiddenWritable(facts, name, []);
1256
+ __defineHiddenWritable(facts, '__keySet', new Set());
1257
+ __defineHiddenWritable(facts, '__keySetComplete', false);
1415
1258
 
1416
1259
  // Build lookup indexes eagerly, but do not populate the duplicate-detection
1417
1260
  // string Set for every input fact. The predicate/subject/object indexes are
@@ -1439,45 +1282,14 @@ function cloneFactIndexesForSnapshot(src, dest) {
1439
1282
  return out;
1440
1283
  }
1441
1284
 
1442
- Object.defineProperty(dest, '__byPred', { value: cloneArrayMap(src.__byPred), enumerable: false, writable: true });
1443
- Object.defineProperty(dest, '__byPS', { value: cloneNestedArrayMap(src.__byPS), enumerable: false, writable: true });
1444
- Object.defineProperty(dest, '__byPO', { value: cloneNestedArrayMap(src.__byPO), enumerable: false, writable: true });
1445
- Object.defineProperty(dest, '__byPNonFastS', {
1446
- value: cloneArrayMap(src.__byPNonFastS),
1447
- enumerable: false,
1448
- writable: true,
1449
- });
1450
- Object.defineProperty(dest, '__byPNonFastO', {
1451
- value: cloneArrayMap(src.__byPNonFastO),
1452
- enumerable: false,
1453
- writable: true,
1454
- });
1455
- Object.defineProperty(dest, '__varPred', { value: src.__varPred.slice(), enumerable: false, writable: true });
1456
- Object.defineProperty(dest, '__varPredPS', {
1457
- value: cloneArrayMap(src.__varPredPS),
1458
- enumerable: false,
1459
- writable: true,
1460
- });
1461
- Object.defineProperty(dest, '__varPredPO', {
1462
- value: cloneArrayMap(src.__varPredPO),
1463
- enumerable: false,
1464
- writable: true,
1465
- });
1466
- Object.defineProperty(dest, '__varPredNonFastS', {
1467
- value: src.__varPredNonFastS.slice(),
1468
- enumerable: false,
1469
- writable: true,
1470
- });
1471
- Object.defineProperty(dest, '__varPredNonFastO', {
1472
- value: src.__varPredNonFastO.slice(),
1473
- enumerable: false,
1474
- writable: true,
1475
- });
1476
- Object.defineProperty(dest, '__keySet', { value: new Set(src.__keySet), enumerable: false, writable: true });
1477
- Object.defineProperty(dest, '__keySetComplete', { value: !!src.__keySetComplete, enumerable: false, writable: true });
1285
+ for (const name of FACT_INDEX_ARRAY_MAP_FIELDS) __defineHiddenWritable(dest, name, cloneArrayMap(src[name]));
1286
+ for (const name of FACT_INDEX_NESTED_ARRAY_MAP_FIELDS) __defineHiddenWritable(dest, name, cloneNestedArrayMap(src[name]));
1287
+ for (const name of FACT_INDEX_ARRAY_FIELDS) __defineHiddenWritable(dest, name, src[name].slice());
1288
+ __defineHiddenWritable(dest, '__keySet', new Set(src.__keySet));
1289
+ __defineHiddenWritable(dest, '__keySetComplete', !!src.__keySetComplete);
1478
1290
  }
1479
1291
 
1480
- function addToIndexArrayMap(map, key, value) {
1292
+ function pushMapArray(map, key, value) {
1481
1293
  let bucket = map.get(key);
1482
1294
  if (!bucket) {
1483
1295
  bucket = [];
@@ -1486,6 +1298,15 @@ function addToIndexArrayMap(map, key, value) {
1486
1298
  bucket.push(value);
1487
1299
  }
1488
1300
 
1301
+ function getOrCreateMap(map, key) {
1302
+ let inner = map.get(key);
1303
+ if (!inner) {
1304
+ inner = new Map();
1305
+ map.set(key, inner);
1306
+ }
1307
+ return inner;
1308
+ }
1309
+
1489
1310
  function indexFact(facts, tr, idx, addKeySet = true) {
1490
1311
  const sk = termLookupKey(tr.s);
1491
1312
  const ok = termLookupKey(tr.o);
@@ -1496,45 +1317,30 @@ function indexFact(facts, tr, idx, addKeySet = true) {
1496
1317
  const pk = tr.p.__tid;
1497
1318
  pkForKey = pk;
1498
1319
 
1499
- let pb = facts.__byPred.get(pk);
1500
- if (!pb) {
1501
- pb = [];
1502
- facts.__byPred.set(pk, pb);
1503
- }
1504
- pb.push(idx);
1320
+ pushMapArray(facts.__byPred, pk, idx);
1505
1321
 
1506
1322
  if (sk !== null) {
1507
- let ps = facts.__byPS.get(pk);
1508
- if (!ps) {
1509
- ps = new Map();
1510
- facts.__byPS.set(pk, ps);
1511
- }
1512
- addToIndexArrayMap(ps, sk, idx);
1323
+ pushMapArray(getOrCreateMap(facts.__byPS, pk), sk, idx);
1513
1324
  } else {
1514
- addToIndexArrayMap(facts.__byPNonFastS, pk, idx);
1325
+ pushMapArray(facts.__byPNonFastS, pk, idx);
1515
1326
  }
1516
1327
 
1517
1328
  if (ok !== null) {
1518
- let po = facts.__byPO.get(pk);
1519
- if (!po) {
1520
- po = new Map();
1521
- facts.__byPO.set(pk, po);
1522
- }
1523
- addToIndexArrayMap(po, ok, idx);
1329
+ pushMapArray(getOrCreateMap(facts.__byPO, pk), ok, idx);
1524
1330
  } else {
1525
- addToIndexArrayMap(facts.__byPNonFastO, pk, idx);
1331
+ pushMapArray(facts.__byPNonFastO, pk, idx);
1526
1332
  }
1527
1333
  } else if (tr.p instanceof Var) {
1528
1334
  facts.__varPred.push(idx);
1529
1335
 
1530
1336
  if (sk !== null) {
1531
- addToIndexArrayMap(facts.__varPredPS, sk, idx);
1337
+ pushMapArray(facts.__varPredPS, sk, idx);
1532
1338
  } else {
1533
1339
  facts.__varPredNonFastS.push(idx);
1534
1340
  }
1535
1341
 
1536
1342
  if (ok !== null) {
1537
- addToIndexArrayMap(facts.__varPredPO, ok, idx);
1343
+ pushMapArray(facts.__varPredPO, ok, idx);
1538
1344
  } else {
1539
1345
  facts.__varPredNonFastO.push(idx);
1540
1346
  }
@@ -1688,16 +1494,8 @@ function makeDerivedRecord(fact, rule, premises, subst, captureExplanations) {
1688
1494
  function ensureBackRuleIndexes(backRules) {
1689
1495
  if (backRules.__byHeadPred && backRules.__wildHeadPred) return;
1690
1496
 
1691
- Object.defineProperty(backRules, '__byHeadPred', {
1692
- value: new Map(),
1693
- enumerable: false,
1694
- writable: true,
1695
- });
1696
- Object.defineProperty(backRules, '__wildHeadPred', {
1697
- value: [],
1698
- enumerable: false,
1699
- writable: true,
1700
- });
1497
+ __defineHiddenWritable(backRules, '__byHeadPred', new Map());
1498
+ __defineHiddenWritable(backRules, '__wildHeadPred', []);
1701
1499
 
1702
1500
  for (const r of backRules) indexBackRule(backRules, r);
1703
1501
  }
@@ -1706,13 +1504,7 @@ function indexBackRule(backRules, r) {
1706
1504
  if (!r || !r.conclusion || r.conclusion.length !== 1) return;
1707
1505
  const head = r.conclusion[0];
1708
1506
  if (head && head.p instanceof Iri) {
1709
- const k = head.p.__tid;
1710
- let bucket = backRules.__byHeadPred.get(k);
1711
- if (!bucket) {
1712
- bucket = [];
1713
- backRules.__byHeadPred.set(k, bucket);
1714
- }
1715
- bucket.push(r);
1507
+ pushMapArray(backRules.__byHeadPred, head.p.__tid, r);
1716
1508
  } else {
1717
1509
  backRules.__wildHeadPred.push(r);
1718
1510
  }
@@ -1747,12 +1539,11 @@ function isSinglePremiseAgendaRuleSafe(r, backRules) {
1747
1539
  return backRules.__wildHeadPred.length === 0;
1748
1540
  }
1749
1541
 
1750
- function mergeSinglePremiseAgendaBuckets() {
1542
+ function mergeSinglePremiseAgendaBuckets(...buckets) {
1751
1543
  let out = null;
1752
1544
  let seen = null;
1753
1545
 
1754
- for (let i = 0; i < arguments.length; i++) {
1755
- const bucket = arguments[i];
1546
+ for (const bucket of buckets) {
1756
1547
  if (!bucket || bucket.length === 0) continue;
1757
1548
 
1758
1549
  if (out === null) {
@@ -1762,8 +1553,7 @@ function mergeSinglePremiseAgendaBuckets() {
1762
1553
  }
1763
1554
 
1764
1555
  if (!seen) seen = new Set(out);
1765
- for (let j = 0; j < bucket.length; j++) {
1766
- const entry = bucket[j];
1556
+ for (const entry of bucket) {
1767
1557
  if (seen.has(entry)) continue;
1768
1558
  seen.add(entry);
1769
1559
  out.push(entry);
@@ -1773,18 +1563,6 @@ function mergeSinglePremiseAgendaBuckets() {
1773
1563
  return out;
1774
1564
  }
1775
1565
 
1776
- function termContainsVarForAgenda(t) {
1777
- if (t instanceof Var) return true;
1778
- if (t instanceof ListTerm) return t.elems.some(termContainsVarForAgenda);
1779
- if (t instanceof OpenListTerm) return true;
1780
- if (t instanceof GraphTerm)
1781
- return t.triples.some(
1782
- (tr) =>
1783
- termContainsVarForAgenda(tr.s) || termContainsVarForAgenda(tr.p) || termContainsVarForAgenda(tr.o),
1784
- );
1785
- return false;
1786
- }
1787
-
1788
1566
  function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
1789
1567
  const index = {
1790
1568
  byPred: new Map(),
@@ -1799,15 +1577,6 @@ function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
1799
1577
  size: 0,
1800
1578
  };
1801
1579
 
1802
- function addToMapArray(m, k, v) {
1803
- let bucket = m.get(k);
1804
- if (!bucket) {
1805
- bucket = [];
1806
- m.set(k, bucket);
1807
- }
1808
- bucket.push(v);
1809
- }
1810
-
1811
1580
  for (let i = 0; i < forwardRules.length; i++) {
1812
1581
  const r = forwardRules[i];
1813
1582
  if (!isSinglePremiseAgendaRuleSafe(r, backRules)) continue;
@@ -1833,29 +1602,15 @@ function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
1833
1602
  index.size += 1;
1834
1603
 
1835
1604
  if (entry.goalPredTid !== null) {
1836
- addToMapArray(index.byPredAll, entry.goalPredTid, entry);
1605
+ pushMapArray(index.byPredAll, entry.goalPredTid, entry);
1837
1606
  index.allIriPred.push(entry);
1838
- if (entry.goalSKey === null && entry.goalOKey === null) addToMapArray(index.byPred, entry.goalPredTid, entry);
1839
- if (entry.goalSKey !== null) {
1840
- let ps = index.byPS.get(entry.goalPredTid);
1841
- if (!ps) {
1842
- ps = new Map();
1843
- index.byPS.set(entry.goalPredTid, ps);
1844
- }
1845
- addToMapArray(ps, entry.goalSKey, entry);
1846
- }
1847
- if (entry.goalOKey !== null) {
1848
- let po = index.byPO.get(entry.goalPredTid);
1849
- if (!po) {
1850
- po = new Map();
1851
- index.byPO.set(entry.goalPredTid, po);
1852
- }
1853
- addToMapArray(po, entry.goalOKey, entry);
1854
- }
1607
+ if (entry.goalSKey === null && entry.goalOKey === null) pushMapArray(index.byPred, entry.goalPredTid, entry);
1608
+ if (entry.goalSKey !== null) pushMapArray(getOrCreateMap(index.byPS, entry.goalPredTid), entry.goalSKey, entry);
1609
+ if (entry.goalOKey !== null) pushMapArray(getOrCreateMap(index.byPO, entry.goalPredTid), entry.goalOKey, entry);
1855
1610
  } else {
1856
1611
  if (entry.goalSKey === null && entry.goalOKey === null) index.wildPred.push(entry);
1857
- if (entry.goalSKey !== null) addToMapArray(index.wildPS, entry.goalSKey, entry);
1858
- if (entry.goalOKey !== null) addToMapArray(index.wildPO, entry.goalOKey, entry);
1612
+ if (entry.goalSKey !== null) pushMapArray(index.wildPS, entry.goalSKey, entry);
1613
+ if (entry.goalOKey !== null) pushMapArray(index.wildPO, entry.goalOKey, entry);
1859
1614
  }
1860
1615
  }
1861
1616
 
@@ -1871,7 +1626,7 @@ function getSinglePremiseAgendaCandidates(index, fact) {
1871
1626
  let exact = null;
1872
1627
  if (fact.p instanceof Iri) {
1873
1628
  const pk = fact.p.__tid;
1874
- if ((sk === null && termContainsVarForAgenda(fact.s)) || (ok === null && termContainsVarForAgenda(fact.o))) {
1629
+ if ((sk === null && containsVarTerm(fact.s)) || (ok === null && containsVarTerm(fact.o))) {
1875
1630
  // A fact with a variable-bearing subject/object (most importantly a
1876
1631
  // top-level variable fact such as `?S :p ?O.`) can match rules whose
1877
1632
  // premise is fixed in that position. The ordinary `(p,s)` / `(p,o)` lookup
@@ -1916,11 +1671,11 @@ function getSinglePremiseAgendaCandidates(index, fact) {
1916
1671
  // ===========================================================================
1917
1672
 
1918
1673
  function isLogImplies(p) {
1919
- return p instanceof Iri && p.value === LOG_NS + 'implies';
1674
+ return p instanceof Iri && p.value === LOG_IMPLIES_IRI;
1920
1675
  }
1921
1676
 
1922
1677
  function isLogImpliedBy(p) {
1923
- return p instanceof Iri && p.value === LOG_NS + 'impliedBy';
1678
+ return p instanceof Iri && p.value === LOG_IMPLIED_BY_IRI;
1924
1679
  }
1925
1680
 
1926
1681
  // ===========================================================================
@@ -1953,16 +1708,7 @@ function __makeGoalTable() {
1953
1708
 
1954
1709
  function __attachGoalTable(scopeCarrier, goalTable) {
1955
1710
  if (!scopeCarrier) return goalTable;
1956
- if (!hasOwn.call(scopeCarrier, 'goalTable')) {
1957
- Object.defineProperty(scopeCarrier, 'goalTable', {
1958
- value: goalTable,
1959
- enumerable: false,
1960
- writable: true,
1961
- configurable: true,
1962
- });
1963
- } else {
1964
- scopeCarrier.goalTable = goalTable;
1965
- }
1711
+ __setHiddenWritable(scopeCarrier, 'goalTable', goalTable);
1966
1712
  return goalTable;
1967
1713
  }
1968
1714
 
@@ -2017,11 +1763,10 @@ function __canStoreGoalMemo(visited, maxResults) {
2017
1763
  // Unification + substitution
2018
1764
  // ===========================================================================
2019
1765
 
2020
- function containsVarTerm(t, v) {
2021
- if (t instanceof Iri || t instanceof Literal || t instanceof Blank) return false;
2022
- if (t instanceof Var) return t.name === v;
1766
+ function containsVarTerm(t, v = null) {
1767
+ if (t instanceof Var) return v === null || t.name === v;
2023
1768
  if (t instanceof ListTerm) return t.elems.some((e) => containsVarTerm(e, v));
2024
- if (t instanceof OpenListTerm) return t.prefix.some((e) => containsVarTerm(e, v)) || t.tailVar === v;
1769
+ if (t instanceof OpenListTerm) return t.prefix.some((e) => containsVarTerm(e, v)) || v === null || t.tailVar === v;
2025
1770
  if (t instanceof GraphTerm)
2026
1771
  return t.triples.some((tr) => containsVarTerm(tr.s, v) || containsVarTerm(tr.p, v) || containsVarTerm(tr.o, v));
2027
1772
  return false;
@@ -2226,16 +1971,8 @@ function unifyOpenWithList(prefix, tailv, ys, subst) {
2226
1971
  }
2227
1972
 
2228
1973
  function graphTriplesContainVars(triples) {
2229
- function termHasVar(t) {
2230
- if (t instanceof Var) return true;
2231
- if (t instanceof ListTerm) return t.elems.some(termHasVar);
2232
- if (t instanceof OpenListTerm) return t.prefix.some(termHasVar) || true;
2233
- if (t instanceof GraphTerm) return t.triples.some((tr) => termHasVar(tr.s) || termHasVar(tr.p) || termHasVar(tr.o));
2234
- return false;
2235
- }
2236
-
2237
1974
  for (const tr of triples) {
2238
- if (termHasVar(tr.s) || termHasVar(tr.p) || termHasVar(tr.o)) return true;
1975
+ if (containsVarTerm(tr.s) || containsVarTerm(tr.p) || containsVarTerm(tr.o)) return true;
2239
1976
  }
2240
1977
  return false;
2241
1978
  }
@@ -2520,19 +2257,7 @@ function __tripleHasVarOrBlank(tr) {
2520
2257
  }
2521
2258
 
2522
2259
  function __builtinIsSatisfiableWhenFullyUnbound(pIriVal) {
2523
- return (
2524
- pIriVal === MATH_NS + 'sin' ||
2525
- pIriVal === MATH_NS + 'cos' ||
2526
- pIriVal === MATH_NS + 'tan' ||
2527
- pIriVal === MATH_NS + 'asin' ||
2528
- pIriVal === MATH_NS + 'acos' ||
2529
- pIriVal === MATH_NS + 'atan' ||
2530
- pIriVal === MATH_NS + 'sinh' ||
2531
- pIriVal === MATH_NS + 'cosh' ||
2532
- pIriVal === MATH_NS + 'tanh' ||
2533
- pIriVal === MATH_NS + 'degrees' ||
2534
- pIriVal === MATH_NS + 'negation'
2535
- );
2260
+ return MATH_BUILTINS_SATISFIABLE_WHEN_FULLY_UNBOUND.has(pIriVal);
2536
2261
  }
2537
2262
 
2538
2263
  function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxResults, opts) {
@@ -3167,12 +2892,7 @@ function __proofTripleKey(tr) {
3167
2892
 
3168
2893
  function __copyProofSource(from, to) {
3169
2894
  if (from && to && Object.prototype.hasOwnProperty.call(from, '__source')) {
3170
- Object.defineProperty(to, '__source', {
3171
- value: from.__source,
3172
- enumerable: false,
3173
- writable: false,
3174
- configurable: true,
3175
- });
2895
+ __defineHiddenValue(to, '__source', from.__source);
3176
2896
  }
3177
2897
  return to;
3178
2898
  }
@@ -3184,12 +2904,7 @@ function __annotateProofVarSourceNames(rule) {
3184
2904
  const m = /^(.*)__\d+$/.exec(name);
3185
2905
  sourceNames[name] = m ? m[1] : name;
3186
2906
  }
3187
- Object.defineProperty(rule, '__proofVarSourceNames', {
3188
- value: sourceNames,
3189
- enumerable: false,
3190
- writable: false,
3191
- configurable: true,
3192
- });
2907
+ __defineHiddenValue(rule, '__proofVarSourceNames', sourceNames);
3193
2908
  return rule;
3194
2909
  }
3195
2910
 
@@ -3395,45 +3110,16 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
3395
3110
  // until a scoped snapshot exists (or a given closure level is reached).
3396
3111
  // Helper functions are module-scoped: __computeForwardRuleScopedSkipInfo, etc.
3397
3112
  function setScopedSnapshot(snap, level) {
3398
- if (!hasOwn.call(facts, '__scopedSnapshot')) {
3399
- Object.defineProperty(facts, '__scopedSnapshot', {
3400
- value: snap,
3401
- enumerable: false,
3402
- writable: true,
3403
- configurable: true,
3404
- });
3405
- } else {
3406
- facts.__scopedSnapshot = snap;
3407
- }
3408
-
3409
- if (!hasOwn.call(facts, '__scopedClosureLevel')) {
3410
- Object.defineProperty(facts, '__scopedClosureLevel', {
3411
- value: level,
3412
- enumerable: false,
3413
- writable: true,
3414
- configurable: true,
3415
- });
3416
- } else {
3417
- facts.__scopedClosureLevel = level;
3418
- }
3113
+ __setHiddenWritable(facts, '__scopedSnapshot', snap);
3114
+ __setHiddenWritable(facts, '__scopedClosureLevel', level);
3419
3115
  }
3420
3116
 
3421
3117
  function makeScopedSnapshot() {
3422
3118
  const snap = facts.slice();
3423
3119
  cloneFactIndexesForSnapshot(facts, snap);
3424
- Object.defineProperty(snap, '__scopedSnapshot', {
3425
- value: snap,
3426
- enumerable: false,
3427
- writable: true,
3428
- configurable: true,
3429
- });
3120
+ __defineHiddenWritable(snap, '__scopedSnapshot', snap);
3430
3121
  // Propagate closure level so nested scoped builtins can see it.
3431
- Object.defineProperty(snap, '__scopedClosureLevel', {
3432
- value: scopedClosureLevel,
3433
- enumerable: false,
3434
- writable: true,
3435
- configurable: true,
3436
- });
3122
+ __defineHiddenWritable(snap, '__scopedClosureLevel', scopedClosureLevel);
3437
3123
  return snap;
3438
3124
  }
3439
3125
 
@@ -3781,36 +3467,12 @@ function __withScopedSnapshotForQueries(facts, fn) {
3781
3467
  // Create a frozen snapshot of the saturated closure.
3782
3468
  const snap = facts.slice();
3783
3469
  ensureFactIndexes(snap);
3784
- Object.defineProperty(snap, '__scopedSnapshot', {
3785
- value: snap,
3786
- enumerable: false,
3787
- writable: true,
3788
- configurable: true,
3789
- });
3790
- Object.defineProperty(snap, '__scopedClosureLevel', {
3791
- value: Number.MAX_SAFE_INTEGER,
3792
- enumerable: false,
3793
- writable: true,
3794
- configurable: true,
3795
- });
3470
+ __defineHiddenWritable(snap, '__scopedSnapshot', snap);
3471
+ __defineHiddenWritable(snap, '__scopedClosureLevel', Number.MAX_SAFE_INTEGER);
3796
3472
 
3797
3473
  // Ensure the live facts array exposes the snapshot/level for builtins.
3798
- if (!hasOwn.call(facts, '__scopedSnapshot')) {
3799
- Object.defineProperty(facts, '__scopedSnapshot', {
3800
- value: null,
3801
- enumerable: false,
3802
- writable: true,
3803
- configurable: true,
3804
- });
3805
- }
3806
- if (!hasOwn.call(facts, '__scopedClosureLevel')) {
3807
- Object.defineProperty(facts, '__scopedClosureLevel', {
3808
- value: 0,
3809
- enumerable: false,
3810
- writable: true,
3811
- configurable: true,
3812
- });
3813
- }
3474
+ __setHiddenWritable(facts, '__scopedSnapshot', null);
3475
+ __setHiddenWritable(facts, '__scopedClosureLevel', 0);
3814
3476
 
3815
3477
  facts.__scopedSnapshot = snap;
3816
3478
  facts.__scopedClosureLevel = Number.MAX_SAFE_INTEGER;