@calcit/procs 0.11.0-a9 → 0.11.1

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 (34) hide show
  1. package/.gitattributes +1 -0
  2. package/.yarn/install-state.gz +0 -0
  3. package/build.rs +74 -0
  4. package/editing-history/2026-0213-1841-trait-origin-structural-eq.md +91 -0
  5. package/editing-history/2026-0213-1926-docs-tests-followup.md +33 -0
  6. package/editing-history/2026-0214-2050-js-codegen-recursion-tag-migration.md +39 -0
  7. package/editing-history/2026-0214-2358-emit-js-modularization-shift-left.md +63 -0
  8. package/editing-history/2026-0215-1941-macro-diagnostics-refinement.md +39 -0
  9. package/editing-history/2026-0215-diagnostics-consolidated.md +35 -0
  10. package/editing-history/2026-0216-2043-core-api-docs-cleanup.md +40 -0
  11. package/editing-history/2026-0216-2128-docs-smoke-and-trait-errors.md +20 -0
  12. package/lib/calcit-data.mjs +9 -0
  13. package/lib/calcit.procs.mjs +60 -21
  14. package/lib/custom-formatter.mjs +2 -2
  15. package/lib/js-arity-helpers.mjs +9 -0
  16. package/lib/js-cirru.mjs +3 -3
  17. package/lib/js-enum.mjs +11 -5
  18. package/lib/js-impl.mjs +2 -1
  19. package/lib/js-record.mjs +32 -16
  20. package/lib/js-tag-helpers.mjs +15 -0
  21. package/lib/js-tuple.mjs +12 -10
  22. package/lib/package.json +9 -2
  23. package/package.json +9 -2
  24. package/ts-src/calcit-data.mts +9 -0
  25. package/ts-src/calcit.procs.mts +63 -23
  26. package/ts-src/custom-formatter.mts +2 -2
  27. package/ts-src/js-arity-helpers.mts +11 -0
  28. package/ts-src/js-cirru.mts +2 -4
  29. package/ts-src/js-enum.mts +11 -6
  30. package/ts-src/js-impl.mts +4 -1
  31. package/ts-src/js-primes.mts +2 -0
  32. package/ts-src/js-record.mts +32 -17
  33. package/ts-src/js-tag-helpers.mts +17 -0
  34. package/ts-src/js-tuple.mts +14 -11
@@ -149,8 +149,8 @@ export let load_console_formatter_$x_ = () => {
149
149
  }, `${obj.len()}`), preview);
150
150
  }
