@metta-ts/core 1.0.1 → 1.0.2

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 +2602 -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);
2532
3894
  }
2533
- function scopeVars(b, prev) {
3895
+ function queryVarsOf(args) {
3896
+ const out = [];
3897
+ for (const a of args) if (!a.ground) out.push(...atomVars(a));
3898
+ return out;
3899
+ }
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,271 @@ 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") return void 0;
5407
+ const op = rhs.items[0].name;
5408
+ const args = rhs.items.slice(1);
5409
+ if (env.compiled?.get(op)?.kind !== "imperative" || args.some((a) => !a.ground)) return void 0;
5410
+ return { op, args };
5411
+ };
5412
+ const head = opOf(buildExpr);
5413
+ if (head === "let" && buildExpr.items.length === 4 && atomEq(buildExpr.items[3], DONE_UNIT)) {
5414
+ const v = voidable(buildExpr.items[2]);
5415
+ if (v === void 0) return void 0;
5416
+ return { prefix: expr([buildExpr.items[0], buildExpr.items[1], DONE_UNIT, DONE_UNIT]), op: v.op, args: v.args };
5417
+ }
5418
+ if (head === "let*" && buildExpr.items.length === 3 && buildExpr.items[1].kind === "expr" && atomEq(buildExpr.items[2], DONE_UNIT)) {
5419
+ const pairs = buildExpr.items[1].items;
5420
+ const lastPair = pairs[pairs.length - 1];
5421
+ if (lastPair === void 0 || lastPair.kind !== "expr" || lastPair.items.length !== 2) return void 0;
5422
+ const v = voidable(lastPair.items[1]);
5423
+ if (v === void 0) return void 0;
5424
+ const newPairs = [...pairs.slice(0, -1), expr([lastPair.items[0], DONE_UNIT])];
5425
+ return { prefix: expr([buildExpr.items[0], expr(newPairs), DONE_UNIT]), op: v.op, args: v.args };
5426
+ }
5427
+ return void 0;
5428
+ }
5429
+ function addAtomVars(into, atom) {
5430
+ for (const name of atomVars(atom)) into.add(name);
5431
+ }
5432
+ function hasAnyAtomVar(vars, atoms) {
5433
+ for (const atom of atoms) for (const name of atomVars(atom)) if (vars.has(name)) return true;
5434
+ return false;
5435
+ }
5436
+ function tailMatchBuild(body) {
5437
+ if (body.kind !== "expr") return void 0;
5438
+ const op = opOf(body);
5439
+ if (op === "match" && body.items.length === 4)
5440
+ return { buildExpr: DONE_UNIT, tailMatch: body, boundVars: /* @__PURE__ */ new Set() };
5441
+ if (op === "let" && body.items.length === 4) {
5442
+ const inner = tailMatchBuild(body.items[3]);
5443
+ if (inner === void 0) return void 0;
5444
+ const boundVars = new Set(inner.boundVars);
5445
+ addAtomVars(boundVars, body.items[1]);
5446
+ return {
5447
+ buildExpr: expr([body.items[0], body.items[1], body.items[2], inner.buildExpr]),
5448
+ tailMatch: inner.tailMatch,
5449
+ boundVars
5450
+ };
5451
+ }
5452
+ if (op === "let*" && body.items.length === 3 && body.items[1].kind === "expr") {
5453
+ const inner = tailMatchBuild(body.items[2]);
5454
+ if (inner === void 0) return void 0;
5455
+ const boundVars = new Set(inner.boundVars);
5456
+ for (const pair of body.items[1].items) {
5457
+ if (pair.kind !== "expr" || pair.items.length !== 2) return void 0;
5458
+ addAtomVars(boundVars, pair.items[0]);
5459
+ }
5460
+ return {
5461
+ buildExpr: expr([body.items[0], body.items[1], inner.buildExpr]),
5462
+ tailMatch: inner.tailMatch,
5463
+ boundVars
5464
+ };
5465
+ }
5466
+ return void 0;
5467
+ }
5468
+ function prepareCollapseRoute(env, st, bnd, call) {
5469
+ 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)
5470
+ return void 0;
5471
+ if (isDefinedHead(env, st.world, DONE_UNIT.name)) return void 0;
5472
+ const op = call.items[0].name;
5473
+ if (st.world.selfRules.has(op) || env.pureFunctors?.has(op) === true) return void 0;
5474
+ const rules = env.ruleIndex.get(op);
5475
+ if (rules === void 0 || rules.length !== 1) return void 0;
5476
+ const args = call.items.slice(1);
5477
+ if (args.some((arg) => !isNormalForm(env, st.world, arg))) return void 0;
5478
+ if (typeMismatch(env, st.world, op, args, env.sigs.get(op)) !== void 0) return void 0;
5479
+ const [lhs, rhs] = rules[0];
5480
+ if (lhs.kind !== "expr" || lhs.items.length !== call.items.length || !canMatchShallow(lhs, call))
5481
+ return void 0;
5482
+ const suffix = "#" + st.counter;
5483
+ const matches = [];
5484
+ for (const mb of matchAtomsScoped(lhs, call, suffix))
5485
+ for (const m of merge(bnd, mb)) if (!hasLoop(m)) matches.push(m);
5486
+ if (matches.length !== 1) return void 0;
5487
+ const body = inst(env, matches[0], rhs, suffix);
5488
+ const tail = tailMatchBuild(body);
5489
+ if (tail === void 0) return void 0;
5490
+ if (hasAnyAtomVar(tail.boundVars, tail.tailMatch.items.slice(1))) return void 0;
5491
+ let buildExpr = tail.buildExpr;
5492
+ let voidCall;
5493
+ if (voidBuildEnabled()) {
5494
+ const split = splitVoidBuild(buildExpr, env);
5495
+ if (split !== void 0) {
5496
+ buildExpr = split.prefix;
5497
+ voidCall = { op: split.op, args: split.args };
5498
+ }
5499
+ }
5500
+ return {
5501
+ buildExpr,
5502
+ tailMatch: tail.tailMatch,
5503
+ st: { counter: st.counter + 1, world: st.world },
5504
+ bnd: matches[0],
5505
+ voidCall
5506
+ };
5507
+ }
5508
+ function tryCountAggregate(env, st, bnd, match) {
5509
+ if (match.items.length < 3) return void 0;
5510
+ const { getCandidates, patterns } = matchSetup(env, st, match.items[1], match.items[2], bnd);
5511
+ if (patterns.length !== 1) return void 0;
5512
+ const pat = inst(env, bnd, patterns[0]);
5513
+ if (pat.kind !== "expr" || pat.items.length === 0 || pat.items[0].kind !== "sym") return void 0;
5514
+ const seen = /* @__PURE__ */ new Set();
5515
+ for (let i = 1; i < pat.items.length; i++) {
5516
+ const a = pat.items[i];
5517
+ if (a.kind !== "var" || seen.has(a.name)) return void 0;
5518
+ seen.add(a.name);
5519
+ }
5520
+ if (seen.size === 0) return void 0;
5521
+ const k = headKey(pat);
5522
+ const arity = pat.items.length;
5523
+ const unifies = (a) => a.kind === "var" || a.kind === "expr" && a.items.length === arity && (headKey(a) === k || a.items[0].kind === "var");
5524
+ const w = st.world;
5525
+ const sn = spaceName(w, inst(env, bnd, match.items[1]));
5526
+ 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) {
5527
+ let count2 = 0;
5528
+ let iterated2 = 0;
5529
+ for (let p = w.selfExtra; p !== null; p = p.prev) {
5530
+ const akk = headKey(p.atom);
5531
+ if (akk === void 0 || akk === k) {
5532
+ iterated2 += 1;
5533
+ if (unifies(p.atom)) count2 += 1;
5534
+ }
5535
+ }
5536
+ return { count: count2, iterated: iterated2 };
5537
+ }
5538
+ const source = getCandidates(pat);
5539
+ let count = 0;
5540
+ let iterated = 0;
5541
+ for (const cand of source) {
5542
+ iterated += 1;
5543
+ if (unifies(cand)) count += 1;
5544
+ }
5545
+ iterated += candidateCounterPadding(source);
5546
+ return { count, iterated };
5547
+ }
5548
+ function* countTailMatchG(env, fuel, st, bnd, match) {
5549
+ const agg = countAggregateEnabled() ? tryCountAggregate(env, st, bnd, match) : void 0;
5550
+ if (agg !== void 0)
5551
+ return { count: agg.count, state: { counter: st.counter + agg.iterated, world: st.world } };
5552
+ {
5553
+ const { getCandidates, patterns } = matchSetup(env, st, match.items[1], match.items[2], bnd);
5554
+ const tc = patterns.length >= 2 && conjCountEnabled() ? matchConjCount(env, getCandidates, patterns, st, bnd) : env.useTrail === true ? matchCountTrail(getCandidates, patterns, st, bnd) : void 0;
5555
+ if (tc !== void 0)
5556
+ return { count: tc.count, state: { counter: tc.counter, world: st.world } };
5557
+ }
5558
+ let count = 0;
5559
+ const [, stC] = yield* interpretLoopG(
5560
+ env,
5561
+ fuel,
5562
+ st,
5563
+ [
5564
+ {
5565
+ stack: atomToStack(expr([sym("metta"), countOnlyMatch(match), UNDEF, sym("&self")]), null),
5566
+ bnd
5567
+ }
5568
+ ],
5569
+ () => {
5570
+ count++;
5571
+ }
5572
+ );
5573
+ return { count, state: stC };
5574
+ }
5575
+ function* tryCollapseRouteG(env, fuel, st, bnd, call) {
5576
+ const route = prepareCollapseRoute(env, st, bnd, call);
5577
+ if (route === void 0) return void 0;
5578
+ const [built, stAfterPrefix] = yield* interpretLoopG(env, fuel, route.st, [
5579
+ {
5580
+ stack: atomToStack(expr([sym("metta"), route.buildExpr, UNDEF, sym("&self")]), null),
5581
+ bnd: route.bnd
5582
+ }
5583
+ ]);
5584
+ if (built.length !== 1 || !atomEq(built[0][0], DONE_UNIT)) return void 0;
5585
+ let stAfterBuild = stAfterPrefix;
5586
+ if (route.voidCall !== void 0) {
5587
+ const cr = runCompiled(
5588
+ env,
5589
+ route.voidCall.op,
5590
+ route.voidCall.args,
5591
+ stAfterPrefix,
5592
+ COMPILED_IMPURE_OPS,
5593
+ true
5594
+ );
5595
+ if (cr === void 0 || cr.state === void 0) return void 0;
5596
+ stAfterBuild = cr.state;
5597
+ }
5598
+ return yield* countTailMatchG(env, fuel, stAfterBuild, built[0][1], route.tailMatch);
5599
+ }
5600
+ function canStreamStdlibCase(env, w) {
5601
+ return STREAM_CASE && (env.ruleIndex.get("case")?.length ?? 0) === 1 && env.varRulesVar.length === 0 && !w.selfRules.has("case") && w.selfVarRules.length === 0;
5602
+ }
5603
+ function streamCaseSource(env, st, bnd, matchExpr, cases) {
5604
+ if (cases.kind !== "expr" || cases.items.length !== 1) return void 0;
5605
+ const onlyCase = cases.items[0];
5606
+ if (onlyCase.kind !== "expr" || onlyCase.items.length !== 2 || onlyCase.items[0].kind !== "var")
5607
+ return void 0;
5608
+ const casePattern = inst(env, bnd, onlyCase.items[0]);
5609
+ const caseTemplate = inst(env, bnd, onlyCase.items[1]);
5610
+ const caseRuleEnd = { counter: st.counter + 1, world: st.world };
5611
+ const plan = matchPlan(
5612
+ env,
5613
+ caseRuleEnd,
5614
+ matchExpr.items[1],
5615
+ matchExpr.items[2],
5616
+ matchExpr.items[3],
5617
+ bnd
5618
+ );
5619
+ if (!plan.valuesAreNormal) return void 0;
5620
+ let valueCount = 0;
5621
+ const valueIter = plan.foldValues()[Symbol.iterator]();
5622
+ for (let next = valueIter.next(); !next.done; next = valueIter.next()) valueCount += 1;
5623
+ const switchCount = valueCount === 0 ? 1 : valueCount;
5624
+ const endState = {
5625
+ counter: plan.endState.counter + 2 * switchCount,
5626
+ world: plan.endState.world
5627
+ };
5628
+ const bodyFor = (value) => {
5629
+ for (const mb of matchAtoms(value, casePattern))
5630
+ for (const m of merge(bnd, mb)) if (!hasLoop(m)) return inst(env, m, caseTemplate);
5631
+ return sym("Empty");
5632
+ };
5633
+ return {
5634
+ endState,
5635
+ *foldItems() {
5636
+ let any = false;
5637
+ for (const value of plan.foldValues()) {
5638
+ any = true;
5639
+ yield {
5640
+ stack: atomToStack(expr([sym("metta"), bodyFor(value), UNDEF, sym("&self")]), null),
5641
+ bnd
5642
+ };
5643
+ }
5644
+ if (!any)
5645
+ yield {
5646
+ stack: atomToStack(
5647
+ expr([sym("metta"), bodyFor(sym("Empty")), UNDEF, sym("&self")]),
5648
+ null
5649
+ ),
5650
+ bnd
5651
+ };
5652
+ }
5653
+ };
5654
+ }
3411
5655
  function* mettaEvalG(env, fuel, st, bnd, a) {
3412
5656
  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];
