@calcit/procs 0.11.0-a8 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/js-record.mjs CHANGED
@@ -1,7 +1,9 @@
1
+ import { CalcitImpl } from "./js-impl.mjs";
1
2
  import { castTag, toString, findInFields } from "./calcit-data.mjs";
2
3
  import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
4
+ import { CalcitStruct } from "./js-struct.mjs";
3
5
  export class CalcitRecord {
4
- constructor(name, fields, values, impls) {
6
+ constructor(name, fields, values, structRef) {
5
7
  this.name = name;
6
8
  let fieldNames = fields.map(castTag);
7
9
  this.fields = fields;
@@ -15,7 +17,7 @@ export class CalcitRecord {
15
17
  this.values = new Array(fieldNames.length);
16
18
  }
17
19
  this.cachedHash = null;
18
- this.impls = impls || [];
20
+ this.structRef = structRef || new CalcitStruct(name, fields, new Array(fields.length).fill(null));
19
21
  }
20
22
  get(k) {
21
23
  let field = castTag(k);
@@ -48,7 +50,7 @@ export class CalcitRecord {
48
50
  values[idx] = this.values[idx];
49
51
  }
50
52
  }
51
- return new CalcitRecord(this.name, this.fields, values, this.impls);
53
+ return new CalcitRecord(this.name, this.fields, values, this.structRef);
52
54
  }
53
55
  /** return -1 for missing */
54
56
  findIndex(k) {
@@ -70,12 +72,18 @@ export class CalcitRecord {
70
72
  return parts.join("");
71
73
  }
72
74
  withImpls(impl) {
73
- if (impl instanceof CalcitRecord) {
74
- return new CalcitRecord(this.name, this.fields, this.values, [impl]);
75
+ let nextImpls;
76
+ if (impl instanceof CalcitImpl) {
77
+ nextImpls = [impl];
78
+ }
79
+ else if (Array.isArray(impl)) {
80
+ nextImpls = impl;
75
81
  }
76
82
  else {
77
- throw new Error("Expected a record");
83
+ throw new Error("Expected an impl or array of impls");
78
84
  }
85
+ let nextStruct = new CalcitStruct(this.name, this.fields, this.structRef.fieldTypes, this.structRef.impls.concat(nextImpls));
86
+ return new CalcitRecord(this.name, this.fields, this.values, nextStruct);
79
87
  }
80
88
  }
81
89
  export let new_record = (name, ...fields) => {
@@ -104,7 +112,9 @@ export let new_impl_record = (impl, name, ...fields) => {
104
112
  throw new Error(`Unexpected duplication in record fields: ${x.toString()}`);
105
113
  }
106
114
  });
107
- return new CalcitRecord(castTag(name), fieldNames, undefined, [impl]);
115
+ let nameTag = castTag(name);
116
+ let structRef = new CalcitStruct(nameTag, fieldNames, new Array(fieldNames.length).fill(null), [impl]);
117
+ return new CalcitRecord(nameTag, fieldNames, undefined, structRef);
108
118
  };
109
119
  export let fieldsEqual = (xs, ys) => {
110
120
  if (xs === ys) {
@@ -146,7 +156,7 @@ export let _$n__PCT__$M_ = (proto, ...xs) => {
146
156
  }
147
157
  values[i] = xs[idx * 2 + 1];
148
158
  }
149
- return new CalcitRecord(proto.name, proto.fields, values, proto.impls);
159
+ return new CalcitRecord(proto.name, proto.fields, values, proto.structRef);
150
160
  }
151
161
  else {
152
162
  throw new Error("Expected prototype to be a record");
@@ -168,7 +178,7 @@ export let _$n_record_$o_with = (proto, ...xs) => {
168
178
  }
169
179
  values[idx] = v;
170
180
  }
171
- return new CalcitRecord(proto.name, proto.fields, values, proto.impls);
181
+ return new CalcitRecord(proto.name, proto.fields, values, proto.structRef);
172
182
  }