151
151
  if (obj instanceof CalcitRecord) {
152
- if (obj.impls.length > 0) {
153
- let ret = div({ color: hsl(280, 80, 60, 0.4), maxWidth: "100%" }, span({}, "%{}"), span({ marginLeft: "6px" }, embedObject(obj.impls[0])), span({ marginLeft: "6px" }, embedObject(obj.name)), span({ marginLeft: "6px" }, `...`));
152
+ if (obj.structRef.impls.length > 0) {
153
+ let ret = div({ color: hsl(280, 80, 60, 0.4), maxWidth: "100%" }, span({}, "%{}"), span({ marginLeft: "6px" }, embedObject(obj.structRef.impls[0])), span({ marginLeft: "6px" }, embedObject(obj.name)), span({ marginLeft: "6px" }, `...`));
154
154
  return ret;
155
155
  }
156
156
  else {
@@ -0,0 +1,9 @@
1
+ export let _args_throw = (name, expected, got) => {
2
+ return new Error(`\`${name}\` expected ${expected} params, got ${got}`);
3
+ };
4
+ export let _args_fewer_throw = (name, min, got) => {
5
+ return new Error(`\`${name}\` expected at least ${min} params, got ${got}`);
6
+ };
7
+ export let _args_between_throw = (name, min, max, got) => {
8
+ return new Error(`\`${name}\` expected ${min}-${max} params, got ${got}`);
9
+ };
package/lib/js-cirru.mjs CHANGED
@@ -360,7 +360,7 @@ export let extract_cirru_edn = (x, options) => {
360
360
  if (!deepEqual(v.fields, fields)) {
361
361
  throw new Error(`Fields mismatch for ${name}, expected ${fields}, got ${v.fields}`);
362
362
  }
363
- return new CalcitRecord(extractFieldTag(name), fields, values, v.impls);
363
+ return new CalcitRecord(extractFieldTag(name), fields, values, v.structRef);
364
364
  }
365
365
  }
366
366
  return new CalcitRecord(extractFieldTag(name), fields, values);
@@ -399,7 +399,7 @@ export let extract_cirru_edn = (x, options) => {
399
399
  return new CalcitTuple(extract_cirru_edn(x[1], options), x
400
400
  .slice(2)
401
401
  .filter(notComment)
402
- .map((x) => extract_cirru_edn(x, options)), []);
402
+ .map((x) => extract_cirru_edn(x, options)));
403
403
  }
404
404
  if (x[0] === "%::") {
405
405
  if (x.length < 3) {
@@ -416,7 +416,7 @@ export let extract_cirru_edn = (x, options) => {
416
416
  return new CalcitTuple(extract_cirru_edn(x[2], options), x
417
417
  .slice(3)
418
418
  .filter(notComment)
419
- .map((x) => extract_cirru_edn(x, options)), [], enumPrototype);
419
+ .map((x) => extract_cirru_edn(x, options)), enumPrototype);
420
420
  }
421
421
  if (x[0] === "atom") {
422
422
  if (x.length !== 2) {
package/lib/js-enum.mjs CHANGED
@@ -1,21 +1,27 @@
1
1
  import { CalcitImpl } from "./js-impl.mjs";
2
2
  export class CalcitEnum {
3
- constructor(prototype, impls = []) {
3
+ constructor(prototype) {
4
4
  this.prototype = prototype;
5
- this.impls = impls;
6
5
  this.cachedHash = null;
7
6
  }
8
7
  name() {
9
8
  return this.prototype.name.value;
10
9
  }
10
+ get impls() {
11
+ return this.prototype.structRef.impls;
12
+ }
11
13
  withImpls(impls) {
14
+ let nextImpls;
12
15
  if (impls instanceof CalcitImpl) {
13
- return new CalcitEnum(this.prototype, [impls]);
16
+ nextImpls = [impls];
14
17
  }
15
18
  else if (Array.isArray(impls)) {
16
- return new CalcitEnum(this.prototype, impls);
19
+ nextImpls = impls;
20
+ }
21
+ else {
22
+ throw new Error("Expected an impl as implementation");
17
23
  }
18
- throw new Error("Expected an impl as implementation");
24
+ return new CalcitEnum(this.prototype.withImpls(nextImpls));
19
25
  }
20
26
  toString() {
21
27
  return `(%enum :${this.prototype.name.value})`;
package/lib/js-impl.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { castTag, findInFields, toString } from "./calcit-data.mjs";
2
2
  export class CalcitImpl {
3
- constructor(name, fields, values) {
3
+ constructor(name, fields, values, origin = null) {
4
4
  this.name = name;
5
+ this.origin = origin;
5
6
  this.fields = fields;
6
7
  this.values = values;
7
8
  this.cachedHash = null;
package/lib/js-record.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import { CalcitImpl } from "./js-impl.mjs";
2
2
  import { castTag, toString, findInFields } from "./calcit-data.mjs";
3
3
  import { CalcitMap, CalcitSliceMap } from "./js-map.mjs";
4
+ import { CalcitStruct } from "./js-struct.mjs";
4
5
  export class CalcitRecord {
5
- constructor(name, fields, values, impls) {
6
+ constructor(name, fields, values, structRef) {
6
7
  this.name = name;
7
8
  let fieldNames = fields.map(castTag);
8
9
  this.fields = fields;
@@ -16,7 +17,7 @@ export class CalcitRecord {
16
17
  this.values = new Array(fieldNames.length);
17
18
  }
18
19
  this.cachedHash = null;
19
- this.impls = impls || [];
20
+ this.structRef = structRef || new CalcitStruct(name, fields, new Array(fields.length).fill(null));
20
21
  }
21
22
  get(k) {
22
23
  let field = castTag(k);
@@ -49,7 +50,7 @@ export class CalcitRecord {
49
50
  values[idx] = this.values[idx];
50
51
  }
51
52
  }
52
- return new CalcitRecord(this.name, this.fields, values, this.impls);
53
+ return new CalcitRecord(this.name, this.fields, values, this.structRef);
53
54
  }
54
55
  /** return -1 for missing */
55
56
  findIndex(k) {
@@ -71,12 +72,18 @@ export class CalcitRecord {
71
72
  return parts.join("");
72
73
  }
73
74
  withImpls(impl) {
75
+ let nextImpls;
74
76
  if (impl instanceof CalcitImpl) {
75
- return new CalcitRecord(this.name, this.fields, this.values, [impl]);
77
+ nextImpls = [impl];
78
+ }
79
+ else if (Array.isArray(impl)) {
80
+ nextImpls = impl;
76
81
  }
77
82
  else {
78
- throw new Error("Expected an impl");
83
+ throw new Error("Expected an impl or array of impls");
79
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);
80
87
  }
81
88
  }
82
89
  export let new_record = (name, ...fields) => {
@@ -105,7 +112,9 @@ export let new_impl_record = (impl, name, ...fields) => {
105
112
  throw new Error(`Unexpected duplication in record fields: ${x.toString()}`);
106
113
  }
107
114
  });
108
- 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);
109
118
  };
110
119
  export let fieldsEqual = (xs, ys) => {
111
120
  if (xs === ys) {
@@ -122,18 +131,28 @@ export let fieldsEqual = (xs, ys) => {
122
131
  return true;
123
132
  };
124
133
  export let _$n__PCT__$M_ = (proto, ...xs) => {
134
+ let recordProto;
125
135
  if (proto instanceof CalcitRecord) {
136
+ recordProto = proto;
137
+ }
138
+ else if (proto instanceof CalcitStruct) {
139
+ recordProto = new CalcitRecord(proto.name, proto.fields, new Array(proto.fields.length).fill(null), proto);
140
+ }
141
+ else {
142
+ throw new Error("Expected prototype to be a record");
143
+ }
144
+ {
126
145
  if (xs.length % 2 !== 0) {
127
146
  throw new Error("Expected even number of key/value");
128
147
  }
129
- if (xs.length !== proto.fields.length * 2) {
148
+ if (xs.length !== recordProto.fields.length * 2) {
130
149
  throw new Error("fields size does not match");
131
150
  }
132
- let values = new Array(proto.fields.length);
133
- for (let i = 0; i < proto.fields.length; i++) {
151
+ let values = new Array(recordProto.fields.length);
152
+ for (let i = 0; i < recordProto.fields.length; i++) {
134
153
  let idx = -1;
135
- let k = proto.fields[i];
136
- for (let j = 0; j < proto.fields.length; j++) {
154
+ let k = recordProto.fields[i];
155
+ for (let j = 0; j < recordProto.fields.length; j++) {
137
156
  if (k === castTag(xs[j * 2])) {
138
157
  idx = j;
139
158
  break;
@@ -147,10 +166,7 @@ export let _$n__PCT__$M_ = (proto, ...xs) => {
147
166
  }
148
167
  values[i] = xs[idx * 2 + 1];
149
168
  }
150
- return new CalcitRecord(proto.name, proto.fields, values, proto.impls);
151
- }
152
- else {
153
- throw new Error("Expected prototype to be a record");
169
+ return new CalcitRecord(recordProto.name, recordProto.fields, values, recordProto.structRef);
154
170
  }
155
171
  };
156
172
  /// update record with new values
@@ -169,7 +185,7 @@ export let _$n_record_$o_with = (proto, ...xs) => {
169
185
  }
170
186
  values[idx] = v;
171
187
  }
172
- return new CalcitRecord(proto.name, proto.fields, values, proto.impls);
188
+ return new CalcitRecord(proto.name, proto.fields, values, proto.structRef);
173
189
  }
174
190
  else {
175
191
  throw new Error("Expected prototype to be a record");
@@ -0,0 +1,15 @@
1
+ import { newTag } from "./calcit-data.mjs";
2
+ let _tag_cache = {};
3
+ export let init_tags = (arr) => {
4
+ let tags = {};
5
+ for (let idx = 0; idx < arr.length; idx++) {
6
+ let name = arr[idx];
7
+ let item = _tag_cache[name];
8
+ if (item === undefined) {
9
+ item = newTag(name);
10
+ _tag_cache[name] = item;
11
+ }
12
+ tags[name] = item;
13
+ }
14
+ return tags;
15
+ };
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-a9",
3
+ "version": "0.11.1",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.0.9",
@@ -8,11 +8,18 @@
8
8
  },
9
9
  "scripts": {
10
10
  "compile": "rm -rfv lib/* && tsc",
11
- "procs-link": "ln -s ../../ node_modules/@calcit/procs",
11
+ "procs-link": "ln -sfn ../../ node_modules/@calcit/procs",
12
12
  "cp-mac": "cargo build --release && rm -rfv builds/* && node scripts/cp-version.js && scp builds/* rsync-user@calcit-lang.org:/web-assets/repo/calcit-lang/binaries/macos/",
13
13
  "eval": "cargo run --bin cr -- eval",
14
+ "fmt-rs": "cargo fmt --all",
15
+ "lint-rs": "cargo clippy --all-targets -- -D warnings",
16
+ "test-rs": "cargo test -q",
17
+ "test-snippets": "cargo test -q snippets::tests",
18
+ "bench-recur-smoke": "cargo run --bin cr -- calcit/test.cirru -1 js && node --input-type=module -e \"import { test_loop } from './js-out/test-recursion.main.mjs'; const n=3000; const t0=process.hrtime.bigint(); for(let i=0;i<n;i++) test_loop(); const dt=Number(process.hrtime.bigint()-t0)/1e6; console.log('test_loop_ms='+dt.toFixed(3));\"",
19
+ "check-smooth": "yarn fmt-rs && yarn lint-rs && yarn test-rs && yarn check-all",
14
20
  "check-all": "yarn compile && yarn try-rs && yarn try-js && yarn try-ir",
15
21
  "try-rs": "cargo run --bin cr -- calcit/test.cirru -1",
22
+ "warn-dyn-method": "cargo run --bin cr -- calcit/test.cirru -1 --warn-dyn-method",
16
23
  "try-js-brk": "cargo run --bin cr -- calcit/test.cirru -1 js && node --inspect-brk js-out/main.mjs",
17
24
  "try-js": "cargo run --bin cr -- calcit/test.cirru -1 js && node js-out/main.mjs",
18
25
  "try-ir": "cargo run --bin cr -- calcit/test.cirru -1 js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.11.0-a9",
3
+ "version": "0.11.1",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.0.9",
@@ -8,11 +8,18 @@
8
8
  },
9
9
  "scripts": {
10
10
  "compile": "rm -rfv lib/* && tsc",
11
- "procs-link": "ln -s ../../ node_modules/@calcit/procs",
11
+ "procs-link": "ln -sfn ../../ node_modules/@calcit/procs",
12
12
  "cp-mac": "cargo build --release && rm -rfv builds/* && node scripts/cp-version.js && scp builds/* rsync-user@calcit-lang.org:/web-assets/repo/calcit-lang/binaries/macos/",
13
13
  "eval": "cargo run --bin cr -- eval",
14
+ "fmt-rs": "cargo fmt --all",
15
+ "lint-rs": "cargo clippy --all-targets -- -D warnings",
16
+ "test-rs": "cargo test -q",
17
+ "test-snippets": "cargo test -q snippets::tests",
18
+ "bench-recur-smoke": "cargo run --bin cr -- calcit/test.cirru -1 js && node --input-type=module -e \"import { test_loop } from './js-out/test-recursion.main.mjs'; const n=3000; const t0=process.hrtime.bigint(); for(let i=0;i<n;i++) test_loop(); const dt=Number(process.hrtime.bigint()-t0)/1e6; console.log('test_loop_ms='+dt.toFixed(3));\"",
19
+ "check-smooth": "yarn fmt-rs && yarn lint-rs && yarn test-rs && yarn check-all",
14
20
  "check-all": "yarn compile && yarn try-rs && yarn try-js && yarn try-ir",
15
21
  "try-rs": "cargo run --bin cr -- calcit/test.cirru -1",
22
+ "warn-dyn-method": "cargo run --bin cr -- calcit/test.cirru -1 --warn-dyn-method",
16
23
  "try-js-brk": "cargo run --bin cr -- calcit/test.cirru -1 js && node --inspect-brk js-out/main.mjs",
17
24
  "try-js": "cargo run --bin cr -- calcit/test.cirru -1 js && node js-out/main.mjs",
18
25
  "try-ir": "cargo run --bin cr -- calcit/test.cirru -1 js"
@@ -320,6 +320,9 @@ export let hashFunction = (x: CalcitValue): Hash => {
320
320
  if (x instanceof CalcitImpl) {
321
321
  let base = defaultHash_impl;
322
322
  base = mergeValueHash(base, hashFunction(x.name));
323
+ if (x.origin != null) {
324
+ base = mergeValueHash(base, hashFunction(x.origin));
325
+ }
323
326
  for (let idx = 0; idx < x.fields.length; idx++) {
324
327
  base = mergeValueHash(base, hashFunction(x.fields[idx]));
325
328
  base = mergeValueHash(base, hashFunction(x.values[idx]));
@@ -708,6 +711,12 @@ export let _$n__$e_ = (x: CalcitValue, y: CalcitValue): boolean => {
708
711
  if (x.name !== y.name) {
709
712
  return false;
710
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
+ }
711
720
  if (!fieldsEqual(x.fields, y.fields)) {
712
721
  return false;
713
722
  }
@@ -41,6 +41,8 @@ export * from "./js-tuple.mjs";
41
41
  export * from "./js-trait.mjs";
42
42
  export * from "./custom-formatter.mjs";
43
43
  export * from "./js-cirru.mjs";
44
+ export * from "./js-arity-helpers.mjs";
45
+ export * from "./js-tag-helpers.mjs";
44
46
  export { _$n_compare } from "./js-primes.mjs";
45
47
 
46
48
  import { CalcitList, CalcitSliceList, foldl } from "./js-list.mjs";
@@ -230,14 +232,15 @@ export let defenum = (name: CalcitValue, ...variants: CalcitValue[]): CalcitEnum
230
232
  const tags = entries.map((entry) => entry.tag);
231
233
  const values = entries.map((entry) => entry.payload);
232
234
  const prototype = new CalcitRecord(enumName, tags, values, null);
233
- return new CalcitEnum(prototype, null);
235
+ return new CalcitEnum(prototype);
234
236
  };
235
237
 
236
238
  export let _$n_impl_$o__$o_new = (name: CalcitValue, ...pairs: CalcitValue[]): CalcitImpl => {
237
239
  if (name === undefined) throw new Error("&impl::new expected arguments");
238
- const implName = castTag(name);
240
+ const origin = name instanceof CalcitTrait ? name : null;
241
+ const implName = origin ? origin.name : castTag(name);
239
242
  if (pairs.length === 0) {
240
- return new CalcitImpl(implName, [], []);
243
+ return new CalcitImpl(implName, [], [], origin);
241
244
  }
242
245
  const entries: Array<{ tag: CalcitTag; value: CalcitValue }> = [];
243
246
  for (let idx = 0; idx < pairs.length; idx++) {
@@ -268,7 +271,7 @@ export let _$n_impl_$o__$o_new = (name: CalcitValue, ...pairs: CalcitValue[]): C
268
271
  }
269
272
  const fields = entries.map((entry) => entry.tag);
270
273
  const values = entries.map((entry) => entry.value);
271
- return new CalcitImpl(implName, fields, values);
274
+ return new CalcitImpl(implName, fields, values, origin);
272
275
  };
273
276
 
274
277
  export let _$n_struct_$o__$o_new = (name: CalcitValue, ...entries: CalcitValue[]): CalcitStruct => {
@@ -508,14 +511,26 @@ export let _$n_tuple_$o_with_impls = function (x: CalcitTuple, y: CalcitValue) {
508
511
  if (arguments.length !== 2) throw new Error("&tuple:with-impls takes 2 arguments");
509
512
  if (!(x instanceof CalcitTuple)) throw new Error("&tuple:with-impls expects a tuple");
510
513
  const impl = coerce_impl(y, "&tuple:with-impls");
511
- return new CalcitTuple(x.tag, x.extra, [impl], x.enumPrototype);
514
+ let proto = x.enumPrototype;
515
+ if (proto == null) {
516
+ proto = new CalcitEnum(new CalcitRecord(newTag("anonymous-tuple"), [], [], new CalcitStruct(newTag("anonymous-tuple"), [], [])));
517
+ }
518
+ return new CalcitTuple(x.tag, x.extra, proto.withImpls(impl));
512
519
  };
513
520
 
514
521
  export let _$n_tuple_$o_impl_traits = function (x: CalcitValue, ...traits: CalcitValue[]) {
515
522
  if (traits.length < 1) throw new Error("&tuple:impl-traits takes 2+ arguments");
516
523
  if (!(x instanceof CalcitTuple)) throw new Error("&tuple:impl-traits expects a tuple");
517
524
  const impls = traits.map((trait) => coerce_impl(trait, "&tuple:impl-traits"));
518
- return new CalcitTuple(x.tag, x.extra, x.impls.concat(impls), x.enumPrototype);
525
+ let proto = x.enumPrototype;
526
+ if (proto == null) {
527
+ const tagName = x.tag instanceof CalcitTag ? x.tag : newTag("tag");
528
+ const anyTypes = new CalcitSliceList(new Array(x.extra.length).fill(newTag("any")));
529
+ proto = new CalcitEnum(
530
+ new CalcitRecord(newTag("anonymous-tuple"), [tagName], [anyTypes], new CalcitStruct(newTag("anonymous-tuple"), [tagName], [anyTypes]))
531
+ );
532
+ }
533
+ return new CalcitTuple(x.tag, x.extra, proto.withImpls(impls));
519
534
  };
520
535
 
521
536
  export let _$n_tuple_$o_enum = function (x: CalcitTuple) {
@@ -527,7 +542,7 @@ export let _$n_tuple_$o_enum = function (x: CalcitTuple) {
527
542
  if (x.enumPrototype instanceof CalcitEnum) {
528
543
  return x.enumPrototype;
529
544
  }
530
- return new CalcitEnum(x.enumPrototype as CalcitRecord, null);
545
+ return new CalcitEnum(x.enumPrototype as CalcitRecord);
531
546
  };
532
547
 
533
548
  const unwrap_enum_prototype = (enumPrototype: CalcitValue, procName: string): CalcitRecord => {
@@ -649,7 +664,7 @@ export let _$n_record_$o_assoc = function (xs: CalcitValue, k: CalcitValue, v: C
649
664
 
650
665
  export let _$n_record_$o_impls = function (xs: CalcitValue) {
651
666
  if (arguments.length !== 1) throw new Error("&record:impls takes 1 argument");
652
- if (xs instanceof CalcitRecord) return new CalcitSliceList(xs.impls);
667
+ if (xs instanceof CalcitRecord) return new CalcitSliceList(xs.structRef.impls);
653
668
  throw new Error("&record:impls expected a record");
654
669
  };
655
670
 
@@ -657,7 +672,8 @@ export let _$n_record_$o_impl_traits = function (xs: CalcitValue, ...traits: Cal
657
672
  if (traits.length < 1) throw new Error("&record:impl-traits takes 2+ arguments");
658
673
  if (!(xs instanceof CalcitRecord)) throw new Error("&record:impl-traits expected a record");
659
674
  const impls = traits.map((trait) => coerce_impl(trait, "&record:impl-traits"));
660
- return new CalcitRecord(xs.name, xs.fields, xs.values, xs.impls.concat(impls));
675
+ const nextStruct = new CalcitStruct(xs.name, xs.fields, xs.structRef.fieldTypes, xs.structRef.impls.concat(impls));
676
+ return new CalcitRecord(xs.name, xs.fields, xs.values, nextStruct);
661
677
  };
662
678
 
663
679
  export let _$n_struct_$o_impl_traits = function (xs: CalcitValue, ...traits: CalcitValue[]) {
@@ -672,15 +688,42 @@ export let _$n_enum_$o_impl_traits = function (xs: CalcitValue, ...traits: Calci
672
688
  if (traits.length < 1) throw new Error("&enum:impl-traits takes 2+ arguments");
673
689
  const addedImpls = traits.map((trait) => coerce_impl(trait, "&enum:impl-traits"));
674
690
  if (xs instanceof CalcitEnum) {
675
- const baseImpls = xs.impls ?? [];
676
- return new CalcitEnum(xs.prototype, baseImpls.concat(addedImpls));
691
+ return xs.withImpls(addedImpls);
677
692
  }
678
693
  if (xs instanceof CalcitRecord) {
679
- return new CalcitRecord(xs.name, xs.fields, xs.values, xs.impls.concat(addedImpls));
694
+ const nextStruct = new CalcitStruct(xs.name, xs.fields, xs.structRef.fieldTypes, xs.structRef.impls.concat(addedImpls));
695
+ return new CalcitRecord(xs.name, xs.fields, xs.values, nextStruct);
680
696
  }
681
697
  throw new Error("&enum:impl-traits expected an enum or enum record");
682
698
  };
683
699
 
700
+ export let _$n_impl_$o_origin = function (impl: CalcitValue): CalcitValue {
701
+ if (arguments.length !== 1) throw new Error("&impl:origin expected 1 argument");
702
+ if (impl instanceof CalcitImpl) {
703
+ return impl.origin ?? null;
704
+ }
705
+ throw new Error(`&impl:origin expected an impl, but received: ${toString(impl, true)}`);
706
+ };
707
+
708
+ export let _$n_impl_$o_get = function (impl: CalcitValue, name: CalcitValue): CalcitValue {
709
+ if (arguments.length !== 2) throw new Error("&impl:get expected 2 arguments");
710
+ if (!(impl instanceof CalcitImpl)) {
711
+ throw new Error(`&impl:get expected an impl as first argument, but received: ${toString(impl, true)}`);
712
+ }
713
+ return impl.get(name);
714
+ };
715
+
716
+ export let _$n_impl_$o_nth = function (impl: CalcitValue, index: CalcitValue): CalcitValue {
717
+ if (arguments.length !== 2) throw new Error("&impl:nth expected 2 arguments");
718
+ if (!(impl instanceof CalcitImpl)) {
719
+ throw new Error(`&impl:nth expected an impl as first argument, but received: ${toString(impl, true)}`);
720
+ }
721
+ if (typeof index !== "number" || !Number.isInteger(index) || index < 0) {
722
+ throw new Error(`&impl:nth expected a non-negative integer index, but received: ${toString(index, true)}`);
723
+ }
724
+ return impl.values[index];
725
+ };
726
+
684
727
  export let _$n_list_$o_assoc_before = function (xs: CalcitList | CalcitSliceList, k: number, v: CalcitValue): CalcitList {
685
728
  if (arguments.length !== 3) {
686
729
  throw new Error("assoc takes 3 arguments");
@@ -1601,7 +1644,7 @@ export let _$n_js_object = (...xs: CalcitValue[]): Record<string, CalcitValue> =
1601
1644
  };
1602
1645
 
1603
1646
  export let _$o__$o_ = (tagName: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
1604
- return new CalcitTuple(tagName, extra, [], null);
1647
+ return new CalcitTuple(tagName, extra, null);
1605
1648
  };
1606
1649
 
1607
1650
  export let _PCT__$o__$o_ = (enumPrototype: CalcitValue, tag: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
@@ -1624,7 +1667,7 @@ export let _PCT__$o__$o_ = (enumPrototype: CalcitValue, tag: CalcitValue, ...ext
1624
1667
  }
1625
1668
 
1626
1669
  const tupleEnumPrototype = enumPrototype instanceof CalcitEnum ? enumPrototype : proto;
1627
- return new CalcitTuple(tag, extra, [], tupleEnumPrototype);
1670
+ return new CalcitTuple(tag, extra, tupleEnumPrototype);
1628
1671
  };
1629
1672
 
1630
1673
  export let _PCT__PCT__$o__$o_ = (impl: CalcitValue, enumPrototype: CalcitValue, tag: CalcitValue, ...extra: CalcitValue[]): CalcitTuple => {
@@ -1647,9 +1690,9 @@ export let _PCT__PCT__$o__$o_ = (impl: CalcitValue, enumPrototype: CalcitValue,
1647
1690
  throw new Error(`Expected variant definition to be a list, got ${variantDefinition}`);
1648
1691
  }
1649
1692
 
1650
- const tupleEnumPrototype = enumPrototype instanceof CalcitEnum ? enumPrototype : proto;
1693
+ const tupleEnumPrototype = enumPrototype instanceof CalcitEnum ? enumPrototype : (proto as any);
1651
1694
  const implValue = coerce_impl(impl, "%:: with impl");
1652
- return new CalcitTuple(tag, extra, [implValue], tupleEnumPrototype);
1695
+ return new CalcitTuple(tag, extra, tupleEnumPrototype.withImpls(implValue));
1653
1696
  };
1654
1697
 
1655
1698
  // mutable place for core to register
@@ -1699,7 +1742,7 @@ function lookup_impls(obj: CalcitValue): [CalcitImpl[], string] {
1699
1742
  impls = normalize_builtin_impls(calcit_builtin_impls.map);
1700
1743
  } else if (obj instanceof CalcitRecord) {
1701
1744
  tag = obj.name.toString();
1702
- impls = obj.impls;
1745
+ impls = obj.structRef.impls;
1703
1746
  } else if (obj instanceof CalcitTuple) {
1704
1747
  tag = obj.tag.toString();
1705
1748
  impls = obj.impls;
@@ -1808,7 +1851,8 @@ export function _$n_inspect_methods(obj: CalcitValue, note: CalcitValue): Calcit
1808
1851
  for (let k = 0; k < impl.fields.length; k++) {
1809
1852
  names.push("." + impl.fields[k].value);
1810
1853
  }
1811
- console.log(` #${i}: ${impl.name.toString()} (${names.join(" ")})`);
1854
+ const originName = impl.origin != null ? impl.origin.name.toString() : impl.name.toString();
1855
+ console.log(` #${i}: ${originName} (${names.join(" ")})`);
1812
1856
  }
1813
1857
 
1814
1858
  let ms = _$n_methods_of(obj);
@@ -1841,7 +1885,7 @@ export function _$n_trait_call(traitDef: CalcitValue, method: CalcitValue, obj:
1841
1885
  let idx = reverse ? impls.length - 1 : 0;
1842
1886
  while (reverse ? idx >= 0 : idx < impls.length) {
1843
1887
  const impl = impls[idx];
1844
- if (impl != null && impl.name.value === traitDef.name.value) {
1888
+ if (impl != null && impl.origin != null && impl.origin.name.value === traitDef.name.value) {
1845
1889
  const fn = impl.getOrNil(methodName);
1846
1890
  if (fn != null) {
1847
1891
  if (typeof fn !== "function") {
@@ -2004,9 +2048,5 @@ export let macroexpand = unavailableProc;
2004
2048
  export let macroexpand_all = unavailableProc;
2005
2049
  export let _$n_get_calcit_running_mode = unavailableProc;
2006
2050
 
2007
- export let _args_throw = (name: string, expected: number, got: number) => {
2008
- return new Error(`\`${name}\` expected ${expected} params, got ${got}`);
2009
- };
2010
-
2011
2051
  // already handled in code emitter
2012
2052
  export let raise = unavailableProc;
@@ -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
  );
@@ -0,0 +1,11 @@
1
+ export let _args_throw = (name: string, expected: number, got: number) => {
2
+ return new Error(`\`${name}\` expected ${expected} params, got ${got}`);
3
+ };
4
+
5
+ export let _args_fewer_throw = (name: string, min: number, got: number) => {
6
+ return new Error(`\`${name}\` expected at least ${min} params, got ${got}`);
7
+ };
8
+
9
+ export let _args_between_throw = (name: string, min: number, max: number, got: number) => {
10
+ return new Error(`\`${name}\` expected ${min}-${max} params, got ${got}`);
11
+ };
@@ -351,7 +351,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat, options: CalcitValue): Calcit
351
351
  if (!deepEqual(v.fields, fields)) {
352
352
  throw new Error(`Fields mismatch for ${name}, expected ${fields}, got ${v.fields}`);
353
353
  }
354
- return new CalcitRecord(extractFieldTag(name), fields, values, v.impls);
354
+ return new CalcitRecord(extractFieldTag(name), fields, values, v.structRef);
355
355
  }
356
356
  }
357
357
 
@@ -397,8 +397,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat, options: CalcitValue): Calcit
397
397
  x
398
398
  .slice(2)
399
399
  .filter(notComment)
400
- .map((x) => extract_cirru_edn(x, options)),
401
- []
400
+ .map((x) => extract_cirru_edn(x, options))
402
401
  );
403
402
  }
404
403
  if (x[0] === "%::") {
@@ -419,7 +418,6 @@ export let extract_cirru_edn = (x: CirruEdnFormat, options: CalcitValue): Calcit
419
418
  .slice(3)
420
419
  .filter(notComment)
421
420
  .map((x) => extract_cirru_edn(x, options)),
422
- [],
423
421
  enumPrototype
424
422
  );
425
423
  }
@@ -3,12 +3,10 @@ import { CalcitImpl } from "./js-impl.mjs";
3
3
 
4
4
  export class CalcitEnum {
5
5
  prototype: CalcitRecord;
6
- impls: CalcitImpl[];
7
6
  cachedHash: number;
8
7
 
9
- constructor(prototype: CalcitRecord, impls: CalcitImpl[] = []) {
8
+ constructor(prototype: CalcitRecord) {
10
9
  this.prototype = prototype;
11
- this.impls = impls;
12
10
  this.cachedHash = null;
13
11
  }
14
12
 
@@ -16,13 +14,20 @@ export class CalcitEnum {
16
14
  return this.prototype.name.value;
17
15
  }
18
16
 
17
+ get impls(): CalcitImpl[] {
18
+ return this.prototype.structRef.impls;
19
+ }
20
+
19
21
  withImpls(impls: CalcitImpl | CalcitImpl[]): CalcitEnum {
22
+ let nextImpls: CalcitImpl[];
20
23
  if (impls instanceof CalcitImpl) {
21
- return new CalcitEnum(this.prototype, [impls]);
24
+ nextImpls = [impls];
22
25
  } else if (Array.isArray(impls)) {
23
- return new CalcitEnum(this.prototype, impls);
26
+ nextImpls = impls;
27
+ } else {
28
+ throw new Error("Expected an impl as implementation");
24
29
  }
25
- throw new Error("Expected an impl as implementation");
30
+ return new CalcitEnum(this.prototype.withImpls(nextImpls));
26
31
  }
27
32
 
28
33
  toString(): string {