5657
+ return [[[makeExpr(env, [sym("Error"), inst(env, bnd, a), sym("StackOverflow")]), bnd]], st];
5658
+ const w = inst(env, bnd, a);
5659
+ if (w.kind === "expr" && w.ground && env.evaluatedAtoms.has(w)) return [[[w, bnd]], st];
5660
+ 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))
5661
+ return [[[w, bnd]], st];
3416
5662
  const isErr = (x) => x.kind === "expr" && x.items.length >= 1 && x.items[0].kind === "sym" && x.items[0].name === "Error";
3417
5663
  if (w.kind === "expr" && w.items.length > 0 && w.items[0].kind === "sym") {
3418
5664
  let la = a;
@@ -3430,7 +5676,35 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3430
5676
  reduceTrampoline: for (; ; ) {
3431
5677
  const op = lw.items[0].name;
3432
5678
  const args = lw.items.slice(1);
5679
+ if (op === "collapse" && args.length === 1) {
5680
+ const match = matchInsideOnce(args[0]);
5681
+ if (match !== void 0) {
5682
+ const namedMatch = tryFastNamedOnceMatch(env, lst, match, lbnd);
5683
+ if (namedMatch !== void 0) {
5684
+ const items = namedMatch.value === void 0 ? [] : [namedMatch.value];
5685
+ return flushReturn([[expr(items), lbnd]], namedMatch.state);
5686
+ }
5687
+ }
5688
+ }
5689
+ if (op === "if" && args.length === 3) {
5690
+ const added = tryFastNamedAddIfAbsent(env, lst, lw, lbnd);
5691
+ if (added !== void 0)
5692
+ return flushReturn(added.added ? [[emptyExpr, lbnd]] : [], added.state);
5693
+ }
5694
+ if (op === "add-unique-or-fail" && args.length === 2) {
5695
+ const added = tryFastAddUniqueOrFailCall(env, lst, lw, lbnd);
5696
+ if (added !== void 0)
5697
+ return flushReturn(added.added ? [[emptyExpr, lbnd]] : [], added.state);
5698
+ }
3433
5699
  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)) {
5700
+ const z = args[0].items[1];
5701
+ if (z.kind === "expr" && opOf(z) === "match" && z.items.length === 4) {
5702
+ const counted = yield* countTailMatchG(env, fuel, lst, lbnd, z);
5703
+ return flushReturn([[gint(BigInt(counted.count)), lbnd]], counted.state);
5704
+ }
5705
+ const routed = yield* tryCollapseRouteG(env, fuel, lst, lbnd, z);
5706
+ if (routed !== void 0)
5707
+ return flushReturn([[gint(BigInt(routed.count)), lbnd]], routed.state);
3434
5708
  let count = 0;
3435
5709
  const [, stC] = yield* interpretLoopG(
3436
5710
  env,
@@ -3483,7 +5757,21 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3483
5757
  lst
3484
5758
  );
3485
5759
  }