173
183
  else {
174
184
  throw new Error("Expected prototype to be a record");
package/lib/js-struct.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { toString } from "./calcit-data.mjs";
2
- import { CalcitRecord } from "./js-record.mjs";
2
+ import { CalcitImpl } from "./js-impl.mjs";
3
3
  export class CalcitStruct {
4
4
  constructor(name, fields, fieldTypes, impls = []) {
5
5
  if (fields.length !== fieldTypes.length) {
@@ -12,13 +12,13 @@ export class CalcitStruct {
12
12
  this.cachedHash = null;
13
13
  }
14
14
  withImpls(impls) {
15
- if (impls instanceof CalcitRecord) {
15
+ if (impls instanceof CalcitImpl) {
16
16
  return new CalcitStruct(this.name, this.fields, this.fieldTypes, [impls]);
17
17
  }
18
18
  else if (Array.isArray(impls)) {
19
19
  return new CalcitStruct(this.name, this.fields, this.fieldTypes, impls);
20
20
  }
21
- throw new Error("Expected a record as implementation");
21
+ throw new Error("Expected an impl as implementation");
22
22
  }
23
23
  toString(disableJsDataWarning = false) {
24
24
  if (this.fields.length !== this.fieldTypes.length) {
package/lib/js-tuple.mjs CHANGED
@@ -1,13 +1,21 @@
1
1
  import { _$n__$e_, toString } from "./calcit-data.mjs";
2
2
  import { CalcitEnum } from "./js-enum.mjs";
3
3
  export class CalcitTuple {
4
- constructor(tagName, extra, impls = [], enumPrototype = null) {
4
+ constructor(tagName, extra, enumPrototype = null) {
5
5
  this.tag = tagName;
6
6
  this.extra = extra;
7
- this.impls = impls;
8
7
  this.enumPrototype = enumPrototype;
9
8
  this.cachedHash = null;
10
9
  }
10
+ get impls() {
11
+ if (this.enumPrototype == null) {
12
+ return [];
13
+ }
14
+ if (this.enumPrototype instanceof CalcitEnum) {
15
+ return this.enumPrototype.impls;
16
+ }
17
+ return this.enumPrototype.structRef.impls;
18
+ }
11
19
  get(n) {
12
20
  if (n === 0) {
13
21
  return this.tag;
@@ -21,12 +29,12 @@ export class CalcitTuple {
21
29
  }
22
30
  assoc(n, v) {
23
31
  if (n === 0) {
24
- return new CalcitTuple(v, this.extra, this.impls, this.enumPrototype);
32
+ return new CalcitTuple(v, this.extra, this.enumPrototype);
25
33
  }
26
34
  else if (n - 1 < this.extra.length) {
27
35
  let next_extra = this.extra.slice();
28
36
  next_extra[n - 1] = v;
29
- return new CalcitTuple(this.tag, next_extra, this.impls, this.enumPrototype);
37
+ return new CalcitTuple(this.tag, next_extra, this.enumPrototype);
30
38
  }
31
39
  else {
32
40
  throw new Error(`Tuple only have ${this.extra.length} elements`);
@@ -60,15 +68,9 @@ export class CalcitTuple {
60
68
  }
61
69
  const hasEnum = this.enumPrototype != null;
62
70
  const enumName = hasEnum ? (this.enumPrototype instanceof CalcitEnum ? this.enumPrototype.prototype.name.value : this.enumPrototype.name.value) : null;
63
- if (this.impls.length > 0 && hasEnum) {
64
- return `(%:: ${content} (:impls ${this.impls[0].name.value}) (:enum ${enumName}))`;
65
- }
66
71
  if (hasEnum) {
67
72
  return `(%:: ${content} (:enum ${enumName}))`;
68
73
  }
69
- if (this.impls.length > 0) {
70
- return `(:: ${content} (:impls ${this.impls[0].name.value}))`;
71
- }
72
74
  return `(:: ${content})`;
73
75
  }
74
76
  }
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.11.0-a8",
3
+ "version": "0.11.0",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.0.9",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.11.0-a8",
3
+ "version": "0.11.0",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.0.9",
@@ -4,6 +4,7 @@ import { overwriteMapComparator } from "./js-map.mjs";
4
4
  import { disableListStructureCheck } from "@calcit/ternary-tree";
5
5
 
6
6
  import { CalcitRecord, fieldsEqual } from "./js-record.mjs";
7
+ import { CalcitImpl } from "./js-impl.mjs";
7
8
  import { CalcitStruct } from "./js-struct.mjs";
8
9
  import { CalcitEnum } from "./js-enum.mjs";
9
10
  import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
@@ -82,6 +83,9 @@ export let isNestedCalcitData = (x: CalcitValue): boolean => {
82
83
  if (x instanceof CalcitRecord) {
83
84
  return x.fields.length > 0;
84
85
  }
86
+ if (x instanceof CalcitImpl) {
87
+ return x.fields.length > 0;
88
+ }
85
89
  if (x instanceof CalcitSet) {
86
90
  return false;
87
91
  }
@@ -98,6 +102,9 @@ export let tipNestedCalcitData = (x: CalcitValue): string => {
98
102
  if (x instanceof CalcitRecord) {
99
103
  return "'%{}...";
100
104
  }
105
+ if (x instanceof CalcitImpl) {
106
+ return "'%impl...";
107
+ }
101
108
  if (x instanceof CalcitSet) {
102
109
  return "'#{}...";
103
110
  }
@@ -180,6 +187,7 @@ let defaultHash_set = valueHash("set:");
180
187
  let defaultHash_list = valueHash("list:");
181
188
  let defaultHash_map = valueHash("map:");
182
189
  let defaultHash_record = valueHash("record:");
190
+ let defaultHash_impl = valueHash("impl:");
183
191
  let defaultHash_struct = valueHash("struct:");
184
192
  let defaultHash_enum = valueHash("enum:");
185
193
  let defaultHash_cirru_quote = valueHash("cirru-quote:");
@@ -309,6 +317,19 @@ export let hashFunction = (x: CalcitValue): Hash => {
309
317
  x.cachedHash = base;
310
318
  return base;
311
319
  }
320
+ if (x instanceof CalcitImpl) {
321
+ let base = defaultHash_impl;
322
+ base = mergeValueHash(base, hashFunction(x.name));
323
+ if (x.origin != null) {
324
+ base = mergeValueHash(base, hashFunction(x.origin));
325
+ }
326
+ for (let idx = 0; idx < x.fields.length; idx++) {
327
+ base = mergeValueHash(base, hashFunction(x.fields[idx]));
328
+ base = mergeValueHash(base, hashFunction(x.values[idx]));
329
+ }
330
+ x.cachedHash = base;
331
+ return base;
332
+ }
312
333
  if (x instanceof CalcitStruct) {
313
334
  let base = defaultHash_struct;
314
335
  base = mergeValueHash(base, hashFunction(x.name));
@@ -405,6 +426,9 @@ export let toString = (x: CalcitValue, escaped: boolean, disableJsDataWarning: b
405
426
  if (x instanceof CalcitRecord) {
406
427
  return x.toString(disableJsDataWarning);
407
428
  }
429
+ if (x instanceof CalcitImpl) {
430
+ return x.toString(disableJsDataWarning);
431
+ }
408
432
  if (x instanceof CalcitStruct) {
409
433
  return x.toString(disableJsDataWarning);
410
434
  }
@@ -682,6 +706,32 @@ export let _$n__$e_ = (x: CalcitValue, y: CalcitValue): boolean => {
682
706
  }
683
707
  return false;
684
708
  }
709
+ if (x instanceof CalcitImpl) {
710
+ if (y instanceof CalcitImpl) {
711
+ if (x.name !== y.name) {
712
+ return false;
713
+ }
714
+ if ((x.origin == null) !== (y.origin == null)) {
715
+ return false;
716
+ }
717
+ if (x.origin != null && y.origin != null && x.origin.name.value !== y.origin.name.value) {
718
+ return false;
719
+ }
720
+ if (!fieldsEqual(x.fields, y.fields)) {
721
+ return false;
722
+ }
723
+ if (x.values.length !== y.values.length) {
724
+ return false;
725
+ }
726
+ for (let idx = 0; idx < x.fields.length; idx++) {
727
+ if (!_$n__$e_(x.values[idx], y.values[idx])) {
728
+ return false;
729
+ }
730
+ }
731
+ return true;
732
+ }
733
+ return false;
734
+ }
685
735
  if (x instanceof CalcitStruct) {
686
736
  if (y instanceof CalcitStruct) {
687
737
  return x.name === y.name && fieldsEqual(x.fields, y.fields);
@@ -23,12 +23,14 @@ import {
23
23
 
24
24
  import { CalcitRef } from "./js-ref.mjs";
25
25
  import { fieldsEqual, CalcitRecord } from "./js-record.mjs";
26
+ import { CalcitImpl } from "./js-impl.mjs";
26
27
  import { CalcitStruct } from "./js-struct.mjs";
27
28
  import { CalcitEnum } from "./js-enum.mjs";
28
29
  import { CalcitTrait } from "./js-trait.mjs";
29
30
 
30
31
  export * from "./calcit-data.mjs";
31
32
  export * from "./js-record.mjs";
33
+ export * from "./js-impl.mjs";
32
34
  export * from "./js-struct.mjs";
33
35
  export * from "./js-enum.mjs";
34
36
  export * from "./js-map.mjs";
@@ -83,6 +85,9 @@ export let type_of = (x: any): CalcitTag => {
83
85
  if (x instanceof CalcitRecord) {
84
86
  return newTag("record");
85
87
  }
88
+ if (x instanceof CalcitImpl) {
89
+ return newTag("impl");
90
+ }
86
91
  if (x instanceof CalcitStruct) {
87
92
  return newTag("struct");
88
93
  }
@@ -225,7 +230,46 @@ export let defenum = (name: CalcitValue, ...variants: CalcitValue[]): CalcitEnum
225
230
  const tags = entries.map((entry) => entry.tag);
226
231
  const values = entries.map((entry) => entry.payload);
227
232
  const prototype = new CalcitRecord(enumName, tags, values, null);
228
- return new CalcitEnum(prototype, null);
233
+ return new CalcitEnum(prototype);
234
+ };
235
+
236
+ export let _$n_impl_$o__$o_new = (name: CalcitValue, ...pairs: CalcitValue[]): CalcitImpl => {
237
+ if (name === undefined) throw new Error("&impl::new expected arguments");
238
+ const origin = name instanceof CalcitTrait ? name : null;
239
+ const implName = origin ? origin.name : castTag(name);
240
+ if (pairs.length === 0) {
241
+ return new CalcitImpl(implName, [], [], origin);
242
+ }
243
+ const entries: Array<{ tag: CalcitTag; value: CalcitValue }> = [];
244
+ for (let idx = 0; idx < pairs.length; idx++) {
245
+ const pairValue = pairs[idx];
246
+ let fieldTag: CalcitTag;
247
+ let value: CalcitValue;
248
+ if (pairValue instanceof CalcitTuple) {
249
+ if (pairValue.extra.length !== 1) {
250
+ throw new Error(`&impl::new expects (field value) pairs, got: ${toString(pairValue, true)}`);
251
+ }
252
+ fieldTag = castTag(pairValue.tag);
253
+ value = pairValue.extra[0];
254
+ } else {
255
+ const pair = list_items(pairValue);
256
+ if (pair.length !== 2) {
257
+ throw new Error(`&impl::new expects (field value) pairs, got: ${toString(pairValue, true)}`);
258
+ }
259
+ fieldTag = castTag(pair[0]);
260
+ value = pair[1];
261
+ }
262
+ entries.push({ tag: fieldTag, value });
263
+ }
264
+ entries.sort((a, b) => a.tag.idx - b.tag.idx);
265
+ for (let i = 1; i < entries.length; i++) {
266
+ if (entries[i - 1].tag.value === entries[i].tag.value) {
267
+ throw new Error(`&impl::new duplicated field: ${entries[i].tag.toString()}`);
268
+ }
269
+ }
270
+ const fields = entries.map((entry) => entry.tag);
271
+ const values = entries.map((entry) => entry.value);
272
+ return new CalcitImpl(implName, fields, values, origin);
229
273
  };
230
274
 
231
275
  export let _$n_struct_$o__$o_new = (name: CalcitValue, ...entries: CalcitValue[]): CalcitStruct => {
@@ -444,6 +488,13 @@ export let _$n_tuple_$o_count = function (xs: CalcitValue) {
444
488
  throw new Error("Does not support `count` on this type");
445
489
  };
446
490
 
491
+ const coerce_impl = (value: CalcitValue, procName: string): CalcitImpl => {
492
+ if (value instanceof CalcitImpl) {
493
+ return value;
494
+ }
495
+ throw new Error(`${procName} expects trait impls as impls`);
496
+ };
497
+
447
498
  export let _$n_tuple_$o_impls = function (x: CalcitTuple) {
448
499
  if (arguments.length !== 1) throw new Error("&tuple:impls takes 1 argument");
449
500
  return new CalcitSliceList(x.impls);
@@ -454,22 +505,30 @@ export let _$n_tuple_$o_params = function (x: CalcitTuple) {
454
505
  return new CalcitSliceList(x.extra);
455
506
  };
456
507
 
457
- export let _$n_tuple_$o_with_impls = function (x: CalcitTuple, y: CalcitRecord) {
508
+ export let _$n_tuple_$o_with_impls = function (x: CalcitTuple, y: CalcitValue) {
458
509
  if (arguments.length !== 2) throw new Error("&tuple:with-impls takes 2 arguments");
459
510
  if (!(x instanceof CalcitTuple)) throw new Error("&tuple:with-impls expects a tuple");
460
- if (!(y instanceof CalcitRecord)) throw new Error("&tuple:with-impls expects second argument in record");
461
- return new CalcitTuple(x.tag, x.extra, [y], x.enumPrototype);
511
+ const impl = coerce_impl(y, "&tuple:with-impls");
512
+ let proto = x.enumPrototype;
513
+ if (proto == null) {
514
+ proto = new CalcitEnum(new CalcitRecord(newTag("anonymous-tuple"), [], [], new CalcitStruct(newTag("anonymous-tuple"), [], [])));
515
+ }
516
+ return new CalcitTuple(x.tag, x.extra, proto.withImpls(impl));
462
517
  };
463
518
 
464
519
  export let _$n_tuple_$o_impl_traits = function (x: CalcitValue, ...traits: CalcitValue[]) {
465
520
  if (traits.length < 1) throw new Error("&tuple:impl-traits takes 2+ arguments");
466
521
  if (!(x instanceof CalcitTuple)) throw new Error("&tuple:impl-traits expects a tuple");
467
- for (let idx = 0; idx < traits.length; idx++) {
468
- if (!(traits[idx] instanceof CalcitRecord)) {
469
- throw new Error("&tuple:impl-traits expects trait impls as records");
470
- }
522
+ const impls = traits.map((trait) => coerce_impl(trait, "&tuple:impl-traits"));
523
+ let proto = x.enumPrototype;
524
+ if (proto == null) {
525
+ const tagName = x.tag instanceof CalcitTag ? x.tag : newTag("tag");
526
+ const anyTypes = new CalcitSliceList(new Array(x.extra.length).fill(newTag("any")));
527
+ proto = new CalcitEnum(
528
+ new CalcitRecord(newTag("anonymous-tuple"), [tagName], [anyTypes], new CalcitStruct(newTag("anonymous-tuple"), [tagName], [anyTypes]))
529
+ );
471
530
  }
472
- return new CalcitTuple(x.tag, x.extra, x.impls.concat(traits as CalcitRecord[]), x.enumPrototype);
531
+ return new CalcitTuple(x.tag, x.extra, proto.withImpls(impls));
473
532
  };
474
533
 
475
534
  export let _$n_tuple_$o_enum = function (x: CalcitTuple) {
@@ -481,7 +540,7 @@ export let _$n_tuple_$o_enum = function (x: CalcitTuple) {
481
540
  if (x.enumPrototype instanceof CalcitEnum) {
482
541
  return x.enumPrototype;
483
542
  }
484
- return new CalcitEnum(x.enumPrototype as CalcitRecord, null);
543
+ return new CalcitEnum(x.enumPrototype as CalcitRecord);
485
544
  };
486
545
 
487
546
  const unwrap_enum_prototype = (enumPrototype: CalcitValue, procName: string): CalcitRecord => {
@@ -603,50 +662,47 @@ export let _$n_record_$o_assoc = function (xs: CalcitValue, k: CalcitValue, v: C
603
662
 
604
663
  export let _$n_record_$o_impls = function (xs: CalcitValue) {
605
664
  if (arguments.length !== 1) throw new Error("&record:impls takes 1 argument");
606
- if (xs instanceof CalcitRecord) return new CalcitSliceList(xs.impls);
665
+ if (xs instanceof CalcitRecord) return new CalcitSliceList(xs.structRef.impls);
607
666
  throw new Error("&record:impls expected a record");
608
667
  };
609
668
 
610
669
  export let _$n_record_$o_impl_traits = function (xs: CalcitValue, ...traits: CalcitValue[]) {
611
670
  if (traits.length < 1) throw new Error("&record:impl-traits takes 2+ arguments");
612
671
  if (!(xs instanceof CalcitRecord)) throw new Error("&record:impl-traits expected a record");
613
- for (let idx = 0; idx < traits.length; idx++) {
614
- if (!(traits[idx] instanceof CalcitRecord)) {
615
- throw new Error("&record:impl-traits expects trait impls as records");
616
- }
617
- }
618
- return new CalcitRecord(xs.name, xs.fields, xs.values, xs.impls.concat(traits as CalcitRecord[]));
672
+ const impls = traits.map((trait) => coerce_impl(trait, "&record:impl-traits"));
673
+ const nextStruct = new CalcitStruct(xs.name, xs.fields, xs.structRef.fieldTypes, xs.structRef.impls.concat(impls));
674
+ return new CalcitRecord(xs.name, xs.fields, xs.values, nextStruct);
619
675
  };
620
676
 
621
677
  export let _$n_struct_$o_impl_traits = function (xs: CalcitValue, ...traits: CalcitValue[]) {
622
678
  if (traits.length < 1) throw new Error("&struct:impl-traits takes 2+ arguments");
623
679
  if (!(xs instanceof CalcitStruct)) throw new Error("&struct:impl-traits expected a struct");
624
- for (let idx = 0; idx < traits.length; idx++) {
625
- if (!(traits[idx] instanceof CalcitRecord)) {
626
- throw new Error("&struct:impl-traits expects trait impls as records");
627
- }
628
- }
629
- const impls = xs.impls ?? [];
630
- return new CalcitStruct(xs.name, xs.fields, xs.fieldTypes, impls.concat(traits as CalcitRecord[]));
680
+ const addedImpls = traits.map((trait) => coerce_impl(trait, "&struct:impl-traits"));
681
+ const baseImpls = xs.impls ?? [];
682
+ return new CalcitStruct(xs.name, xs.fields, xs.fieldTypes, baseImpls.concat(addedImpls));
631
683
  };
632
684
 
633
685
  export let _$n_enum_$o_impl_traits = function (xs: CalcitValue, ...traits: CalcitValue[]) {
634
686
  if (traits.length < 1) throw new Error("&enum:impl-traits takes 2+ arguments");
635
- for (let idx = 0; idx < traits.length; idx++) {
636
- if (!(traits[idx] instanceof CalcitRecord)) {
637
- throw new Error("&enum:impl-traits expects trait impls as records");
638
- }
639
- }
687
+ const addedImpls = traits.map((trait) => coerce_impl(trait, "&enum:impl-traits"));
640
688
  if (xs instanceof CalcitEnum) {
641
- const impls = xs.impls ?? [];
642
- return new CalcitEnum(xs.prototype, impls.concat(traits as CalcitRecord[]));
689
+ return xs.withImpls(addedImpls);
643
690
  }
644
691
  if (xs instanceof CalcitRecord) {
645
- return new CalcitRecord(xs.name, xs.fields, xs.values, xs.impls.concat(traits as CalcitRecord[]));
692
+ const nextStruct = new CalcitStruct(xs.name, xs.fields, xs.structRef.fieldTypes, xs.structRef.impls.concat(addedImpls));
693
+ return new CalcitRecord(xs.name, xs.fields, xs.values, nextStruct);
646
694
  }
647
695
  throw new Error("&enum:impl-traits expected an enum or enum record");
648
696
  };
649
697
 
698
+ export let _$n_impl_$o_origin = function (impl: CalcitValue): CalcitValue {
699
+ if (arguments.length !== 1) throw new Error("&impl:origin expected 1 argument");
700
+ if (impl instanceof CalcitImpl) {
701
+ return impl.origin ?? null;
702
+ }
703
+ throw new Error(`&impl:origin expected an impl, but received: ${toString(impl, true)}`);
704
+ };
705
+
650
706
  export let _$n_list_$o_assoc_before = function (xs: CalcitList | CalcitSliceList, k: number, v: CalcitValue): CalcitList {
651
707
  if (arguments.length !== 3) {
652
708
  throw new Error("assoc takes 3 arguments");
@@ -1567,7 +1623,7 @@ export let _$n_js_object = (...xs: CalcitValue[]): Record<string, CalcitValue> =
1567
1623
  };
1568
1624
 
1569
1625
  export let _$o__$o_ = (tagName: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
1570
- return new CalcitTuple(tagName, extra, [], null);
1626
+ return new CalcitTuple(tagName, extra, null);
1571
1627
  };
1572
1628
 
1573
1629
  export let _PCT__$o__$o_ = (enumPrototype: CalcitValue, tag: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
@@ -1590,10 +1646,10 @@ export let _PCT__$o__$o_ = (enumPrototype: CalcitValue, tag: CalcitValue, ...ext
1590
1646
  }
1591
1647
 
1592
1648
  const tupleEnumPrototype = enumPrototype instanceof CalcitEnum ? enumPrototype : proto;
1593
- return new CalcitTuple(tag, extra, [], tupleEnumPrototype);
1649
+ return new CalcitTuple(tag, extra, tupleEnumPrototype);
1594
1650
  };
1595
1651
 
1596
- export let _PCT__PCT__$o__$o_ = (impl: CalcitRecord, enumPrototype: CalcitValue, tag: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
1652
+ export let _PCT__PCT__$o__$o_ = (impl: CalcitValue, enumPrototype: CalcitValue, tag: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
1597
1653
  // Runtime validation: check if tag exists in enum and arity matches
1598
1654
  const proto = assert_enum_tag_args("%%::", enumPrototype, tag as CalcitTag);
1599
1655
  const tagValue = tag as CalcitTag;
@@ -1613,12 +1669,13 @@ export let _PCT__PCT__$o__$o_ = (impl: CalcitRecord, enumPrototype: CalcitValue,
1613
1669
  throw new Error(`Expected variant definition to be a list, got ${variantDefinition}`);
1614
1670
  }
1615
1671
 
1616
- const tupleEnumPrototype = enumPrototype instanceof CalcitEnum ? enumPrototype : proto;
1617
- return new CalcitTuple(tag, extra, [impl], tupleEnumPrototype);
1672
+ const tupleEnumPrototype = enumPrototype instanceof CalcitEnum ? enumPrototype : (proto as any);
1673
+ const implValue = coerce_impl(impl, "%:: with impl");
1674
+ return new CalcitTuple(tag, extra, tupleEnumPrototype.withImpls(implValue));
1618
1675
  };
1619
1676
 
1620
1677
  // mutable place for core to register
1621
- type CalcitImplEntry = CalcitRecord | CalcitList | CalcitSliceList | null;
1678
+ type CalcitImplEntry = CalcitImpl | CalcitList | CalcitSliceList | null;
1622
1679
 
1623
1680
  let calcit_builtin_impls = {
1624
1681
  number: null as CalcitImplEntry,
@@ -1641,17 +1698,20 @@ export function invoke_method_closure(p: string) {
1641
1698
  };
1642
1699
  }
1643
1700
 
1644
- function normalize_builtin_impls(entry: CalcitImplEntry): CalcitRecord[] | null {
1701
+ function normalize_builtin_impls(entry: CalcitImplEntry): CalcitImpl[] | null {
1645
1702
  if (entry == null) return null;
1646
- if (entry instanceof CalcitRecord) return [entry];
1703
+ if (entry instanceof CalcitImpl) return [entry];
1647
1704
  if (entry instanceof CalcitList || entry instanceof CalcitSliceList) {
1648
- return list_items(entry) as CalcitRecord[];
1705
+ return list_items(entry).map((item) => {
1706
+ if (item instanceof CalcitImpl) return item;
1707
+ throw new Error(`invoke-method expects impls in list, but received: ${toString(item, true)}`);
1708
+ }) as CalcitImpl[];
1649
1709
  }
1650
1710
  return null;
1651
1711
  }
1652
1712
 
1653
- function lookup_impls(obj: CalcitValue): [CalcitRecord[], string] {
1654
- let impls: CalcitRecord[];
1713
+ function lookup_impls(obj: CalcitValue): [CalcitImpl[], string] {
1714
+ let impls: CalcitImpl[];
1655
1715
  let tag: string;
1656
1716
  if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
1657
1717
  tag = "&core-list-methods";
@@ -1661,7 +1721,7 @@ function lookup_impls(obj: CalcitValue): [CalcitRecord[], string] {
1661
1721
  impls = normalize_builtin_impls(calcit_builtin_impls.map);
1662
1722
  } else if (obj instanceof CalcitRecord) {
1663
1723
  tag = obj.name.toString();
1664
- impls = obj.impls;
1724
+ impls = obj.structRef.impls;
1665
1725
  } else if (obj instanceof CalcitTuple) {
1666
1726
  tag = obj.tag.toString();
1667
1727
  impls = obj.impls;
@@ -1755,7 +1815,7 @@ export function _$n_inspect_methods(obj: CalcitValue, note: CalcitValue): Calcit
1755
1815
  console.log("Method call syntax: `.method self p1 p2`");
1756
1816
  console.log(" - dot is part of the method name, first arg is the receiver\n");
1757
1817
 
1758
- let implsInOrder: CalcitRecord[] = [];
1818
+ let implsInOrder: CalcitImpl[] = [];
1759
1819
  let idx = reverse ? impls.length - 1 : 0;
1760
1820
  while (reverse ? idx >= 0 : idx < impls.length) {
1761
1821
  let impl = impls[idx];
@@ -1763,14 +1823,15 @@ export function _$n_inspect_methods(obj: CalcitValue, note: CalcitValue): Calcit
1763
1823
  idx += reverse ? -1 : 1;
1764
1824
  }
1765
1825
 
1766
- console.log(`Impl records (high → low precedence): ${implsInOrder.length}`);
1826
+ console.log(`Impls (high → low precedence): ${implsInOrder.length}`);
1767
1827
  for (let i = 0; i < implsInOrder.length; i++) {
1768
1828
  let impl = implsInOrder[i];
1769
1829
  let names: string[] = [];
1770
1830
  for (let k = 0; k < impl.fields.length; k++) {
1771
1831
  names.push("." + impl.fields[k].value);
1772
1832
  }
1773
- console.log(` #${i}: ${impl.name.toString()} (${names.join(" ")})`);
1833
+ const originName = impl.origin != null ? impl.origin.name.toString() : impl.name.toString();
1834
+ console.log(` #${i}: ${originName} (${names.join(" ")})`);
1774
1835
  }
1775
1836
 
1776
1837
  let ms = _$n_methods_of(obj);
@@ -1803,7 +1864,7 @@ export function _$n_trait_call(traitDef: CalcitValue, method: CalcitValue, obj:
1803
1864
  let idx = reverse ? impls.length - 1 : 0;
1804
1865
  while (reverse ? idx >= 0 : idx < impls.length) {
1805
1866
  const impl = impls[idx];
1806
- if (impl != null && impl.name.value === traitDef.name.value) {
1867
+ if (impl != null && impl.origin != null && impl.origin.name.value === traitDef.name.value) {
1807
1868
  const fn = impl.getOrNil(methodName);
1808
1869
  if (fn != null) {
1809
1870
  if (typeof fn !== "function") {
@@ -1815,7 +1876,7 @@ export function _$n_trait_call(traitDef: CalcitValue, method: CalcitValue, obj:
1815
1876
  idx += reverse ? -1 : 1;
1816
1877
  }
1817
1878
  throw new Error(
1818
- `&trait-call: cannot find impl for trait ${traitDef.name.toString()} on ${toString(obj, true)}. Hint: use defimpl to create impl records tagged by trait.`
1879
+ `&trait-call: cannot find impl for trait ${traitDef.name.toString()} on ${toString(obj, true)}. Hint: use defimpl to create impls tagged by trait.`
1819
1880
  );
1820
1881
  }
1821
1882
 
@@ -180,11 +180,11 @@ export let load_console_formatter_$x_ = () => {
180
180
  );
181
181
  }
182
182
  if (obj instanceof CalcitRecord) {
183
- if (obj.impls.length > 0) {
183
+ if (obj.structRef.impls.length > 0) {
184
184
  let ret: any[] = div(
185
185
  { color: hsl(280, 80, 60, 0.4), maxWidth: "100%" },
186
186
  span({}, "%{}"),
187
- span({ marginLeft: "6px" }, embedObject(obj.impls[0])),
187
+ span({ marginLeft: "6px" }, embedObject(obj.structRef.impls[0])),
188
188
  span({ marginLeft: "6px" }, embedObject(obj.name)),
189
189
  span({ marginLeft: "6px" }, `...`)
190
190
  );
@@ -9,6 +9,7 @@ import { CalcitSet } from "./js-set.mjs";
9
9
  import { CalcitTag, CalcitSymbol, CalcitRecur, newTag } from "./calcit-data.mjs";
10
10
  import { CalcitTuple } from "./js-tuple.mjs";
11
11
  import { CalcitEnum } from "./js-enum.mjs";
12
+ import { CalcitImpl } from "./js-impl.mjs";
12
13
  import { CalcitRef } from "./js-ref.mjs";
13
14
  import { deepEqual } from "@calcit/ternary-tree/lib/utils.mjs";
14
15
  import { atom } from "./js-ref.mjs";
@@ -182,6 +183,8 @@ export let to_cirru_edn = (x: CalcitValue): CirruEdnFormat => {
182
183
  return ["%::", enumTag, x.tag.toString(), ...x.extra.map(to_cirru_edn)];
183
184
  } else if (x.tag instanceof CalcitRecord) {
184
185
  return ["%::", enumTag, x.tag.name.toString(), ...x.extra.map(to_cirru_edn)];
186
+ } else if (x.tag instanceof CalcitImpl) {
187
+ return ["%::", enumTag, x.tag.name.toString(), ...x.extra.map(to_cirru_edn)];
185
188
  } else {
186
189
  throw new Error(`Unsupported tag for EDN: ${x.tag}`);
187
190
  }
@@ -189,6 +192,8 @@ export let to_cirru_edn = (x: CalcitValue): CirruEdnFormat => {
189
192
  return ["::", x.tag.toString(), ...x.extra.map(to_cirru_edn)];
190
193
  } else if (x.tag instanceof CalcitRecord) {
191
194
  return ["::", x.tag.name.toString(), ...x.extra.map(to_cirru_edn)];
195
+ } else if (x.tag instanceof CalcitImpl) {
196
+ return ["::", x.tag.name.toString(), ...x.extra.map(to_cirru_edn)];
192
197
  } else {
193
198
  throw new Error(`Unsupported tag for EDN: ${x.tag}`);
194
199
  }
@@ -346,7 +351,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat, options: CalcitValue): Calcit
346
351
  if (!deepEqual(v.fields, fields)) {
347
352
  throw new Error(`Fields mismatch for ${name}, expected ${fields}, got ${v.fields}`);
348
353
  }
349
- return new CalcitRecord(extractFieldTag(name), fields, values, v.impls);
354
+ return new CalcitRecord(extractFieldTag(name), fields, values, v.structRef);
350
355
  }
351
356
  }
352
357
 
@@ -392,8 +397,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat, options: CalcitValue): Calcit
392
397
  x
393
398
  .slice(2)
394
399
  .filter(notComment)
395
- .map((x) => extract_cirru_edn(x, options)),
396
- []
400
+ .map((x) => extract_cirru_edn(x, options))
397
401
  );
398
402
  }
399
403
  if (x[0] === "%::") {
@@ -414,7 +418,6 @@ export let extract_cirru_edn = (x: CirruEdnFormat, options: CalcitValue): Calcit
414
418
  .slice(3)
415
419
  .filter(notComment)
416
420
  .map((x) => extract_cirru_edn(x, options)),
417
- [],
418
421
  enumPrototype
419
422
  );
420
423
  }