@metta-ts/core 1.0.1 → 1.0.3

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 (3) hide show
  1. package/dist/index.d.ts +147 -38
  2. package/dist/index.js +2614 -331
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -75,6 +75,10 @@ function groundEq(a, b) {
75
75
  }
76
76
  }
77
77
  var SYM_INTERN = /* @__PURE__ */ new Map();
78
+ var MIN_EXPR_INTERN_ARITY = 64;
79
+ function canInternExprItems(items) {
80
+ return items.length >= MIN_EXPR_INTERN_ARITY;
81
+ }
78
82
  function sym(name) {
79
83
  let s = SYM_INTERN.get(name);
80
84
  if (s === void 0) {
@@ -122,6 +126,112 @@ function expr(items) {
122
126
  ground
123
127
  };
124
128
  }
129
+ function createInternTable() {
130
+ return {
131
+ buckets: /* @__PURE__ */ new Map(),
132
+ variables: /* @__PURE__ */ new Map(),
133
+ expressions: /* @__PURE__ */ new WeakSet(),
134
+ hasUnsafeGrounded: /* @__PURE__ */ new WeakMap()
135
+ };
136
+ }
137
+ function bucketIntern(table, a) {
138
+ const h = hashOf(a);
139
+ const entry = table.buckets.get(h);
140
+ if (entry === void 0) {
141
+ table.buckets.set(h, a);
142
+ if (a.kind === "expr") table.expressions.add(a);
143
+ return a;
144
+ }
145
+ if (!Array.isArray(entry)) {
146
+ if (atomEq(entry, a)) return entry;
147
+ table.buckets.set(h, [entry, a]);
148
+ if (a.kind === "expr") table.expressions.add(a);
149
+ return a;
150
+ }
151
+ for (const existing of entry) {
152
+ if (atomEq(existing, a)) return existing;
153
+ }
154
+ entry.push(a);
155
+ if (a.kind === "expr") table.expressions.add(a);
156
+ return a;
157
+ }
158
+ function isStateExpression(a) {
159
+ const head = a.items[0];
160
+ return head?.kind === "sym" && (head.name === "State" || head.name === "StateValue");
161
+ }
162
+ function hasUnsafeGrounded(table, a) {
163
+ if (a.kind === "gnd") return true;
164
+ if (a.kind !== "expr") return false;
165
+ if (isStateExpression(a)) return true;
166
+ const cached = table.hasUnsafeGrounded.get(a);
167
+ if (cached !== void 0) return cached;
168
+ for (const it of a.items) {
169
+ if (hasUnsafeGrounded(table, it)) {
170
+ table.hasUnsafeGrounded.set(a, true);
171
+ return true;
172
+ }
173
+ }
174
+ table.hasUnsafeGrounded.set(a, false);
175
+ return false;
176
+ }
177
+ function internVariable(table, a) {
178
+ let v = table.variables.get(a.name);
179
+ if (v === void 0) {
180
+ v = a;
181
+ table.variables.set(a.name, v);
182
+ }
183
+ return v;
184
+ }
185
+ function internAtom(table, a) {
186
+ if (table === void 0) return a;
187
+ switch (a.kind) {
188
+ case "sym":
189
+ return sym(a.name);
190
+ case "var":
191
+ return internVariable(table, a);
192
+ case "expr":
193
+ return internExpr(table, a);
194
+ case "gnd":
195
+ return a;
196
+ }
197
+ }
198
+ function internExpr(table, a) {
199
+ if (table === void 0 || table.expressions.has(a) || !a.ground || !canInternExprItems(a.items) || hasUnsafeGrounded(table, a)) {
200
+ return a;
201
+ }
202
+ const its = a.items;
203
+ let items = null;
204
+ let ground = true;
205
+ for (let i = 0; i < its.length; i++) {
206
+ const it = its[i];
207
+ const r = internAtom(table, it);
208
+ if (!r.ground) ground = false;
209
+ if (items !== null) items.push(r);
210
+ else if (r !== it) {
211
+ items = its.slice(0, i);
212
+ items.push(r);
213
+ }
214
+ }
215
+ const candidate = items === null && ground === a.ground ? a : expr(items ?? its);
216
+ return bucketIntern(table, candidate);
217
+ }
218
+ function internBuiltExpr(table, a) {
219
+ if (table === void 0 || table.expressions.has(a) || !a.ground || !canInternExprItems(a.items) || hasUnsafeGrounded(table, a)) {
220
+ return a;
221
+ }
222
+ const its = a.items;
223
+ let items = null;
224
+ for (let i = 0; i < its.length; i++) {
225
+ const it = its[i];
226
+ const r = it.kind === "var" ? internVariable(table, it) : it.kind === "sym" ? sym(it.name) : it;
227
+ if (items !== null) items.push(r);
228
+ else if (r !== it) {
229
+ items = its.slice(0, i);
230
+ items.push(r);
231
+ }
232
+ }
233
+ return bucketIntern(table, items === null ? a : expr(items));
234
+ }
125
235
  function groundType(v) {
126
236
  switch (v.g) {
127
237
  case "int":
@@ -425,12 +535,32 @@ function format(a) {
425
535
  var emptyBindings = [];
426
536
  var valRel = (x, a) => ({ tag: "val", x, a, y: void 0 });
427
537
  var eqRel = (x, y) => ({ tag: "eq", x, a: void 0, y });
538
+ function isValFor(r, x) {
539
+ return r.tag === "val" && r.x === x;
540
+ }
541
+ function firstValIndex(b, x) {
542
+ for (let i = 0; i < b.length; i++) if (isValFor(b[i], x)) return i;
543
+ return -1;
544
+ }
545
+ function copyWithoutVal(b, x, first, out = []) {
546
+ for (let i = 0; i < first; i++) out.push(b[i]);
547
+ for (let i = first + 1; i < b.length; i++) {
548
+ const r = b[i];
549
+ if (!isValFor(r, x)) out.push(r);
550
+ }
551
+ return out;
552
+ }
428
553
  function lookupVal(b, x) {
429
- for (const r of b) if (r.tag === "val" && r.x === x) return r.a;
554
+ for (let i = 0; i < b.length; i++) {
555
+ const r = b[i];
556
+ if (isValFor(r, x)) return r.a;
557
+ }
430
558
  return void 0;
431
559
  }
432
560
  function removeVal(b, x) {
433
- return b.filter((r) => !(r.tag === "val" && r.x === x));
561
+ const first = firstValIndex(b, x);
562
+ if (first < 0) return b;
563
+ return copyWithoutVal(b, x, first);
434
564
  }
435
565
  function hasLoop(b) {
436
566
  for (const r of b) {
@@ -440,10 +570,48 @@ function hasLoop(b) {
440
570
  return false;
441
571
  }
442
572
  function addValRaw(b, x, a) {
443
- return [valRel(x, a), ...removeVal(b, x)];
573
+ const first = firstValIndex(b, x);
574
+ if (first < 0) {
575
+ return prependValRaw(b, x, a);
576
+ }
577
+ return copyWithoutVal(b, x, first, [valRel(x, a)]);
578
+ }
579
+ function prependValRaw(b, x, a) {
580
+ const rel = valRel(x, a);
581
+ return b.length === 0 ? [rel] : [rel, ...b];
444
582
  }
445
583
  function addEqRaw(b, x, y) {
446
- return x === y ? b : [eqRel(x, y), ...b];
584
+ if (x === y) return b;
585
+ return [eqRel(x, y), ...b];
586
+ }
587
+ function makeValRel(x, a) {
588
+ return valRel(x, a);
589
+ }
590
+ function fromRelations(rels) {
591
+ return rels;
592
+ }
593
+ function size(b) {
594
+ return b.length;
595
+ }
596
+ function isEmpty(b) {
597
+ return b.length === 0;
598
+ }
599
+ function relations(b) {
600
+ return b;
601
+ }
602
+ function* valEntries(b) {
603
+ for (const r of b) if (r.tag === "val") yield [r.x, r.a];
604
+ }
605
+ function someVal(b, pred) {
606
+ for (const r of b) if (r.tag === "val" && pred(r.x, r.a)) return true;
607
+ return false;
608
+ }
609
+ function hasEq(b) {
610
+ for (const r of b) if (r.tag === "eq") return true;
611
+ return false;
612
+ }
613
+ function* eqRelations(b) {
614
+ for (const r of b) if (r.tag === "eq") yield r;
447
615
  }
448
616
 
449
617
  // src/match.ts
@@ -480,25 +648,26 @@ function occursThrough(target, a, rels, b, seen) {
480
648
  function reconcile(b, l, r) {
481
649
  const out = [];
482
650
  for (const mb of matchAtoms(l, r)) {
483
- if (mb.some((rel) => rel.tag === "val" && occursThrough(rel.x, rel.a, mb, b, /* @__PURE__ */ new Set())))
484
- continue;
651
+ if (someVal(mb, (x, a) => occursThrough(x, a, mb, b, /* @__PURE__ */ new Set()))) continue;
485
652
  for (const m of merge(b, mb)) out.push(m);
486
653
  }
487
654
  return out;
488
655
  }
489
656
  function addVarBinding(b, x, v) {
490
657
  const prev = lookupVal(b, x);
491
- if (prev === void 0) return [addValRaw(b, x, v)];
658
+ if (prev === void 0) return [prependValRaw(b, x, v)];
492
659
  if (atomEq(prev, v)) return [b];
493
660
  return reconcile(b, prev, v);
494
661
  }
495
662
  function addVarEquality(b, x, y) {
663
+ if (x === y) return [b];
496
664
  const vx = lookupVal(b, x);
497
665
  const vy = lookupVal(b, y);
498
666
  if (vx === void 0 || vy === void 0 || atomEq(vx, vy)) return [addEqRaw(b, x, y)];
499
667
  return reconcile(b, vx, vy);
500
668
  }
501
669
  function mergeOne(bs, r) {
670
+ if (r.tag === "eq" && r.x === r.y) return bs;
502
671
  const out = [];
503
672
  for (const b of bs) {
504
673
  const ext = r.tag === "val" ? addVarBinding(b, r.x, r.a) : addVarEquality(b, r.x, r.y);
@@ -508,37 +677,30 @@ function mergeOne(bs, r) {
508
677
  }
509
678
  function merge(a, b) {
510
679
  let acc = [a];
511
- for (const r of b) acc = mergeOne(acc, r);
680
+ for (const r of relations(b)) acc = mergeOne(acc, r);
512
681
  return acc;
513
682
  }
514
683
  function matchAtomsWith(custom, l, r, leftSuffix = "") {
515
- if (l.kind === "sym" && r.kind === "sym") return l.name === r.name ? [[]] : [];
684
+ if (l.kind === "sym" && r.kind === "sym") return l.name === r.name ? [emptyBindings] : [];
516
685
  if (l.kind === "var" && r.kind === "var") {
517
686
  const lx = l.name + leftSuffix;
518
- return lx === r.name ? [[]] : [[{ tag: "val", x: lx, a: r, y: void 0 }]];
687
+ return lx === r.name ? [emptyBindings] : [prependValRaw(emptyBindings, lx, r)];
519
688
  }
520
- if (l.kind === "var") return [[{ tag: "val", x: l.name + leftSuffix, a: r, y: void 0 }]];
689
+ if (l.kind === "var") return [prependValRaw(emptyBindings, l.name + leftSuffix, r)];
521
690
  if (r.kind === "var")
522
691
  return [
523
- [
524
- {
525
- tag: "val",
526
- x: r.name,
527
- a: leftSuffix === "" ? l : suffixVars(l, leftSuffix),
528
- y: void 0
529
- }
530
- ]
692
+ prependValRaw(emptyBindings, r.name, leftSuffix === "" ? l : suffixVars(l, leftSuffix))
531
693
  ];
532
694
  if (l.kind === "expr" && r.kind === "expr")
533
- return matchAll(custom, [[]], l.items, r.items, leftSuffix);
695
+ return matchAll(custom, [emptyBindings], l.items, r.items, leftSuffix);
534
696
  if (l.kind === "gnd") return matchGrounded(custom, l, r);
535
697
  if (r.kind === "gnd") return matchGrounded(custom, r, l);
536
- return atomEq(l, r) ? [[]] : [];
698
+ return atomEq(l, r) ? [emptyBindings] : [];
537
699
  }
538
700
  function matchGrounded(custom, g, other) {
539
701
  if (g.kind === "gnd" && g.match !== void 0) return g.match(other);
540
702
  if (custom !== void 0) return custom(g, other);
541
- return atomEq(g, other) ? [[]] : [];
703
+ return atomEq(g, other) ? [emptyBindings] : [];
542
704
  }
543
705
  function matchAll(custom, acc, xs, ys, leftSuffix = "") {
544
706
  if (xs.length !== ys.length) return [];
@@ -559,6 +721,81 @@ function matchAtomsScoped(l, r, suffix) {
559
721
  return matchAtomsWith(void 0, l, r, suffix);
560
722
  }
561
723
 
724
+ // src/trail.ts
725
+ var Trail = class {
726
+ binds = /* @__PURE__ */ new Map();
727
+ trail = [];
728
+ /** A restore point: the current trail length. */
729
+ mark() {
730
+ return this.trail.length;
731
+ }
732
+ /** Undo every binding made since `m`. */
733
+ undo(m) {
734
+ const t = this.trail;
735
+ while (t.length > m) this.binds.delete(t.pop());
736
+ }
737
+ /** Bind `$name` to `a` and record it on the trail. The caller guarantees `$name` is currently unbound. */
738
+ bind(name, a) {
739
+ this.binds.set(name, a);
740
+ this.trail.push(name);
741
+ }
742
+ /** Follow variable bindings to the representative: a non-variable, or an unbound variable. */
743
+ deref(a) {
744
+ let cur = a;
745
+ while (cur.kind === "var") {
746
+ const v = this.binds.get(cur.name);
747
+ if (v === void 0) return cur;
748
+ cur = v;
749
+ }
750
+ return cur;
751
+ }
752
+ /** The atom currently bound to `$name`, if any (the direct binding, not dereferenced). */
753
+ get(name) {
754
+ return this.binds.get(name);
755
+ }
756
+ /** Resolve `a` against the current bindings, one pass (the same discipline as the immutable
757
+ * `instantiate`/`applySubst`): a variable becomes its bound value as-is; the value's own variables are
758
+ * not re-resolved, and an expression's children are resolved. This matches the evaluator exactly,
759
+ * including that a cyclic binding (`$y = (.. $y ..)`, which `matchAtoms` produces and `hasLoop` does not
760
+ * reject) terminates instead of looping. A new term is built only where a child changed. */
761
+ resolve(a) {
762
+ if (a.kind === "var") return this.deref(a);
763
+ if (a.kind !== "expr" || a.ground) return a;
764
+ const its = a.items;
765
+ let items = null;
766
+ for (let i = 0; i < its.length; i++) {
767
+ const it = its[i];
768
+ const r = this.resolve(it);
769
+ if (items !== null) items.push(r);
770
+ else if (r !== it) {
771
+ items = its.slice(0, i);
772
+ items.push(r);
773
+ }
774
+ }
775
+ return items === null ? a : { ...a, items };
776
+ }
777
+ };
778
+ function unifyTrail(tr, l0, r0) {
779
+ const l = tr.deref(l0);
780
+ const r = tr.deref(r0);
781
+ if (l === r) return true;
782
+ if (l.kind === "var") {
783
+ if (r.kind === "var" && l.name === r.name) return true;
784
+ tr.bind(l.name, r);
785
+ return true;
786
+ }
787
+ if (r.kind === "var") {
788
+ tr.bind(r.name, l);
789
+ return true;
790
+ }
791
+ if (l.kind === "sym") return r.kind === "sym" && l.name === r.name;
792
+ if (l.kind === "gnd") return r.kind === "gnd" && atomEq(l, r);
793
+ if (r.kind !== "expr" || l.items.length !== r.items.length) return false;
794
+ for (let i = 0; i < l.items.length; i++)
795
+ if (!unifyTrail(tr, l.items[i], r.items[i])) return false;
796
+ return true;
797
+ }
798
+
562
799
  // src/substitution.ts
563
800
  var emptySubst = [];
564
801
  function lookupSubst(s, x) {
@@ -610,29 +847,31 @@ function occurs(x, a) {
610
847
  // src/instantiate.ts
611
848
  function bindingsToSubst(b) {
612
849
  const out = [];
613
- for (const r of b) if (r.tag === "val") out.push([r.x, r.a]);
850
+ for (const e of valEntries(b)) out.push(e);
614
851
  return out;
615
852
  }
616
- function instantiate(b, a, suffix = "") {
853
+ function instantiate(b, a, suffix = "", intern) {
617
854
  if (a.kind === "var") {
618
- if (suffix === "") return b.length === 0 ? a : lookupVal(b, a.name) ?? a;
855
+ if (suffix === "") return isEmpty(b) ? a : lookupVal(b, a.name) ?? a;
619
856
  const name = a.name + suffix;
620
857
  return lookupVal(b, name) ?? variable(name);
621
858
  }
622
859
  if (a.ground || a.kind !== "expr") return a;
623
- if (b.length === 0 && suffix === "") return a;
860
+ if (isEmpty(b) && suffix === "") return a;
624
861
  const its = a.items;
625
862
  let items = null;
626
863
  for (let i = 0; i < its.length; i++) {
627
864
  const it = its[i];
628
- const r = instantiate(b, it, suffix);
865
+ const r = instantiate(b, it, suffix, intern);
629
866
  if (items !== null) items.push(r);
630
867
  else if (r !== it) {
631
868
  items = its.slice(0, i);
632
869
  items.push(r);
633
870
  }
634
871
  }
635
- return items === null ? a : { ...a, items };
872
+ if (items === null) return a;
873
+ if (intern === void 0 || !canInternExprItems(items)) return expr(items);
874
+ return internBuiltExpr(intern, expr(items));
636
875
  }
637
876
 
638
877
  // src/pmap.ts
@@ -711,13 +950,30 @@ var idxCount = (idx, atom) => {
711
950
  };
712
951
  var emptyLog = null;
713
952
  var logSize = (log) => log === null ? 0 : log.size;
714
- var logGroundIdx = (log) => log === null ? emptyPMap : log.groundIdx;
953
+ var idxCache = /* @__PURE__ */ new WeakMap();
954
+ var logGroundIdx = (log) => {
955
+ if (log === null) return emptyPMap;
956
+ const hit = idxCache.get(log);
957
+ if (hit !== void 0) return hit;
958
+ const chain = [];
959
+ let node = log;
960
+ while (node !== null && !idxCache.has(node)) {
961
+ chain.push(node);
962
+ node = node.prev;
963
+ }
964
+ let idx = node === null ? emptyPMap : idxCache.get(node);
965
+ for (let i = chain.length - 1; i >= 0; i--) {
966
+ const n = chain[i];
967
+ if (n.atom.ground) idx = idxAdd(idx, n.atom);
968
+ idxCache.set(n, idx);
969
+ }
970
+ return idx;
971
+ };
715
972
  var logNonGround = (log) => log === null ? 0 : log.nonGround;
716
973
  var logAppend = (log, atom) => ({
717
974
  atom,
718
975
  prev: log,
719
976
  size: (log === null ? 0 : log.size) + 1,
720
- groundIdx: atom.ground ? idxAdd(logGroundIdx(log), atom) : logGroundIdx(log),
721
977
  nonGround: (log === null ? 0 : log.nonGround) + (atom.ground ? 0 : 1)
722
978
  });
723
979
  function logAppendAll(log, atoms) {
@@ -734,6 +990,374 @@ function logToArray(log) {
734
990
  }
735
991
  var logFromArray = (atoms) => logAppendAll(emptyLog, atoms);
736
992
 
993
+ // src/flat-atomspace.ts
994
+ var TERM_SYM = 1;
995
+ var TERM_GND = 2;
996
+ var TERM_VAR = 3;
997
+ var TERM_EXPR = 4;
998
+ var CHUNK_SIZE = 16384;
999
+ var ABSENT = -1;
1000
+ var Int32Chunks = class {
1001
+ chunks = [];
1002
+ tail = new Int32Array(CHUNK_SIZE);
1003
+ length = 0;
1004
+ push(value) {
1005
+ const index = this.length;
1006
+ const offset = index % CHUNK_SIZE;
1007
+ if (offset === 0) {
1008
+ if (index > 0) this.chunks.push(this.tail);
1009
+ this.tail = new Int32Array(CHUNK_SIZE);
1010
+ }
1011
+ this.tail[offset] = value | 0;
1012
+ this.length = index + 1;
1013
+ return index;
1014
+ }
1015
+ get(index) {
1016
+ return index < this.chunks.length * CHUNK_SIZE ? this.chunks[Math.floor(index / CHUNK_SIZE)][index % CHUNK_SIZE] : this.tail[index % CHUNK_SIZE];
1017
+ }
1018
+ };
1019
+ function groundKey(v) {
1020
+ switch (v.g) {
1021
+ case "int":
1022
+ return "i\0" + typeof v.n + "\0" + String(v.n);
1023
+ case "float":
1024
+ return "f\0" + String(v.n);
1025
+ case "str":
1026
+ return "s\0" + v.s;
1027
+ case "bool":
1028
+ return v.b ? "b\x001" : "b\x000";
1029
+ case "unit":
1030
+ return "u";
1031
+ case "error":
1032
+ return "e\0" + v.msg;
1033
+ case "ext":
1034
+ return "x\0" + v.kind + "\0" + v.id;
1035
+ }
1036
+ }
1037
+ function groundHash2(v) {
1038
+ return strHash(groundKey(v));
1039
+ }
1040
+ function canCompactAtom(a) {
1041
+ switch (a.kind) {
1042
+ case "sym":
1043
+ case "var":
1044
+ return true;
1045
+ case "gnd":
1046
+ return a.exec === void 0 && a.match === void 0;
1047
+ case "expr":
1048
+ return a.items.every(canCompactAtom);
1049
+ }
1050
+ }
1051
+ var FlatAtomSpaceTable = class {
1052
+ termKind = new Int32Chunks();
1053
+ termStart = new Int32Chunks();
1054
+ termLen = new Int32Chunks();
1055
+ termHash = new Int32Chunks();
1056
+ termGround = new Int32Chunks();
1057
+ termData = new Int32Chunks();
1058
+ factRoot = new Int32Chunks();
1059
+ factHeadSym = new Int32Chunks();
1060
+ hashBuckets = /* @__PURE__ */ new Map();
1061
+ symByName = /* @__PURE__ */ new Map();
1062
+ groundByKey = /* @__PURE__ */ new Map();
1063
+ varByName = /* @__PURE__ */ new Map();
1064
+ termFacts = /* @__PURE__ */ new Map();
1065
+ symbols = [];
1066
+ grounds = [];
1067
+ vars = [];
1068
+ get factCount() {
1069
+ return this.factRoot.length;
1070
+ }
1071
+ insertFact(atom) {
1072
+ const root = this.insertAtom(atom);
1073
+ const id = this.factRoot.push(root);
1074
+ this.factHeadSym.push(this.headSymOf(root));
1075
+ const facts = this.termFacts.get(root);
1076
+ if (facts === void 0) this.termFacts.set(root, [id]);
1077
+ else facts.push(id);
1078
+ return id;
1079
+ }
1080
+ factsForTerm(term) {
1081
+ return this.termFacts.get(term) ?? [];
1082
+ }
1083
+ insertAtom(atom) {
1084
+ switch (atom.kind) {
1085
+ case "sym":
1086
+ return this.internLeaf(
1087
+ TERM_SYM,
1088
+ this.internSym(atom.name),
1089
+ strHash("s\0" + atom.name),
1090
+ true
1091
+ );
1092
+ case "gnd": {
1093
+ const key = groundKey(atom.value);
1094
+ return this.internLeaf(
1095
+ TERM_GND,
1096
+ this.internGround(key, atom.value),
1097
+ groundHash2(atom.value),
1098
+ true
1099
+ );
1100
+ }
1101
+ case "var":
1102
+ return this.internLeaf(
1103
+ TERM_VAR,
1104
+ this.internVar(atom.name),
1105
+ strHash("v\0" + atom.name),
1106
+ false
1107
+ );
1108
+ case "expr": {
1109
+ const children = atom.items.map((child) => this.insertAtom(child));
1110
+ return this.internExpr(children);
1111
+ }
1112
+ }
1113
+ }
1114
+ lookupAtom(atom) {
1115
+ switch (atom.kind) {
1116
+ case "sym": {
1117
+ const leaf = this.symByName.get(atom.name);
1118
+ return leaf === void 0 ? void 0 : this.lookupLeaf(TERM_SYM, leaf, strHash("s\0" + atom.name));
1119
+ }
1120
+ case "gnd": {
1121
+ if (!canCompactAtom(atom)) return void 0;
1122
+ const key = groundKey(atom.value);
1123
+ const leaf = this.groundByKey.get(key);
1124
+ return leaf === void 0 ? void 0 : this.lookupLeaf(TERM_GND, leaf, groundHash2(atom.value));
1125
+ }
1126
+ case "var": {
1127
+ const leaf = this.varByName.get(atom.name);
1128
+ return leaf === void 0 ? void 0 : this.lookupLeaf(TERM_VAR, leaf, strHash("v\0" + atom.name));
1129
+ }
1130
+ case "expr": {
1131
+ const children = [];
1132
+ for (const child of atom.items) {
1133
+ const term = this.lookupAtom(child);
1134
+ if (term === void 0) return void 0;
1135
+ children.push(term);
1136
+ }
1137
+ return this.lookupExpr(children);
1138
+ }
1139
+ }
1140
+ }
1141
+ decodeTerm(term) {
1142
+ const kind = this.termKind.get(term);
1143
+ const start = this.termStart.get(term);
1144
+ switch (kind) {
1145
+ case TERM_SYM:
1146
+ return sym(this.symbols[start]);
1147
+ case TERM_GND: {
1148
+ const ground = this.grounds[start];
1149
+ return gnd(ground, groundType(ground));
1150
+ }
1151
+ case TERM_VAR:
1152
+ return variable(this.vars[start]);
1153
+ case TERM_EXPR: {
1154
+ const len = this.termLen.get(term);
1155
+ const items = [];
1156
+ for (let i = 0; i < len; i++) items.push(this.decodeTerm(this.termData.get(start + i)));
1157
+ return expr(items);
1158
+ }
1159
+ default:
1160
+ throw new Error(`flat-atomspace: bad term kind ${kind}`);
1161
+ }
1162
+ }
1163
+ isTermGround(term) {
1164
+ return this.termGround.get(term) === 1;
1165
+ }
1166
+ headSymOf(term) {
1167
+ const kind = this.termKind.get(term);
1168
+ if (kind === TERM_SYM) return this.termStart.get(term);
1169
+ if (kind !== TERM_EXPR || this.termLen.get(term) === 0) return ABSENT;
1170
+ const head = this.termData.get(this.termStart.get(term));
1171
+ return this.termKind.get(head) === TERM_SYM ? this.termStart.get(head) : ABSENT;
1172
+ }
1173
+ lookupHeadSym(name) {
1174
+ return this.symByName.get(name);
1175
+ }
1176
+ internSym(name) {
1177
+ const existing = this.symByName.get(name);
1178
+ if (existing !== void 0) return existing;
1179
+ const id = this.symbols.length;
1180
+ this.symbols.push(name);
1181
+ this.symByName.set(name, id);
1182
+ return id;
1183
+ }
1184
+ internGround(key, value) {
1185
+ const existing = this.groundByKey.get(key);
1186
+ if (existing !== void 0) return existing;
1187
+ const id = this.grounds.length;
1188
+ this.grounds.push(value);
1189
+ this.groundByKey.set(key, id);
1190
+ return id;
1191
+ }
1192
+ internVar(name) {
1193
+ const existing = this.varByName.get(name);
1194
+ if (existing !== void 0) return existing;
1195
+ const id = this.vars.length;
1196
+ this.vars.push(name);
1197
+ this.varByName.set(name, id);
1198
+ return id;
1199
+ }
1200
+ internLeaf(kind, leaf, hash, ground) {
1201
+ const existing = this.lookupLeaf(kind, leaf, hash);
1202
+ if (existing !== void 0) return existing;
1203
+ return this.pushTerm(kind, leaf, 1, hash, ground);
1204
+ }
1205
+ lookupLeaf(kind, leaf, hash) {
1206
+ const bucket = this.hashBuckets.get(hash);
1207
+ if (bucket === void 0) return void 0;
1208
+ for (const term of bucket)
1209
+ if (this.termKind.get(term) === kind && this.termStart.get(term) === leaf) return term;
1210
+ return void 0;
1211
+ }
1212
+ internExpr(children) {
1213
+ const existing = this.lookupExpr(children);
1214
+ if (existing !== void 0) return existing;
1215
+ let hash = mixHash(1163415634, children.length);
1216
+ let ground = true;
1217
+ const start = this.termData.length;
1218
+ for (const child of children) {
1219
+ hash = mixHash(hash, child);
1220
+ if (!this.isTermGround(child)) ground = false;
1221
+ this.termData.push(child);
1222
+ }
1223
+ return this.pushTerm(TERM_EXPR, start, children.length, hash, ground);
1224
+ }
1225
+ lookupExpr(children) {
1226
+ let hash = mixHash(1163415634, children.length);
1227
+ for (const child of children) hash = mixHash(hash, child);
1228
+ const bucket = this.hashBuckets.get(hash);
1229
+ if (bucket === void 0) return void 0;
1230
+ termLoop: for (const term of bucket) {
1231
+ if (this.termKind.get(term) !== TERM_EXPR || this.termLen.get(term) !== children.length)
1232
+ continue;
1233
+ const start = this.termStart.get(term);
1234
+ for (let i = 0; i < children.length; i++)
1235
+ if (this.termData.get(start + i) !== children[i]) continue termLoop;
1236
+ return term;
1237
+ }
1238
+ return void 0;
1239
+ }
1240
+ pushTerm(kind, start, len, hash, ground) {
1241
+ const term = this.termKind.length;
1242
+ this.termKind.push(kind);
1243
+ this.termStart.push(start);
1244
+ this.termLen.push(len);
1245
+ this.termHash.push(hash);
1246
+ this.termGround.push(ground ? 1 : 0);
1247
+ const bucket = this.hashBuckets.get(hash);
1248
+ if (bucket === void 0) this.hashBuckets.set(hash, [term]);
1249
+ else bucket.push(term);
1250
+ return term;
1251
+ }
1252
+ };
1253
+ var FlatAtomSpace = class _FlatAtomSpace {
1254
+ constructor(table, ranges, dead, liveCount, nonGroundCount) {
1255
+ this.table = table;
1256
+ this.ranges = ranges;
1257
+ this.dead = dead;
1258
+ this.liveCount = liveCount;
1259
+ this.nonGroundCount = nonGroundCount;
1260
+ }
1261
+ table;
1262
+ ranges;
1263
+ dead;
1264
+ liveCount;
1265
+ nonGroundCount;
1266
+ static empty() {
1267
+ return new _FlatAtomSpace(new FlatAtomSpaceTable(), [], /* @__PURE__ */ new Set(), 0, 0);
1268
+ }
1269
+ static fromAtoms(atoms) {
1270
+ if (!atoms.every(canCompactAtom)) return void 0;
1271
+ return _FlatAtomSpace.empty().appendAll(atoms);
1272
+ }
1273
+ get size() {
1274
+ return this.liveCount;
1275
+ }
1276
+ appendAll(atoms) {
1277
+ if (atoms.length === 0) return this;
1278
+ const start = this.table.factCount;
1279
+ let nonGround = this.nonGroundCount;
1280
+ for (const atom of atoms) {
1281
+ const fact = this.table.insertFact(atom);
1282
+ if (!this.table.isTermGround(this.table.factRoot.get(fact))) nonGround += 1;
1283
+ }
1284
+ const end = this.table.factCount;
1285
+ return new _FlatAtomSpace(
1286
+ this.table,
1287
+ appendRange(this.ranges, start, end),
1288
+ this.dead,
1289
+ this.liveCount + atoms.length,
1290
+ nonGround
1291
+ );
1292
+ }
1293
+ removeOne(atom) {
1294
+ const term = this.table.lookupAtom(atom);
1295
+ if (term === void 0) return this;
1296
+ for (const fact of this.visibleFactIds()) {
1297
+ if (this.table.factRoot.get(fact) !== term) continue;
1298
+ const dead = new Set(this.dead);
1299
+ dead.add(fact);
1300
+ const nonGround = this.table.isTermGround(term) ? this.nonGroundCount : this.nonGroundCount - 1;
1301
+ return new _FlatAtomSpace(this.table, this.ranges, dead, this.liveCount - 1, nonGround);
1302
+ }
1303
+ return this;
1304
+ }
1305
+ exactCount(atom) {
1306
+ if (!atom.ground) return 0;
1307
+ const term = this.table.lookupAtom(atom);
1308
+ if (term === void 0) return 0;
1309
+ let count = 0;
1310
+ for (const fact of this.table.factsForTerm(term))
1311
+ if (this.factVisible(fact) && !this.dead.has(fact)) count += 1;
1312
+ return count;
1313
+ }
1314
+ *candidatesFor(patternHead) {
1315
+ if (patternHead === void 0) {
1316
+ for (const fact of this.visibleFactIds()) yield this.decodeFact(fact);
1317
+ return;
1318
+ }
1319
+ const head = this.table.lookupHeadSym(patternHead);
1320
+ if (head === void 0) {
1321
+ for (const fact of this.visibleFactIds())
1322
+ if (this.table.factHeadSym.get(fact) === ABSENT) yield this.decodeFact(fact);
1323
+ return;
1324
+ }
1325
+ for (const fact of this.visibleFactIds()) {
1326
+ const factHead = this.table.factHeadSym.get(fact);
1327
+ if (factHead === ABSENT || factHead === head) yield this.decodeFact(fact);
1328
+ }
1329
+ }
1330
+ toArray() {
1331
+ const out = [];
1332
+ for (const fact of this.visibleFactIds()) out.push(this.decodeFact(fact));
1333
+ return out;
1334
+ }
1335
+ roundTrip(atom) {
1336
+ return this.table.decodeTerm(this.table.insertAtom(atom));
1337
+ }
1338
+ decodeFact(fact) {
1339
+ return this.table.decodeTerm(this.table.factRoot.get(fact));
1340
+ }
1341
+ *visibleFactIds() {
1342
+ for (const range of this.ranges)
1343
+ for (let fact = range.start; fact < range.end; fact++) if (!this.dead.has(fact)) yield fact;
1344
+ }
1345
+ factVisible(fact) {
1346
+ for (const range of this.ranges) {
1347
+ if (fact < range.start) return false;
1348
+ if (fact < range.end) return true;
1349
+ }
1350
+ return false;
1351
+ }
1352
+ };
1353
+ function appendRange(ranges, start, end) {
1354
+ if (start === end) return ranges;
1355
+ const last = ranges[ranges.length - 1];
1356
+ if (last !== void 0 && last.end === start)
1357
+ return [...ranges.slice(0, -1), { start: last.start, end }];
1358
+ return [...ranges, { start, end }];
1359
+ }
1360
+
737
1361
  // src/wcojoin.ts
738
1362
  function allVars(rels) {
739
1363
  const seen = /* @__PURE__ */ new Set();
@@ -746,7 +1370,7 @@ function allVars(rels) {
746
1370
  }
747
1371
  return out;
748
1372
  }
749
- function wcoJoin(rels, key, varOrder) {
1373
+ function wcoJoinFold(rels, key, hooks, varOrder) {
750
1374
  const order = varOrder ?? allVars(rels);
751
1375
  const relInfos = rels.map((r) => {
752
1376
  const relVars = order.filter((v) => r.vars.includes(v));
@@ -770,12 +1394,10 @@ function wcoJoin(rels, key, varOrder) {
770
1394
  const participants = order.map(
771
1395
  (v) => relInfos.map((ri, r) => ri.relVars.includes(v) ? r : -1).filter((r) => r >= 0)
772
1396
  );
773
- const out = [];
774
- const partial = /* @__PURE__ */ new Map();
775
1397
  const cursors = relInfos.map((ri) => ri.root);
776
1398
  const recurse = (i) => {
777
1399
  if (i === order.length) {
778
- out.push(new Map(partial));
1400
+ hooks.onLeaf();
779
1401
  return;
780
1402
  }
781
1403
  const parts = participants[i];
@@ -797,13 +1419,27 @@ function wcoJoin(rels, key, varOrder) {
797
1419
  if (!ok2) continue;
798
1420
  const saved = advanced.map(([r]) => [r, cursors[r]]);
799
1421
  for (const [r, child] of advanced) cursors[r] = child;
800
- partial.set(v, entry.val);
1422
+ hooks.onDescend(v, entry.val);
801
1423
  recurse(i + 1);
1424
+ hooks.onAscend(v);
802
1425
  for (const [r, c] of saved) cursors[r] = c;
803
1426
  }
804
- partial.delete(v);
805
1427
  };
806
1428
  recurse(0);
1429
+ }
1430
+ function wcoJoin(rels, key, varOrder) {
1431
+ const out = [];
1432
+ const partial = /* @__PURE__ */ new Map();
1433
+ wcoJoinFold(
1434
+ rels,
1435
+ key,
1436
+ {
1437
+ onDescend: (v, val) => partial.set(v, val),
1438
+ onAscend: (v) => partial.delete(v),
1439
+ onLeaf: () => out.push(new Map(partial))
1440
+ },
1441
+ varOrder
1442
+ );
807
1443
  return out;
808
1444
  }
809
1445
 
@@ -1818,16 +2454,607 @@ function inferType(a, varTypes, holders) {
1818
2454
  if (op === "let" && a.items.length === 4) return inferType(a.items[3], varTypes, holders);
1819
2455
  return holders.get(op)?.retType;
1820
2456
  }
1821
- function compileEnv(env) {
1822
- const pure = env.pureFunctors ?? /* @__PURE__ */ new Set();
1823
- const cand = /* @__PURE__ */ new Map();
1824
- for (const f of pure) {
1825
- const h = singleClauseHead(env, f);
1826
- if (h !== void 0) cand.set(f, h);
1827
- }
2457
+ function compileRewriteCellPat(a, seen) {
2458
+ if (a.kind === "sym") return { tag: "sym", atom: a };
2459
+ if (a.kind !== "var" || seen.has(a.name)) return void 0;
2460
+ seen.add(a.name);
2461
+ return { tag: "var", name: a.name };
2462
+ }
2463
+ function compileRewriteArgPat(a, seen) {
2464
+ if (a.kind === "sym") return { tag: "sym", atom: a };
2465
+ if (a.kind !== "expr" || a.items.length === 0) return void 0;
2466
+ const items = a.items.map((it) => compileRewriteCellPat(it, seen));
2467
+ if (items.some((it) => it === void 0)) return void 0;
2468
+ return { tag: "tuple", items };
2469
+ }
2470
+ function compileRewriteOut(a, vars) {
2471
+ if (a.kind !== "expr" || a.items.length === 0) return void 0;
2472
+ const out = [];
2473
+ for (const it of a.items) {
2474
+ if (it.kind === "sym") out.push({ tag: "sym", atom: it });
2475
+ else if (it.kind === "var" && vars.has(it.name)) out.push({ tag: "var", name: it.name });
2476
+ else return void 0;
2477
+ }
2478
+ return out;
2479
+ }
2480
+ function capturePositions(args) {
2481
+ const vars = /* @__PURE__ */ new Map();
2482
+ args.forEach((arg, i) => {
2483
+ if (arg.tag === "tuple")
2484
+ arg.items.forEach((cell, j) => {
2485
+ if (cell.tag === "var") vars.set(cell.name, { arg: i, cell: j });
2486
+ });
2487
+ });
2488
+ return vars;
2489
+ }
2490
+ function rewriteParamTypes(args) {
2491
+ return args.map((arg) => arg.tag === "sym" ? "sym" : `symtuple${arg.items.length}`);
2492
+ }
2493
+ function sameRewriteParamType(arg, type) {
2494
+ if (type === "sym") return arg.tag === "sym";
2495
+ if (!type.startsWith("symtuple") || arg.tag !== "tuple") return false;
2496
+ return arg.items.length === Number(type.slice("symtuple".length));
2497
+ }
2498
+ function atomToRewriteArg(a, type) {
2499
+ if (type === "sym") {
2500
+ if (a.kind === "sym") return { tag: "sym", atom: a };
2501
+ if (a.kind === "var") return { tag: "qvar", name: a.name };
2502
+ return void 0;
2503
+ }
2504
+ if (!type.startsWith("symtuple") || a.kind !== "expr") return void 0;
2505
+ const width = Number(type.slice("symtuple".length));
2506
+ if (a.items.length !== width) return void 0;
2507
+ const items = [];
2508
+ for (const it of a.items) {
2509
+ if (it.kind !== "sym") return void 0;
2510
+ items.push(it);
2511
+ }
2512
+ return { tag: "tuple", items };
2513
+ }
2514
+ function bindQueryVar(b, name, atom) {
2515
+ for (const rel of b) {
2516
+ if (rel.tag === "val" && rel.x === name) return rel.a === atom ? b : void 0;
2517
+ }
2518
+ return prependValRaw(b, name, atom);
2519
+ }
2520
+ function runRewriteRule(rule, vals) {
2521
+ let b = emptyBindings;
2522
+ for (let i = 0; i < rule.args.length; i++) {
2523
+ const pat = rule.args[i];
2524
+ const actual = vals[i];
2525
+ if (pat.tag === "sym") {
2526
+ if (actual.tag === "sym") {
2527
+ if (actual.atom !== pat.atom) return void 0;
2528
+ } else if (actual.tag === "qvar") {
2529
+ const nb = bindQueryVar(b, actual.name, pat.atom);
2530
+ if (nb === void 0) return void 0;
2531
+ b = nb;
2532
+ } else return void 0;
2533
+ continue;
2534
+ }
2535
+ if (actual.tag !== "tuple" || actual.items.length !== pat.items.length) return void 0;
2536
+ for (let j = 0; j < pat.items.length; j++) {
2537
+ const cell = pat.items[j];
2538
+ if (cell.tag === "sym" && actual.items[j] !== cell.atom) return void 0;
2539
+ }
2540
+ }
2541
+ const out = rule.out.map((part) => {
2542
+ if (part.tag === "sym") return part.atom;
2543
+ const pos = rule.vars.get(part.name);
2544
+ return vals[pos.arg].items[pos.cell];
2545
+ });
2546
+ return { atom: expr(out), bnd: b };
2547
+ }
2548
+ function compileRewrite(env, functor) {
2549
+ const eqs = env.ruleIndex.get(functor);
2550
+ if (eqs === void 0 || eqs.length === 0) return void 0;
2551
+ const rules = [];
2552
+ let arity;
2553
+ let retType;
2554
+ let paramTypes;
2555
+ for (const [lhs, rhs] of eqs) {
2556
+ if (lhs.kind !== "expr" || lhs.items.length === 0 || lhs.items[0].kind !== "sym")
2557
+ return void 0;
2558
+ if (lhs.items[0].name !== functor) return void 0;
2559
+ arity ??= lhs.items.length - 1;
2560
+ if (lhs.items.length - 1 !== arity) return void 0;
2561
+ const seen = /* @__PURE__ */ new Set();
2562
+ const args = lhs.items.slice(1).map((arg) => compileRewriteArgPat(arg, seen));
2563
+ if (args.some((arg) => arg === void 0)) return void 0;
2564
+ const typedArgs = args;
2565
+ if (paramTypes === void 0) paramTypes = rewriteParamTypes(typedArgs);
2566
+ else if (typedArgs.length !== paramTypes.length || typedArgs.some((arg, i) => !sameRewriteParamType(arg, paramTypes[i])))
2567
+ return void 0;
2568
+ const vars = capturePositions(typedArgs);
2569
+ const out = compileRewriteOut(rhs, new Set(vars.keys()));
2570
+ if (out === void 0) return void 0;
2571
+ const rt = `symtuple${out.length}`;
2572
+ if (retType === void 0) retType = rt;
2573
+ else if (retType !== rt) return void 0;
2574
+ rules.push({ args: typedArgs, out, vars });
2575
+ }
2576
+ if (arity === void 0 || retType === void 0 || paramTypes === void 0) return void 0;
2577
+ const run = (partAtoms) => {
2578
+ const vals = [];
2579
+ const qvars = /* @__PURE__ */ new Set();
2580
+ for (let i = 0; i < partAtoms.length; i++) {
2581
+ const v = atomToRewriteArg(partAtoms[i], paramTypes[i]);
2582
+ if (v === void 0) return void 0;
2583
+ if (v.tag === "qvar") {
2584
+ if (qvars.has(v.name)) return void 0;
2585
+ qvars.add(v.name);
2586
+ }
2587
+ vals.push(v);
2588
+ }
2589
+ const results = [];
2590
+ for (const rule of rules) {
2591
+ const r = runRewriteRule(rule, vals);
2592
+ if (r !== void 0) results.push(r);
2593
+ }
2594
+ return results.length === 0 ? void 0 : { results, counterDelta: rules.length };
2595
+ };
2596
+ return { kind: "rewrite", arity, retType, paramTypes, ruleCount: rules.length, run };
2597
+ }
2598
+ function compileSymPat(a, slots) {
2599
+ if (a.kind === "sym") return { tag: "sym", name: a.name };
2600
+ if (a.kind === "var") {
2601
+ if (slots.has(a.name)) return void 0;
2602
+ const slot = slots.size;
2603
+ slots.set(a.name, slot);
2604
+ return { tag: "slot", slot };
2605
+ }
2606
+ if (a.kind === "gnd") return { tag: "lit", atom: a };
2607
+ const items = [];
2608
+ for (const it of a.items) {
2609
+ const p = compileSymPat(it, slots);
2610
+ if (p === void 0) return void 0;
2611
+ items.push(p);
2612
+ }
2613
+ return { tag: "expr", items };
2614
+ }
2615
+ function compileSymTpl(a, slots) {
2616
+ if (a.kind === "var") {
2617
+ const slot = slots.get(a.name);
2618
+ return slot === void 0 ? { tag: "fresh", name: a.name } : { tag: "slot", slot };
2619
+ }
2620
+ if (a.kind !== "expr") return { tag: "atom", atom: a };
2621
+ return { tag: "expr", items: a.items.map((it) => compileSymTpl(it, slots)) };
2622
+ }
2623
+ function matchSymPat(pat, arg, slots) {
2624
+ switch (pat.tag) {
2625
+ case "sym":
2626
+ return arg.kind === "sym" && arg.name === pat.name;
2627
+ case "slot":
2628
+ slots[pat.slot] = arg;
2629
+ return true;
2630
+ case "lit":
2631
+ return atomEq(arg, pat.atom);
2632
+ case "expr": {
2633
+ if (arg.kind !== "expr" || arg.items.length !== pat.items.length) return false;
2634
+ for (let i = 0; i < pat.items.length; i++)
2635
+ if (!matchSymPat(pat.items[i], arg.items[i], slots)) return false;
2636
+ return true;
2637
+ }
2638
+ }
2639
+ }
2640
+ function bindSymQueryVar(bs, name, value) {
2641
+ const out = [];
2642
+ for (const b of bs) for (const ext of addVarBinding(b, name, value)) out.push(ext);
2643
+ return out;
2644
+ }
2645
+ function matchSymPatQuery(pat, arg, slots, bs) {
2646
+ switch (pat.tag) {
2647
+ case "sym":
2648
+ if (arg.kind === "var") return bindSymQueryVar(bs, arg.name, sym(pat.name));
2649
+ return arg.kind === "sym" && arg.name === pat.name ? [...bs] : [];
2650
+ case "slot":
2651
+ slots[pat.slot] = arg;
2652
+ return [...bs];
2653
+ case "lit":
2654
+ if (arg.kind === "var") return bindSymQueryVar(bs, arg.name, pat.atom);
2655
+ return atomEq(arg, pat.atom) ? [...bs] : [];
2656
+ case "expr": {
2657
+ if (arg.kind === "var") return void 0;
2658
+ if (arg.kind !== "expr" || arg.items.length !== pat.items.length) return [];
2659
+ let cur = [...bs];
2660
+ for (let i = 0; i < pat.items.length; i++) {
2661
+ const next = matchSymPatQuery(pat.items[i], arg.items[i], slots, cur);
2662
+ if (next === void 0) return void 0;
2663
+ if (next.length === 0) return [];
2664
+ cur = next;
2665
+ }
2666
+ return cur;
2667
+ }
2668
+ }
2669
+ }
2670
+ function buildSymTpl(tpl, slots, suffix) {
2671
+ switch (tpl.tag) {
2672
+ case "atom":
2673
+ return tpl.atom;
2674
+ case "slot":
2675
+ return slots[tpl.slot];
2676
+ case "fresh":
2677
+ return variable(tpl.name + suffix);
2678
+ case "expr":
2679
+ return expr(tpl.items.map((t) => buildSymTpl(t, slots, suffix)));
2680
+ }
2681
+ }
2682
+ function compileSymbolic(env, functor) {
2683
+ if (env.varRulesVar.length !== 0) return void 0;
2684
+ const eqs = env.ruleIndex.get(functor);
2685
+ if (eqs === void 0 || eqs.length === 0) return void 0;
2686
+ const clauses = [];
2687
+ let arity;
2688
+ for (const [lhs, rhs] of eqs) {
2689
+ if (lhs.kind !== "expr" || lhs.items.length === 0) return void 0;
2690
+ if (lhs.items[0].kind !== "sym" || lhs.items[0].name !== functor) return void 0;
2691
+ const a = lhs.items.length - 1;
2692
+ if (arity === void 0) arity = a;
2693
+ else if (a !== arity) return void 0;
2694
+ const slots = /* @__PURE__ */ new Map();
2695
+ const pats = [];
2696
+ for (let i = 1; i < lhs.items.length; i++) {
2697
+ const p = compileSymPat(lhs.items[i], slots);
2698
+ if (p === void 0) return void 0;
2699
+ pats.push(p);
2700
+ }
2701
+ clauses.push({ pats, tpl: compileSymTpl(rhs, slots), nslots: slots.size });
2702
+ }
2703
+ if (arity === void 0) return void 0;
2704
+ const clauseCount = clauses.length;
2705
+ const run = (partAtoms, counter) => {
2706
+ const results = [];
2707
+ for (let i = 0; i < clauseCount; i++) {
2708
+ const clause = clauses[i];
2709
+ const slots = new Array(clause.nslots);
2710
+ let bnds = [emptyBindings];
2711
+ for (let j = 0; j < clause.pats.length; j++) {
2712
+ if (partAtoms[j].ground) {
2713
+ if (!matchSymPat(clause.pats[j], partAtoms[j], slots)) {
2714
+ bnds = [];
2715
+ break;
2716
+ }
2717
+ continue;
2718
+ }
2719
+ const next = matchSymPatQuery(clause.pats[j], partAtoms[j], slots, bnds);
2720
+ if (next === void 0) return void 0;
2721
+ bnds = next;
2722
+ if (bnds.length === 0) break;
2723
+ }
2724
+ if (bnds.length > 0) {
2725
+ const atom = buildSymTpl(clause.tpl, slots, "#" + (counter + i));
2726
+ for (const bnd of bnds)
2727
+ results.push({
2728
+ atom,
2729
+ bnd
2730
+ });
2731
+ }
2732
+ }
2733
+ return results.length === 0 ? void 0 : { results, counterDelta: clauseCount };
2734
+ };
2735
+ return { kind: "symbolic", arity, clauseCount, run };
2736
+ }
2737
+ var IMP_GROUNDED = /* @__PURE__ */ new Set(["==", "<", ">", "<=", ">=", "+", "-", "*", "%"]);
2738
+ var DATA_DENY = /* @__PURE__ */ new Set([...KNOWN_OPS, "let*", "add-atom"]);
2739
+ var addCounter = (st, n) => n === 0 ? st : { counter: st.counter + n, world: st.world };
2740
+ var impBail = () => BAIL;
2741
+ function impMeta(parts) {
2742
+ const callees = /* @__PURE__ */ new Set();
2743
+ let directEffect = false;
2744
+ for (const part of parts) {
2745
+ if (part.directEffect) directEffect = true;
2746
+ for (const c of part.callees) callees.add(c);
2747
+ }
2748
+ return { directEffect, callees };
2749
+ }
2750
+ function impConst(atom) {
2751
+ return { node: (_slots, st) => ({ value: atom, st }), directEffect: false, callees: /* @__PURE__ */ new Set() };
2752
+ }
2753
+ function isDataSymbol(env, name) {
2754
+ return !DATA_DENY.has(name) && !env.ruleIndex.has(name) && !env.gt.has(name);
2755
+ }
2756
+ function compileImpStaticAtom(env, a, scope) {
2757
+ if (a.kind === "var") {
2758
+ const slot = scope.vars.get(a.name);
2759
+ if (slot === void 0) return void 0;
2760
+ return {
2761
+ node: (slots, st) => ({ value: slots[slot], st }),
2762
+ directEffect: false,
2763
+ callees: /* @__PURE__ */ new Set()
2764
+ };
2765
+ }
2766
+ if (a.kind === "sym") return isDataSymbol(env, a.name) ? impConst(a) : void 0;
2767
+ if (a.kind === "gnd") return impConst(a);
2768
+ if (a.items.length === 0) return impConst(a);
2769
+ const head = a.items[0];
2770
+ if (head.kind === "var") return void 0;
2771
+ if (head.kind === "sym" && !isDataSymbol(env, head.name)) return void 0;
2772
+ const items = a.items.map((it) => compileImpStaticAtom(env, it, scope));
2773
+ if (items.some((it) => it === void 0)) return void 0;
2774
+ const parts = items;
2775
+ return {
2776
+ node: (slots, st, ops) => {
2777
+ const out = [];
2778
+ let cur = st;
2779
+ for (const part of parts) {
2780
+ const r = part.node(slots, cur, ops);
2781
+ if (r === BAIL) return BAIL;
2782
+ out.push(r.value);
2783
+ cur = r.st;
2784
+ }
2785
+ return { value: expr(out), st: cur };
2786
+ },
2787
+ ...impMeta(parts)
2788
+ };
2789
+ }
2790
+ function compileImpGrounded(env, op, args, scope, holders) {
2791
+ if (env.ruleIndex.has(op)) return void 0;
2792
+ const parts = args.map((arg) => compileImpAtom(env, arg, scope, holders));
2793
+ if (parts.some((part) => part === void 0)) return void 0;
2794
+ const compiled = parts;
2795
+ return {
2796
+ node: (slots, st, ops) => {
2797
+ const vals = [];
2798
+ let cur = st;
2799
+ for (const part of compiled) {
2800
+ const r = part.node(slots, cur, ops);
2801
+ if (r === BAIL) return BAIL;
2802
+ vals.push(r.value);
2803
+ cur = r.st;
2804
+ }
2805
+ const gr = callGrounded(env.gt, op, vals);
2806
+ return gr.tag === "ok" && gr.results.length === 1 ? { value: gr.results[0], st: cur } : BAIL;
2807
+ },
2808
+ ...impMeta(compiled)
2809
+ };
2810
+ }
2811
+ function compileImpIf(env, args, scope, holders) {
2812
+ if (args.length !== 3 || (env.ruleIndex.get("if")?.length ?? 0) !== 2) return void 0;
2813
+ const cond = compileImpAtom(env, args[0], scope, holders);
2814
+ const then_ = compileImpAtom(env, args[1], scope, holders);
2815
+ const els = compileImpAtom(env, args[2], scope, holders);
2816
+ if (cond === void 0 || then_ === void 0 || els === void 0) return void 0;
2817
+ return {
2818
+ node: (slots, st, ops, discard) => {
2819
+ const c = cond.node(slots, st, ops);
2820
+ if (c === BAIL) return BAIL;
2821
+ const stIf = addCounter(c.st, 2);
2822
+ if (c.value.kind !== "gnd" || c.value.value.g !== "bool") return BAIL;
2823
+ return (c.value.value.b ? then_ : els).node(slots, stIf, ops, discard);
2824
+ },
2825
+ ...impMeta([cond, then_, els])
2826
+ };
2827
+ }
2828
+ function compileImpLet(env, args, scope, holders) {
2829
+ if (args.length !== 3 || args[0].kind !== "var" || (env.ruleIndex.get("let")?.length ?? 0) !== 1)
2830
+ return void 0;
2831
+ const value = compileImpAtom(env, args[1], scope, holders);
2832
+ if (value === void 0) return void 0;
2833
+ const slot = scope.len;
2834
+ const nextScope = {
2835
+ vars: new Map(scope.vars).set(args[0].name, slot),
2836
+ len: slot + 1
2837
+ };
2838
+ const body = compileImpAtom(env, args[2], nextScope, holders);
2839
+ if (body === void 0) return void 0;
2840
+ return {
2841
+ node: (slots, st, ops, discard) => {
2842
+ const v = value.node(slots, st, ops);
2843
+ if (v === BAIL) return BAIL;
2844
+ const local = slots.slice();
2845
+ local[slot] = v.value;
2846
+ return body.node(local, addCounter(v.st, 1), ops, discard);
2847
+ },
2848
+ ...impMeta([value, body])
2849
+ };
2850
+ }
2851
+ function compileImpLetStar(env, args, scope, holders) {
2852
+ if (args.length !== 2 || args[0].kind !== "expr" || (env.ruleIndex.get("let*")?.length ?? 0) !== 1 || (env.ruleIndex.get("let")?.length ?? 0) !== 1)
2853
+ return void 0;
2854
+ let curScope = scope;
2855
+ const bindings = [];
2856
+ for (const pair of args[0].items) {
2857
+ if (pair.kind !== "expr" || pair.items.length !== 2 || pair.items[0].kind !== "var")
2858
+ return void 0;
2859
+ const value = compileImpAtom(env, pair.items[1], curScope, holders);
2860
+ if (value === void 0) return void 0;
2861
+ const slot = curScope.len;
2862
+ bindings.push({ slot, value });
2863
+ curScope = {
2864
+ vars: new Map(curScope.vars).set(pair.items[0].name, slot),
2865
+ len: slot + 1
2866
+ };
2867
+ }
2868
+ const body = compileImpAtom(env, args[1], curScope, holders);
2869
+ if (body === void 0) return void 0;
2870
+ const parts = [...bindings.map((b) => b.value), body];
2871
+ return {
2872
+ node: (slots, st, ops, discard) => {
2873
+ const local = slots.slice();
2874
+ let cur = addCounter(st, 1);
2875
+ for (const binding of bindings) {
2876
+ const v = binding.value.node(local, cur, ops);
2877
+ if (v === BAIL) return BAIL;
2878
+ local[binding.slot] = v.value;
2879
+ cur = addCounter(addCounter(v.st, 1), 1);
2880
+ }
2881
+ return body.node(local, cur, ops, discard);
2882
+ },
2883
+ ...impMeta(parts)
2884
+ };
2885
+ }
2886
+ function compileImpAddAtom(env, args, scope) {
2887
+ if (args.length !== 2 || args[0].kind !== "sym") return void 0;
2888
+ const added = args[1];
2889
+ if (added.kind !== "expr" || added.items.length === 0 || added.items[0].kind !== "sym" || added.items[0].name === "=")
2890
+ return void 0;
2891
+ const space = compileImpStaticAtom(env, args[0], scope);
2892
+ const atom = compileImpStaticAtom(env, added, scope);
2893
+ if (space === void 0 || atom === void 0) return void 0;
2894
+ return {
2895
+ node: (slots, st, ops) => {
2896
+ const s = space.node(slots, st, ops);
2897
+ if (s === BAIL) return BAIL;
2898
+ const a = atom.node(slots, s.st, ops);
2899
+ if (a === BAIL) return BAIL;
2900
+ const st2 = ops.addAtom(env, a.st, s.value, a.value);
2901
+ return st2 === void 0 ? BAIL : { value: emptyExpr, st: st2 };
2902
+ },
2903
+ directEffect: true,
2904
+ callees: /* @__PURE__ */ new Set()
2905
+ };
2906
+ }
2907
+ function compileImpCall(env, op, args, scope, holders) {
2908
+ const h = holders.get(op);
2909
+ if (h === void 0 || args.length !== h.arity) return void 0;
2910
+ const compiledArgs = args.map((arg) => compileImpAtom(env, arg, scope, holders));
2911
+ if (compiledArgs.some((arg) => arg === void 0)) return void 0;
2912
+ const parts = compiledArgs;
2913
+ const meta = impMeta(parts);
2914
+ return {
2915
+ node: (slots, st, ops, discard) => {
2916
+ const vals = [];
2917
+ let cur = st;
2918
+ for (const part of parts) {
2919
+ const r = part.node(slots, cur, ops);
2920
+ if (r === BAIL) return BAIL;
2921
+ vals.push(r.value);
2922
+ cur = r.st;
2923
+ }
2924
+ return h.run(vals, cur, ops, discard);
2925
+ },
2926
+ directEffect: meta.directEffect,
2927
+ callees: /* @__PURE__ */ new Set([...meta.callees, op])
2928
+ };
2929
+ }
2930
+ function compileImpTuple(env, items, scope, holders) {
2931
+ const parts = items.map((it) => compileImpAtom(env, it, scope, holders));
2932
+ if (parts.some((part) => part === void 0)) return void 0;
2933
+ const compiled = parts;
2934
+ return {
2935
+ node: (slots, st, ops, discard) => {
2936
+ let cur = st;
2937
+ if (discard === true) {
2938
+ for (const part of compiled) {
2939
+ const r = part.node(slots, cur, ops, true);
2940
+ if (r === BAIL) return BAIL;
2941
+ cur = r.st;
2942
+ }
2943
+ return { value: emptyExpr, st: cur };
2944
+ }
2945
+ const out = [];
2946
+ for (const part of compiled) {
2947
+ const r = part.node(slots, cur, ops);
2948
+ if (r === BAIL) return BAIL;
2949
+ out.push(r.value);
2950
+ cur = r.st;
2951
+ }
2952
+ return { value: expr(out), st: cur };
2953
+ },
2954
+ ...impMeta(compiled)
2955
+ };
2956
+ }
2957
+ function compileImpAtom(env, a, scope, holders) {
2958
+ if (a.kind !== "expr" || a.items.length === 0) return compileImpStaticAtom(env, a, scope);
2959
+ const head = a.items[0];
2960
+ if (head.kind !== "sym") {
2961
+ if (head.kind === "var") return void 0;
2962
+ return compileImpTuple(env, a.items, scope, holders);
2963
+ }
2964
+ const op = head.name;
2965
+ const args = a.items.slice(1);
2966
+ if (op === "if") return compileImpIf(env, args, scope, holders);
2967
+ if (op === "let") return compileImpLet(env, args, scope, holders);
2968
+ if (op === "let*") return compileImpLetStar(env, args, scope, holders);
2969
+ if (op === "add-atom") return compileImpAddAtom(env, args, scope);
2970
+ if (IMP_GROUNDED.has(op)) return compileImpGrounded(env, op, args, scope, holders);
2971
+ const call = compileImpCall(env, op, args, scope, holders);
2972
+ if (call !== void 0) return call;
2973
+ return compileImpStaticAtom(env, a, scope);
2974
+ }
2975
+ function buildImpScope(params) {
2976
+ const vars = /* @__PURE__ */ new Map();
2977
+ for (let i = 0; i < params.length; i++) {
2978
+ const p = params[i];
2979
+ if (typeof p !== "string") return void 0;
2980
+ vars.set(p, i);
2981
+ }
2982
+ return { vars, len: params.length };
2983
+ }
2984
+ function compileImperative(env, compiled) {
2985
+ if (env.varRulesVar.length !== 0) return;
2986
+ const cand = /* @__PURE__ */ new Map();
2987
+ for (const f of env.ruleIndex.keys()) {
2988
+ if (compiled.has(f)) continue;
2989
+ const h = singleClauseHead(env, f);
2990
+ if (h !== void 0 && h.params.every((p) => typeof p === "string")) cand.set(f, h);
2991
+ }
2992
+ const holders = /* @__PURE__ */ new Map();
2993
+ for (const [f, { params }] of cand)
2994
+ holders.set(f, { kind: "imperative", arity: params.length, clauseCount: 1, run: impBail });
2995
+ for (; ; ) {
2996
+ let removed = false;
2997
+ const bodies = /* @__PURE__ */ new Map();
2998
+ for (const [f, h] of [...holders]) {
2999
+ const cd = cand.get(f);
3000
+ const scope = buildImpScope(cd.params);
3001
+ const body = scope === void 0 ? void 0 : compileImpAtom(env, cd.body, scope, holders);
3002
+ if (body === void 0) {
3003
+ holders.delete(f);
3004
+ removed = true;
3005
+ } else {
3006
+ bodies.set(f, body);
3007
+ h.arity = cd.params.length;
3008
+ }
3009
+ }
3010
+ if (removed) continue;
3011
+ const effectful = /* @__PURE__ */ new Set();
3012
+ for (const [f, body] of bodies) if (body.directEffect) effectful.add(f);
3013
+ for (let changed = true; changed; ) {
3014
+ changed = false;
3015
+ for (const [f, body] of bodies) {
3016
+ if (effectful.has(f)) continue;
3017
+ for (const callee of body.callees)
3018
+ if (effectful.has(callee)) {
3019
+ effectful.add(f);
3020
+ changed = true;
3021
+ break;
3022
+ }
3023
+ }
3024
+ }
3025
+ for (const f of [...holders.keys()])
3026
+ if (!effectful.has(f)) {
3027
+ holders.delete(f);
3028
+ removed = true;
3029
+ }
3030
+ if (removed) continue;
3031
+ for (const [f, body] of bodies) {
3032
+ const arity = cand.get(f).params.length;
3033
+ holders.get(f).run = (partAtoms, st, ops, discard) => {
3034
+ if (partAtoms.length !== arity || partAtoms.some((a) => !a.ground)) return BAIL;
3035
+ try {
3036
+ return body.node(partAtoms, addCounter(st, 1), ops, discard);
3037
+ } catch (e) {
3038
+ if (e === BAIL) return BAIL;
3039
+ throw e;
3040
+ }
3041
+ };
3042
+ }
3043
+ for (const [f, h] of holders) compiled.set(f, h);
3044
+ return;
3045
+ }
3046
+ }
3047
+ function compileEnv(env) {
3048
+ const pure = env.pureFunctors ?? /* @__PURE__ */ new Set();
3049
+ const cand = /* @__PURE__ */ new Map();
3050
+ for (const f of pure) {
3051
+ const h = singleClauseHead(env, f);
3052
+ if (h !== void 0) cand.set(f, h);
3053
+ }
1828
3054
  const holders = /* @__PURE__ */ new Map();
1829
3055
  for (const [f, { params }] of cand)
1830
3056
  holders.set(f, {
3057
+ kind: "functional",
1831
3058
  arity: params.length,
1832
3059
  retType: void 0,
1833
3060
  paramTypes: paramTypesOf(params),
@@ -1873,13 +3100,32 @@ function compileEnv(env) {
1873
3100
  if (!removed) {
1874
3101
  for (const [f, { node, arity }] of result)
1875
3102
  holders.get(f).run = makeRun(arity, node, selfCallCount(cand.get(f).body, f) >= 2);
1876
- return holders;
3103
+ const compiled = new Map(holders);
3104
+ for (const f of pure) {
3105
+ if (compiled.has(f)) continue;
3106
+ const rewrite = compileRewrite(env, f);
3107
+ if (rewrite !== void 0) {
3108
+ compiled.set(f, rewrite);
3109
+ continue;
3110
+ }
3111
+ const symbolic = compileSymbolic(env, f);
3112
+ if (symbolic !== void 0) compiled.set(f, symbolic);
3113
+ }
3114
+ compileImperative(env, compiled);
3115
+ return compiled;
1877
3116
  }
1878
3117
  }
1879
3118
  }
1880
- function runCompiled(env, op, partAtoms) {
3119
+ function runCompiled(env, op, partAtoms, st, ops, discard) {
1881
3120
  const h = env.compiled?.get(op);
1882
3121
  if (h === void 0 || partAtoms.length !== h.arity) return void 0;
3122
+ if (h.kind === "rewrite") return h.run(partAtoms);
3123
+ if (h.kind === "symbolic") return h.run(partAtoms, st.counter);
3124
+ if (h.kind === "imperative") {
3125
+ if (ops === void 0) return void 0;
3126
+ const r = h.run(partAtoms, st, ops, discard);
3127
+ return r === BAIL ? void 0 : { results: [{ atom: r.value, bnd: emptyBindings }], counterDelta: 0, state: r.st };
3128
+ }
1883
3129
  const vals = [];
1884
3130
  for (const a of partAtoms) {
1885
3131
  if (a.kind === "gnd" && a.value.g === "int") vals.push(a.value.n);
@@ -1889,9 +3135,8 @@ function runCompiled(env, op, partAtoms) {
1889
3135
  }
1890
3136
  try {
1891
3137
  const r = h.run(vals);
1892
- if (typeof r === "boolean") return gbool(r);
1893
- if (r instanceof Tup) return expr(r.v.map((n) => gint(n)));
1894
- return gint(r);
3138
+ const atom = typeof r === "boolean" ? gbool(r) : r instanceof Tup ? expr(r.v.map((n) => gint(n))) : gint(r);
3139
+ return { results: [{ atom, bnd: emptyBindings }], counterDelta: 0 };
1895
3140
  } catch (e) {
1896
3141
  if (e === BAIL || e instanceof RangeError) return void 0;
1897
3142
  throw e;
@@ -1899,6 +3144,18 @@ function runCompiled(env, op, partAtoms) {
1899
3144
  }
1900
3145
 
1901
3146
  // src/eval.ts
3147
+ var CTOR_SC = process.env.METTA_CTOR_SC !== "0";
3148
+ var STREAM_CASE = process.env.METTA_STREAM_CASE !== "0";
3149
+ function exactCandidateSource(atom, count, total) {
3150
+ return {
3151
+ counterPadding: total - count,
3152
+ *[Symbol.iterator]() {
3153
+ for (let i = 0; i < count; i++) yield atom;
3154
+ }
3155
+ };
3156
+ }
3157
+ var candidateCounterPadding = (source) => source.counterPadding ?? 0;
3158
+ var syntheticCandidateSource = (source) => Object.prototype.hasOwnProperty.call(source, "counterPadding");
1902
3159
  var LAZY_ARGS_OPS = /* @__PURE__ */ new Set(["par", "race", "once", "with-mutex"]);
1903
3160
  var AsyncInSyncError = class extends Error {
1904
3161
  constructor(op) {
@@ -1933,6 +3190,9 @@ function* callGroundedG(env, op, args) {
1933
3190
  return callGrounded(env.gt, op, args);
1934
3191
  }
1935
3192
  var cons = (head, tail) => ({ head, tail });
3193
+ function isItemSource(work) {
3194
+ return !Array.isArray(work);
3195
+ }
1936
3196
  var frame = (atom, ret = "none", vars = [], fin = false) => ({
1937
3197
  atom,
1938
3198
  ret,
@@ -1943,13 +3203,15 @@ var notReducibleA = sym("NotReducible");
1943
3203
  var emptyA = sym("Empty");
1944
3204
  var unitA = emptyExpr;
1945
3205
  var errAtom = (a, msg) => expr([sym("Error"), a, sym(msg)]);
3206
+ var makeExpr = (_env, items) => expr(items);
3207
+ var inst = (env, b, a, suffix = "") => instantiate(b, a, suffix, env.intern);
1946
3208
  function opOf(a) {
1947
3209
  return a.kind === "expr" && a.items.length > 0 && a.items[0].kind === "sym" ? a.items[0].name : void 0;
1948
3210
  }
1949
3211
  function tryParHyperpose(env, world, bnd, arg, firstOnly) {
1950
3212
  if (env.parEval === void 0) return void 0;
1951
3213
  if (world.selfRules.size > 0) return void 0;
1952
- const a = instantiate(bnd, arg);
3214
+ const a = inst(env, bnd, arg);
1953
3215
  if (a.kind !== "expr" || opOf(a) !== "hyperpose" || a.items.length !== 2) return void 0;
1954
3216
  const tup = a.items[1];
1955
3217
  if (tup.kind !== "expr" || tup.items.length === 0) return void 0;
@@ -2018,6 +3280,40 @@ function headKey(a) {
2018
3280
  return a.items[0].name;
2019
3281
  return void 0;
2020
3282
  }
3283
+ function isDefinedHead(env, w, name) {
3284
+ return env.ruleIndex.has(name) || env.sigs.has(name) || w.selfRules.has(name) || env.gt.has(name) || IMPURE_OPS.has(name);
3285
+ }
3286
+ function isNormalForm(env, w, t) {
3287
+ switch (t.kind) {
3288
+ case "var":
3289
+ case "gnd":
3290
+ return true;
3291
+ case "sym":
3292
+ return !isDefinedHead(env, w, t.name);
3293
+ case "expr": {
3294
+ const its = t.items;
3295
+ if (its.length === 0) return true;
3296
+ const h = its[0];
3297
+ if (h.kind !== "sym" || isDefinedHead(env, w, h.name)) return false;
3298
+ for (let i = 1; i < its.length; i++) if (!isNormalForm(env, w, its[i])) return false;
3299
+ return true;
3300
+ }
3301
+ }
3302
+ }
3303
+ function isNormalFormAssumingVars(env, w, t) {
3304
+ switch (t.kind) {
3305
+ case "var":
3306
+ return true;
3307
+ case "sym":
3308
+ case "gnd":
3309
+ return isNormalForm(env, w, t);
3310
+ case "expr": {
3311
+ if (t.items.length === 0) return true;
3312
+ const h = t.items[0];
3313
+ return h.kind === "sym" && !isDefinedHead(env, w, h.name) && t.items.every((x) => isNormalFormAssumingVars(env, w, x));
3314
+ }
3315
+ }
3316
+ }
2021
3317
  function atomToStack(a, prev) {
2022
3318
  if (a.kind === "expr") {
2023
3319
  const op = opOf(a);
@@ -2075,6 +3371,7 @@ function emptyEnv(gt) {
2075
3371
  return {
2076
3372
  ruleIndex: /* @__PURE__ */ new Map(),
2077
3373
  varRules: [],
3374
+ varRulesVar: [],
2078
3375
  sigs: /* @__PURE__ */ new Map(),
2079
3376
  gt,
2080
3377
  atoms: [],
@@ -2083,6 +3380,7 @@ function emptyEnv(gt) {
2083
3380
  exprTypes: [],
2084
3381
  agt: /* @__PURE__ */ new Map(),
2085
3382
  mutexes: /* @__PURE__ */ new Map(),
3383
+ evaluatedAtoms: /* @__PURE__ */ new WeakSet(),
2086
3384
  factIndex: /* @__PURE__ */ new Map(),
2087
3385
  argIndex: /* @__PURE__ */ new Map(),
2088
3386
  nonGroundAtPos: /* @__PURE__ */ new Map(),
@@ -2190,43 +3488,46 @@ function ensureCompiled(env) {
2190
3488
  }
2191
3489
  }
2192
3490
  function disableTabling(env) {
3491
+ env.evaluatedAtoms = /* @__PURE__ */ new WeakSet();
3492
+ env.compiled = void 0;
3493
+ env.compileDirty = void 0;
2193
3494
  if (env.table !== void 0) {
2194
3495
  env.table.clear();
2195
3496
  env.pureFunctors = /* @__PURE__ */ new Set();
2196
- if (env.compiled !== void 0) {
2197
- env.compiled = /* @__PURE__ */ new Map();
2198
- env.compileDirty = false;
2199
- }
2200
3497
  }
2201
3498
  }
2202
3499
  function addAtomToEnv(env, x) {
2203
- env.atoms.push(x);
2204
- const fk = headKey(x);
2205
- if (fk === void 0) env.varHeadedFacts.push(x);
3500
+ const atom = env.intern === void 0 ? x : internAtom(env.intern, x);
3501
+ env.atoms.push(atom);
3502
+ const fk = headKey(atom);
3503
+ if (fk === void 0) env.varHeadedFacts.push(atom);
2206
3504
  else {
2207
- pushTo(env.factIndex, fk, x);
2208
- if (x.kind === "expr")
2209
- for (let i = 1; i < x.items.length; i++) {
2210
- const ak = argKey(x.items[i]);
2211
- if (ak !== void 0) pushTo(env.argIndex, fk + KEY_SEP + i + KEY_SEP + ak, x);
2212
- else pushTo(env.nonGroundAtPos, fk + KEY_SEP + i, x);
3505
+ pushTo(env.factIndex, fk, atom);
3506
+ if (atom.kind === "expr")
3507
+ for (let i = 1; i < atom.items.length; i++) {
3508
+ const ak = argKey(atom.items[i]);
3509
+ if (ak !== void 0) pushTo(env.argIndex, fk + KEY_SEP + i + KEY_SEP + ak, atom);
3510
+ else pushTo(env.nonGroundAtPos, fk + KEY_SEP + i, atom);
2213
3511
  }
2214
3512
  }
2215
- if (opOf(x) === "=" && x.kind === "expr" && x.items.length === 3) {
2216
- const lhs = x.items[1];
2217
- const rhs = x.items[2];
3513
+ if (opOf(atom) === "=" && atom.kind === "expr" && atom.items.length === 3) {
3514
+ env.evaluatedAtoms = /* @__PURE__ */ new WeakSet();
3515
+ const lhs = atom.items[1];
3516
+ const rhs = atom.items[2];
2218
3517
  const k = headKey(lhs);
2219
- if (k === void 0) env.varRules.push([lhs, rhs]);
2220
- else {
3518
+ if (k === void 0) {
3519
+ env.varRules.push([lhs, rhs]);
3520
+ if (isVariableHeaded(lhs)) env.varRulesVar.push([lhs, rhs]);
3521
+ } else {
2221
3522
  const cur = env.ruleIndex.get(k);
2222
3523
  if (cur === void 0) env.ruleIndex.set(k, [[lhs, rhs]]);
2223
3524
  else cur.push([lhs, rhs]);
2224
3525
  }
2225
3526
  invalidateTabling(env);
2226
3527
  }
2227
- if (x.kind === "expr" && opOf(x) === ":" && x.items.length === 3) {
2228
- const subj = x.items[1];
2229
- const t = x.items[2];
3528
+ if (atom.kind === "expr" && opOf(atom) === ":" && atom.items.length === 3) {
3529
+ const subj = atom.items[1];
3530
+ const t = atom.items[2];
2230
3531
  if (subj.kind === "sym") {
2231
3532
  if (opOf(t) === "->" && t.kind === "expr") env.sigs.set(subj.name, t.items.slice(1));
2232
3533
  env.types.set(subj.name, [...env.types.get(subj.name) ?? [], t]);
@@ -2259,12 +3560,36 @@ function registerImportedTypes(env, atoms) {
2259
3560
  }
2260
3561
  }
2261
3562
  function selfAtoms(env, w) {
2262
- return logSize(w.selfExtra) === 0 ? env.atoms : [...env.atoms, ...logToArray(w.selfExtra)];
3563
+ const runtime = runtimeAtoms(w);
3564
+ return runtime.length === 0 ? env.atoms : [...env.atoms, ...runtime];
3565
+ }
3566
+ function runtimeAtoms(w) {
3567
+ const flat = w.flatSelfExtra?.toArray() ?? [];
3568
+ const log = logToArray(w.selfExtra);
3569
+ if (flat.length === 0) return log;
3570
+ if (log.length === 0) return flat;
3571
+ return [...flat, ...log];
2263
3572
  }
2264
3573
  function candidates(env, toEval) {
2265
3574
  const k = headKey(toEval);
3575
+ if (k === void 0 && toEval.kind === "expr" && toEval.items.length > 0)
3576
+ return [...env.varRules];
2266
3577
  const keyed = k !== void 0 ? env.ruleIndex.get(k) ?? [] : [];
2267
- return [...keyed, ...env.varRules];
3578
+ return env.varRulesVar.length === 0 ? keyed : [...keyed, ...env.varRulesVar];
3579
+ }
3580
+ function namedSpaceAtoms(space) {
3581
+ return logToArray(space ?? emptyLog);
3582
+ }
3583
+ function namedSpaceCandidateGetter(w, space) {
3584
+ let scan;
3585
+ return (pInst) => {
3586
+ const log = space ?? emptyLog;
3587
+ if (pInst.ground && logNonGround(log) === 0 && w.store.size === 0) {
3588
+ return exactCandidateSource(pInst, idxCount(logGroundIdx(log), pInst), logSize(log));
3589
+ }
3590
+ scan ??= namedSpaceAtoms(space).map((x) => resolveStates(w, x));
3591
+ return scan;
3592
+ };
2268
3593
  }
2269
3594
  var initSt = () => ({
2270
3595
  counter: 0,
@@ -2273,6 +3598,7 @@ var initSt = () => ({
2273
3598
  store: /* @__PURE__ */ new Map(),
2274
3599
  tokens: /* @__PURE__ */ new Map(),
2275
3600
  selfExtra: emptyLog,
3601
+ flatSelfExtra: void 0,
2276
3602
  selfRules: /* @__PURE__ */ new Map(),
2277
3603
  selfVarRules: [],
2278
3604
  maxStackDepth: 0
@@ -2284,6 +3610,7 @@ function cloneWorld(w) {
2284
3610
  store: new Map(w.store),
2285
3611
  tokens: new Map(w.tokens),
2286
3612
  selfExtra: w.selfExtra,
3613
+ flatSelfExtra: w.flatSelfExtra,
2287
3614
  selfRules: new Map(w.selfRules),
2288
3615
  selfVarRules: w.selfVarRules,
2289
3616
  maxStackDepth: w.maxStackDepth
@@ -2309,27 +3636,32 @@ function applyAtomDelta(into, added, removed) {
2309
3636
  return out;
2310
3637
  }
2311
3638
  function mergeWorlds(base, branches) {
2312
- const baseSelf = logToArray(base.selfExtra);
3639
+ const baseSelf = runtimeAtoms(base);
2313
3640
  let selfExtra = baseSelf.slice();
2314
3641
  const spaces = new Map(base.spaces);
2315
3642
  const store = new Map(base.store);
2316
3643
  const tokens = new Map(base.tokens);
2317
3644
  for (const w of branches) {
2318
- const d = multisetDelta(baseSelf, logToArray(w.selfExtra));
3645
+ const d = multisetDelta(baseSelf, runtimeAtoms(w));
2319
3646
  selfExtra = applyAtomDelta(selfExtra, d.added, d.removed);
2320
3647
  for (const [k, v] of w.spaces) {
2321
- const baseV = base.spaces.get(k) ?? [];
2322
- const sd = multisetDelta(baseV, v);
2323
- spaces.set(k, applyAtomDelta(spaces.get(k) ?? baseV.slice(), sd.added, sd.removed));
3648
+ const baseV = namedSpaceAtoms(base.spaces.get(k));
3649
+ const sd = multisetDelta(baseV, namedSpaceAtoms(v));
3650
+ spaces.set(
3651
+ k,
3652
+ logFromArray(applyAtomDelta(namedSpaceAtoms(spaces.get(k)), sd.added, sd.removed))
3653
+ );
2324
3654
  }
2325
3655
  for (const [k, v] of w.store) if (!Object.is(base.store.get(k), v)) store.set(k, v);
2326
3656
  for (const [k, v] of w.tokens) if (!Object.is(base.tokens.get(k), v)) tokens.set(k, v);
2327
3657
  }
3658
+ const flat = base.flatSelfExtra === void 0 ? void 0 : FlatAtomSpace.fromAtoms(selfExtra);
2328
3659
  const merged = {
2329
3660
  spaces,
2330
3661
  store,
2331
3662
  tokens,
2332
- selfExtra: logFromArray(selfExtra),
3663
+ selfExtra: flat === void 0 ? logFromArray(selfExtra) : emptyLog,
3664
+ flatSelfExtra: flat,
2333
3665
  selfRules: /* @__PURE__ */ new Map(),
2334
3666
  selfVarRules: [],
2335
3667
  maxStackDepth: base.maxStackDepth
@@ -2379,10 +3711,13 @@ function resolveStates(w, a) {
2379
3711
  }
2380
3712
  return a;
2381
3713
  }
2382
- function subTokens(w, a) {
3714
+ function subTokens(w, a, intern) {
2383
3715
  if (w.tokens.size === 0) return a;
2384
3716
  if (a.kind === "sym") return w.tokens.get(a.name) ?? a;
2385
- if (a.kind === "expr") return expr(a.items.map((x) => subTokens(w, x)));
3717
+ if (a.kind === "expr") {
3718
+ const out = expr(a.items.map((x) => subTokens(w, x, intern)));
3719
+ return intern === void 0 ? out : internBuiltExpr(intern, out);
3720
+ }
2386
3721
  return a;
2387
3722
  }
2388
3723
  function wrapStates(w, a) {
@@ -2399,7 +3734,7 @@ function wrapStates(w, a) {
2399
3734
  }
2400
3735
  return a;
2401
3736
  }
2402
- var typePrep = (w, a) => wrapStates(w, subTokens(w, a));
3737
+ var typePrep = (env, w, a) => wrapStates(w, subTokens(w, a, env.intern));
2403
3738
  function candidatesW(env, w, toEval) {
2404
3739
  const k2 = headKey(toEval);
2405
3740
  const headRules = k2 !== void 0 ? w.selfRules.get(k2) ?? [] : [];
@@ -2407,7 +3742,12 @@ function candidatesW(env, w, toEval) {
2407
3742
  }
2408
3743
  var ruleVarsCache = /* @__PURE__ */ new WeakMap();
2409
3744
  function ruleVars(lhs, rhs) {
2410
- let vs = ruleVarsCache.get(lhs);
3745
+ let rhsCache = ruleVarsCache.get(lhs);
3746
+ if (rhsCache === void 0) {
3747
+ rhsCache = /* @__PURE__ */ new WeakMap();
3748
+ ruleVarsCache.set(lhs, rhsCache);
3749
+ }
3750
+ let vs = rhsCache.get(rhs);
2411
3751
  if (vs === void 0) {
2412
3752
  vs = atomVars(lhs);
2413
3753
  const seen = new Set(vs);
@@ -2416,11 +3756,12 @@ function ruleVars(lhs, rhs) {
2416
3756
  seen.add(v);
2417
3757
  vs.push(v);
2418
3758
  }
2419
- ruleVarsCache.set(lhs, vs);
3759
+ rhsCache.set(rhs, vs);
2420
3760
  }
2421
3761
  return vs;
2422
3762
  }
2423
3763
  function freshenSub(counter, lhs, rhs) {
3764
+ if (lhs.ground && rhs.ground) return [];
2424
3765
  const vs = ruleVars(lhs, rhs);
2425
3766
  return vs.length === 0 ? [] : vs.map((v) => [v, variable(v + "#" + String(counter))]);
2426
3767
  }
@@ -2449,7 +3790,7 @@ function queryOp(env, st, prev, toEval, b) {
2449
3790
  counter += 1;
2450
3791
  for (const mb of matchAtomsScoped(lhs0, toEval, suffix)) {
2451
3792
  for (const m of merge(b, mb)) {
2452
- if (!hasLoop(m)) out.push(evalResult(prev, instantiate(m, rhs0, suffix), m));
3793
+ if (!hasLoop(m)) out.push(evalResult(prev, inst(env, m, rhs0, suffix), m));
2453
3794
  }
2454
3795
  }
2455
3796
  }
@@ -2465,11 +3806,28 @@ function hasRuleFor(env, w, counter, a) {
2465
3806
  return false;
2466
3807
  }
2467
3808
  function* evalOpG(env, st, prev, x, b) {
2468
- const x2 = instantiate(b, x);
3809
+ const x2 = inst(env, b, x);
2469
3810
  const op = opOf(x2);
3811
+ if (op === "collapse" && x2.kind === "expr" && x2.items.length === 2) {
3812
+ const match = matchInsideOnce(x2.items[1]);
3813
+ if (match !== void 0) {
3814
+ const namedMatch = tryFastNamedOnceMatch(env, st, match, b);
3815
+ if (namedMatch !== void 0) {
3816
+ const items = namedMatch.value === void 0 ? [] : [namedMatch.value];
3817
+ return [[evalResult(prev, expr(items), b)], namedMatch.state];
3818
+ }
3819
+ }
3820
+ }
3821
+ if (op === "if" && x2.kind === "expr" && x2.items.length === 4) {
3822
+ const added = tryFastNamedAddIfAbsent(env, st, x2, b);
3823
+ if (added !== void 0) {
3824
+ const out = added.added ? [finItem(prev, emptyExpr, b)] : [];
3825
+ return [out, added.state];
3826
+ }
3827
+ }
2470
3828
  const useGrounded = op !== void 0 && x2.kind === "expr" && !(pettaOpNames.has(op) && hasRuleFor(env, st.world, st.counter, x2));
2471
3829
  if (useGrounded) {
2472
- const args = x2.items.slice(1).map((a) => resolveStates(st.world, subTokens(st.world, a)));
3830
+ const args = x2.items.slice(1).map((a) => resolveStates(st.world, subTokens(st.world, a, env.intern)));
2473
3831
  const r = yield* callGroundedG(env, op, args);
2474
3832
  if (r.tag === "ok") return [r.results.map((res) => evalResult(prev, res, b)), st];
2475
3833
  if (r.tag === "runtimeError") return [[finItem(prev, errAtom(x2, r.msg), b)], st];
@@ -2478,7 +3836,7 @@ function* evalOpG(env, st, prev, x, b) {
2478
3836
  if (x2.kind === "expr" && x2.items.length > 0) {
2479
3837
  const head = x2.items[0];
2480
3838
  if (head.kind === "gnd" && head.exec !== void 0) {
2481
- const args = x2.items.slice(1).map((a) => resolveStates(st.world, subTokens(st.world, a)));
3839
+ const args = x2.items.slice(1).map((a) => resolveStates(st.world, subTokens(st.world, a, env.intern)));
2482
3840
  try {
2483
3841
  const results = head.exec(args);
2484
3842
  return [results.map((res) => evalResult(prev, res, b)), st];
@@ -2491,55 +3849,65 @@ function* evalOpG(env, st, prev, x, b) {
2491
3849
  if (isEmbeddedOp(x2)) return [[{ stack: atomToStack(x2, prev), bnd: b }], st];
2492
3850
  return queryOp(env, st, prev, x2, b);
2493
3851
  }
2494
- function unifyOp(prev, a, p, t, e, b) {
3852
+ function unifyOp(env, prev, a, p, t, e, b) {
2495
3853
  const ms = [];
2496
3854
  for (const mb of matchAtoms(a, p))
2497
- for (const m of merge(b, mb)) if (!hasLoop(m)) ms.push(finItem(prev, instantiate(m, t), m));
3855
+ for (const m of merge(b, mb)) if (!hasLoop(m)) ms.push(finItem(prev, inst(env, m, t), m));
2498
3856
  return ms.length === 0 ? [finItem(prev, e, b)] : ms;
2499
3857
  }
2500
3858
  var isFinal = (it) => it.stack !== null && it.stack.tail === null && it.stack.head.fin;
2501
- function finalPair(it) {
3859
+ function finalPair(env, it) {
2502
3860
  const f = it.stack;
2503
- return f === null ? [emptyA, []] : [instantiate(it.bnd, f.head.atom), it.bnd];
3861
+ return f === null ? [emptyA, []] : [inst(env, it.bnd, f.head.atom), it.bnd];
2504
3862
  }
2505
- function exhaustedPair(it) {
3863
+ function exhaustedPair(env, it) {
2506
3864
  const f = it.stack;
2507
- return f === null ? [emptyA, it.bnd] : [expr([sym("Error"), instantiate(it.bnd, f.head.atom), sym("StackOverflow")]), it.bnd];
3865
+ return f === null ? [emptyA, it.bnd] : [makeExpr(env, [sym("Error"), inst(env, it.bnd, f.head.atom), sym("StackOverflow")]), it.bnd];
2508
3866
  }
2509
- function resolveAtomFix(b, n, a) {
2510
- let cur = a;
2511
- for (let i = 0; i < n; i++) {
2512
- const next = instantiate(b, cur);
3867
+ function resolveBoundVarFix(env, b, n, x) {
3868
+ let cur = lookupVal(b, x);
3869
+ if (cur === void 0 || cur.ground) return cur;
3870
+ for (let i = 1; i < n; i++) {
3871
+ const next = inst(env, b, cur);
2513
3872
  if (atomEq(next, cur)) return cur;
2514
3873
  cur = next;
2515
3874
  }
2516
3875
  return cur;
2517
3876
  }
2518
- function restrictBnd(vars, b) {
3877
+ function restrictBnd(env, vars, b) {
3878
+ if (vars.length === 0) return emptyBindings;
2519
3879
  const solved = [];
2520
3880
  for (const x of vars) {
2521
- const v = resolveAtomFix(b, b.length + 1, variable(x));
2522
- if (!(v.kind === "var" && v.name === x)) solved.push({ tag: "val", x, a: v, y: void 0 });
3881
+ const v = resolveBoundVarFix(env, b, size(b) + 1, x);
3882
+ if (v !== void 0 && !(v.kind === "var" && v.name === x)) solved.push(makeValRel(x, v));
2523
3883
  }
2524
- if (!b.some((r) => r.tag === "eq")) return solved;
3884
+ if (!hasEq(b)) return fromRelations(solved);
2525
3885
  const vset = new Set(vars);
2526
- const eqs = b.filter((r) => r.tag === "eq" && vset.has(r.x) && vset.has(r.y));
2527
- return solved.length === 0 ? eqs : [...solved, ...eqs];
3886
+ const eqs = [];
3887
+ for (const r of eqRelations(b)) if (vset.has(r.x) && vset.has(r.y)) eqs.push(r);
3888
+ return fromRelations(solved.length === 0 ? eqs : [...solved, ...eqs]);
2528
3889
  }
2529
- function mergeRestrict(vars, baseB, pb) {
3890
+ function mergeRestrict(env, vars, baseB, pb) {
3891
+ if (vars.length === 0) return emptyBindings;
2530
3892
  const merged = merge(baseB, pb);
2531
- return restrictBnd(vars, merged.length > 0 ? merged[0] : pb);
3893
+ return restrictBnd(env, vars, merged.length > 0 ? merged[0] : pb);
3894
+ }
3895
+ function queryVarsOf(args) {
3896
+ const out = [];
3897
+ for (const a of args) if (!a.ground) out.push(...atomVars(a));
3898
+ return out;
2532
3899
  }
2533
- function scopeVars(b, prev) {
3900
+ function scopeVars(env, b, prev) {
2534
3901
  const out = [];
2535
3902
  const seen = /* @__PURE__ */ new Set();
2536
- for (let p = prev; p !== null; p = p.tail) collectVars(instantiate(b, p.head.atom), out, seen);
3903
+ for (let p = prev; p !== null; p = p.tail) collectVars(inst(env, b, p.head.atom), out, seen);
2537
3904
  return out;
2538
3905
  }
2539
- function frameVars(prev) {
3906
+ function chainLiveVars(cont, prev) {
2540
3907
  const out = [];
2541
3908
  const seen = /* @__PURE__ */ new Set();
2542
3909
  for (let p = prev; p !== null; p = p.tail) collectVars(p.head.atom, out, seen);
3910
+ collectVars(cont, out, seen);
2543
3911
  return out;
2544
3912
  }
2545
3913
  function superposeItem(prev, b, pair) {
@@ -2620,13 +3988,13 @@ function getTypesUncached(env, a) {
2620
3988
  const params = ts.slice(0, -1);
2621
3989
  let tb = [];
2622
3990
  for (let i = 0; i < params.length && i < argTs.length; i++) {
2623
- const m = matchAtoms(instantiate(tb, params[i]), argTs[i]);
3991
+ const m = matchAtoms(inst(env, tb, params[i]), argTs[i]);
2624
3992
  if (m.length > 0) {
2625
3993
  const merged = merge(tb, m[0]);
2626
3994
  if (merged.length > 0) tb = merged[0];
2627
3995
  }
2628
3996
  }
2629
- out.push(instantiate(tb, ret));
3997
+ out.push(inst(env, tb, ret));
2630
3998
  }
2631
3999
  }
2632
4000
  return out.length > 0 ? out : UNDEF_T;
@@ -2645,7 +4013,7 @@ function getTypesForQuery(env, a) {
2645
4013
  for (const combo of combos) for (const t of opts) next.push([...combo, t]);
2646
4014
  combos = next;
2647
4015
  }
2648
- return combos.map((c) => expr(c));
4016
+ return combos.map((c) => makeExpr(env, c));
2649
4017
  }
2650
4018
  function matchReduced(tb, expected, actual) {
2651
4019
  if (atomEq(expected, UNDEF) || atomEq(actual, UNDEF)) return tb;
@@ -2676,11 +4044,11 @@ function typeCheckArgs(env, w, argTypes, i, tb, argsLeft) {
2676
4044
  if (argsLeft.length === 0) return void 0;
2677
4045
  const ti0 = argTypes[i];
2678
4046
  if (ti0 === void 0) return void 0;
2679
- const ti = instantiate(tb, ti0);
4047
+ const ti = inst(env, tb, ti0);
2680
4048
  if (ti.kind === "sym" && (ti.name === "Atom" || ti.name === "%Undefined%"))
2681
4049
  return typeCheckArgs(env, w, argTypes, i + 1, tb, argsLeft.slice(1));
2682
4050
  const ai = argsLeft[0];
2683
- const prepped = typePrep(w, ai);
4051
+ const prepped = typePrep(env, w, ai);
2684
4052
  if (ti.kind === "sym" && ti.name === metaType(prepped))
2685
4053
  return typeCheckArgs(env, w, argTypes, i + 1, tb, argsLeft.slice(1));
2686
4054
  const actuals = getTypes(env, prepped);
@@ -2694,12 +4062,12 @@ function typeMismatch(env, w, op, args, ts = env.sigs.get(op)) {
2694
4062
  if (ts === void 0) return void 0;
2695
4063
  return typeCheckArgs(env, w, ts.slice(0, -1), 0, [], args);
2696
4064
  }
2697
- function matchCandidates(env, w, pInst) {
4065
+ function* matchCandidates(env, w, pInst) {
2698
4066
  const k = headKey(pInst);
2699
4067
  if (k === void 0) {
2700
- const extra2 = logToArray(w.selfExtra);
2701
- const all = extra2.length === 0 ? env.atoms.slice() : [...env.atoms, ...extra2];
2702
- return resolveAll(w, all);
4068
+ for (const atom of resolveAll(w, env.atoms.slice())) yield atom;
4069
+ yield* runtimeCandidates(w, void 0);
4070
+ return;
2703
4071
  }
2704
4072
  let bestKey;
2705
4073
  let bestPosKey;
@@ -2710,9 +4078,9 @@ function matchCandidates(env, w, pInst) {
2710
4078
  if (ak === void 0) continue;
2711
4079
  const ik = k + KEY_SEP + i + KEY_SEP + ak;
2712
4080
  const posKey = k + KEY_SEP + i;
2713
- const size = (env.argIndex.get(ik)?.length ?? 0) + (env.nonGroundAtPos.get(posKey)?.length ?? 0);
2714
- if (size < bestSize) {
2715
- bestSize = size;
4081
+ const size2 = (env.argIndex.get(ik)?.length ?? 0) + (env.nonGroundAtPos.get(posKey)?.length ?? 0);
4082
+ if (size2 < bestSize) {
4083
+ bestSize = size2;
2716
4084
  bestKey = ik;
2717
4085
  bestPosKey = posKey;
2718
4086
  }
@@ -2724,71 +4092,111 @@ function matchCandidates(env, w, pInst) {
2724
4092
  cands = (env.factIndex.get(k) ?? []).slice();
2725
4093
  }
2726
4094
  cands.push(...env.varHeadedFacts);
2727
- if (pInst.ground && logNonGround(w.selfExtra) === 0 && w.store.size === 0) {
4095
+ if (pInst.ground && logNonGround(w.selfExtra) === 0 && (w.flatSelfExtra?.nonGroundCount ?? 0) === 0 && w.store.size === 0) {
2728
4096
  const c = idxCount(logGroundIdx(w.selfExtra), pInst);
2729
- for (let i = 0; i < c; i++) cands.push(pInst);
2730
- return cands;
2731
- }
2732
- const extra = logToArray(w.selfExtra);
2733
- for (const a of extra) {
2734
- const akk = headKey(a);
2735
- if (akk === void 0 || akk === k) cands.push(a);
4097
+ for (const atom of cands) yield atom;
4098
+ const flatCount = w.flatSelfExtra?.exactCount(pInst) ?? 0;
4099
+ for (let i = 0; i < c + flatCount; i++) yield pInst;
4100
+ return;
2736
4101
  }
2737
- return resolveAll(w, cands);
4102
+ for (const atom of resolveAll(w, cands)) yield atom;
4103
+ yield* runtimeCandidates(w, k);
2738
4104
  }
2739
4105
  function resolveAll(w, atoms) {
2740
4106
  return w.store.size === 0 ? atoms : atoms.map((x) => resolveStates(w, x));
2741
4107
  }
2742
- function matchConj(getCandidates, patterns, st, sols) {
4108
+ function* runtimeCandidates(w, k) {
4109
+ if (w.flatSelfExtra !== void 0) {
4110
+ for (const a of w.flatSelfExtra.candidatesFor(k)) yield resolveStates(w, a);
4111
+ }
4112
+ for (const a of logToArray(w.selfExtra)) {
4113
+ if (k === void 0) yield resolveStates(w, a);
4114
+ else {
4115
+ const akk = headKey(a);
4116
+ if (akk === void 0 || akk === k) yield resolveStates(w, a);
4117
+ }
4118
+ }
4119
+ }
4120
+ function matchConj(env, getCandidates, patterns, st, sols) {
2743
4121
  let cur = sols;
2744
4122
  let counter = st.counter;
2745
4123
  for (const p of patterns) {
2746
4124
  const next = [];
2747
4125
  for (const b of cur) {
2748
- const pInst = instantiate(b, p);
2749
- for (const atom of getCandidates(pInst)) {
4126
+ const pInst = inst(env, b, p);
4127
+ const source = getCandidates(pInst);
4128
+ for (const atom of source) {
2750
4129
  const atom2 = freshenRule(counter, atom, atom)[0];
2751
4130
  counter += 1;
2752
4131
  for (const mb of matchAtoms(pInst, atom2))
2753
4132
  for (const m of merge(b, mb)) if (!hasLoop(m)) next.push(m);
2754
4133
  }
4134
+ counter += candidateCounterPadding(source);
2755
4135
  }
2756
4136
  cur = next;
2757
4137
  }
2758
4138
  return [cur, { counter, world: st.world }];
2759
4139
  }
2760
- function matchConjJoin(getCandidates, patterns, st, b0) {
4140
+ function splitConjGoals(env, getCandidates, patterns, st, b0, perPositionAdmit) {
2761
4141
  let counter = st.counter;
4142
+ const insts = patterns.map((p) => inst(env, b0, p));
4143
+ const pvarsList = insts.map((pInst) => atomVars(pInst));
4144
+ let joinVars;
4145
+ if (perPositionAdmit) {
4146
+ const seen = /* @__PURE__ */ new Set();
4147
+ const shared = /* @__PURE__ */ new Set();
4148
+ for (const pvars of pvarsList)
4149
+ for (const v of new Set(pvars)) (seen.has(v) ? shared : seen).add(v);
4150
+ joinVars = shared;
4151
+ }
2762
4152
  const groundRels = [];
2763
4153
  const otherPatterns = [];
2764
- for (const p of patterns) {
2765
- const pInst = instantiate(b0, p);
2766
- const pvars = atomVars(pInst);
4154
+ for (let i = 0; i < patterns.length; i++) {
4155
+ const p = patterns[i];
4156
+ const pvars = pvarsList[i];
2767
4157
  if (pvars.length === 0) {
2768
4158
  otherPatterns.push(p);
2769
4159
  continue;
2770
4160
  }
4161
+ const pInst = insts[i];
2771
4162
  const tuples = [];
2772
- let allGround = true;
2773
- for (const atom of getCandidates(pInst)) {
4163
+ let relational = true;
4164
+ const source = getCandidates(pInst);
4165
+ for (const atom of source) {
2774
4166
  const fresh = freshenRule(counter, atom, atom)[0];
2775
4167
  counter += 1;
2776
4168
  for (const mb of matchAtoms(pInst, fresh)) {
2777
4169
  const t = /* @__PURE__ */ new Map();
2778
4170
  for (const v of pvars) {
2779
- const val = instantiate(mb, variable(v));
4171
+ const val = lookupVal(mb, v) ?? variable(v);
2780
4172
  t.set(v, val);
2781
- if (!val.ground) allGround = false;
4173
+ if (!val.ground && (joinVars === void 0 || joinVars.has(v))) relational = false;
2782
4174
  }
2783
4175
  tuples.push(t);
2784
4176
  }
2785
4177
  }
2786
- if (allGround) groundRels.push({ vars: pvars, tuples });
4178
+ counter += candidateCounterPadding(source);
4179
+ if (relational) groundRels.push({ vars: pvars, tuples });
2787
4180
  else otherPatterns.push(p);
2788
4181
  }
2789
- let cur;
4182
+ return { groundRels, otherPatterns, counter };
4183
+ }
4184
+ function conjJoinPartials(env, getCandidates, patterns, st, b0) {
4185
+ const { groundRels, otherPatterns, counter } = splitConjGoals(
4186
+ env,
4187
+ getCandidates,
4188
+ patterns,
4189
+ st,
4190
+ b0,
4191
+ // Result path: admit schematic facts at non-join positions to the leapfrog only when the fast matcher is
4192
+ // on. The leapfrog reorders results and freshens differently, so an admitted schematic goal makes the
4193
+ // answer alpha-equivalent (not byte-identical) to the coupled path; the default (trail off) keeps the
4194
+ // conservative all-ground gate, so the byte-identical reference order holds and the oracle is unaffected.
4195
+ env.useTrail === true
4196
+ );
4197
+ let partials;
2790
4198
  if (groundRels.length > 0) {
2791
- cur = [];
4199
+ partials = [];
2792
4200
  for (const sol of wcoJoin(groundRels, mutexKey)) {
2793
4201
  let bs = [b0];
2794
4202
  for (const [v, val] of sol) {
@@ -2796,31 +4204,88 @@ function matchConjJoin(getCandidates, patterns, st, b0) {
2796
4204
  for (const b of bs) nb.push(...addVarBinding(b, v, val));
2797
4205
  bs = nb;
2798
4206
  }
2799
- for (const b of bs) if (!hasLoop(b)) cur.push(b);
4207
+ for (const b of bs) if (!hasLoop(b)) partials.push(b);
2800
4208
  }
2801
4209
  } else {
2802
- cur = [b0];
2803
- }
4210
+ partials = [b0];
4211
+ }
4212
+ return { partials, otherPatterns, counter };
4213
+ }
4214
+ function matchConjJoin(env, getCandidates, patterns, st, b0) {
4215
+ const {
4216
+ partials,
4217
+ otherPatterns,
4218
+ counter: c0
4219
+ } = conjJoinPartials(env, getCandidates, patterns, st, b0);
4220
+ let cur = partials;
4221
+ let counter = c0;
2804
4222
  for (const p of otherPatterns) {
2805
4223
  const next = [];
2806
4224
  const freshCache = /* @__PURE__ */ new Map();
2807
4225
  for (const b of cur) {
2808
- const pInst = instantiate(b, p);
2809
- for (const atom of getCandidates(pInst)) {
2810
- let fresh = freshCache.get(atom);
4226
+ const pInst = inst(env, b, p);
4227
+ const source = getCandidates(pInst);
4228
+ const cache3 = syntheticCandidateSource(source) ? void 0 : freshCache;
4229
+ for (const atom of source) {
4230
+ let fresh = cache3?.get(atom);
2811
4231
  if (fresh === void 0) {
2812
4232
  fresh = freshenRule(counter, atom, atom)[0];
2813
4233
  counter += 1;
2814
- freshCache.set(atom, fresh);
4234
+ cache3?.set(atom, fresh);
2815
4235
  }
2816
4236
  for (const mb of matchAtoms(pInst, fresh))
2817
4237
  for (const m of merge(b, mb)) if (!hasLoop(m)) next.push(m);
2818
4238
  }
4239
+ counter += candidateCounterPadding(source);
2819
4240
  }
2820
4241
  cur = next;
2821
4242
  }
2822
4243
  return [cur, { counter, world: st.world }];
2823
4244
  }
4245
+ function matchConjCount(env, getCandidates, patterns, st, b0) {
4246
+ const {
4247
+ groundRels,
4248
+ otherPatterns,
4249
+ counter: c0
4250
+ // Match the result path's admission gate (conjJoinPartials) so the fold and the materializing count split
4251
+ // goals identically and advance the gensym counter in lockstep: the conservative all-ground split by
4252
+ // default (byte-identical, the reference the corpus pins), the per-position unify-capable admission only
4253
+ // under experimental.trail (where the result path also admits, so both stay consistent).
4254
+ } = splitConjGoals(env, getCandidates, patterns, st, b0, env.useTrail === true);
4255
+ if (groundRels.length === 0) {
4256
+ for (const p of patterns) if (atomHasCustomGrounded(p)) return void 0;
4257
+ return countTrailDFS(seededTrail(b0), getCandidates, patterns, c0);
4258
+ }
4259
+ for (const p of otherPatterns) if (atomHasCustomGrounded(p)) return void 0;
4260
+ const tr = seededTrail(b0);
4261
+ const tailFreshCaches = otherPatterns.map(() => /* @__PURE__ */ new Map());
4262
+ let counter = c0;
4263
+ let count = 0;
4264
+ let bailed = false;
4265
+ const marks = [];
4266
+ wcoJoinFold(groundRels, mutexKey, {
4267
+ onDescend: (v, val) => {
4268
+ marks.push(tr.mark());
4269
+ tr.bind(v, val);
4270
+ },
4271
+ onAscend: () => tr.undo(marks.pop()),
4272
+ onLeaf: () => {
4273
+ if (bailed) return;
4274
+ if (otherPatterns.length === 0) {
4275
+ count += 1;
4276
+ return;
4277
+ }
4278
+ const tc = countTrailDFS(tr, getCandidates, otherPatterns, counter, tailFreshCaches);
4279
+ if (tc === void 0) {
4280
+ bailed = true;
4281
+ return;
4282
+ }
4283
+ count += tc.count;
4284
+ counter = tc.counter;
4285
+ }
4286
+ });
4287
+ return bailed ? void 0 : { count, counter };
4288
+ }
2824
4289
  function getDocOf(env, w, atom) {
2825
4290
  const atoms = selfAtoms(env, w);
2826
4291
  const ty = atom.kind === "sym" ? headOr(env.types.get(atom.name) ?? [], UNDEF) : env.exprTypes.find((p) => atomEq(p[0], atom))?.[1] ?? UNDEF;
@@ -2884,12 +4349,12 @@ function* interpretStack1G(env, fuel, st, it) {
2884
4349
  if (prev === null) return [[it], st];
2885
4350
  const pf = prev.head;
2886
4351
  const pprev = prev.tail;
2887
- const res = instantiate(it.bnd, top.atom);
4352
+ const res = inst(env, it.bnd, top.atom);
2888
4353
  if (pf.ret === "chain") {
2889
4354
  if (opOf(pf.atom) === "chain" && pf.atom.kind === "expr" && pf.atom.items.length === 4) {
2890
4355
  const v = pf.atom.items[2];
2891
4356
  const templ = pf.atom.items[3];
2892
- const nf = frame(expr([sym("chain"), res, v, templ]), pf.ret, pf.vars, false);
4357
+ const nf = frame(makeExpr(env, [sym("chain"), res, v, templ]), pf.ret, pf.vars, false);
2893
4358
  return [[{ stack: cons(nf, pprev), bnd: it.bnd }], st];
2894
4359
  }
2895
4360
  return [[finItem(pprev, errAtom(pf.atom, "chain: corrupt frame"), it.bnd)], st];
@@ -2918,23 +4383,24 @@ function* interpretStack1G(env, fuel, st, it) {
2918
4383
  if (it2.length === 4 && it2[2].kind === "var") {
2919
4384
  const v = it2[2].name;
2920
4385
  const cont = applySubst([[v, it2[1]]], it2[3]);
2921
- const bnd = restrictBnd(atomVars(cont, frameVars(prev)), it.bnd);
4386
+ const bnd = restrictBnd(env, chainLiveVars(cont, prev), it.bnd);
2922
4387
  return [[{ stack: atomToStack(cont, prev), bnd }], st];
2923
4388
  }
2924
4389
  break;
2925
4390
  case "unify":
2926
- if (it2.length === 5) return [unifyOp(prev, it2[1], it2[2], it2[3], it2[4], it.bnd), st];
4391
+ if (it2.length === 5)
4392
+ return [unifyOp(env, prev, it2[1], it2[2], it2[3], it2[4], it.bnd), st];
2927
4393
  break;
2928
4394
  case "cons-atom":
2929
4395
  if (it2.length === 3 && it2[2].kind === "expr")
2930
- return [[finItem(prev, expr([it2[1], ...it2[2].items]), it.bnd)], st];
4396
+ return [[finItem(prev, makeExpr(env, [it2[1], ...it2[2].items]), it.bnd)], st];
2931
4397
  if (it2.length === 3)
2932
4398
  return [[finItem(prev, errAtom(a, "cons-atom: expected expression tail"), it.bnd)], st];
2933
4399
  break;
2934
4400
  case "decons-atom":
2935
4401
  if (it2.length === 2 && it2[1].kind === "expr" && it2[1].items.length > 0) {
2936
4402
  const [h, ...t] = it2[1].items;
2937
- return [[finItem(prev, expr([h, expr(t)]), it.bnd)], st];
4403
+ return [[finItem(prev, makeExpr(env, [h, makeExpr(env, t)]), it.bnd)], st];
2938
4404
  }
2939
4405
  if (it2.length === 2)
2940
4406
  return [
@@ -2952,8 +4418,9 @@ function* interpretStack1G(env, fuel, st, it) {
2952
4418
  const [pairs, st2] = yield* mettaEvalG(env, fuel, st, it.bnd, atom);
2953
4419
  if (op === "metta-thread") {
2954
4420
  const out = [];
4421
+ const scoped = scopeVars(env, it.bnd, prev);
2955
4422
  for (const p of pairs)
2956
- for (const m of merge(it.bnd, restrictBnd(scopeVars(it.bnd, prev), p[1])))
4423
+ for (const m of merge(it.bnd, restrictBnd(env, scoped, p[1])))
2957
4424
  out.push(finItem(prev, p[0], m));
2958
4425
  return [out, st2];
2959
4426
  }
@@ -2963,22 +4430,25 @@ function* interpretStack1G(env, fuel, st, it) {
2963
4430
  case "get-type-space": {
2964
4431
  let typeEnv = env;
2965
4432
  if (op === "get-type-space") {
2966
- const sp = instantiate(it.bnd, it2[1]);
4433
+ const sp = inst(env, it.bnd, it2[1]);
2967
4434
  const sname = sp.kind === "sym" ? sp.name : void 0;
2968
4435
  if (sname !== void 0 && sname !== "&self") {
2969
- const sa = st.world.spaces.get(sname);
2970
- if (sa !== void 0 && sa.length > 0) typeEnv = buildEnv([...env.atoms, ...sa], env.gt);
4436
+ const sa = namedSpaceAtoms(st.world.spaces.get(sname));
4437
+ if (sa.length > 0) typeEnv = buildEnv([...env.atoms, ...sa], env.gt);
2971
4438
  }
2972
4439
  }
2973
4440
  const x = op === "get-type-space" ? it2[2] : it2[1];
2974
- return yield* getTypeOpG(typeEnv, fuel, st, prev, instantiate(it.bnd, x), it.bnd);
4441
+ return yield* getTypeOpG(typeEnv, fuel, st, prev, inst(typeEnv, it.bnd, x), it.bnd);
2975
4442
  }
2976
4443
  case "get-doc":
2977
4444
  if (it2.length === 2)
2978
- return [[finItem(prev, getDocOf(env, st.world, instantiate(it.bnd, it2[1])), it.bnd)], st];
4445
+ return [[finItem(prev, getDocOf(env, st.world, inst(env, it.bnd, it2[1])), it.bnd)], st];
2979
4446
  break;
2980
4447
  case "match":
2981
- if (it2.length === 4) return matchOp(env, st, prev, it2[1], it2[2], it2[3], it.bnd);
4448
+ if (it2.length === 4) {
4449
+ if (!STREAM_CASE) return matchOp(env, st, prev, it2[1], it2[2], it2[3], it.bnd);
4450
+ return [matchItemSource(env, st, prev, it2[1], it2[2], it2[3], it.bnd), st];
4451
+ }
2982
4452
  break;
2983
4453
  case "superpose-bind":
2984
4454
  if (it2.length === 2 && it2[1].kind === "expr")
@@ -2989,7 +4459,19 @@ function* interpretStack1G(env, fuel, st, it) {
2989
4459
  const [atoms, st2] = yield* interpretLoopG(env, fuel, st, [
2990
4460
  { stack: atomToStack(it2[1], null), bnd: it.bnd }
2991
4461
  ]);
2992
- return [[finItem(prev, expr(atoms.map((p) => expr([p[0], unitA]))), it.bnd)], st2];
4462
+ return [
4463
+ [
4464
+ finItem(
4465
+ prev,
4466
+ makeExpr(
4467
+ env,
4468
+ atoms.map((p) => makeExpr(env, [p[0], unitA]))
4469
+ ),
4470
+ it.bnd
4471
+ )
4472
+ ],
4473
+ st2
4474
+ ];
2993
4475
  }
2994
4476
  // TS-native extension. `(transaction <body>)` evaluates the body and atomically commits its
2995
4477
  // space mutations only if the body succeeds. Because the world is threaded copy-on-write
@@ -3050,13 +4532,18 @@ function* interpretStack1G(env, fuel, st, it) {
3050
4532
  const first2 = par.length > 0 ? [par[0]] : [];
3051
4533
  return [first2.map((a2) => finItem(prev, a2, it.bnd)), st];
3052
4534
  }
4535
+ const namedMatch = tryFastNamedOnceMatch(env, st, it2[1], it.bnd);
4536
+ if (namedMatch !== void 0) {
4537
+ const first2 = namedMatch.value === void 0 ? [] : [finItem(prev, namedMatch.value, it.bnd)];
4538
+ return [first2, namedMatch.state];
4539
+ }
3053
4540
  const [pairs, st2] = yield* mettaEvalG(env, fuel, st, it.bnd, it2[1]);
3054
4541
  const first = pairs.length > 0 ? [pairs[0]] : [];
3055
- return [first.map((p) => finItem(prev, p[0], it.bnd)), st2];
4542
+ return [first.map((p) => finItem(prev, p[0], p[1])), st2];
3056
4543
  }
3057
4544
  case "with-mutex": {
3058
4545
  if (it2.length !== 3) break;
3059
- const name = mutexKey(instantiate(it.bnd, it2[1]));
4546
+ const name = mutexKey(inst(env, it.bnd, it2[1]));
3060
4547
  const body = it2[2];
3061
4548
  pendingAsyncOp = "with-mutex";
3062
4549
  const result = yield (async () => {
@@ -3079,34 +4566,28 @@ function* interpretStack1G(env, fuel, st, it) {
3079
4566
  if (it2.length !== 2) break;
3080
4567
  const id = st.counter;
3081
4568
  const w = cloneWorld(st.world);
3082
- w.store.set(id, instantiate(it.bnd, it2[1]));
4569
+ w.store.set(id, inst(env, it.bnd, it2[1]));
3083
4570
  return [[finItem(prev, stateHandle(id), it.bnd)], { counter: id + 1, world: w }];
3084
4571
  }
3085
4572
  case "get-state": {
3086
4573
  if (it2.length !== 2) break;
3087
- const id = stateId(st.world, instantiate(it.bnd, it2[1]));
4574
+ const id = stateId(st.world, inst(env, it.bnd, it2[1]));
3088
4575
  if (id !== void 0) return [[finItem(prev, st.world.store.get(id) ?? emptyA, it.bnd)], st];
3089
4576
  return [
3090
- [finItem(prev, errAtom(instantiate(it.bnd, it2[1]), "get-state: not a state"), it.bnd)],
4577
+ [finItem(prev, errAtom(inst(env, it.bnd, it2[1]), "get-state: not a state"), it.bnd)],
3091
4578
  st
3092
4579
  ];
3093
4580
  }
3094
4581
  case "change-state!": {
3095
4582
  if (it2.length !== 3) break;
3096
- const id = stateId(st.world, instantiate(it.bnd, it2[1]));
4583
+ const id = stateId(st.world, inst(env, it.bnd, it2[1]));
3097
4584
  if (id !== void 0) {
3098
4585
  const w = cloneWorld(st.world);
3099
- w.store.set(id, instantiate(it.bnd, it2[2]));
4586
+ w.store.set(id, inst(env, it.bnd, it2[2]));
3100
4587
  return [[finItem(prev, stateHandle(id), it.bnd)], { counter: st.counter, world: w }];
3101
4588
  }
3102
4589
  return [
3103
- [
3104
- finItem(
3105
- prev,
3106
- errAtom(instantiate(it.bnd, it2[1]), "change-state!: not a state"),
3107
- it.bnd
3108
- )
3109
- ],
4590
+ [finItem(prev, errAtom(inst(env, it.bnd, it2[1]), "change-state!: not a state"), it.bnd)],
3110
4591
  st
3111
4592
  ];
3112
4593
  }
@@ -3115,57 +4596,65 @@ function* interpretStack1G(env, fuel, st, it) {
3115
4596
  const id = st.counter;
3116
4597
  const name = "&space-" + String(id);
3117
4598
  const w = cloneWorld(st.world);
3118
- w.spaces.set(name, []);
4599
+ w.spaces.set(name, emptyLog);
3119
4600
  return [[finItem(prev, sym(name), it.bnd)], { counter: id + 1, world: w }];
3120
4601
  }
3121
4602
  case "fork-space": {
3122
4603
  if (it2.length !== 2) break;
3123
- const src = spaceName(st.world, instantiate(it.bnd, it2[1]));
4604
+ const src = spaceName(st.world, inst(env, it.bnd, it2[1]));
3124
4605
  if (src === void 0)
3125
4606
  return [
3126
- [finItem(prev, errAtom(instantiate(it.bnd, it2[1]), "fork-space: not a space"), it.bnd)],
4607
+ [finItem(prev, errAtom(inst(env, it.bnd, it2[1]), "fork-space: not a space"), it.bnd)],
3127
4608
  st
3128
4609
  ];
3129
- const srcAtoms = src === "&self" ? selfAtoms(env, st.world) : st.world.spaces.get(src) ?? [];
4610
+ const srcAtoms = src === "&self" ? selfAtoms(env, st.world) : namedSpaceAtoms(st.world.spaces.get(src));
3130
4611
  const id = st.counter;
3131
4612
  const name = "&space-" + String(id);
3132
4613
  const w = cloneWorld(st.world);
3133
- w.spaces.set(name, [...srcAtoms]);
4614
+ w.spaces.set(name, logFromArray(srcAtoms));
3134
4615
  return [[finItem(prev, sym(name), it.bnd)], { counter: id + 1, world: w }];
3135
4616
  }
3136
4617
  case "add-atom":
3137
4618
  if (it2.length === 3) {
3138
- const added = instantiate(it.bnd, it2[2]);
4619
+ const added = inst(env, it.bnd, it2[2]);
3139
4620
  if (opOf(added) === "=") disableTabling(env);
3140
- return spaceMutate(st, prev, it2[1], it.bnd, (w, name) => appendSpace(w, name, [added]));
4621
+ return spaceMutate(
4622
+ env,
4623
+ st,
4624
+ prev,
4625
+ it2[1],
4626
+ it.bnd,
4627
+ (w, name) => appendSpace(env, w, name, [added])
4628
+ );
3141
4629
  }
3142
4630
  break;
3143
4631
  case "remove-atom":
3144
4632
  if (it2.length === 3)
3145
4633
  return spaceMutate(
4634
+ env,
3146
4635
  st,
3147
4636
  prev,
3148
4637
  it2[1],
3149
4638
  it.bnd,
3150
- (w, name) => eraseSpace(w, name, instantiate(it.bnd, it2[2]))
4639
+ (w, name) => eraseSpace(w, name, inst(env, it.bnd, it2[2]))
3151
4640
  );
3152
4641
  break;
3153
4642
  case "get-atoms": {
3154
4643
  if (it2.length !== 2) break;
3155
- const name = spaceName(st.world, instantiate(it.bnd, it2[1]));
4644
+ const name = spaceName(st.world, inst(env, it.bnd, it2[1]));
3156
4645
  if (name === void 0)
3157
4646
  return [
3158
- [finItem(prev, errAtom(instantiate(it.bnd, it2[1]), "get-atoms: not a space"), it.bnd)],
4647
+ [finItem(prev, errAtom(inst(env, it.bnd, it2[1]), "get-atoms: not a space"), it.bnd)],
3159
4648
  st
3160
4649
  ];
3161
- const list = name === "&self" ? selfAtoms(env, st.world) : st.world.spaces.get(name) ?? [];
4650
+ const list = name === "&self" ? selfAtoms(env, st.world) : namedSpaceAtoms(st.world.spaces.get(name));
3162
4651
  return [list.map((x) => finItem(prev, x, it.bnd)), st];
3163
4652
  }
3164
4653
  case "pragma!": {
3165
4654
  if (it2.length !== 3) break;
3166
- const key = instantiate(it.bnd, it2[1]);
4655
+ const key = inst(env, it.bnd, it2[1]);
3167
4656
  if (key.kind === "sym" && key.name === "max-stack-depth") {
3168
- const val = instantiate(it.bnd, it2[2]);
4657
+ const val = inst(env, it.bnd, it2[2]);
3169
4658
  const n = val.kind === "gnd" && val.value.g === "int" ? val.value.n : void 0;
3170
4659
  if (n === void 0 || n < 0 || typeof n === "number" && !Number.isInteger(n))
3171
4660
  return [[finItem(prev, errAtom(a, "UnsignedIntegerIsExpected"), it.bnd)], st];
@@ -3177,22 +4666,29 @@ function* interpretStack1G(env, fuel, st, it) {
3177
4666
  }
3178
4667
  case "bind!": {
3179
4668
  if (it2.length !== 3) break;
3180
- const tok2 = instantiate(it.bnd, it2[1]);
4669
+ const tok2 = inst(env, it.bnd, it2[1]);
3181
4670
  if (tok2.kind === "sym") {
3182
4671
  const w = cloneWorld(st.world);
3183
- w.tokens.set(tok2.name, instantiate(it.bnd, it2[2]));
4672
+ w.tokens.set(tok2.name, inst(env, it.bnd, it2[2]));
3184
4673
  return [[finItem(prev, emptyExpr, it.bnd)], { counter: st.counter, world: w }];
3185
4674
  }
3186
4675
  return [[finItem(prev, errAtom(tok2, "bind!: token must be a symbol"), it.bnd)], st];
3187
4676
  }
3188
4677
  case "import!": {
3189
4678
  if (it2.length !== 3) break;
3190
- const fileAtom = instantiate(it.bnd, it2[2]);
4679
+ const fileAtom = inst(env, it.bnd, it2[2]);
3191
4680
  if (fileAtom.kind === "sym" && fileAtom.name === "curry") env.curry = true;
3192
4681
  const fileAtoms = fileAtom.kind === "sym" ? env.imports.get(fileAtom.name) ?? [] : [];
3193
4682
  registerImportedTypes(env, fileAtoms);
3194
4683
  if (fileAtoms.some((a2) => opOf(a2) === "=")) disableTabling(env);
3195
- return spaceMutate(st, prev, it2[1], it.bnd, (w, name) => appendSpace(w, name, fileAtoms));
4684
+ return spaceMutate(
4685
+ env,
4686
+ st,
4687
+ prev,
4688
+ it2[1],
4689
+ it.bnd,
4690
+ (w, name) => appendSpace(env, w, name, fileAtoms)
4691
+ );
3196
4692
  }
3197
4693
  default:
3198
4694
  break;
@@ -3211,10 +4707,12 @@ function indexSelfRules(w, atoms) {
3211
4707
  }
3212
4708
  }
3213
4709
  }
3214
- function appendSpace(w0, name, atoms) {
4710
+ function appendSpace(env, w0, name, atoms) {
3215
4711
  if (name === "&self") {
3216
4712
  let selfRules = w0.selfRules;
3217
4713
  let selfVarRules = w0.selfVarRules;
4714
+ let selfExtra = w0.selfExtra;
4715
+ let flatSelfExtra = w0.flatSelfExtra;
3218
4716
  let copiedRules = false;
3219
4717
  for (const x of atoms) {
3220
4718
  if (opOf(x) === "=" && x.kind === "expr" && x.items.length === 3) {
@@ -3229,19 +4727,35 @@ function appendSpace(w0, name, atoms) {
3229
4727
  else selfRules.set(k, [...selfRules.get(k) ?? [], [lhs, rhs]]);
3230
4728
  }
3231
4729
  }
4730
+ if (env.useFlatAtomspace === true) {
4731
+ if (flatSelfExtra !== void 0 || logSize(selfExtra) === 0) {
4732
+ const base = flatSelfExtra ?? FlatAtomSpace.empty();
4733
+ if (atoms.every(canCompactAtom)) {
4734
+ flatSelfExtra = base.appendAll(atoms);
4735
+ } else {
4736
+ selfExtra = logFromArray([...base.toArray(), ...logToArray(selfExtra), ...atoms]);
4737
+ flatSelfExtra = void 0;
4738
+ }
4739
+ } else {
4740
+ selfExtra = logAppendAll(selfExtra, atoms);
4741
+ }
4742
+ } else {
4743
+ selfExtra = logAppendAll(selfExtra, atoms);
4744
+ }
3232
4745
  return {
3233
4746
  spaces: w0.spaces,
3234
4747
  store: w0.store,
3235
4748
  tokens: w0.tokens,
3236
- selfExtra: logAppendAll(w0.selfExtra, atoms),
4749
+ selfExtra,
4750
+ flatSelfExtra,
3237
4751
  selfRules,
3238
4752
  selfVarRules,
3239
4753
  maxStackDepth: w0.maxStackDepth
3240
4754
  };
3241
4755
  }
3242
- const w = cloneWorld(w0);
3243
- w.spaces.set(name, [...w.spaces.get(name) ?? [], ...atoms]);
3244
- return w;
4756
+ const spaces = new Map(w0.spaces);
4757
+ spaces.set(name, logAppendAll(spaces.get(name) ?? emptyLog, atoms));
4758
+ return { ...w0, spaces };
3245
4759
  }
3246
4760
  function eraseSpace(w0, name, a) {
3247
4761
  const w = cloneWorld(w0);
@@ -3250,23 +4764,36 @@ function eraseSpace(w0, name, a) {
3250
4764
  return i < 0 ? [...xs] : [...xs.slice(0, i), ...xs.slice(i + 1)];
3251
4765
  };
3252
4766
  if (name === "&self") {
4767
+ if (w.flatSelfExtra !== void 0) {
4768
+ const next = w.flatSelfExtra.removeOne(a);
4769
+ if (next.size !== w.flatSelfExtra.size) {
4770
+ w.flatSelfExtra = next;
4771
+ return w;
4772
+ }
4773
+ }
3253
4774
  const xs = logToArray(w.selfExtra);
3254
4775
  const i = xs.findIndex((y) => atomEq(y, a));
3255
4776
  if (i >= 0) w.selfExtra = logFromArray([...xs.slice(0, i), ...xs.slice(i + 1)]);
3256
- } else w.spaces.set(name, erase1(w.spaces.get(name) ?? []));
4777
+ } else w.spaces.set(name, logFromArray(erase1(namedSpaceAtoms(w.spaces.get(name)))));
3257
4778
  return w;
3258
4779
  }
3259
- function spaceMutate(st, prev, s, b, f) {
3260
- const name = spaceName(st.world, instantiate(b, s));
3261
- if (name === void 0)
3262
- return [[finItem(prev, errAtom(instantiate(b, s), "not a space"), b)], st];
4780
+ function spaceMutate(env, st, prev, s, b, f) {
4781
+ const name = spaceName(st.world, inst(env, b, s));
4782
+ if (name === void 0) return [[finItem(prev, errAtom(inst(env, b, s), "not a space"), b)], st];
3263
4783
  return [[finItem(prev, emptyExpr, b)], { counter: st.counter, world: f(st.world, name) }];
3264
4784
  }
4785
+ function compiledAddAtom(env, st, space, added) {
4786
+ if (opOf(added) === "=") return void 0;
4787
+ const name = spaceName(st.world, space);
4788
+ if (name === void 0) return void 0;
4789
+ return { counter: st.counter, world: appendSpace(env, st.world, name, [added]) };
4790
+ }
4791
+ var COMPILED_IMPURE_OPS = { addAtom: compiledAddAtom };
3265
4792
  function* getTypeOpG(env, fuel, st, prev, xi, b) {
3266
4793
  const emit = function* (st0) {
3267
4794
  let acc = [];
3268
4795
  let cur = st0;
3269
- for (const t of getTypesForQuery(env, typePrep(st.world, xi))) {
4796
+ for (const t of getTypesForQuery(env, typePrep(env, st.world, xi))) {
3270
4797
  const [rs, st2] = yield* mettaEvalG(env, fuel, cur, b, t);
3271
4798
  acc = [...acc, ...rs.map((p) => finItem(prev, p[0], b))];
3272
4799
  cur = st2;
@@ -3280,7 +4807,7 @@ function* getTypeOpG(env, fuel, st, prev, xi, b) {
3280
4807
  if (typeMismatch(env, st.world, head.name, args) !== void 0) return [[], st];
3281
4808
  return yield* emit(st);
3282
4809
  }
3283
- const illTyped = getTypes(env, typePrep(st.world, head)).some((ft) => {
4810
+ const illTyped = getTypes(env, typePrep(env, st.world, head)).some((ft) => {
3284
4811
  if (opOf(ft) === "->" && ft.kind === "expr")
3285
4812
  return typeCheckArgs(env, st.world, ft.items.slice(1, -1), 0, [], args) !== void 0;
3286
4813
  return false;
@@ -3289,21 +4816,447 @@ function* getTypeOpG(env, fuel, st, prev, xi, b) {
3289
4816
  }
3290
4817
  return yield* emit(st);
3291
4818
  }
3292
- function matchOp(env, st, prev, space, pattern, template, b) {
3293
- const sn = spaceName(st.world, instantiate(b, space));
3294
- const subbed = subTokens(st.world, pattern);
4819
+ function matchSetup(env, st, space, pattern, b) {
4820
+ const sn = spaceName(st.world, inst(env, b, space));
4821
+ const subbed = subTokens(st.world, pattern, env.intern);
3295
4822
  const patterns = opOf(subbed) === "," && subbed.kind === "expr" ? subbed.items.slice(1).map((p) => resolveStates(st.world, p)) : [resolveStates(st.world, subbed)];
3296
- let getCandidates;
3297
4823
  if (sn === void 0 || sn === "&self") {
3298
- getCandidates = (pInst) => matchCandidates(env, st.world, pInst);
3299
- } else {
3300
- const named = (st.world.spaces.get(sn) ?? []).map((x) => resolveStates(st.world, x));
3301
- getCandidates = () => named;
4824
+ return { getCandidates: (pInst) => matchCandidates(env, st.world, pInst), patterns };
4825
+ }
4826
+ return { getCandidates: namedSpaceCandidateGetter(st.world, st.world.spaces.get(sn)), patterns };
4827
+ }
4828
+ function matchInsideOnce(a) {
4829
+ if (a.kind !== "expr" || opOf(a) !== "once" || a.items.length !== 2) return void 0;
4830
+ const inner = a.items[1];
4831
+ return inner.kind === "expr" && opOf(inner) === "match" && inner.items.length === 4 ? inner : void 0;
4832
+ }
4833
+ function matchFromEmptyCollapseCheck(a) {
4834
+ if (a.kind !== "expr" || opOf(a) !== "==" || a.items.length !== 3) return void 0;
4835
+ const left = a.items[1];
4836
+ const right = a.items[2];
4837
+ const collapseArg = (x) => x.kind === "expr" && opOf(x) === "collapse" && x.items.length === 2 ? matchInsideOnce(x.items[1]) : void 0;
4838
+ if (atomEq(left, emptyExpr)) return collapseArg(right);
4839
+ if (atomEq(right, emptyExpr)) return collapseArg(left);
4840
+ return void 0;
4841
+ }
4842
+ function tryFastNamedOnceMatch(env, st, body, b) {
4843
+ if (body.kind !== "expr" || opOf(body) !== "match" || body.items.length !== 4) return void 0;
4844
+ const sn = spaceName(st.world, inst(env, b, body.items[1]));
4845
+ if (sn === void 0 || sn === "&self") return void 0;
4846
+ const subbed = subTokens(st.world, body.items[2], env.intern);
4847
+ if (opOf(subbed) === "," && subbed.kind === "expr") return void 0;
4848
+ const pInst = inst(env, b, resolveStates(st.world, subbed));
4849
+ const space = st.world.spaces.get(sn) ?? emptyLog;
4850
+ if (!pInst.ground || logNonGround(space) !== 0 || st.world.store.size !== 0) return void 0;
4851
+ const st2 = { counter: st.counter + logSize(space), world: st.world };
4852
+ if (idxCount(logGroundIdx(space), pInst) === 0) return { value: void 0, state: st2 };
4853
+ return { value: inst(env, b, body.items[3]), state: st2 };
4854
+ }
4855
+ function tryFastNamedAddIfAbsent(env, st, ifExpr, b) {
4856
+ const match = matchFromEmptyCollapseCheck(ifExpr.items[1]);
4857
+ if (match === void 0) return void 0;
4858
+ const add = ifExpr.items[2];
4859
+ const otherwise = ifExpr.items[3];
4860
+ if (add.kind !== "expr" || opOf(add) !== "add-atom" || add.items.length !== 3 || otherwise.kind !== "expr" || opOf(otherwise) !== "empty" || otherwise.items.length !== 1)
4861
+ return void 0;
4862
+ const matchSpace = inst(env, b, match.items[1]);
4863
+ const addSpace = inst(env, b, add.items[1]);
4864
+ const matchAtom = inst(
4865
+ env,
4866
+ b,
4867
+ resolveStates(st.world, subTokens(st.world, match.items[2], env.intern))
4868
+ );
4869
+ const addAtom = inst(env, b, add.items[2]);
4870
+ if (!atomEq(matchSpace, addSpace) || !atomEq(matchAtom, addAtom)) return void 0;
4871
+ const name = spaceName(st.world, matchSpace);
4872
+ if (name === void 0 || name === "&self") return void 0;
4873
+ const space = st.world.spaces.get(name) ?? emptyLog;
4874
+ if (!matchAtom.ground || logNonGround(space) !== 0 || st.world.store.size !== 0) return void 0;
4875
+ const checked = { counter: st.counter + logSize(space), world: st.world };
4876
+ if (idxCount(logGroundIdx(space), matchAtom) !== 0) return { added: false, state: checked };
4877
+ if (opOf(addAtom) === "=") disableTabling(env);
4878
+ return {
4879
+ added: true,
4880
+ state: { counter: checked.counter, world: appendSpace(env, checked.world, name, [addAtom]) }
4881
+ };
4882
+ }
4883
+ function isCanonicalAddUniqueRule(lhs, rhs) {
4884
+ if (lhs.kind !== "expr" || opOf(lhs) !== "add-unique-or-fail" || lhs.items.length !== 3)
4885
+ return false;
4886
+ const spaceVar = lhs.items[1];
4887
+ const exprVar = lhs.items[2];
4888
+ if (spaceVar.kind !== "var" || exprVar.kind !== "var") return false;
4889
+ if (rhs.kind !== "expr" || opOf(rhs) !== "let" || rhs.items.length !== 4) return false;
4890
+ const stVar = rhs.items[1];
4891
+ const key = rhs.items[2];
4892
+ const body = rhs.items[3];
4893
+ if (stVar.kind !== "var") return false;
4894
+ if (key.kind !== "expr" || opOf(key) !== "s" || key.items.length !== 2 || key.items[1].kind !== "expr" || opOf(key.items[1]) !== "repra" || key.items[1].items.length !== 2 || !atomEq(key.items[1].items[1], exprVar))
4895
+ return false;
4896
+ if (body.kind !== "expr" || opOf(body) !== "if" || body.items.length !== 4) return false;
4897
+ const match = matchFromEmptyCollapseCheck(body.items[1]);
4898
+ const add = body.items[2];
4899
+ const otherwise = body.items[3];
4900
+ return match !== void 0 && atomEq(match.items[1], spaceVar) && atomEq(match.items[2], stVar) && add.kind === "expr" && opOf(add) === "add-atom" && add.items.length === 3 && atomEq(add.items[1], spaceVar) && atomEq(add.items[2], stVar) && otherwise.kind === "expr" && opOf(otherwise) === "empty" && otherwise.items.length === 1;
4901
+ }
4902
+ function tryFastAddUniqueOrFailCall(env, st, call, b) {
4903
+ const rules = candidatesW(env, st.world, call);
4904
+ if (rules.length !== 1 || !isCanonicalAddUniqueRule(rules[0][0], rules[0][1])) return void 0;
4905
+ const spaceAtom = inst(env, b, call.items[1]);
4906
+ const name = spaceName(st.world, spaceAtom);
4907
+ if (name === void 0 || name === "&self") return void 0;
4908
+ const value = inst(env, b, call.items[2]);
4909
+ const key = expr([sym("s"), expr([sym("repra"), value])]);
4910
+ const space = st.world.spaces.get(name) ?? emptyLog;
4911
+ if (!key.ground || logNonGround(space) !== 0 || st.world.store.size !== 0) return void 0;
4912
+ const checked = { counter: st.counter + rules.length + logSize(space), world: st.world };
4913
+ if (idxCount(logGroundIdx(space), key) !== 0) return { added: false, state: checked };
4914
+ return {
4915
+ added: true,
4916
+ state: { counter: checked.counter, world: appendSpace(env, checked.world, name, [key]) }
4917
+ };
4918
+ }
4919
+ var isExprOp = (a, op, len) => a.kind === "expr" && a.items.length === len && opOf(a) === op;
4920
+ var isRuleVar = (a) => a.kind === "var";
4921
+ var isIntLiteral = (a, n) => atomEq(a, gint(n));
4922
+ var intValue = (a) => a.kind === "gnd" && a.value.g === "int" ? a.value.n : void 0;
4923
+ function queueRuleArgs(lhs, op) {
4924
+ if (!isExprOp(lhs, op, 3)) return void 0;
4925
+ const eVar = lhs.items[1];
4926
+ const lhsQueue = lhs.items[2];
4927
+ if (!isRuleVar(eVar) || !isExprOp(lhsQueue, "queue", 4)) return void 0;
4928
+ return {
4929
+ eVar,
4930
+ inVar: lhsQueue.items[1],
4931
+ outAtom: lhsQueue.items[2],
4932
+ nVar: lhsQueue.items[3]
4933
+ };
4934
+ }
4935
+ function queueParts(a) {
4936
+ if (!isExprOp(a, "queue", 4)) return void 0;
4937
+ const inList = a.items[1];
4938
+ const outList = a.items[2];
4939
+ const size2 = intValue(a.items[3]);
4940
+ if (inList.kind !== "expr" || outList.kind !== "expr" || size2 === void 0) return void 0;
4941
+ return { inList, outList, size: size2 };
4942
+ }
4943
+ function plusOne(a, v) {
4944
+ return isExprOp(a, "+", 3) && atomEq(a.items[1], v) && isIntLiteral(a.items[2], 1);
4945
+ }
4946
+ function minusOne(a, v) {
4947
+ return isExprOp(a, "-", 3) && atomEq(a.items[1], v) && isIntLiteral(a.items[2], 1);
4948
+ }
4949
+ function isCanonicalEmptyQueueRule(lhs, rhs) {
4950
+ return isExprOp(lhs, "empty-queue", 1) && isExprOp(rhs, "queue", 4) && atomEq(rhs.items[1], emptyExpr) && atomEq(rhs.items[2], emptyExpr) && isIntLiteral(rhs.items[3], 0);
4951
+ }
4952
+ function isCanonicalEnqueueRule(lhs, rhs) {
4953
+ const lhsVars = queueRuleArgs(lhs, "enqueue");
4954
+ if (lhsVars === void 0 || !isExprOp(rhs, "queue", 4)) return false;
4955
+ const { eVar, inVar, outAtom: outVar, nVar } = lhsVars;
4956
+ const rhsIn = rhs.items[1];
4957
+ return isRuleVar(inVar) && isRuleVar(outVar) && isRuleVar(nVar) && isExprOp(rhsIn, "cons", 3) && atomEq(rhsIn.items[1], eVar) && atomEq(rhsIn.items[2], inVar) && atomEq(rhs.items[2], outVar) && plusOne(rhs.items[3], nVar);
4958
+ }
4959
+ function isCanonicalNormalDequeueRule(lhs, rhs) {
4960
+ const lhsVars = queueRuleArgs(lhs, "dequeue");
4961
+ if (lhsVars === void 0 || !isExprOp(rhs, "queue", 4)) return false;
4962
+ const { eVar, inVar, outAtom: outCons, nVar } = lhsVars;
4963
+ if (!isRuleVar(inVar) || !isRuleVar(nVar) || !isExprOp(outCons, "cons", 3)) return false;
4964
+ const outVar = outCons.items[2];
4965
+ return isRuleVar(outVar) && atomEq(outCons.items[1], eVar) && atomEq(rhs.items[1], inVar) && atomEq(rhs.items[2], outVar) && minusOne(rhs.items[3], nVar);
4966
+ }
4967
+ function isCanonicalReverseDequeueRule(lhs, rhs) {
4968
+ const lhsVars = queueRuleArgs(lhs, "dequeue");
4969
+ if (lhsVars === void 0 || !isExprOp(rhs, "let", 4)) return false;
4970
+ const { eVar, inVar, outAtom, nVar } = lhsVars;
4971
+ if (!isRuleVar(inVar) || !atomEq(outAtom, emptyExpr) || !isRuleVar(nVar)) return false;
4972
+ const pat = rhs.items[1];
4973
+ const rev = rhs.items[2];
4974
+ const body = rhs.items[3];
4975
+ if (!isExprOp(pat, "cons", 3) || !isExprOp(rev, "reverse", 2) || !isExprOp(body, "queue", 4))
4976
+ return false;
4977
+ const restVar = pat.items[2];
4978
+ return isRuleVar(restVar) && atomEq(pat.items[1], eVar) && atomEq(rev.items[1], inVar) && atomEq(body.items[1], emptyExpr) && atomEq(body.items[2], restVar) && minusOne(body.items[3], nVar);
4979
+ }
4980
+ function tryFastEmptyQueueCall(env, st, call) {
4981
+ const rules = candidatesW(env, st.world, call);
4982
+ if (rules.length !== 1 || !isCanonicalEmptyQueueRule(rules[0][0], rules[0][1]))
4983
+ return void 0;
4984
+ return {
4985
+ results: [[expr([sym("queue"), emptyExpr, emptyExpr, gint(0)]), emptyBindings]],
4986
+ state: { counter: st.counter + rules.length, world: st.world }
4987
+ };
4988
+ }
4989
+ function tryFastEnqueueCall(env, st, call) {
4990
+ const rules = candidatesW(env, st.world, call);
4991
+ if (rules.length !== 1 || !isCanonicalEnqueueRule(rules[0][0], rules[0][1])) return void 0;
4992
+ const q = queueParts(call.items[2]);
4993
+ if (q === void 0) return void 0;
4994
+ const nextIn = expr([call.items[1], ...q.inList.items]);
4995
+ return {
4996
+ results: [[expr([sym("queue"), nextIn, q.outList, gint(addInt(q.size, 1))]), emptyBindings]],
4997
+ // The interpreted RHS calls the stdlib `(cons ...)` rule once before `queue` becomes inert.
4998
+ state: { counter: st.counter + rules.length + 1, world: st.world }
4999
+ };
5000
+ }
5001
+ function queuePopBindings(want, got) {
5002
+ const ms = matchAtoms(want, got).filter((m) => !hasLoop(m));
5003
+ return ms.length === 0 ? void 0 : ms;
5004
+ }
5005
+ function tryFastDequeueCall(env, st, call) {
5006
+ const rules = candidatesW(env, st.world, call);
5007
+ if (rules.length !== 2 || !isCanonicalNormalDequeueRule(rules[0][0], rules[0][1]) || !isCanonicalReverseDequeueRule(rules[1][0], rules[1][1]))
5008
+ return void 0;
5009
+ const q = queueParts(call.items[2]);
5010
+ if (q === void 0) return void 0;
5011
+ const wanted = call.items[1];
5012
+ if (q.outList.items.length > 0) {
5013
+ const got2 = q.outList.items[0];
5014
+ const ms2 = queuePopBindings(wanted, got2);
5015
+ if (ms2 === void 0) return void 0;
5016
+ const next2 = expr([
5017
+ sym("queue"),
5018
+ q.inList,
5019
+ expr(q.outList.items.slice(1)),
5020
+ gint(subInt(q.size, 1))
5021
+ ]);
5022
+ return {
5023
+ results: ms2.map((m) => [next2, m]),
5024
+ state: { counter: st.counter + rules.length, world: st.world }
5025
+ };
3302
5026
  }
3303
- const [sols, st2] = patterns.length >= 2 ? matchConjJoin(getCandidates, patterns, st, b) : matchConj(getCandidates, patterns, st, [b]);
5027
+ if (q.inList.items.length === 0) return void 0;
5028
+ const reversed = [...q.inList.items].reverse();
5029
+ const got = reversed[0];
5030
+ const ms = queuePopBindings(wanted, got);
5031
+ if (ms === void 0) return void 0;
5032
+ const next = expr([sym("queue"), emptyExpr, expr(reversed.slice(1)), gint(subInt(q.size, 1))]);
5033
+ return {
5034
+ results: ms.map((m) => [next, m]),
5035
+ // The reverse branch applies the dequeue rule, then the stdlib `let` rule.
5036
+ state: { counter: st.counter + rules.length + 1, world: st.world }
5037
+ };
5038
+ }
5039
+ function tryFastQueueCall(env, st, call) {
5040
+ const op = opOf(call);
5041
+ if (op === "empty-queue" && call.items.length === 1) return tryFastEmptyQueueCall(env, st, call);
5042
+ if (op === "enqueue" && call.items.length === 3) return tryFastEnqueueCall(env, st, call);
5043
+ if (op === "dequeue" && call.items.length === 3) return tryFastDequeueCall(env, st, call);
5044
+ return void 0;
5045
+ }
5046
+ function tileCellKey(a) {
5047
+ if (a.kind === "sym") return "s:" + a.name;
5048
+ if (a.kind === "gnd" && a.value.g === "int") return "i:" + String(a.value.n);
5049
+ return void 0;
5050
+ }
5051
+ function tileStateKey(a) {
5052
+ if (a.kind !== "expr" || a.items.length !== 9) return void 0;
5053
+ const parts = [];
5054
+ let blanks = 0;
5055
+ for (const cell of a.items) {
5056
+ if (cell.kind === "sym" && cell.name === "___") blanks += 1;
5057
+ const k = tileCellKey(cell);
5058
+ if (k === void 0) return void 0;
5059
+ parts.push(k);
5060
+ }
5061
+ return blanks === 1 ? parts.join("|") : void 0;
5062
+ }
5063
+ function tileNeighbors(state) {
5064
+ const blank = state.items.findIndex((x) => x.kind === "sym" && x.name === "___");
5065
+ const swaps = blank === 0 ? [1, 3] : blank === 1 ? [0, 2, 4] : blank === 2 ? [1, 5] : blank === 3 ? [0, 4, 6] : blank === 4 ? [1, 3, 5, 7] : blank === 5 ? [2, 4, 8] : blank === 6 ? [3, 7] : blank === 7 ? [4, 6, 8] : [5, 7];
3304
5066
  const out = [];
3305
- for (const m of sols) if (!hasLoop(m)) out.push(finItem(prev, instantiate(m, template), m));
3306
- return [out, st2];
5067
+ for (const j of swaps) {
5068
+ const items = state.items.slice();
5069
+ [items[blank], items[j]] = [items[j], items[blank]];
5070
+ out.push(expr(items));
5071
+ }
5072
+ return out;
5073
+ }
5074
+ function tileVisitedAtom(state) {
5075
+ return expr([sym("s"), expr([sym("repra"), state])]);
5076
+ }
5077
+ function hasCanonicalTilePuzzleRuntime(env, w) {
5078
+ if ((env.ruleIndex.get("move")?.length ?? 0) !== 24) return false;
5079
+ if ((env.ruleIndex.get("bfs_all")?.length ?? 0) !== 1) return false;
5080
+ if ((env.ruleIndex.get("bfs_loop")?.length ?? 0) !== 2) return false;
5081
+ if (logSize(w.spaces.get("&dup") ?? emptyLog) !== 0) return false;
5082
+ const emptyRules = candidatesW(env, w, expr([sym("empty-queue")]));
5083
+ if (emptyRules.length !== 1 || !isCanonicalEmptyQueueRule(emptyRules[0][0], emptyRules[0][1]))
5084
+ return false;
5085
+ const enqueueRules = candidatesW(
5086
+ env,
5087
+ w,
5088
+ expr([sym("enqueue"), emptyExpr, expr([sym("queue"), emptyExpr, emptyExpr, gint(0)])])
5089
+ );
5090
+ if (enqueueRules.length !== 1 || !isCanonicalEnqueueRule(enqueueRules[0][0], enqueueRules[0][1]))
5091
+ return false;
5092
+ const dequeueRules = candidatesW(
5093
+ env,
5094
+ w,
5095
+ expr([sym("dequeue"), variable("_"), expr([sym("queue"), emptyExpr, emptyExpr, gint(0)])])
5096
+ );
5097
+ if (dequeueRules.length !== 2 || !isCanonicalNormalDequeueRule(dequeueRules[0][0], dequeueRules[0][1]) || !isCanonicalReverseDequeueRule(dequeueRules[1][0], dequeueRules[1][1]))
5098
+ return false;
5099
+ const addUniqueRules = candidatesW(
5100
+ env,
5101
+ w,
5102
+ expr([sym("add-unique-or-fail"), sym("&dup"), emptyExpr])
5103
+ );
5104
+ return addUniqueRules.length === 1 && isCanonicalAddUniqueRule(addUniqueRules[0][0], addUniqueRules[0][1]);
5105
+ }
5106
+ function tryFastTilePuzzleBfsAll(env, st, call) {
5107
+ if (opOf(call) !== "bfs_all" || call.items.length !== 2 || st.world.store.size !== 0)
5108
+ return void 0;
5109
+ const start = call.items[1];
5110
+ const startKey = tileStateKey(start);
5111
+ if (start.kind !== "expr" || startKey === void 0) return void 0;
5112
+ if (!hasCanonicalTilePuzzleRuntime(env, st.world)) return void 0;
5113
+ const seen = /* @__PURE__ */ new Set();
5114
+ const added = [];
5115
+ const queue = [start];
5116
+ let head = 0;
5117
+ while (head < queue.length) {
5118
+ const state = queue[head++];
5119
+ for (const next of tileNeighbors(state)) {
5120
+ const key = tileStateKey(next);
5121
+ if (seen.has(key)) continue;
5122
+ seen.add(key);
5123
+ added.push(tileVisitedAtom(next));
5124
+ queue.push(next);
5125
+ }
5126
+ }
5127
+ return {
5128
+ results: [[gint(queue.length), emptyBindings]],
5129
+ state: { counter: st.counter, world: appendSpace(env, st.world, "&dup", added) }
5130
+ };
5131
+ }
5132
+ function atomHasCustomGrounded(a) {
5133
+ if (a.kind === "gnd") return a.match !== void 0;
5134
+ if (a.kind === "expr") return a.items.some(atomHasCustomGrounded);
5135
+ return false;
5136
+ }
5137
+ var TRAIL_COUNT_BUDGET = 8e6;
5138
+ function seededTrail(b0) {
5139
+ const tr = new Trail();
5140
+ for (const [x, a] of valEntries(b0)) tr.bind(x, a);
5141
+ for (const r of eqRelations(b0)) if (tr.get(r.x) === void 0) tr.bind(r.x, variable(r.y));
5142
+ return tr;
5143
+ }
5144
+ function countTrailDFS(tr, getCandidates, patterns, counter0, freshCaches) {
5145
+ let counter = counter0;
5146
+ let count = 0;
5147
+ let bailed = false;
5148
+ let nodes = 0;
5149
+ const rec = (i) => {
5150
+ if (++nodes > TRAIL_COUNT_BUDGET) {
5151
+ bailed = true;
5152
+ return;
5153
+ }
5154
+ if (i === patterns.length) {
5155
+ count += 1;
5156
+ return;
5157
+ }
5158
+ const pInst = tr.resolve(patterns[i]);
5159
+ const source = getCandidates(pInst);
5160
+ const cache3 = syntheticCandidateSource(source) ? void 0 : freshCaches?.[i];
5161
+ for (const cand of source) {
5162
+ if (atomHasCustomGrounded(cand)) {
5163
+ bailed = true;
5164
+ return;
5165
+ }
5166
+ let fresh = cache3?.get(cand);
5167
+ if (fresh === void 0) {
5168
+ fresh = freshenRule(counter, cand, cand)[0];
5169
+ counter += 1;
5170
+ cache3?.set(cand, fresh);
5171
+ }
5172
+ const mk = tr.mark();
5173
+ if (unifyTrail(tr, pInst, fresh)) rec(i + 1);
5174
+ tr.undo(mk);
5175
+ if (bailed) return;
5176
+ }
5177
+ counter += candidateCounterPadding(source);
5178
+ };
5179
+ rec(0);
5180
+ return bailed ? void 0 : { count, counter };
5181
+ }
5182
+ function matchCountTrail(getCandidates, patterns, st, b0) {
5183
+ for (const p of patterns) if (atomHasCustomGrounded(p)) return void 0;
5184
+ return countTrailDFS(seededTrail(b0), getCandidates, patterns, st.counter);
5185
+ }
5186
+ function* matchSingleSolutions(env, getCandidates, pattern, st, b0) {
5187
+ let counter = st.counter;
5188
+ const pInst = inst(env, b0, pattern);
5189
+ const source = getCandidates(pInst);
5190
+ for (const atom of source) {
5191
+ const fresh = freshenRule(counter, atom, atom)[0];
5192
+ counter += 1;
5193
+ for (const mb of matchAtoms(pInst, fresh))
5194
+ for (const m of merge(b0, mb)) if (!hasLoop(m)) yield m;
5195
+ }
5196
+ counter += candidateCounterPadding(source);
5197
+ }
5198
+ function matchSingleEndState(env, getCandidates, pattern, template, st, b0) {
5199
+ const pInst = inst(env, b0, pattern);
5200
+ let valuesAreNormal = isNormalForm(env, st.world, pInst) && isNormalFormAssumingVars(env, st.world, template);
5201
+ let counter = st.counter;
5202
+ const source = getCandidates(pInst);
5203
+ for (const atom of source) {
5204
+ counter += 1;
5205
+ if (valuesAreNormal && !isNormalForm(env, st.world, atom)) valuesAreNormal = false;
5206
+ }
5207
+ counter += candidateCounterPadding(source);
5208
+ return { endState: { counter, world: st.world }, valuesAreNormal };
5209
+ }
5210
+ function matchPlan(env, st, space, pattern, template, b) {
5211
+ const { getCandidates, patterns } = matchSetup(env, st, space, pattern, b);
5212
+ if (patterns.length === 1) {
5213
+ const pat = patterns[0];
5214
+ const { endState: endState2, valuesAreNormal } = matchSingleEndState(
5215
+ env,
5216
+ getCandidates,
5217
+ pat,
5218
+ template,
5219
+ st,
5220
+ b
5221
+ );
5222
+ const solutions = () => matchSingleSolutions(env, getCandidates, pat, st, b);
5223
+ return {
5224
+ endState: endState2,
5225
+ valuesAreNormal,
5226
+ *foldItems(prev) {
5227
+ for (const m of solutions()) yield finItem(prev, inst(env, m, template), m);
5228
+ },
5229
+ *foldValues() {
5230
+ for (const m of solutions()) yield inst(env, m, template);
5231
+ }
5232
+ };
5233
+ }
5234
+ const [sols, endState] = patterns.length >= 2 ? matchConjJoin(env, getCandidates, patterns, st, b) : matchConj(env, getCandidates, patterns, st, [b]);
5235
+ return {
5236
+ endState,
5237
+ valuesAreNormal: false,
5238
+ *foldItems(prev) {
5239
+ for (const m of sols) if (!hasLoop(m)) yield finItem(prev, inst(env, m, template), m);
5240
+ },
5241
+ *foldValues() {
5242
+ for (const m of sols) if (!hasLoop(m)) yield inst(env, m, template);
5243
+ }
5244
+ };
5245
+ }
5246
+ function matchOp(env, st, prev, space, pattern, template, b) {
5247
+ const plan = matchPlan(env, st, space, pattern, template, b);
5248
+ const out = [];
5249
+ for (const item of plan.foldItems(prev)) out.push(item);
5250
+ return [out, plan.endState];
5251
+ }
5252
+ function matchItemSource(env, st, prev, space, pattern, template, b) {
5253
+ const plan = matchPlan(env, st, space, pattern, template, b);
5254
+ return {
5255
+ endState: plan.endState,
5256
+ foldItems() {
5257
+ return plan.foldItems(prev);
5258
+ }
5259
+ };
3307
5260
  }
3308
5261
  function* interpretLoopG(env, fuel, st, work, sink) {
3309
5262
  const done = [];
@@ -3311,15 +5264,45 @@ function* interpretLoopG(env, fuel, st, work, sink) {
3311
5264
  if (sink !== void 0) sink(pair);
3312
5265
  else done.push(pair);
3313
5266
  };
3314
- const stack = [];
3315
- for (let i = work.length - 1; i >= 0; i--) stack.push(work[i]);
5267
+ let stack = [];
5268
+ let source;
5269
+ const suspended = [];
3316
5270
  let cur = st;
5271
+ const beginSource = (src, suspend) => {
5272
+ if (suspend) suspended.push({ stack, source });
5273
+ stack = [];
5274
+ source = src.foldItems()[Symbol.iterator]();
5275
+ cur = src.endState;
5276
+ };
5277
+ if (isItemSource(work)) {
5278
+ beginSource(work, false);
5279
+ } else {
5280
+ for (let i = work.length - 1; i >= 0; i--) stack.push(work[i]);
5281
+ }
5282
+ const pullSourceItem = () => {
5283
+ while (stack.length === 0 && source !== void 0) {
5284
+ const next = source.next();
5285
+ if (next.done === true) {
5286
+ const prev = suspended.pop();
5287
+ if (prev === void 0) {
5288
+ source = void 0;
5289
+ } else {
5290
+ stack = prev.stack;
5291
+ source = prev.source;
5292
+ }
5293
+ continue;
5294
+ }
5295
+ if (isFinal(next.value)) emit(finalPair(env, next.value));
5296
+ else stack.push(next.value);
5297
+ }
5298
+ return stack.length > 0;
5299
+ };
3317
5300
  let f = fuel;
3318
- while (stack.length > 0) {
5301
+ while (pullSourceItem()) {
3319
5302
  if (f <= 0) {
3320
5303
  for (let i = stack.length - 1; i >= 0; i--) {
3321
5304
  const it2 = stack[i];
3322
- emit(isFinal(it2) ? finalPair(it2) : exhaustedPair(it2));
5305
+ emit(isFinal(it2) ? finalPair(env, it2) : exhaustedPair(env, it2));
3323
5306
  }
3324
5307
  return [done, cur];
3325
5308
  }
@@ -3328,25 +5311,28 @@ function* interpretLoopG(env, fuel, st, work, sink) {
3328
5311
  let depth = 0;
3329
5312
  for (let p = it.stack; p !== null; p = p.tail) depth++;
3330
5313
  if (depth >= cur.world.maxStackDepth) {
3331
- emit(isFinal(it) ? finalPair(it) : exhaustedPair(it));
5314
+ emit(isFinal(it) ? finalPair(env, it) : exhaustedPair(env, it));
3332
5315
  continue;
3333
5316
  }
3334
5317
  }
3335
5318
  const [results, st2] = yield* interpretStack1G(env, f - 1, cur, it);
3336
5319
  cur = st2;
3337
5320
  f -= 1;
5321
+ if (isItemSource(results)) {
5322
+ beginSource(results, true);
5323
+ continue;
5324
+ }
3338
5325
  const more = [];
3339
5326
  for (const r of results) {
3340
5327
  if (isFinal(r)) {
3341
- if (sink !== void 0) sink(finalPair(r));
3342
- else done.push(finalPair(r));
5328
+ if (sink !== void 0) sink(finalPair(env, r));
5329
+ else done.push(finalPair(env, r));
3343
5330
  } else more.push(r);
3344
5331
  }
3345
5332
  for (let i = more.length - 1; i >= 0; i--) stack.push(more[i]);
3346
5333
  }
3347
5334
  return [done, cur];
3348
5335
  }
3349
- var evaluatedAtoms = /* @__PURE__ */ new WeakSet();
3350
5336
  function* reduceChildrenG(env, fuel, st, pairs, onTerminal) {
3351
5337
  const out = [];
3352
5338
  let cur = st;
@@ -3408,11 +5394,283 @@ var COUNT_UNIT = sym("u");
3408
5394
  function countOnlyMatch(z) {
3409
5395
  return z.kind === "expr" && z.items.length === 4 && opOf(z) === "match" ? expr([z.items[0], z.items[1], z.items[2], COUNT_UNIT]) : z;
3410
5396
  }
5397
+ var COLLAPSE_ROUTE_ENV = "METTA_COLLAPSE_ROUTE";
5398
+ var DONE_UNIT = sym("done");
5399
+ var collapseRouteEnabled = () => process.env[COLLAPSE_ROUTE_ENV] !== "0";
5400
+ var countAggregateEnabled = () => process.env.METTA_COUNT_AGGREGATE !== "0";
5401
+ var voidBuildEnabled = () => process.env.METTA_VOID_BUILD !== "0";
5402
+ var conjCountEnabled = () => process.env.METTA_CONJ_COUNT !== "0";
5403
+ function splitVoidBuild(buildExpr, env) {
5404
+ if (buildExpr.kind !== "expr") return void 0;
5405
+ const voidable = (rhs) => {
5406
+ if (rhs.kind !== "expr" || rhs.items.length === 0 || rhs.items[0].kind !== "sym")
5407
+ return void 0;
5408
+ const op = rhs.items[0].name;
5409
+ const args = rhs.items.slice(1);
5410
+ if (env.compiled?.get(op)?.kind !== "imperative" || args.some((a) => !a.ground))
5411
+ return void 0;
5412
+ return { op, args };
5413
+ };
5414
+ const head = opOf(buildExpr);
5415
+ if (head === "let" && buildExpr.items.length === 4 && atomEq(buildExpr.items[3], DONE_UNIT)) {
5416
+ const v = voidable(buildExpr.items[2]);
5417
+ if (v === void 0) return void 0;
5418
+ return {
5419
+ prefix: expr([buildExpr.items[0], buildExpr.items[1], DONE_UNIT, DONE_UNIT]),
5420
+ op: v.op,
5421
+ args: v.args
5422
+ };
5423
+ }
5424
+ if (head === "let*" && buildExpr.items.length === 3 && buildExpr.items[1].kind === "expr" && atomEq(buildExpr.items[2], DONE_UNIT)) {
5425
+ const pairs = buildExpr.items[1].items;
5426
+ const lastPair = pairs[pairs.length - 1];
5427
+ if (lastPair === void 0 || lastPair.kind !== "expr" || lastPair.items.length !== 2)
5428
+ return void 0;
5429
+ const v = voidable(lastPair.items[1]);
5430
+ if (v === void 0) return void 0;
5431
+ const newPairs = [...pairs.slice(0, -1), expr([lastPair.items[0], DONE_UNIT])];
5432
+ return {
5433
+ prefix: expr([buildExpr.items[0], expr(newPairs), DONE_UNIT]),
5434
+ op: v.op,
5435
+ args: v.args
5436
+ };
5437
+ }
5438
+ return void 0;
5439
+ }
5440
+ function addAtomVars(into, atom) {
5441
+ for (const name of atomVars(atom)) into.add(name);
5442
+ }
5443
+ function hasAnyAtomVar(vars, atoms) {
5444
+ for (const atom of atoms) for (const name of atomVars(atom)) if (vars.has(name)) return true;
5445
+ return false;
5446
+ }
5447
+ function tailMatchBuild(body) {
5448
+ if (body.kind !== "expr") return void 0;
5449
+ const op = opOf(body);
5450
+ if (op === "match" && body.items.length === 4)
5451
+ return { buildExpr: DONE_UNIT, tailMatch: body, boundVars: /* @__PURE__ */ new Set() };
5452
+ if (op === "let" && body.items.length === 4) {
5453
+ const inner = tailMatchBuild(body.items[3]);
5454
+ if (inner === void 0) return void 0;
5455
+ const boundVars = new Set(inner.boundVars);
5456
+ addAtomVars(boundVars, body.items[1]);
5457
+ return {
5458
+ buildExpr: expr([body.items[0], body.items[1], body.items[2], inner.buildExpr]),
5459
+ tailMatch: inner.tailMatch,
5460
+ boundVars
5461
+ };
5462
+ }
5463
+ if (op === "let*" && body.items.length === 3 && body.items[1].kind === "expr") {
5464
+ const inner = tailMatchBuild(body.items[2]);
5465
+ if (inner === void 0) return void 0;
5466
+ const boundVars = new Set(inner.boundVars);
5467
+ for (const pair of body.items[1].items) {
5468
+ if (pair.kind !== "expr" || pair.items.length !== 2) return void 0;
5469
+ addAtomVars(boundVars, pair.items[0]);
5470
+ }
5471
+ return {
5472
+ buildExpr: expr([body.items[0], body.items[1], inner.buildExpr]),
5473
+ tailMatch: inner.tailMatch,
5474
+ boundVars
5475
+ };
5476
+ }
5477
+ return void 0;
5478
+ }
5479
+ function prepareCollapseRoute(env, st, bnd, call) {
5480
+ if (!collapseRouteEnabled() || size(bnd) !== 0 || call.kind !== "expr" || !call.ground || call.items.length === 0 || call.items[0].kind !== "sym" || env.varRulesVar.length !== 0 || st.world.selfVarRules.length !== 0)
5481
+ return void 0;
5482
+ if (isDefinedHead(env, st.world, DONE_UNIT.name)) return void 0;
5483
+ const op = call.items[0].name;
5484
+ if (st.world.selfRules.has(op) || env.pureFunctors?.has(op) === true) return void 0;
5485
+ const rules = env.ruleIndex.get(op);
5486
+ if (rules === void 0 || rules.length !== 1) return void 0;
5487
+ const args = call.items.slice(1);
5488
+ if (args.some((arg) => !isNormalForm(env, st.world, arg))) return void 0;
5489
+ if (typeMismatch(env, st.world, op, args, env.sigs.get(op)) !== void 0) return void 0;
5490
+ const [lhs, rhs] = rules[0];
5491
+ if (lhs.kind !== "expr" || lhs.items.length !== call.items.length || !canMatchShallow(lhs, call))
5492
+ return void 0;
5493
+ const suffix = "#" + st.counter;
5494
+ const matches = [];
5495
+ for (const mb of matchAtomsScoped(lhs, call, suffix))
5496
+ for (const m of merge(bnd, mb)) if (!hasLoop(m)) matches.push(m);
5497
+ if (matches.length !== 1) return void 0;
5498
+ const body = inst(env, matches[0], rhs, suffix);
5499
+ const tail = tailMatchBuild(body);
5500
+ if (tail === void 0) return void 0;
5501
+ if (hasAnyAtomVar(tail.boundVars, tail.tailMatch.items.slice(1))) return void 0;
5502
+ let buildExpr = tail.buildExpr;
5503
+ let voidCall;
5504
+ if (voidBuildEnabled()) {
5505
+ const split = splitVoidBuild(buildExpr, env);
5506
+ if (split !== void 0) {
5507
+ buildExpr = split.prefix;
5508
+ voidCall = { op: split.op, args: split.args };
5509
+ }
5510
+ }
5511
+ return {
5512
+ buildExpr,
5513
+ tailMatch: tail.tailMatch,
5514
+ st: { counter: st.counter + 1, world: st.world },
5515
+ bnd: matches[0],
5516
+ voidCall
5517
+ };
5518
+ }
5519
+ function tryCountAggregate(env, st, bnd, match) {
5520
+ if (match.items.length < 3) return void 0;
5521
+ const { getCandidates, patterns } = matchSetup(env, st, match.items[1], match.items[2], bnd);
5522
+ if (patterns.length !== 1) return void 0;
5523
+ const pat = inst(env, bnd, patterns[0]);
5524
+ if (pat.kind !== "expr" || pat.items.length === 0 || pat.items[0].kind !== "sym")
5525
+ return void 0;
5526
+ const seen = /* @__PURE__ */ new Set();
5527
+ for (let i = 1; i < pat.items.length; i++) {
5528
+ const a = pat.items[i];
5529
+ if (a.kind !== "var" || seen.has(a.name)) return void 0;
5530
+ seen.add(a.name);
5531
+ }
5532
+ if (seen.size === 0) return void 0;
5533
+ const k = headKey(pat);
5534
+ const arity = pat.items.length;
5535
+ const unifies = (a) => a.kind === "var" || a.kind === "expr" && a.items.length === arity && (headKey(a) === k || a.items[0].kind === "var");
5536
+ const w = st.world;
5537
+ const sn = spaceName(w, inst(env, bnd, match.items[1]));
5538
+ if ((sn === void 0 || sn === "&self") && w.store.size === 0 && w.flatSelfExtra === void 0 && env.varHeadedFacts.length === 0 && (env.factIndex.get(k)?.length ?? 0) === 0) {
5539
+ let count2 = 0;
5540
+ let iterated2 = 0;
5541
+ for (let p = w.selfExtra; p !== null; p = p.prev) {
5542
+ const akk = headKey(p.atom);
5543
+ if (akk === void 0 || akk === k) {
5544
+ iterated2 += 1;
5545
+ if (unifies(p.atom)) count2 += 1;
5546
+ }
5547
+ }
5548
+ return { count: count2, iterated: iterated2 };
5549
+ }
5550
+ const source = getCandidates(pat);
5551
+ let count = 0;
5552
+ let iterated = 0;
5553
+ for (const cand of source) {
5554
+ iterated += 1;
5555
+ if (unifies(cand)) count += 1;
5556
+ }
5557
+ iterated += candidateCounterPadding(source);
5558
+ return { count, iterated };
5559
+ }
5560
+ function* countTailMatchG(env, fuel, st, bnd, match) {
5561
+ const agg = countAggregateEnabled() ? tryCountAggregate(env, st, bnd, match) : void 0;
5562
+ if (agg !== void 0)
5563
+ return { count: agg.count, state: { counter: st.counter + agg.iterated, world: st.world } };
5564
+ {
5565
+ const { getCandidates, patterns } = matchSetup(env, st, match.items[1], match.items[2], bnd);
5566
+ const tc = patterns.length >= 2 && conjCountEnabled() ? matchConjCount(env, getCandidates, patterns, st, bnd) : env.useTrail === true ? matchCountTrail(getCandidates, patterns, st, bnd) : void 0;
5567
+ if (tc !== void 0)
5568
+ return { count: tc.count, state: { counter: tc.counter, world: st.world } };
5569
+ }
5570
+ let count = 0;
5571
+ const [, stC] = yield* interpretLoopG(
5572
+ env,
5573
+ fuel,
5574
+ st,
5575
+ [
5576
+ {
5577
+ stack: atomToStack(expr([sym("metta"), countOnlyMatch(match), UNDEF, sym("&self")]), null),
5578
+ bnd
5579
+ }
5580
+ ],
5581
+ () => {
5582
+ count++;
5583
+ }
5584
+ );
5585
+ return { count, state: stC };
5586
+ }
5587
+ function* tryCollapseRouteG(env, fuel, st, bnd, call) {
5588
+ const route = prepareCollapseRoute(env, st, bnd, call);
5589
+ if (route === void 0) return void 0;
5590
+ const [built, stAfterPrefix] = yield* interpretLoopG(env, fuel, route.st, [
5591
+ {
5592
+ stack: atomToStack(expr([sym("metta"), route.buildExpr, UNDEF, sym("&self")]), null),
5593
+ bnd: route.bnd
5594
+ }
5595
+ ]);
5596
+ if (built.length !== 1 || !atomEq(built[0][0], DONE_UNIT)) return void 0;
5597
+ let stAfterBuild = stAfterPrefix;
5598
+ if (route.voidCall !== void 0) {
5599
+ const cr = runCompiled(
5600
+ env,
5601
+ route.voidCall.op,
5602
+ route.voidCall.args,
5603
+ stAfterPrefix,
5604
+ COMPILED_IMPURE_OPS,
5605
+ true
5606
+ );
5607
+ if (cr === void 0 || cr.state === void 0) return void 0;
5608
+ stAfterBuild = cr.state;
5609
+ }
5610
+ return yield* countTailMatchG(env, fuel, stAfterBuild, built[0][1], route.tailMatch);
5611
+ }
5612
+ function canStreamStdlibCase(env, w) {
5613
+ return STREAM_CASE && (env.ruleIndex.get("case")?.length ?? 0) === 1 && env.varRulesVar.length === 0 && !w.selfRules.has("case") && w.selfVarRules.length === 0;
5614
+ }
5615
+ function streamCaseSource(env, st, bnd, matchExpr, cases) {
5616
+ if (cases.kind !== "expr" || cases.items.length !== 1) return void 0;
5617
+ const onlyCase = cases.items[0];
5618
+ if (onlyCase.kind !== "expr" || onlyCase.items.length !== 2 || onlyCase.items[0].kind !== "var")
5619
+ return void 0;
5620
+ const casePattern = inst(env, bnd, onlyCase.items[0]);
5621
+ const caseTemplate = inst(env, bnd, onlyCase.items[1]);
5622
+ const caseRuleEnd = { counter: st.counter + 1, world: st.world };
5623
+ const plan = matchPlan(
5624
+ env,
5625
+ caseRuleEnd,
5626
+ matchExpr.items[1],
5627
+ matchExpr.items[2],
5628
+ matchExpr.items[3],
5629
+ bnd
5630
+ );
5631
+ if (!plan.valuesAreNormal) return void 0;
5632
+ let valueCount = 0;
5633
+ const valueIter = plan.foldValues()[Symbol.iterator]();
5634
+ for (let next = valueIter.next(); !next.done; next = valueIter.next()) valueCount += 1;
5635
+ const switchCount = valueCount === 0 ? 1 : valueCount;
5636
+ const endState = {
5637
+ counter: plan.endState.counter + 2 * switchCount,
5638
+ world: plan.endState.world
5639
+ };
5640
+ const bodyFor = (value) => {
5641
+ for (const mb of matchAtoms(value, casePattern))
5642
+ for (const m of merge(bnd, mb)) if (!hasLoop(m)) return inst(env, m, caseTemplate);
5643
+ return sym("Empty");
5644
+ };
5645
+ return {
5646
+ endState,
5647
+ *foldItems() {
5648
+ let any = false;
5649
+ for (const value of plan.foldValues()) {
5650
+ any = true;
5651
+ yield {
5652
+ stack: atomToStack(expr([sym("metta"), bodyFor(value), UNDEF, sym("&self")]), null),
5653
+ bnd
5654
+ };
5655
+ }
5656
+ if (!any)
5657
+ yield {
5658
+ stack: atomToStack(
5659
+ expr([sym("metta"), bodyFor(sym("Empty")), UNDEF, sym("&self")]),
5660
+ null
5661
+ ),
5662
+ bnd
5663
+ };
5664
+ }
5665
+ };
5666
+ }
3411
5667
  function* mettaEvalG(env, fuel, st, bnd, a) {
3412
5668
  if (fuel <= 0)
3413
- return [[[expr([sym("Error"), instantiate(bnd, a), sym("StackOverflow")]), bnd]], st];
3414
- const w = instantiate(bnd, a);
3415
- if (w.kind === "expr" && w.ground && evaluatedAtoms.has(w)) return [[[w, bnd]], st];
5669
+ return [[[makeExpr(env, [sym("Error"), inst(env, bnd, a), sym("StackOverflow")]), bnd]], st];
5670
+ const w = inst(env, bnd, a);
5671
+ if (w.kind === "expr" && w.ground && env.evaluatedAtoms.has(w)) return [[[w, bnd]], st];
5672
+ if (CTOR_SC && w.kind === "expr" && !w.ground && w.items.length > 0 && env.varRulesVar.length === 0 && st.world.selfVarRules.length === 0 && isNormalForm(env, st.world, w))
5673
+ return [[[w, bnd]], st];
3416
5674
  const isErr = (x) => x.kind === "expr" && x.items.length >= 1 && x.items[0].kind === "sym" && x.items[0].name === "Error";
3417
5675
  if (w.kind === "expr" && w.items.length > 0 && w.items[0].kind === "sym") {
3418
5676
  let la = a;
@@ -3430,7 +5688,35 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3430
5688
  reduceTrampoline: for (; ; ) {
3431
5689
  const op = lw.items[0].name;
3432
5690
  const args = lw.items.slice(1);
5691
+ if (op === "collapse" && args.length === 1) {
5692
+ const match = matchInsideOnce(args[0]);
5693
+ if (match !== void 0) {
5694
+ const namedMatch = tryFastNamedOnceMatch(env, lst, match, lbnd);
5695
+ if (namedMatch !== void 0) {
5696
+ const items = namedMatch.value === void 0 ? [] : [namedMatch.value];
5697
+ return flushReturn([[expr(items), lbnd]], namedMatch.state);
5698
+ }
5699
+ }
5700
+ }
5701
+ if (op === "if" && args.length === 3) {
5702
+ const added = tryFastNamedAddIfAbsent(env, lst, lw, lbnd);
5703
+ if (added !== void 0)
5704
+ return flushReturn(added.added ? [[emptyExpr, lbnd]] : [], added.state);
5705
+ }
5706
+ if (op === "add-unique-or-fail" && args.length === 2) {
5707
+ const added = tryFastAddUniqueOrFailCall(env, lst, lw, lbnd);
5708
+ if (added !== void 0)
5709
+ return flushReturn(added.added ? [[emptyExpr, lbnd]] : [], added.state);
5710
+ }
3433
5711
  if ((op === "length" || op === "size-atom") && args.length === 1 && args[0].kind === "expr" && opOf(args[0]) === "collapse" && args[0].items.length === 2 && !env.ruleIndex.has(op) && !lst.world.selfRules.has(op)) {
5712
+ const z = args[0].items[1];
5713
+ if (z.kind === "expr" && opOf(z) === "match" && z.items.length === 4) {
5714
+ const counted = yield* countTailMatchG(env, fuel, lst, lbnd, z);
5715
+ return flushReturn([[gint(BigInt(counted.count)), lbnd]], counted.state);
5716
+ }
5717
+ const routed = yield* tryCollapseRouteG(env, fuel, lst, lbnd, z);
5718
+ if (routed !== void 0)
5719
+ return flushReturn([[gint(BigInt(routed.count)), lbnd]], routed.state);
3434
5720
  let count = 0;
3435
5721
  const [, stC] = yield* interpretLoopG(
3436
5722
  env,
@@ -3483,7 +5769,21 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3483
5769
  lst
3484
5770
  );
3485
5771
  }
3486
- const queryVars = args.flatMap((x) => atomVars(x));
5772
+ if (op === "case" && args.length === 2 && args[0].kind === "expr" && opOf(args[0]) === "match" && args[0].items.length === 4 && args[1].kind === "expr" && canStreamStdlibCase(env, lst.world)) {
5773
+ const source = streamCaseSource(env, lst, lbnd, args[0], args[1]);
5774
+ if (source !== void 0) {
5775
+ const [selected, stCase] = yield* interpretLoopG(env, fuel, lst, source);
5776
+ const [pairs2, stReduced] = yield* reduceChildrenG(
5777
+ env,
5778
+ fuel,
5779
+ stCase,
5780
+ selected,
5781
+ () => void 0
5782
+ );
5783
+ return flushReturn(pairs2, stReduced);
5784
+ }
5785
+ }
5786
+ const queryVars = queryVarsOf(args);
3487
5787
  const sig = opSig;
3488
5788
  const opReturnsAtom = sig !== void 0 && sig.length > 0 && atomEq(sig[sig.length - 1], sym("Atom"));
3489
5789
  const mask = LAZY_ARGS_OPS.has(op) ? args.map(() => false) : argMask(sig, args.length);
@@ -3498,10 +5798,10 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3498
5798
  const [ps, st2] = yield* mettaEvalG(env, fuel - 1, cur, accB, ae);
3499
5799
  cur = st2;
3500
5800
  for (const p of ps) {
3501
- nextParts.push([[...accAtoms, p[0]], mergeRestrict(queryVars, accB, p[1])]);
5801
+ nextParts.push([[...accAtoms, p[0]], mergeRestrict(env, queryVars, accB, p[1])]);
3502
5802
  }
3503
5803
  } else {
3504
- nextParts.push([[...accAtoms, instantiate(accB, ae)], accB]);
5804
+ nextParts.push([[...accAtoms, inst(env, accB, ae)], accB]);
3505
5805
  }
3506
5806
  }
3507
5807
  partials = nextParts;
@@ -3522,30 +5822,60 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3522
5822
  out.push([errFound, partB]);
3523
5823
  continue;
3524
5824
  }
3525
- const wApp = expr([sym(op), ...partAtoms]);
5825
+ const wApp = makeExpr(env, [sym(op), ...partAtoms]);
3526
5826
  if (env.curry && partAtoms.length >= 1) {
3527
5827
  const ar = functionArity(env, cur2.world, op);
3528
5828
  if (ar !== void 0 && partAtoms.length < ar) {
3529
- out.push([expr([sym("partial"), sym(op), expr(partAtoms)]), partB]);
5829
+ out.push([makeExpr(env, [sym("partial"), sym(op), makeExpr(env, partAtoms)]), partB]);
3530
5830
  continue;
3531
5831
  }
3532
5832
  }
3533
- if (env.compiled !== void 0) {
3534
- const cr = runCompiled(env, op, partAtoms);
5833
+ const fastTilePuzzle = tryFastTilePuzzleBfsAll(env, cur2, wApp);
5834
+ if (fastTilePuzzle !== void 0) {
5835
+ cur2 = fastTilePuzzle.state;
5836
+ for (const [value, rb] of fastTilePuzzle.results)
5837
+ out.push([value, mergeRestrict(env, queryVars, partB, rb)]);
5838
+ continue;
5839
+ }
5840
+ const fastQueue = tryFastQueueCall(env, cur2, wApp);
5841
+ if (fastQueue !== void 0) {
5842
+ cur2 = fastQueue.state;
5843
+ for (const [value, rb] of fastQueue.results)
5844
+ out.push([value, mergeRestrict(env, queryVars, partB, rb)]);
5845
+ continue;
5846
+ }
5847
+ if (env.compiled !== void 0 && !cur2.world.selfRules.has(op) && cur2.world.selfVarRules.length === 0) {
5848
+ const cr = runCompiled(env, op, partAtoms, cur2, COMPILED_IMPURE_OPS);
3535
5849
  if (cr !== void 0) {
3536
- out.push([cr, partB]);
5850
+ const impResult = cr.state !== void 0;
5851
+ if (cr.state !== void 0) cur2 = cr.state;
5852
+ else if (cr.counterDelta !== 0)
5853
+ cur2 = { counter: cur2.counter + cr.counterDelta, world: cur2.world };
5854
+ for (const r of cr.results) {
5855
+ const pb = mergeRestrict(env, queryVars, partB, r.bnd);
5856
+ if (atomEq(r.atom, notReducibleA) || atomEq(r.atom, wApp)) {
5857
+ if (wApp.ground) env.evaluatedAtoms.add(wApp);
5858
+ out.push([wApp, partB]);
5859
+ } else if ((opReturnsAtom || impResult) && !isEmbeddedOp(r.atom)) {
5860
+ out.push([r.atom, pb]);
5861
+ } else {
5862
+ const [more, st4] = yield* mettaEvalG(env, fuel - 1, cur2, pb, r.atom);
5863
+ cur2 = st4;
5864
+ for (const m of more) out.push([m[0], mergeRestrict(env, queryVars, pb, m[1])]);
5865
+ }
5866
+ }
3537
5867
  continue;
3538
5868
  }
3539
5869
  }
3540
5870
  let eligible = false;
3541
5871
  let key = "";
3542
- if (tabling && wApp.ground && keyWellFormed(wApp)) {
5872
+ if (tabling && wApp.ground) {
3543
5873
  if (cur2.world.selfRules.has(op)) {
3544
- if (runtimeFunctorPure(env, cur2.world, op)) {
5874
+ if (runtimeFunctorPure(env, cur2.world, op) && keyWellFormed(wApp)) {
3545
5875
  eligible = true;
3546
5876
  key = tableKey(wApp) + "@v" + rulesVersion(cur2.world.selfRules.get(op));
3547
5877
  }
3548
- } else if (staticPure) {
5878
+ } else if (staticPure && keyWellFormed(wApp)) {
3549
5879
  eligible = true;
3550
5880
  key = tableKey(wApp);
3551
5881
  }
@@ -3559,26 +5889,26 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3559
5889
  }
3560
5890
  const before = out.length;
3561
5891
  const [pairs2, st3] = yield* interpretLoopG(env, fuel, cur2, [
3562
- { stack: atomToStack(expr([sym("eval"), wApp]), null), bnd: lbnd }
5892
+ { stack: atomToStack(makeExpr(env, [sym("eval"), wApp]), null), bnd: lbnd }
3563
5893
  ]);
3564
5894
  cur2 = st3;
3565
5895
  if (partials.length === 1 && queryVars.length === 0 && pairs2.length === 1) {
3566
5896
  const p = pairs2[0];
3567
5897
  const isData = atomEq(p[0], notReducibleA) || atomEq(p[0], wApp);
3568
5898
  if (!isData && !(opReturnsAtom && !isEmbeddedOp(p[0])) && opOf(p[0]) !== void 0) {
3569
- const pb = mergeRestrict(queryVars, partB, p[1]);
5899
+ const pb = mergeRestrict(env, queryVars, partB, p[1]);
3570
5900
  if (eligible) pendingKeys.push(key);
3571
5901
  la = p[0];
3572
5902
  lbnd = pb;
3573
5903
  lst = cur2;
3574
- lw = instantiate(lbnd, la);
5904
+ lw = inst(env, lbnd, la);
3575
5905
  continue reduceTrampoline;
3576
5906
  }
3577
5907
  }
3578
5908
  for (const p of pairs2) {
3579
- const pb = mergeRestrict(queryVars, partB, p[1]);
5909
+ const pb = mergeRestrict(env, queryVars, partB, p[1]);
3580
5910
  if (atomEq(p[0], notReducibleA) || atomEq(p[0], wApp)) {
3581
- if (wApp.ground) evaluatedAtoms.add(wApp);
5911
+ if (wApp.ground) env.evaluatedAtoms.add(wApp);
3582
5912
  out.push([wApp, partB]);
3583
5913
  } else if (opReturnsAtom && !isEmbeddedOp(p[0])) {
3584
5914
  out.push([p[0], pb]);
@@ -3586,7 +5916,7 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3586
5916
  const [more, st4] = yield* mettaEvalG(env, fuel - 1, cur2, pb, p[0]);
3587
5917
  cur2 = st4;
3588
5918
  for (const m of more) {
3589
- out.push([m[0], mergeRestrict(queryVars, pb, m[1])]);
5919
+ out.push([m[0], mergeRestrict(env, queryVars, pb, m[1])]);
3590
5920
  }
3591
5921
  }
3592
5922
  }
@@ -3600,14 +5930,14 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3600
5930
  }
3601
5931
  if (w.kind === "expr" && w.items.length > 0) {
3602
5932
  const [ruleRes, st12] = yield* interpretLoopG(env, fuel, st, [
3603
- { stack: atomToStack(expr([sym("eval"), w]), null), bnd }
5933
+ { stack: atomToStack(makeExpr(env, [sym("eval"), w]), null), bnd }
3604
5934
  ]);
3605
5935
  const reduced = ruleRes.filter((p) => !atomEq(p[0], w) && !atomEq(p[0], notReducibleA));
3606
5936
  if (reduced.length === 0) {
3607
5937
  const [tupleRes, st2] = yield* interpretLoopG(env, fuel, st12, [
3608
5938
  {
3609
5939
  stack: atomToStack(
3610
- expr([sym("eval"), expr([sym("interpret-tuple"), w, sym("&self")])]),
5940
+ makeExpr(env, [sym("eval"), makeExpr(env, [sym("interpret-tuple"), w, sym("&self")])]),
3611
5941
  null
3612
5942
  ),
3613
5943
  bnd
@@ -3624,7 +5954,7 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3624
5954
  return yield* reduceChildrenG(env, fuel, st12, reduced, () => void 0);
3625
5955
  }
3626
5956
  const [pairs, st1] = yield* interpretLoopG(env, fuel, st, [
3627
- { stack: atomToStack(expr([sym("eval"), w]), null), bnd }
5957
+ { stack: atomToStack(makeExpr(env, [sym("eval"), w]), null), bnd }
3628
5958
  ]);
3629
5959
  return yield* reduceChildrenG(
3630
5960
  env,
@@ -3638,22 +5968,22 @@ var DEFAULT_FUEL = 2e6;
3638
5968
  function isNativeStackOverflow(e) {
3639
5969
  return e instanceof RangeError && /call stack/i.test(e.message);
3640
5970
  }
3641
- function stackOverflowResult(st, bnd, a) {
3642
- return [[[expr([sym("Error"), instantiate(bnd, a), sym("StackOverflow")]), bnd]], st];
5971
+ function stackOverflowResult(env, st, bnd, a) {
5972
+ return [[[makeExpr(env, [sym("Error"), inst(env, bnd, a), sym("StackOverflow")]), bnd]], st];
3643
5973
  }
3644
5974
  function mettaEval(env, fuel, st, bnd, a) {
3645
5975
  ensureCompiled(env);
3646
5976
  try {
3647
5977
  return runGenSync(mettaEvalG(env, fuel, st, bnd, a));
3648
5978
  } catch (e) {
3649
- if (isNativeStackOverflow(e)) return stackOverflowResult(st, bnd, a);
5979
+ if (isNativeStackOverflow(e)) return stackOverflowResult(env, st, bnd, a);
3650
5980
  throw e;
3651
5981
  }
3652
5982
  }
3653
5983
  function mettaEvalAsync(env, fuel, st, bnd, a, signal) {
3654
5984
  ensureCompiled(env);
3655
5985
  return runGenAsync(mettaEvalG(env, fuel, st, bnd, a), signal).catch((e) => {
3656
- if (isNativeStackOverflow(e)) return stackOverflowResult(st, bnd, a);
5986
+ if (isNativeStackOverflow(e)) return stackOverflowResult(env, st, bnd, a);
3657
5987
  throw e;
3658
5988
  });
3659
5989
  }
@@ -4169,12 +6499,15 @@ function preludeAtoms() {
4169
6499
  }
4170
6500
  var DEFAULT_FUEL2 = 1e5;
4171
6501
  var DEFAULT_TABLING = true;
4172
- function buildDefaultEnv(imports, tabling) {
6502
+ function buildDefaultEnv(imports, tabling, experimental) {
4173
6503
  const env = buildEnv(
4174
6504
  [...preludeAtoms(), ...stdlibAtoms(), ...pettaStdlibAtoms()],
4175
6505
  stdTable()
4176
6506
  );
4177
6507
  env.imports = withBuiltinModules(imports);
6508
+ if (experimental?.hashCons === true) env.intern = createInternTable();
6509
+ if (experimental?.trail === true) env.useTrail = true;
6510
+ if (experimental?.flatAtomspace === true) env.useFlatAtomspace = true;
4178
6511
  if (tabling) {
4179
6512
  env.table = /* @__PURE__ */ new Map();
4180
6513
  env.pureFunctors = analyzePurity(env);
@@ -4187,7 +6520,7 @@ function evalSequential(atoms, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ n
4187
6520
  const out = [];
4188
6521
  let st = initSt();
4189
6522
  if (opts.maxStackDepth !== void 0) st.world.maxStackDepth = opts.maxStackDepth;
4190
- const env = buildDefaultEnv(imports, opts.tabling ?? DEFAULT_TABLING);
6523
+ const env = buildDefaultEnv(imports, opts.tabling ?? DEFAULT_TABLING, opts.experimental);
4191
6524
  if (opts.parEvalImpl !== void 0) {
4192
6525
  const rulesSrc = atoms.filter((a) => !a.bang).map((a) => format(a.atom)).join("\n");
4193
6526
  const impl = opts.parEvalImpl;
@@ -4209,12 +6542,13 @@ function evalSequential(atoms, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ n
4209
6542
  function runProgram(src, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map(), opts = {}) {
4210
6543
  return evalSequential(parseAll(src, standardTokenizer()), fuel, imports, opts);
4211
6544
  }
4212
- async function runProgramAsync(src, asyncOps = /* @__PURE__ */ new Map(), fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map()) {
6545
+ async function runProgramAsync(src, asyncOps = /* @__PURE__ */ new Map(), fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map(), opts = {}) {
4213
6546
  const parsed = parseAll(src, standardTokenizer());
4214
- const env = buildDefaultEnv(imports, false);
6547
+ const env = buildDefaultEnv(imports, opts.tabling ?? false, opts.experimental);
4215
6548
  for (const [k, v] of asyncOps) env.agt.set(k, v);
4216
6549
  const out = [];
4217
6550
  let st = initSt();
6551
+ if (opts.maxStackDepth !== void 0) st.world.maxStackDepth = opts.maxStackDepth;
4218
6552
  for (const { atom, bang } of parsed) {
4219
6553
  if (!bang) {
4220
6554
  addAtomToEnv(env, atom);
@@ -4276,7 +6610,7 @@ var Interner = class {
4276
6610
  return this.add("s\0" + name, { kind: "sym", name });
4277
6611
  }
4278
6612
  internGround(value) {
4279
- return this.add(groundKey(value), { kind: "gnd", value });
6613
+ return this.add(groundKey2(value), { kind: "gnd", value });
4280
6614
  }
4281
6615
  /** The id for a symbol/ground if already interned, else undefined (a pattern symbol absent from the
4282
6616
  * KB can never match, so its lookup short-circuits). */
@@ -4284,7 +6618,7 @@ var Interner = class {
4284
6618
  return this.byKey.get("s\0" + name);
4285
6619
  }
4286
6620
  lookupGround(value) {
4287
- return this.byKey.get(groundKey(value));
6621
+ return this.byKey.get(groundKey2(value));
4288
6622
  }
4289
6623
  /** Reconstruct the atom for a leaf id. */
4290
6624
  decodeLeaf(id) {
@@ -4295,7 +6629,7 @@ var Interner = class {
4295
6629
  return this.entries.length;
4296
6630
  }
4297
6631
  };
4298
- function groundKey(v) {
6632
+ function groundKey2(v) {
4299
6633
  switch (v.g) {
4300
6634
  case "int":
4301
6635
  return "i\0" + v.n;
@@ -4586,83 +6920,13 @@ function williamTopK(kb, k, refCost = 4) {
4586
6920
  gain: s.gain
4587
6921
  }));
4588
6922
  }
4589
-
4590
- // src/trail.ts
4591
- var Trail = class {
4592
- binds = /* @__PURE__ */ new Map();
4593
- trail = [];
4594
- /** A restore point: the current trail length. */
4595
- mark() {
4596
- return this.trail.length;
4597
- }
4598
- /** Undo every binding made since `m`. */
4599
- undo(m) {
4600
- const t = this.trail;
4601
- while (t.length > m) this.binds.delete(t.pop());
4602
- }
4603
- /** Bind `$name` to `a` and record it on the trail. The caller guarantees `$name` is currently unbound. */
4604
- bind(name, a) {
4605
- this.binds.set(name, a);
4606
- this.trail.push(name);
4607
- }
4608
- /** Follow variable bindings to the representative: a non-variable, or an unbound variable. */
4609
- deref(a) {
4610
- let cur = a;
4611
- while (cur.kind === "var") {
4612
- const v = this.binds.get(cur.name);
4613
- if (v === void 0) return cur;
4614
- cur = v;
4615
- }
4616
- return cur;
4617
- }
4618
- /** Resolve `a` against the current bindings, one pass (the same discipline as the immutable
4619
- * `instantiate`/`applySubst`): a variable becomes its bound value as-is; the value's own variables are
4620
- * not re-resolved, and an expression's children are resolved. This matches the evaluator exactly,
4621
- * including that a cyclic binding (`$y = (.. $y ..)`, which `matchAtoms` produces and `hasLoop` does not
4622
- * reject) terminates instead of looping. A new term is built only where a child changed. */
4623
- resolve(a) {
4624
- if (a.kind === "var") return this.deref(a);
4625
- if (a.kind !== "expr" || a.ground) return a;
4626
- const its = a.items;
4627
- let items = null;
4628
- for (let i = 0; i < its.length; i++) {
4629
- const it = its[i];
4630
- const r = this.resolve(it);
4631
- if (items !== null) items.push(r);
4632
- else if (r !== it) {
4633
- items = its.slice(0, i);
4634
- items.push(r);
4635
- }
4636
- }
4637
- return items === null ? a : { ...a, items };
4638
- }
4639
- };
4640
- function unifyTrail(tr, l0, r0) {
4641
- const l = tr.deref(l0);
4642
- const r = tr.deref(r0);
4643
- if (l === r) return true;
4644
- if (l.kind === "var") {
4645
- if (r.kind === "var" && l.name === r.name) return true;
4646
- tr.bind(l.name, r);
4647
- return true;
4648
- }
4649
- if (r.kind === "var") {
4650
- tr.bind(r.name, l);
4651
- return true;
4652
- }
4653
- if (l.kind === "sym") return r.kind === "sym" && l.name === r.name;
4654
- if (l.kind === "gnd") return r.kind === "gnd" && atomEq(l, r);
4655
- if (r.kind !== "expr" || l.items.length !== r.items.length) return false;
4656
- for (let i = 0; i < l.items.length; i++)
4657
- if (!unifyTrail(tr, l.items[i], r.items[i])) return false;
4658
- return true;
4659
- }
4660
6923
  export {
4661
6924
  AsyncInSyncError,
4662
6925
  BAIL,
4663
6926
  CONCURRENCY_MODULE_SRC,
4664
6927
  CURRY_MODULE_SRC,
4665
6928
  DEFAULT_FUEL2 as DEFAULT_FUEL,
6929
+ FlatAtomSpace,
4666
6930
  FlatKB,
4667
6931
  IMPURE_OPS,
4668
6932
  InMemorySpace,
@@ -4692,11 +6956,14 @@ export {
4692
6956
  buildEnv,
4693
6957
  builtinModules,
4694
6958
  callGrounded,
6959
+ canCompactAtom,
6960
+ canInternExprItems,
4695
6961
  canonInt,
4696
6962
  cmpIntVal,
4697
6963
  collectImports,
4698
6964
  collectVars,
4699
6965
  compileEnv,
6966
+ createInternTable,
4700
6967
  decodeAt,
4701
6968
  decodeAtom,
4702
6969
  emptyBindings,
@@ -4706,6 +6973,7 @@ export {
4706
6973
  encodeAtom,
4707
6974
  encodeInto,
4708
6975
  encodePattern,
6976
+ eqRelations,
4709
6977
  eraseSubst,
4710
6978
  evalAtom,
4711
6979
  evalSequential,
@@ -4713,6 +6981,7 @@ export {
4713
6981
  extendSubst,
4714
6982
  format,
4715
6983
  freshenRule,
6984
+ fromRelations,
4716
6985
  gbool,
4717
6986
  getTypes,
4718
6987
  gfloat,
@@ -4722,6 +6991,7 @@ export {
4722
6991
  groundType,
4723
6992
  gstr,
4724
6993
  gunit,
6994
+ hasEq,
4725
6995
  hasLoop,
4726
6996
  hashOf,
4727
6997
  initSt,
@@ -4729,6 +6999,10 @@ export {
4729
6999
  intAbs,
4730
7000
  intDiv,
4731
7001
  intMod,
7002
+ internAtom,
7003
+ internBuiltExpr,
7004
+ internExpr,
7005
+ isEmpty,
4732
7006
  isErrorAtom,
4733
7007
  isExpr,
4734
7008
  isGnd,
@@ -4739,6 +7013,7 @@ export {
4739
7013
  keyWellFormed,
4740
7014
  lookupSubst,
4741
7015
  lookupVal,
7016
+ makeValRel,
4742
7017
  matchAtoms,
4743
7018
  matchAtomsScoped,
4744
7019
  matchAtomsWith,
@@ -4747,6 +7022,7 @@ export {
4747
7022
  metaType,
4748
7023
  mettaEval,
4749
7024
  mettaEvalAsync,
7025
+ mixHash,
4750
7026
  mulInt,
4751
7027
  occurs,
4752
7028
  oracleReport,
@@ -4754,15 +7030,20 @@ export {
4754
7030
  parseAll,
4755
7031
  pettaOpNames,
4756
7032
  preludeAtoms,
7033
+ prependValRaw,
7034
+ relations,
4757
7035
  removeVal,
4758
7036
  runCompiled,
4759
7037
  runProgram,
4760
7038
  runProgramAsync,
4761
7039
  setOutputSink,
4762
7040
  setRawSink,
7041
+ size,
7042
+ someVal,
4763
7043
  standardTokenizer,
4764
7044
  stdTable,
4765
7045
  stdlibAtoms,
7046
+ strHash,
4766
7047
  subInt,
4767
7048
  sym,
4768
7049
  tableKey,
@@ -4770,8 +7051,10 @@ export {
4770
7051
  unifiable,
4771
7052
  unifyTop,
4772
7053
  unifyTrail,
7054
+ valEntries,
4773
7055
  variable,
4774
7056
  wcoJoin,
7057
+ wcoJoinFold,
4775
7058
  williamTopK,
4776
7059
  withBuiltinModules
4777
7060
  };