3486
- const queryVars = args.flatMap((x) => atomVars(x));
5760
+ 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)) {
5761
+ const source = streamCaseSource(env, lst, lbnd, args[0], args[1]);
5762
+ if (source !== void 0) {
5763
+ const [selected, stCase] = yield* interpretLoopG(env, fuel, lst, source);
5764
+ const [pairs2, stReduced] = yield* reduceChildrenG(
5765
+ env,
5766
+ fuel,
5767
+ stCase,
5768
+ selected,
5769
+ () => void 0
5770
+ );
5771
+ return flushReturn(pairs2, stReduced);
5772
+ }
5773
+ }
5774
+ const queryVars = queryVarsOf(args);
3487
5775
  const sig = opSig;
3488
5776
  const opReturnsAtom = sig !== void 0 && sig.length > 0 && atomEq(sig[sig.length - 1], sym("Atom"));
3489
5777
  const mask = LAZY_ARGS_OPS.has(op) ? args.map(() => false) : argMask(sig, args.length);
@@ -3498,10 +5786,10 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3498
5786
  const [ps, st2] = yield* mettaEvalG(env, fuel - 1, cur, accB, ae);
3499
5787
  cur = st2;
3500
5788
  for (const p of ps) {
3501
- nextParts.push([[...accAtoms, p[0]], mergeRestrict(queryVars, accB, p[1])]);
5789
+ nextParts.push([[...accAtoms, p[0]], mergeRestrict(env, queryVars, accB, p[1])]);
3502
5790
  }
