@calcit/procs 0.29.0-alpha.19 → 0.29.0-alpha.20

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.
@@ -208,6 +208,7 @@ export var refsRegistry = new Map();
208
208
  let defaultHash_nil = valueHash("nil:");
209
209
  let defaultHash_unit = valueHash("unit:");
210
210
  let defaultHash_number = valueHash("number:");
211
+ let defaultHash_nan = valueHash("number:NaN");
211
212
  let defaultHash_string = valueHash("string:");
212
213
  let defaultHash_tag = valueHash("tag:");
213
214
  let defaultHash_true = valueHash("bool:true");
@@ -237,7 +238,10 @@ export let hashFunction = (x) => {
237
238
  if (x === undefined)
238
239
  return defaultHash_unit;
239
240
  if (typeof x === "number") {
240
- return mergeValueHash(defaultHash_number, x);
241
+ // NaN equals NaN, so it needs a hash that equals itself; `0` and `-0` share one hash
242
+ if (Number.isNaN(x))
243
+ return defaultHash_nan;
244
+ return mergeValueHash(defaultHash_number, x === 0 ? 0 : x);
241
245
  }
242
246
  if (typeof x === "string") {
243
247
  return mergeValueHash(defaultHash_string, x);
@@ -369,7 +373,8 @@ export let hashFunction = (x) => {
369
373
  let base = defaultHash_impl;
370
374
  base = mergeValueHash(base, hashFunction(x.name));
371
375
  if (x.origin != null) {
372
- base = mergeValueHash(base, hashFunction(x.origin));
376
+ // Impl equality compares origin names, not trait object identities.
377
+ base = mergeValueHash(base, hashFunction(x.origin.name.value));
373
378
  }
374
379
  for (let idx = 0; idx < x.fields.length; idx++) {
375
380
  base = mergeValueHash(base, hashFunction(x.fields[idx]));
@@ -656,8 +661,8 @@ export let _$n__$e_ = (x, y) => {
656
661
  return false;
657
662
  }
658
663
  if (tx === "number") {
659
- // already checked above
660
- return false;
664
+ // value equality: NaN equals NaN (`0 === -0` already held above)
665
+ return Number.isNaN(x) && Number.isNaN(y);
661
666
  }
662
667
  if (tx === "function") {
663
668
  // method values are closures created on the fly (see invoke_method_closure),
@@ -837,7 +842,11 @@ export let _$n__$e_ = (x, y) => {
837
842
  }
838
843
  if (x instanceof CalcitEnumDef) {
839
844
  if (y instanceof CalcitEnumDef) {
840
- return x.name === y.name;
845
+ // The prototype carries the nominal origin, variant tags and payload
846
+ // schemas. Comparing name methods compares one shared function object.
847
+ return _$n__$e_(x.prototype, y.prototype)
848
+ && x.impls.length === y.impls.length
849
+ && x.impls.every((impl, index) => _$n__$e_(impl, y.impls[index]));
841
850
  }
842
851
  return false;
843
852
  }
@@ -1419,7 +1419,12 @@ export let _$n_str_$o_replace = (x, y, z) => {
1419
1419
  return x.replace(new RegExp(literalPattern, "gu"), () => z);
1420
1420
  };
1421
1421
  export let split = (xs, x) => {
1422
- return new CalcitSliceList(xs.split(x));
1422
+ // An empty delimiter splits by code point, matching native for astral characters.
1423
+ if (x === "") {
1424
+ return new CalcitSliceList(Array.from(xs));
1425
+ }
1426
+ // Drop empty pieces to match native and WASM: `split | |,` is an empty list.
1427
+ return new CalcitSliceList(xs.split(x).filter((piece) => piece !== ""));
1423
1428
  };
1424
1429
  export let split_lines = (xs) => {
1425
1430
  return new CalcitSliceList(xs.split("\n"));
@@ -12,4 +12,6 @@ import { CalcitCirruQuote } from "./js-cirru.mjs";
12
12
  import { CalcitTrait } from "./js-trait.mjs";
13
13
  export type CalcitValue = string | number | boolean | CalcitMap | CalcitSliceMap | CalcitList | CalcitSliceList | CalcitSet | CalcitTag | CalcitSymbol | CalcitRef | CalcitEnumValue | CalcitFn | CalcitRecur | CalcitStructValue | CalcitImpl | CalcitTrait | CalcitStructDef | CalcitEnumDef | CalcitCirruQuote | Uint8Array | undefined | null;
14
14
  export declare let isLiteral: (x: CalcitValue) => boolean;
15
+ /** total order over numbers: `-0` equals `0`, NaN equals NaN and sorts after every number */
16
+ export declare let compareNumbers: (x: number, y: number) => number;
15
17
  export declare let _$n_compare: (a: CalcitValue, b: CalcitValue) => number;
package/lib/js-primes.mjs CHANGED
@@ -101,6 +101,14 @@ let rawCompare = (x, y) => {
101
101
  return 0;
102
102
  }
103
103
  };
104
+ /** total order over numbers: `-0` equals `0`, NaN equals NaN and sorts after every number */
105
+ export let compareNumbers = (x, y) => {
106
+ if (x < y)
107
+ return -1;
108
+ if (x > y)
109
+ return 1;
110
+ return (Number.isNaN(x) ? 1 : 0) - (Number.isNaN(y) ? 1 : 0);
111
+ };
104
112
  /** lexicographic order over two sequences of values, a shorter prefix sorts first (same as Rust `Vec::cmp`) */
105
113
  let compareSequences = (xs, ys) => {
106
114
  let n = Math.min(xs.length, ys.length);
@@ -112,6 +120,18 @@ let compareSequences = (xs, ys) => {
112
120
  return rawCompare(xs.length, ys.length);
113
121
  };
114
122
  let listToArray = (x) => Array.from(x.items());
123
+ // Plain functions compare by identity. IDs are process-local, never serialized,
124
+ // and kept weakly so ordering does not retain closures or mutate frozen hosts.
125
+ const functionOrderIds = new WeakMap();
126
+ let nextFunctionOrderId = 0;
127
+ const functionOrderId = (fn) => {
128
+ let id = functionOrderIds.get(fn);
129
+ if (id === undefined) {
130
+ id = ++nextFunctionOrderId;
131
+ functionOrderIds.set(fn, id);
132
+ }
133
+ return id;
134
+ };
115
135
  export let _$n_compare = (a, b) => {
116
136
  if (a === b)
117
137
  return 0;
@@ -125,7 +145,7 @@ export let _$n_compare = (a, b) => {
125
145
  case PseudoTypeIndex.bool:
126
146
  return rawCompare(a, b);
127
147
  case PseudoTypeIndex.number:
128
- return rawCompare(a, b);
148
+ return compareNumbers(a, b);
129
149
  case PseudoTypeIndex.tag:
130
150
  return rawCompare(a.value, b.value);
131
151
  case PseudoTypeIndex.symbol:
@@ -134,6 +154,36 @@ export let _$n_compare = (a, b) => {
134
154
  return rawCompare(a, b);
135
155
  case PseudoTypeIndex.ref:
136
156
  return rawCompare(a.path, b.path);
157
+ case PseudoTypeIndex.fn: {
158
+ const left = a;
159
+ const right = b;
160
+ // Method closures use name equality, unlike ordinary function values.
161
+ if (left.__calcitMethodName != null || right.__calcitMethodName != null) {
162
+ if (left.__calcitMethodName == null)
163
+ return -1;
164
+ if (right.__calcitMethodName == null)
165
+ return 1;
166
+ return compareUnicodeStrings(left.__calcitMethodName, right.__calcitMethodName);
167
+ }
168
+ return rawCompare(functionOrderId(left), functionOrderId(right));
169
+ }
170
+ case PseudoTypeIndex.impl: {
171
+ const left = a;
172
+ const right = b;
173
+ const nameOrder = compareUnicodeStrings(left.name.value, right.name.value);
174
+ if (nameOrder !== 0)
175
+ return nameOrder;
176
+ if (left.origin == null && right.origin != null)
177
+ return -1;
178
+ if (left.origin != null && right.origin == null)
179
+ return 1;
180
+ if (left.origin != null && right.origin != null) {
181
+ const originOrder = compareUnicodeStrings(left.origin.name.value, right.origin.name.value);
182
+ if (originOrder !== 0)
183
+ return originOrder;
184
+ }
185
+ return compareSequences(left.fields, right.fields) || compareSequences(left.values, right.values);
186
+ }
137
187
  case PseudoTypeIndex.struct_value: {
138
188
  const left = a;
139
189
  const right = b;
@@ -176,6 +226,43 @@ export let _$n_compare = (a, b) => {
176
226
  return tagOrder;
177
227
  return compareSequences(left.extra, right.extra);
178
228
  }
229
+ case PseudoTypeIndex.enum_def: {
230
+ const left = a;
231
+ const right = b;
232
+ const leftRef = left.prototype.structRef.definitionRef;
233
+ const rightRef = right.prototype.structRef.definitionRef;
234
+ if (leftRef !== rightRef) {
235
+ if (leftRef == null)
236
+ return -1;
237
+ if (rightRef == null)
238
+ return 1;
239
+ return compareUnicodeStrings(leftRef, rightRef);
240
+ }
241
+ const nameOrder = compareUnicodeStrings(left.name(), right.name());
242
+ if (nameOrder !== 0)
243
+ return nameOrder;
244
+ const variantCountOrder = rawCompare(left.prototype.fields.length, right.prototype.fields.length);
245
+ if (variantCountOrder !== 0)
246
+ return variantCountOrder;
247
+ for (let index = 0; index < left.prototype.fields.length; index++) {
248
+ const tagOrder = _$n_compare(left.prototype.fields[index], right.prototype.fields[index]);
249
+ if (tagOrder !== 0)
250
+ return tagOrder;
251
+ const leftPayload = left.prototype.values[index];
252
+ const rightPayload = right.prototype.values[index];
253
+ // Native orders variant payloads by arity before comparing types.
254
+ if ((leftPayload instanceof CalcitList || leftPayload instanceof CalcitSliceList)
255
+ && (rightPayload instanceof CalcitList || rightPayload instanceof CalcitSliceList)) {
256
+ const arityOrder = rawCompare(leftPayload.len(), rightPayload.len());
257
+ if (arityOrder !== 0)
258
+ return arityOrder;
259
+ }
260
+ const payloadOrder = _$n_compare(leftPayload, rightPayload);
261
+ if (payloadOrder !== 0)
262
+ return payloadOrder;
263
+ }
264
+ return rawCompare(left.impls.length, right.impls.length) || compareSequences(left.impls, right.impls);
265
+ }
179
266
  case PseudoTypeIndex.set: {
180
267
  // like native: smaller sets first, then the sorted elements
181
268
  const left = Array.from(a.values());
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.29.0-alpha.19",
3
+ "version": "0.29.0-alpha.20",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "files": [
6
6
  "lib/",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.29.0-alpha.19",
3
+ "version": "0.29.0-alpha.20",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "files": [
6
6
  "lib/",