3503
5791
  } else {
3504
- nextParts.push([[...accAtoms, instantiate(accB, ae)], accB]);
5792
+ nextParts.push([[...accAtoms, inst(env, accB, ae)], accB]);
3505
5793
  }
3506
5794
  }
3507
5795
  partials = nextParts;
@@ -3522,30 +5810,60 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3522
5810
  out.push([errFound, partB]);
3523
5811
  continue;
3524
5812
  }
3525
- const wApp = expr([sym(op), ...partAtoms]);
5813
+ const wApp = makeExpr(env, [sym(op), ...partAtoms]);
3526
5814
  if (env.curry && partAtoms.length >= 1) {
3527
5815
  const ar = functionArity(env, cur2.world, op);
3528
5816
  if (ar !== void 0 && partAtoms.length < ar) {
3529
- out.push([expr([sym("partial"), sym(op), expr(partAtoms)]), partB]);
5817
+ out.push([makeExpr(env, [sym("partial"), sym(op), makeExpr(env, partAtoms)]), partB]);
3530
5818
  continue;
3531
5819
  }
3532
5820
  }
3533
- if (env.compiled !== void 0) {
3534
- const cr = runCompiled(env, op, partAtoms);
5821
+ const fastTilePuzzle = tryFastTilePuzzleBfsAll(env, cur2, wApp);
5822
+ if (fastTilePuzzle !== void 0) {
5823
+ cur2 = fastTilePuzzle.state;
5824
+ for (const [value, rb] of fastTilePuzzle.results)
5825
+ out.push([value, mergeRestrict(env, queryVars, partB, rb)]);
5826
+ continue;
5827
+ }
5828
+ const fastQueue = tryFastQueueCall(env, cur2, wApp);
5829
+ if (fastQueue !== void 0) {
5830
+ cur2 = fastQueue.state;
5831
+ for (const [value, rb] of fastQueue.results)
5832
+ out.push([value, mergeRestrict(env, queryVars, partB, rb)]);
5833
+ continue;
5834
+ }
5835
+ if (env.compiled !== void 0 && !cur2.world.selfRules.has(op) && cur2.world.selfVarRules.length === 0) {
5836
+ const cr = runCompiled(env, op, partAtoms, cur2, COMPILED_IMPURE_OPS);
3535
5837
  if (cr !== void 0) {
3536
- out.push([cr, partB]);
5838
+ const impResult = cr.state !== void 0;
5839
+ if (cr.state !== void 0) cur2 = cr.state;
5840
+ else if (cr.counterDelta !== 0)
5841
+ cur2 = { counter: cur2.counter + cr.counterDelta, world: cur2.world };
5842
+ for (const r of cr.results) {
5843
+ const pb = mergeRestrict(env, queryVars, partB, r.bnd);
5844
+ if (atomEq(r.atom, notReducibleA) || atomEq(r.atom, wApp)) {
5845
+ if (wApp.ground) env.evaluatedAtoms.add(wApp);
5846
+ out.push([wApp, partB]);
5847
+ } else if ((opReturnsAtom || impResult) && !isEmbeddedOp(r.atom)) {
5848
+ out.push([r.atom, pb]);
5849
+ } else {
5850
+ const [more, st4] = yield* mettaEvalG(env, fuel - 1, cur2, pb, r.atom);
5851
+ cur2 = st4;
5852
+ for (const m of more) out.push([m[0], mergeRestrict(env, queryVars, pb, m[1])]);
5853
+ }
5854
+ }
3537
5855
  continue;
3538
5856
  }
3539
5857
  }
3540
5858
  let eligible = false;
3541
5859
  let key = "";
3542
- if (tabling && wApp.ground && keyWellFormed(wApp)) {
5860
+ if (tabling && wApp.ground) {
3543
5861
  if (cur2.world.selfRules.has(op)) {
3544
- if (runtimeFunctorPure(env, cur2.world, op)) {
5862
+ if (runtimeFunctorPure(env, cur2.world, op) && keyWellFormed(wApp)) {
3545
5863
  eligible = true;
3546
5864
  key = tableKey(wApp) + "@v" + rulesVersion(cur2.world.selfRules.get(op));
3547
5865
  }
3548
- } else if (staticPure) {
5866
+ } else if (staticPure && keyWellFormed(wApp)) {
3549
5867
  eligible = true;
3550
5868
  key = tableKey(wApp);
3551
5869
  }
@@ -3559,26 +5877,26 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3559
5877
  }
3560
5878
  const before = out.length;
3561
5879
  const [pairs2, st3] = yield* interpretLoopG(env, fuel, cur2, [
3562
- { stack: atomToStack(expr([sym("eval"), wApp]), null), bnd: lbnd }
5880
+ { stack: atomToStack(makeExpr(env, [sym("eval"), wApp]), null), bnd: lbnd }
3563
5881
  ]);
3564
5882
  cur2 = st3;
3565
5883
  if (partials.length === 1 && queryVars.length === 0 && pairs2.length === 1) {
3566
5884
  const p = pairs2[0];
3567
5885
  const isData = atomEq(p[0], notReducibleA) || atomEq(p[0], wApp);
3568
5886
  if (!isData && !(opReturnsAtom && !isEmbeddedOp(p[0])) && opOf(p[0]) !== void 0) {
3569
- const pb = mergeRestrict(queryVars, partB, p[1]);
5887
+ const pb = mergeRestrict(env, queryVars, partB, p[1]);
3570
5888
  if (eligible) pendingKeys.push(key);
3571
5889
  la = p[0];
3572
5890
  lbnd = pb;
3573
5891
  lst = cur2;
3574
- lw = instantiate(lbnd, la);
5892
+ lw = inst(env, lbnd, la);
3575
5893
  continue reduceTrampoline;
3576
5894
  }
3577
5895
  }
3578
5896
  for (const p of pairs2) {
3579
- const pb = mergeRestrict(queryVars, partB, p[1]);
5897
+ const pb = mergeRestrict(env, queryVars, partB, p[1]);
3580
5898
  if (atomEq(p[0], notReducibleA) || atomEq(p[0], wApp)) {
3581
- if (wApp.ground) evaluatedAtoms.add(wApp);
5899
+ if (wApp.ground) env.evaluatedAtoms.add(wApp);
3582
5900
  out.push([wApp, partB]);
3583
5901
  } else if (opReturnsAtom && !isEmbeddedOp(p[0])) {
3584
5902
  out.push([p[0], pb]);
@@ -3586,7 +5904,7 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3586
5904
  const [more, st4] = yield* mettaEvalG(env, fuel - 1, cur2, pb, p[0]);
3587
5905
  cur2 = st4;
3588
5906
  for (const m of more) {
3589
- out.push([m[0], mergeRestrict(queryVars, pb, m[1])]);
5907
+ out.push([m[0], mergeRestrict(env, queryVars, pb, m[1])]);
3590
5908
  }
3591
5909
  }
3592
5910
  }
@@ -3600,14 +5918,14 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3600
5918
  }
3601
5919
  if (w.kind === "expr" && w.items.length > 0) {
3602
5920
  const [ruleRes, st12] = yield* interpretLoopG(env, fuel, st, [
3603
- { stack: atomToStack(expr([sym("eval"), w]), null), bnd }
5921
+ { stack: atomToStack(makeExpr(env, [sym("eval"), w]), null), bnd }
3604
5922
  ]);
3605
5923
  const reduced = ruleRes.filter((p) => !atomEq(p[0], w) && !atomEq(p[0], notReducibleA));
3606
5924
  if (reduced.length === 0) {
3607
5925
  const [tupleRes, st2] = yield* interpretLoopG(env, fuel, st12, [
3608
5926
  {
3609
5927
  stack: atomToStack(
3610
- expr([sym("eval"), expr([sym("interpret-tuple"), w, sym("&self")])]),
5928
+ makeExpr(env, [sym("eval"), makeExpr(env, [sym("interpret-tuple"), w, sym("&self")])]),
3611
5929
  null
3612
5930
  ),
3613
5931
  bnd
@@ -3624,7 +5942,7 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
3624
5942
  return yield* reduceChildrenG(env, fuel, st12, reduced, () => void 0);
3625
5943
  }
3626
5944
  const [pairs, st1] = yield* interpretLoopG(env, fuel, st, [
3627
- { stack: atomToStack(expr([sym("eval"), w]), null), bnd }
5945
+ { stack: atomToStack(makeExpr(env, [sym("eval"), w]), null), bnd }
3628
5946
  ]);
3629
5947
  return yield* reduceChildrenG(
3630
5948
  env,
@@ -3638,22 +5956,22 @@ var DEFAULT_FUEL = 2e6;
3638
5956
  function isNativeStackOverflow(e) {
3639
5957
  return e instanceof RangeError && /call stack/i.test(e.message);
3640
5958
  }
3641
- function stackOverflowResult(st, bnd, a) {
3642
- return [[[expr([sym("Error"), instantiate(bnd, a), sym("StackOverflow")]), bnd]], st];
5959
+ function stackOverflowResult(env, st, bnd, a) {
5960
+ return [[[makeExpr(env, [sym("Error"), inst(env, bnd, a), sym("StackOverflow")]), bnd]], st];
3643
5961
  }
3644
5962
  function mettaEval(env, fuel, st, bnd, a) {
3645
5963
  ensureCompiled(env);
3646
5964
  try {
3647
5965
  return runGenSync(mettaEvalG(env, fuel, st, bnd, a));
3648
5966
  } catch (e) {
3649
- if (isNativeStackOverflow(e)) return stackOverflowResult(st, bnd, a);
5967
+ if (isNativeStackOverflow(e)) return stackOverflowResult(env, st, bnd, a);
3650
5968
  throw e;
3651
5969
  }
3652
5970
  }
3653
5971
  function mettaEvalAsync(env, fuel, st, bnd, a, signal) {
3654
5972
  ensureCompiled(env);
3655
5973
  return runGenAsync(mettaEvalG(env, fuel, st, bnd, a), signal).catch((e) => {
3656
- if (isNativeStackOverflow(e)) return stackOverflowResult(st, bnd, a);
5974
+ if (isNativeStackOverflow(e)) return stackOverflowResult(env, st, bnd, a);
3657
5975
  throw e;
3658
5976
  });
3659
5977
  }
@@ -4169,12 +6487,15 @@ function preludeAtoms() {
4169
6487
  }
4170
6488
  var DEFAULT_FUEL2 = 1e5;
4171
6489
  var DEFAULT_TABLING = true;
4172
- function buildDefaultEnv(imports, tabling) {
6490
+ function buildDefaultEnv(imports, tabling, experimental) {
4173
6491
  const env = buildEnv(
4174
6492
  [...preludeAtoms(), ...stdlibAtoms(), ...pettaStdlibAtoms()],
4175
6493
  stdTable()
4176
6494
  );
4177
6495
  env.imports = withBuiltinModules(imports);
6496
+ if (experimental?.hashCons === true) env.intern = createInternTable();
6497
+ if (experimental?.trail === true) env.useTrail = true;
6498
+ if (experimental?.flatAtomspace === true) env.useFlatAtomspace = true;
4178
6499
  if (tabling) {
4179
6500
  env.table = /* @__PURE__ */ new Map();
4180
6501
  env.pureFunctors = analyzePurity(env);
@@ -4187,7 +6508,7 @@ function evalSequential(atoms, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ n
4187
6508
  const out = [];
4188
6509
  let st = initSt();
4189
6510
  if (opts.maxStackDepth !== void 0) st.world.maxStackDepth = opts.maxStackDepth;
4190
- const env = buildDefaultEnv(imports, opts.tabling ?? DEFAULT_TABLING);
6511
+ const env = buildDefaultEnv(imports, opts.tabling ?? DEFAULT_TABLING, opts.experimental);
4191
6512
  if (opts.parEvalImpl !== void 0) {
4192
6513
  const rulesSrc = atoms.filter((a) => !a.bang).map((a) => format(a.atom)).join("\n");
4193
6514
  const impl = opts.parEvalImpl;
@@ -4209,12 +6530,13 @@ function evalSequential(atoms, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ n
4209
6530
  function runProgram(src, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map(), opts = {}) {
4210
6531
  return evalSequential(parseAll(src, standardTokenizer()), fuel, imports, opts);
4211
6532
  }
4212
- async function runProgramAsync(src, asyncOps = /* @__PURE__ */ new Map(), fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map()) {
6533
+ async function runProgramAsync(src, asyncOps = /* @__PURE__ */ new Map(), fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map(), opts = {}) {
4213
6534
  const parsed = parseAll(src, standardTokenizer());
4214
- const env = buildDefaultEnv(imports, false);
6535
+ const env = buildDefaultEnv(imports, opts.tabling ?? false, opts.experimental);
4215
6536
  for (const [k, v] of asyncOps) env.agt.set(k, v);
4216
6537
  const out = [];
4217
6538
  let st = initSt();
6539
+ if (opts.maxStackDepth !== void 0) st.world.maxStackDepth = opts.maxStackDepth;
4218
6540
  for (const { atom, bang } of parsed) {
4219
6541
  if (!bang) {
4220
6542
  addAtomToEnv(env, atom);
@@ -4276,7 +6598,7 @@ var Interner = class {
4276
6598
  return this.add("s\0" + name, { kind: "sym", name });
4277
6599
  }
4278
6600
  internGround(value) {
4279
- return this.add(groundKey(value), { kind: "gnd", value });
6601
+ return this.add(groundKey2(value), { kind: "gnd", value });
4280
6602
  }
4281
6603
  /** The id for a symbol/ground if already interned, else undefined (a pattern symbol absent from the
4282
6604
  * KB can never match, so its lookup short-circuits). */
@@ -4284,7 +6606,7 @@ var Interner = class {
4284
6606
  return this.byKey.get("s\0" + name);
4285
6607
  }
4286
6608
  lookupGround(value) {
4287
- return this.byKey.get(groundKey(value));
6609
+ return this.byKey.get(groundKey2(value));
4288
6610
  }
4289
6611
  /** Reconstruct the atom for a leaf id. */
4290
6612
  decodeLeaf(id) {
@@ -4295,7 +6617,7 @@ var Interner = class {
4295
6617
  return this.entries.length;
4296
6618
  }
4297
6619
  };
4298
- function groundKey(v) {
6620
+ function groundKey2(v) {
4299
6621
  switch (v.g) {
4300
6622
  case "int":
4301
6623
  return "i\0" + v.n;
@@ -4586,83 +6908,13 @@ function williamTopK(kb, k, refCost = 4) {
4586
6908
  gain: s.gain
4587
6909
  }));
4588
6910
  }
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
6911
  export {
4661
6912
  AsyncInSyncError,
4662
6913
  BAIL,
4663
6914
  CONCURRENCY_MODULE_SRC,
4664
6915
  CURRY_MODULE_SRC,
4665
6916
  DEFAULT_FUEL2 as DEFAULT_FUEL,
6917
+ FlatAtomSpace,
4666
6918
  FlatKB,
4667
6919
  IMPURE_OPS,
4668
6920
  InMemorySpace,
@@ -4692,11 +6944,14 @@ export {
4692
6944
  buildEnv,
4693
6945
  builtinModules,
4694
6946
  callGrounded,
6947
+ canCompactAtom,
6948
+ canInternExprItems,
4695
6949
  canonInt,
4696
6950
  cmpIntVal,
4697
6951
  collectImports,
4698
6952
  collectVars,
4699
6953
  compileEnv,
6954
+ createInternTable,
4700
6955
  decodeAt,
4701
6956
  decodeAtom,
4702
6957
  emptyBindings,
@@ -4706,6 +6961,7 @@ export {
4706
6961
  encodeAtom,
4707
6962
  encodeInto,
4708
6963
  encodePattern,
6964
+ eqRelations,
4709
6965
  eraseSubst,
4710
6966
  evalAtom,
4711
6967
  evalSequential,
@@ -4713,6 +6969,7 @@ export {
4713
6969
  extendSubst,
4714
6970
  format,
4715
6971
  freshenRule,
6972
+ fromRelations,
4716
6973
  gbool,
4717
6974
  getTypes,
4718
6975
  gfloat,
@@ -4722,6 +6979,7 @@ export {
4722
6979
  groundType,
4723
6980
  gstr,
4724
6981
  gunit,
6982
+ hasEq,
4725
6983
  hasLoop,
4726
6984
  hashOf,
4727
6985
  initSt,
@@ -4729,6 +6987,10 @@ export {
4729
6987
  intAbs,
4730
6988
  intDiv,
4731
6989
  intMod,
6990
+ internAtom,
6991
+ internBuiltExpr,
6992
+ internExpr,
6993
+ isEmpty,
4732
6994
  isErrorAtom,
4733
6995
  isExpr,
4734
6996
  isGnd,
@@ -4739,6 +7001,7 @@ export {
4739
7001
  keyWellFormed,
4740
7002
  lookupSubst,
4741
7003
  lookupVal,
7004
+ makeValRel,
4742
7005
  matchAtoms,
4743
7006
  matchAtomsScoped,
4744
7007
  matchAtomsWith,
@@ -4747,6 +7010,7 @@ export {
4747
7010
  metaType,
4748
7011
  mettaEval,
4749
7012
  mettaEvalAsync,
7013
+ mixHash,
4750
7014
  mulInt,
4751
7015
  occurs,
4752
7016
  oracleReport,
@@ -4754,15 +7018,20 @@ export {
4754
7018
  parseAll,
4755
7019
  pettaOpNames,
4756
7020
  preludeAtoms,
7021
+ prependValRaw,
7022
+ relations,
4757
7023
  removeVal,
4758
7024
  runCompiled,
4759
7025
  runProgram,
4760
7026
  runProgramAsync,
4761
7027
  setOutputSink,
4762
7028
  setRawSink,
7029
+ size,
7030
+ someVal,
4763
7031
  standardTokenizer,
4764
7032
  stdTable,
4765
7033
  stdlibAtoms,
7034
+ strHash,
4766
7035
  subInt,
4767
7036
  sym,
4768
7037
  tableKey,
@@ -4770,8 +7039,10 @@ export {
4770
7039
  unifiable,
4771
7040
  unifyTop,
4772
7041
  unifyTrail,
7042
+ valEntries,
4773
7043
  variable,
4774
7044
  wcoJoin,
7045
+ wcoJoinFold,
4775
7046
  williamTopK,
4776
7047
  withBuiltinModules
4777
7048
  };