@calcit/procs 0.13.43 → 0.13.45

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 (83) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/RFCs/04-15-match-syntax-rfc.md +14 -8
  3. package/RFCs/04-15-type-directed-optimization-catalog.md +20 -14
  4. package/RFCs/08-05-systematic-nil-reduction-rfc.md +16 -5
  5. package/editing-history/20260824-2119-validate-number-call-metadata.md +8 -0
  6. package/editing-history/20260824-2155-stable-js-struct-layout.md +11 -0
  7. package/editing-history/20260824-2224-struct-index-review-followups.md +7 -0
  8. package/editing-history/20260824-2233-indexed-struct-js-regressions.md +5 -0
  9. package/editing-history/20260824-2256-dynamic-method-analysis.md +9 -0
  10. package/editing-history/20260824-2329-dynamic-method-review-followups.md +7 -0
  11. package/editing-history/202608241731-contiguous-executable-calls.md +34 -0
  12. package/editing-history/202608241920-borrowed-syntax-arguments.md +34 -0
  13. package/editing-history/202608241924-unify-editing-history-directory.md +7 -0
  14. package/editing-history/202608242013-typed-native-number-ops.md +34 -0
  15. package/editing-history/20260825-0020-indexed-enum-match.md +34 -0
  16. package/editing-history/20260825-0100-indexed-enum-match-validation.md +7 -0
  17. package/editing-history/20260825-0120-indexed-enum-match-review.md +7 -0
  18. package/editing-history/20260825-1215-typed-literal-paths.md +56 -0
  19. package/editing-history/20260825-1344-typed-literal-path-review.md +17 -0
  20. package/editing-history/20260825-1505-typed-method-native-op.md +23 -0
  21. package/editing-history/20260825-1540-nil-unit-runtime-separation.md +15 -0
  22. package/editing-history/20260825-1725-typed-method-error-stack-review.md +10 -0
  23. package/editing-history/20260825-1733-nil-unit-doc-review.md +5 -0
  24. package/editing-history/20260825-1758-nil-unit-review-followup.md +6 -0
  25. package/editing-history/20260825-1845-release-01344.md +6 -0
  26. package/editing-history/20260825-2121-macro-parameter-diagnostics.md +10 -0
  27. package/editing-history/20260825-2138-keep-malformed-macro-params-hard.md +5 -0
  28. package/editing-history/20260825-2311-macro-capability-review-followup.md +10 -0
  29. package/editing-history/20260825-2312-macro-expansion-metrics.md +11 -0
  30. package/editing-history/20260825-2337-macro-query-and-capability-scope.md +11 -0
  31. package/editing-history/20260825-2338-core-structural-macro-contracts.md +10 -0
  32. package/editing-history/20260825-2356-delayed-macro-metrics-review.md +5 -0
  33. package/editing-history/202608252220-phase-aware-macro-signatures.md +35 -0
  34. package/editing-history/202608252249-macro-compile-time-capabilities.md +27 -0
  35. package/editing-history/20260826-0007-assertion-macro-contracts.md +8 -0
  36. package/editing-history/20260826-0023-assertion-macro-review.md +4 -0
  37. package/editing-history/20260826-0038-control-flow-macro-contracts.md +9 -0
  38. package/editing-history/20260826-0100-review-exact-control-flow-contracts.md +5 -0
  39. package/editing-history/20260826-0120-pattern-macro-contracts.md +8 -0
  40. package/editing-history/20260826-0133-collection-macro-contracts.md +9 -0
  41. package/editing-history/20260826-0152-definition-macro-contracts.md +25 -0
  42. package/editing-history/20260826-0203-transform-macro-contracts.md +28 -0
  43. package/editing-history/20260826-0214-binding-update-macro-contracts.md +14 -0
  44. package/editing-history/20260826-0629-type-observability-macros.md +8 -0
  45. package/editing-history/20260826-0642-type-remaining-match-macros.md +7 -0
  46. package/editing-history/20260826-0654-macro-log-capability.md +8 -0
  47. package/editing-history/20260826-0707-release-01345.md +6 -0
  48. package/examples/bench_enum_match.rs +41 -0
  49. package/lib/calcit-data.d.mts +4 -0
  50. package/lib/calcit-data.mjs +59 -9
  51. package/lib/calcit.procs.d.mts +16 -8
  52. package/lib/calcit.procs.mjs +68 -46
  53. package/lib/custom-formatter.mjs +12 -3
  54. package/lib/js-cirru.mjs +6 -5
  55. package/lib/js-impl.mjs +4 -3
  56. package/lib/js-primes.d.mts +1 -1
  57. package/lib/js-primes.mjs +22 -18
  58. package/lib/js-struct-def.mjs +4 -6
  59. package/lib/js-struct-value.d.mts +5 -1
  60. package/lib/js-struct-value.mjs +66 -38
  61. package/lib/package.json +8 -2
  62. package/package.json +8 -2
  63. package/ts-src/calcit-data.mts +54 -9
  64. package/ts-src/calcit.procs.mts +66 -49
  65. package/ts-src/custom-formatter.mts +12 -3
  66. package/ts-src/js-cirru.mts +6 -5
  67. package/ts-src/js-impl.mts +4 -3
  68. package/ts-src/js-primes.mts +5 -1
  69. package/ts-src/js-struct-def.mts +4 -6
  70. package/ts-src/js-struct-value.mts +78 -33
  71. /package/{history → editing-history}/202608191501-release-01326.md +0 -0
  72. /package/{history → editing-history}/202608191628-revert-transparent-union-types.md +0 -0
  73. /package/{history → editing-history}/202608191741-release-01327.md +0 -0
  74. /package/{history → editing-history}/202608212020-release-01328.md +0 -0
  75. /package/{2026082200-release-01330.md → editing-history/2026082200-release-01330.md} +0 -0
  76. /package/{2026082200-same-package-module-meta.md → editing-history/2026082200-same-package-module-meta.md} +0 -0
  77. /package/{2026082200-transitive-module-loading.md → editing-history/2026082200-transitive-module-loading.md} +0 -0
  78. /package/{2026082222-release-01331.md → editing-history/2026082222-release-01331.md} +0 -0
  79. /package/{history → editing-history}/2026082223-release-01332.md +0 -0
  80. /package/{history → editing-history}/2026082223-same-package-namespaces.md +0 -0
  81. /package/{history → editing-history}/2026082300-fix-cross-package-namespace-merge.md +0 -0
  82. /package/{history → editing-history}/2026082300-release-01333.md +0 -0
  83. /package/{history → editing-history}/2026082316-release-01334.md +0 -0
@@ -0,0 +1,10 @@
1
+ # Core structural macro contracts
2
+
3
+ - Migrated `let`, `fn`, `and`, `cond`, and `do` from whole-Dynamic legacy
4
+ schemas to strict, compile-time-pure phase contracts.
5
+ - Kept expansion values as `Expr<Dynamic>` where the result depends on user
6
+ code, while enforcing list-shaped binding/argument/condition syntax.
7
+ - Canonicalized strict Macro storage with explicit empty capability sets and
8
+ added snapshot assertions so the migrated set cannot silently regress.
9
+ - The Calcit test snapshot now exposes 895 strict/pure expansion candidates in
10
+ the measured run (up from 4), while preserving all 2,432 expansions.
@@ -0,0 +1,5 @@
1
+ # Delayed macro metrics review
2
+
3
+ - Clarified that `cacheHits` and `cacheInvalidations` are reserved report fields until the expansion cache is implemented.
4
+ - Made the metrics report unit test operate on local state, avoiding interference with global opt-in metrics state when Rust tests run in parallel.
5
+ - Kept production collection behavior unchanged by extracting small state-local recording and serialization helpers.
@@ -0,0 +1,35 @@
1
+ # Phase-aware macro signatures
2
+
3
+ Implemented roadmap issue #434 after the parameter-shape diagnostics from
4
+ #433/#438 landed.
5
+
6
+ - Added a dedicated `MacroSignature` model instead of representing macros as
7
+ runtime `CalcitFnTypeAnnotation` values.
8
+ - Split raw inputs into `Syntax`, `SyntaxSymbol`, `SyntaxList`, and `Expr<T>`;
9
+ split expansion results into `Expr<T>`, `Definition<T>`, and `Declarations`.
10
+ - Added required, optional, rest, generic, where-bound, and feature metadata.
11
+ - Preserved old `Macro {:args ... :return ...}` snapshots as explicit legacy,
12
+ non-strict signatures; the ordinary Fn parser rejects strict macro fields.
13
+ - Attached signatures to materialized `CalcitMacro` values, typed macro-body
14
+ locals at syntax phase, and added separate call-input and expansion-result
15
+ diagnostics with source locations and macro stacks.
16
+ - Updated snapshot, detailed snapshot, weak-type, and coverage paths so the new
17
+ model survives all formats and contributes accurate coverage.
18
+ - Migrated core `%{}?` to `SyntaxSymbol + & SyntaxList -> Expr<Struct>` and
19
+ documented Respo `defstyle` as the declaration-output case study.
20
+
21
+ Validation performed:
22
+
23
+ - `cargo fmt`
24
+ - `cargo clippy --all-targets -- -D warnings`
25
+ - `cargo test`
26
+ - `yarn compile`
27
+ - `yarn check-all`
28
+ - `yarn check-agent-interface`
29
+ - `calcit docs check-md --entry src/cirru/calcit-core.cirru docs/MacroSignature.md`
30
+ - latest Respo main: 27/27 tests and 126/126 documentation blocks
31
+ - latest Recollect main: 9/9 Calcit tests plus JS tests
32
+
33
+ External regressions used globally installed Calcit 0.13.44 and refreshed
34
+ `@calcit/procs` 0.13.44; stale local 0.13.27 packages were replaced before the
35
+ final run.
@@ -0,0 +1,27 @@
1
+ # Macro compile-time capabilities
2
+
3
+ Issue #435 adds an enforceable effect boundary around strict macro execution.
4
+ The capability policy is centralized in `runner::macro_capability` and remains
5
+ active through ordinary helper calls by using a scoped evaluator context.
6
+
7
+ Strict `MacroSignature` values now serialize a dedicated `:capabilities`
8
+ hashset. Pure expansion needs no declaration. Environment, filesystem,
9
+ platform, clock, mutable-state, and dynamic-eval reads/actions may be declared;
10
+ filesystem writes, process control, and host FFI are classified but always
11
+ rejected. Legacy macro signatures stay compatible, but their effects remain
12
+ unknown and they are not eligible for future pure-expansion caching.
13
+
14
+ The evaluator checks builtin procedures, state/dynamic-eval syntax, native
15
+ methods, registered procedures, and raw host code. Missing declarations use
16
+ `E_MACRO_CAPABILITY_MISSING`; forbidden operations use
17
+ `E_MACRO_CAPABILITY_DISALLOWED`. Both preserve the macro call location and
18
+ helper chain. Quoted code that performs an effect later at runtime remains a
19
+ pure expansion. Macro diagnostics also reuse the raw call-head location instead
20
+ of the locationless resolved import, preserving no-argument call sites.
21
+
22
+ Validation covered formatting, clippy, all Rust and CLI tests, native/JS/IR/WASM
23
+ integration, agent-interface checks, and the macro-signature documentation.
24
+ Latest Respo passed 27 tests and 126 documentation blocks. Latest Recollect
25
+ passed 9 native tests plus JS and WASM regressions. Its production build still
26
+ reports the existing Respo DOM FFI and `:unit`/`:nil` warning baseline; neither
27
+ external repository was modified.
@@ -0,0 +1,8 @@
1
+ # Assertion macro contracts
2
+
3
+ - Migrated the three `calcit.core` assertion macros and five `calcit.test` helpers to strict, pure phase-aware contracts.
4
+ - Kept input values as `Expr<Dynamic>` because equality and truthiness intentionally accept heterogeneous runtime values.
5
+ - Declared precise expansion results: `Expr<Unit>` for assertion helpers and `Expr<Bool>` for `throws?`.
6
+ - Added the missing successful `&unit` branch to `assert=` so its implementation matches its long-standing Unit contract.
7
+ - Added snapshot coverage and exercised definition-attached tests plus public examples.
8
+ - On `calcit/test.cirru`, strict/pure macro candidates increased from 895 to 1,666 while total expansions stayed at 2,432.
@@ -0,0 +1,4 @@
1
+ # Assertion macro review
2
+
3
+ - Strengthened the real Snapshot inventory test to assert the exact required input count for each `calcit.test` assertion helper.
4
+ - Kept the original history timestamp because the commit was created at `2026-08-26 00:13:33 +0800`; the review bot compared against the previous UTC date.
@@ -0,0 +1,9 @@
1
+ # Control-flow macro contracts
2
+
3
+ - Migrated `or`, `either`, `when`, `when-not`, `if-not`, `if-let`, and `when-let` to strict, pure phase-aware contracts.
4
+ - Preserved expression-level Dynamic boundaries where branch value types intentionally vary, while declaring `when-let` as `Expr<Option<Dynamic>>`.
5
+ - Corrected the `or false nil` example to expect the final falsey value (`nil`) and clarified that behavior in its documentation.
6
+ - Fixed strict macro body parameter typing: `SyntaxList` is represented as a list, `SyntaxSymbol` as a symbol, and rest bindings as lists of their declared syntax element type.
7
+ - Added regression coverage for strict macro body parameter representations and the real core Snapshot inventory.
8
+ - Increased strict macro coverage in `calcit/test.cirru` from 1666 to 1805 of 2432 expansions.
9
+ - Verified the release compiler against Respo `be8141e` (27 tests and check-only JS) and Recollect `6c235d0` (9 native tests plus JS/Node tests).
@@ -0,0 +1,5 @@
1
+ # Exact control-flow contract regression checks
2
+
3
+ - Strengthened the core Snapshot inventory to assert each migrated control-flow macro's exact required, optional, and rest syntax contracts.
4
+ - Asserted exact expansion types, including `when-let` as `Expr<Option<Dynamic>>` and the remaining macros as `Expr<Dynamic>`.
5
+ - Documented the strict macro body type helpers added by the original change.
@@ -0,0 +1,8 @@
1
+ # Pattern-matching macro contracts
2
+
3
+ - Migrated `tag-match`, `list-match`, `struct-match`, `case`, and their internal expansion helpers to strict, compile-time-pure macro contracts.
4
+ - Kept branch bodies as `SyntaxList`; retained `list-match`'s heterogeneous public argument sequence as an intentional `Syntax` rest boundary while typing its internal helper exactly.
5
+ - Corrected the pre-existing `tag-match` example expectation from `got:hello` to `hello:got`, matching `str x |:got`.
6
+ - Added exact Snapshot assertions for required, optional, rest, capability, and expansion contracts across both `calcit.core` and `calcit.internal`.
7
+ - Increased strict macro coverage in `calcit/test.cirru` from 1805 to 1949 of 2432 expansions.
8
+ - Verified all repository gates plus Respo `be8141e`, Recollect `6c235d0`, and js-ffi `25869b6`; js-ffi dependencies were reinstalled from its 0.13.44 lockfile before Node/browser contract tests.
@@ -0,0 +1,9 @@
1
+ # Collection macro contracts
2
+
3
+ - Migrated `{}`, `%{}`, and `{,}` to strict, compile-time-pure macro contracts.
4
+ - Declared map literal expansions as `Expr<Map<Dynamic, Dynamic>>` and struct literal expansion as `Expr<Struct>`.
5
+ - Kept pair-oriented inputs as `SyntaxList` and the flat comma-filtering `{,}` body as an intentional raw `Syntax` rest boundary.
6
+ - Corrected the pre-existing `%{}` example to use field pairs `(:x 1)` and `(:y 2)` rather than list-constructor calls that introduced extra fields.
7
+ - Added exact Snapshot assertions for each macro's input and expansion contracts.
8
+ - Increased strict macro coverage in `calcit/test.cirru` from 1949 to 2133 of 2432 expansions.
9
+ - Verified all repository gates plus Respo `be8141e`, Recollect `6c235d0`, and js-ffi `25869b6` with the current compiler.
@@ -0,0 +1,25 @@
1
+ # Definition-value macro contracts
2
+
3
+ ## Changes
4
+
5
+ - Migrated `def` to a pure phase-aware macro contract with a symbol declaration name and an explicit dynamic expression boundary.
6
+ - Migrated `deftrait`, `defstruct`, `defimpl`, and `defenum` to strict syntax-input contracts with precise `Trait`, `StructDef`, `Impl`, and `EnumDef` expression outputs.
7
+ - Kept symbol/tag compatibility for data-definition names by using unrestricted syntax for those positions; method and field forms use list syntax where the macro requires pair/list forms.
8
+ - Added Snapshot assertions for required, optional, rest, capability, and expansion fields so serialization regressions cannot silently weaken these contracts.
9
+
10
+ ## Semantic finding
11
+
12
+ Although these macros generate top-level definition values, the core `def` macro is consumed before the outer expansion-result check. Their observable expansion contract is therefore `Expr<T>`, not `Definition<T>`. Using `Definition<T>` fails against the real core corpus because the checked form is already `&trait::new`, `&struct-def:new`, `&impl::new`, or `&enum-def:new`.
13
+
14
+ ## Validation
15
+
16
+ - Core strict macro expansions: `2133/2432` -> `2341/2432`; legacy bypasses: `299` -> `91`.
17
+ - `cargo fmt --check`
18
+ - `cargo clippy -- -D warnings`
19
+ - `yarn compile`
20
+ - `cargo test`
21
+ - `yarn check-all`
22
+ - `yarn check-agent-interface`
23
+ - Respo `be8141e`: 27 definition-attached tests and JS check-only passed.
24
+ - Recollect `6c235d0`: 9 unit tests, JS generation, and Node runtime passed.
25
+ - js-ffi `25869b6`: default/node/browser checks plus Node and browser-node contracts passed.
@@ -0,0 +1,28 @@
1
+ # Transform macro contracts
2
+
3
+ ## Changes
4
+
5
+ - Migrated `->`, `->%`, and `%<-` with phase-aware base/step contracts.
6
+ - Migrated `apply-args` and `flipped` with callable input contracts and explicit dynamic result boundaries.
7
+ - Migrated anonymous function shorthands `\` and `\.` with syntax inputs and callable expression outputs.
8
+ - Migrated `[,]` with arbitrary syntax inputs and a `List<Dynamic>` expression output.
9
+ - Added exact Snapshot assertions for every required, optional, rest, capability, and expansion field.
10
+
11
+ ## Contract notes
12
+
13
+ - Thread steps in `->` remain unrestricted syntax because the macro deliberately accepts symbol, tag, method, function, and list forms.
14
+ - Calcit's canonical callable schema type is `'Fn`; `'DynFn` is not the public schema spelling.
15
+ - `%<-`, `\`, and `[,]` retain runtime empty-input diagnostics because their implementation uses rest-only parameters and the phase signature mirrors that actual binder shape.
16
+
17
+ ## Validation
18
+
19
+ - Reachable strict expansions: `2341/2432` -> `2364/2432`; legacy bypasses: `91` -> `68`.
20
+ - `cargo fmt --check`
21
+ - `cargo clippy -- -D warnings`
22
+ - `yarn compile`
23
+ - `cargo test` (one unrelated parallel feature-policy test flaked once; isolated and full reruns passed)
24
+ - `yarn check-all`
25
+ - `yarn check-agent-interface`
26
+ - Respo `be8141e`: 27 tests and JS check-only passed.
27
+ - Recollect `6c235d0`: 9 tests, JS generation, and Node runtime passed.
28
+ - js-ffi `25869b6`: default/node/browser checks and both runtime contracts passed.
@@ -0,0 +1,14 @@
1
+ # Binding and update macro contracts
2
+
3
+ ## Changes
4
+
5
+ - Migrated `let-destruct`, `let-sugar`, `let[]`, `let{}`, and `loop` to phase-aware binding and body contracts.
6
+ - Migrated `struct-with`, `swap!`, and `&doseq` with concrete struct/ref/callable inputs and struct/Unit outputs where proven.
7
+ - Added `assert-type pair 'List` inside `let-sugar` so strict macro-body analysis retains the list evidence already guaranteed by its runtime validation.
8
+ - Added exact Snapshot assertions for all contract fields.
9
+
10
+ ## Validation
11
+
12
+ - Reachable strict expansions: `2364/2432` -> `2379/2432`; legacy bypasses: `68` -> `53`.
13
+ - Full `cargo fmt`, Clippy, compile, Rust tests, `yarn check-all`, and Agent interface gates passed.
14
+ - Latest Respo `be8141e`, Recollect `6c235d0`, and js-ffi `25869b6` regressions passed.
@@ -0,0 +1,8 @@
1
+ # Type observability macro contracts
2
+
3
+ - Migrated logging, timing, hygiene, documentation, and debug function-wrapper macros to strict phase-aware signatures.
4
+ - Preserve expression result types for `w-log`, `wo-log`, `with-cpu-time`, and `noted` with a generic `T` contract.
5
+ - Require callable expressions for `call-w-log` and `call-wo-log`, structural symbol/list inputs for function-definition and gensym helpers, and definition-shaped function expansions for `defn-w-log`/`defn-wo-log`.
6
+ - Declare `:platform-read` only for macros that inspect the Calcit running mode while expanding. Runtime logging and `cpu-time` emitted into quoted code do not count as compile-time capabilities.
7
+ - Benchmarked the full macro-contract migration against `3a7afb5e`: both release check-only medians remained about 0.15 seconds across 12 warm runs. Strict/cache-eligible expansion coverage rose from 4 to 2379 before this batch; this batch moves another 8 pure expansions to cache eligibility and classifies 5 platform-dependent expansions honestly.
8
+ - Verified earlier, structured failures for invalid callable/list/ref macro arguments. No expansion cache exists yet, so this work provides visible diagnostics and cache prerequisites rather than a current runtime speedup.
@@ -0,0 +1,7 @@
1
+ # Remaining core match macro contracts
2
+
3
+ - Migrated `case-default`, `field-match`, and `calcit.internal/&field-match-internal` to strict phase-aware macro signatures.
4
+ - `case-default` now validates both value/default expression inputs and requires every pattern arm to be list-shaped syntax while keeping its branch-dependent output honest as `Expr<Dynamic>`.
5
+ - `field-match` and its recursive helper now require a map expression before expansion, so invalid values fail at the public macro boundary with `E_MACRO_INPUT_EXPR_TYPE` instead of reaching generated runtime assertions.
6
+ - Added snapshot assertions for required inputs, rest-arm syntax, pure capability sets, and expansion categories.
7
+ - The core suite now observes 2392 pure/cache-eligible expansions, 5 explicitly platform-dependent expansions, and only 35 legacy expansions, all of which belong to test helper macros.
@@ -0,0 +1,8 @@
1
+ # Compile-time macro log capability
2
+
3
+ - Added the opt-in `:log` macro capability for compile-time `echo`, `println`, and `eprintln` calls.
4
+ - Registered procedures remain forbidden host FFI by default; the three platform console aliases are the narrow exception and still require an explicit capability declaration.
5
+ - Documented that quoted runtime logging stays pure while logging actually executed during expansion is observable and therefore cache-ineligible.
6
+ - Added positive, missing-capability, and unrelated-host-procedure tests for the policy plus schema round-trip coverage for `:log`.
7
+ - Migrated the final test helper macros: `inside-eval:`/`inside-js:` declare `:platform-read`, `add-11` declares `:log`, and the hygienic no-log helper remains pure.
8
+ - Macro metrics now report zero legacy bypasses: 2393 pure/cache-eligible expansions and 39 explicitly capability-dependent expansions out of 2432 total. Cache hits remain zero until the planned cache implementation lands.
@@ -0,0 +1,6 @@
1
+ # Release 0.13.45
2
+
3
+ - Publish the completed phase-aware macro contract migration and compile-time capability policy improvements.
4
+ - Includes strict contracts across the observed core corpus, explicit `:platform-read` and `:log` effects, and zero legacy macro-signature bypasses in `calcit/test.cirru` metrics.
5
+ - Provides the stable compiler version required for Respo's six strict macro contracts, especially `defstyle` compile-time logging.
6
+ - Release validation is based on the merged PR gates plus latest Respo, Recollect, and js-ffi regressions run with the built compiler.
@@ -0,0 +1,41 @@
1
+ use std::hint::black_box;
2
+ use std::sync::Arc;
3
+ use std::time::Instant;
4
+
5
+ use calcit::calcit::{Calcit, CalcitEnumDef, CalcitList, CalcitStructDef, CalcitStructValue};
6
+ use cirru_edn::EdnTag;
7
+
8
+ const ITERATIONS: usize = 5_000_000;
9
+ const VARIANT_COUNT: usize = 16;
10
+
11
+ fn main() {
12
+ let fields: Vec<EdnTag> = (0..VARIANT_COUNT).map(|idx| EdnTag::new(format!("variant-{idx:02}"))).collect();
13
+ let values = vec![Calcit::from(CalcitList::Vector(vec![])); fields.len()];
14
+ let enum_def = CalcitEnumDef::from_struct(CalcitStructValue {
15
+ struct_ref: Arc::new(CalcitStructDef::from_fields(EdnTag::new("DispatchState"), fields)),
16
+ values: Arc::new(values),
17
+ })
18
+ .expect("valid benchmark enum");
19
+ let target = enum_def.variants().last().expect("last variant").tag.clone();
20
+
21
+ run("linear-tag-scan", || {
22
+ enum_def
23
+ .variants()
24
+ .iter()
25
+ .position(|variant| variant.tag == target)
26
+ .expect("target variant")
27
+ });
28
+ run("indexed-branch-slot", || enum_def.variant_index(&target).expect("target variant"));
29
+ }
30
+
31
+ fn run(label: &str, mut dispatch: impl FnMut() -> usize) {
32
+ let mut checksum = 0usize;
33
+ for _ in 0..100_000 {
34
+ checksum = checksum.wrapping_add(black_box(dispatch()));
35
+ }
36
+ let started = Instant::now();
37
+ for _ in 0..ITERATIONS {
38
+ checksum = checksum.wrapping_add(black_box(dispatch()));
39
+ }
40
+ println!("{label}: {:.2}ms checksum={checksum}", started.elapsed().as_secs_f64() * 1000.0);
41
+ }
@@ -25,6 +25,10 @@ export declare let isNestedCalcitData: (x: CalcitValue) => boolean;
25
25
  export declare let tipNestedCalcitData: (x: CalcitValue) => string;
26
26
  export type CalcitFn = (...xs: CalcitValue[]) => CalcitValue;
27
27
  export declare let getStringName: (x: CalcitValue) => string;
28
+ /** Compare tag names by Unicode scalar value, matching Rust `str` ordering. */
29
+ export declare function compareTagNames(x: CalcitTag, y: CalcitTag): number;
30
+ export declare function tagNamesAreCanonical(fields: CalcitTag[]): boolean;
31
+ export declare function canonicalizeTagPairs<T>(fields: CalcitTag[], values: T[], context: string): [CalcitTag[], T[]];
28
32
  /** returns -1 when not found */
29
33
  export declare function findInFields(xs: Array<CalcitTag>, y: CalcitTag): number;
30
34
  export declare let newTag: (content: string) => CalcitTag;
@@ -105,6 +105,51 @@ export let getStringName = (x) => {
105
105
  }
106
106
  throw new Error("Cannot get string as name");
107
107
  };
108
+ /** Compare tag names by Unicode scalar value, matching Rust `str` ordering. */
109
+ export function compareTagNames(x, y) {
110
+ let xIdx = 0;
111
+ let yIdx = 0;
112
+ while (xIdx < x.value.length && yIdx < y.value.length) {
113
+ const xCode = x.value.codePointAt(xIdx);
114
+ const yCode = y.value.codePointAt(yIdx);
115
+ if (xCode < yCode)
116
+ return -1;
117
+ if (xCode > yCode)
118
+ return 1;
119
+ xIdx += xCode > 0xffff ? 2 : 1;
120
+ yIdx += yCode > 0xffff ? 2 : 1;
121
+ }
122
+ if (xIdx < x.value.length)
123
+ return 1;
124
+ if (yIdx < y.value.length)
125
+ return -1;
126
+ return 0;
127
+ }
128
+ export function tagNamesAreCanonical(fields) {
129
+ for (let idx = 1; idx < fields.length; idx++) {
130
+ if (compareTagNames(fields[idx - 1], fields[idx]) >= 0)
131
+ return false;
132
+ }
133
+ return true;
134
+ }
135
+ export function canonicalizeTagPairs(fields, values, context) {
136
+ if (fields.length !== values.length) {
137
+ throw new Error(`${context}: fields and values length mismatch`);
138
+ }
139
+ if (tagNamesAreCanonical(fields))
140
+ return [fields, values];
141
+ const pairs = fields.map((field, idx) => [field, values[idx]]);
142
+ pairs.sort((a, b) => compareTagNames(a[0], b[0]));
143
+ for (let idx = 1; idx < pairs.length; idx++) {
144
+ if (pairs[idx - 1][0].value === pairs[idx][0].value) {
145
+ throw new Error(`${context}: duplicated field :${pairs[idx][0].value}`);
146
+ }
147
+ }
148
+ return [
149
+ pairs.map(([field]) => field),
150
+ pairs.map(([, value]) => value),
151
+ ];
152
+ }
108
153
  /** returns -1 when not found */
109
154
  export function findInFields(xs, y) {
110
155
  let low = 0;
@@ -112,10 +157,11 @@ export function findInFields(xs, y) {
112
157
  while (low <= high) {
113
158
  const mid = Math.floor((low + high) / 2);
114
159
  const midVal = xs[mid];
115
- if (midVal.idx < y.idx) {
160
+ const ordering = compareTagNames(midVal, y);
161
+ if (ordering < 0) {
116
162
  low = mid + 1;
117
163
  }
118
- else if (midVal.idx > y.idx) {
164
+ else if (ordering > 0) {
119
165
  high = mid - 1;
120
166
  }
121
167
  else {
@@ -156,6 +202,7 @@ export let castTag = (x) => {
156
202
  };
157
203
  export var refsRegistry = new Map();
158
204
  let defaultHash_nil = valueHash("nil:");
205
+ let defaultHash_unit = valueHash("unit:");
159
206
  let defaultHash_number = valueHash("number:");
160
207
  let defaultHash_string = valueHash("string:");
161
208
  let defaultHash_tag = valueHash("tag:");
@@ -177,9 +224,11 @@ let defaultHash_unknown = valueHash("unknown:");
177
224
  let fnHashCounter = 0;
178
225
  let jsObjectHashCounter = 0;
179
226
  export let hashFunction = (x) => {
180
- if (x == null) {
227
+ if (x === null) {
181
228
  return defaultHash_nil;
182
229
  }
230
+ if (x === undefined)
231
+ return defaultHash_unit;
183
232
  if (typeof x === "number") {
184
233
  return mergeValueHash(defaultHash_number, x);
185
234
  }
@@ -367,9 +416,11 @@ let hashCirru = (base, x) => {
367
416
  // Dirty code to change ternary-tree behavior
368
417
  overwriteHashGenerator(hashFunction);
369
418
  export let toString = (x, escaped, disableJsDataWarning = false) => {
370
- if (x == null) {
419
+ if (x === null) {
371
420
  return "nil";
372
421
  }
422
+ if (x === undefined)
423
+ return "&unit";
373
424
  if (typeof x === "string") {
374
425
  if (escaped) {
375
426
  // turn to visual string representation
@@ -473,9 +524,11 @@ export let to_js_data = (x, options) => {
473
524
  return to_js_data_inner(x, addColon);
474
525
  };
475
526
  let to_js_data_inner = (x, addColon) => {
476
- if (x == null) {
527
+ if (x === null) {
477
528
  return null;
478
529
  }
530
+ if (x === undefined)
531
+ return undefined;
479
532
  if (x === true || x === false) {
480
533
  return x;
481
534
  }
@@ -560,10 +613,7 @@ export let _$n__$e_ = (x, y) => {
560
613
  if (x === y) {
561
614
  return true;
562
615
  }
563
- if (x == null) {
564
- if (y == null) {
565
- return true;
566
- }
616
+ if (x === null) {
567
617
  return false;
568
618
  }
569
619
  let tx = typeof x;
@@ -18,7 +18,13 @@ export declare const calcit_package_json: {
18
18
  "test-fail": string;
19
19
  "test-snippets": string;
20
20
  "check-js-runtime": string;
21
+ "check-literal-paths": string;
22
+ "check-typed-method-rem": string;
21
23
  "bench-recur-smoke": string;
24
+ "bench-enum-match": string;
25
+ "bench-literal-paths": string;
26
+ "bench-typed-method-rem": string;
27
+ "bench-struct-index": string;
22
28
  "check-smooth": string;
23
29
  "check-all": string;
24
30
  "check-agent-interface": string;
@@ -87,7 +93,9 @@ export declare function _$n_str_$o_count(x: CalcitValue): number;
87
93
  export declare function _$n_map_$o_count(x: CalcitValue): number;
88
94
  export declare function _$n_struct_$o_count(x: CalcitValue): number;
89
95
  export declare function _$n_struct_$o_field_tag(x: CalcitValue, idx: CalcitValue): CalcitTag;
90
- export declare function _$n_struct_$o_nth(x: CalcitValue, idx: CalcitValue): CalcitValue;
96
+ export declare function _$n_struct_$o_nth(x: CalcitValue, idx: CalcitValue, field?: CalcitValue): CalcitValue;
97
+ export declare function _$n_struct_$o_assoc_at(x: CalcitValue, idx: CalcitValue, field: CalcitValue, value: CalcitValue): CalcitValue;
98
+ export declare function _$n_struct_$o_with_at(x: CalcitValue, ...triples: CalcitValue[]): CalcitValue;
91
99
  export declare function _$n_set_$o_count(x: CalcitValue): number;
92
100
  export declare let _$L_: (...xs: CalcitValue[]) => CalcitSliceList;
93
101
  export declare let _SQUO_: (...xs: CalcitValue[]) => CalcitSliceList;
@@ -119,7 +127,7 @@ export declare let _$n_enum_$o_definition: (x: CalcitEnumValue) => CalcitEnumDef
119
127
  export declare let _$n_enum_def_$o_has_variant_$q_: (enumPrototype: CalcitValue, variantTag: CalcitTag) => boolean;
120
128
  export declare let _$n_enum_def_$o_has_variant: (enumPrototype: CalcitValue, variantTag: CalcitTag) => boolean;
121
129
  export declare let _$n_enum_def_$o_variant_arity: (enumPrototype: CalcitValue, variantTag: CalcitTag) => number;
122
- export declare let _$n_enum_$o_validate: (enumValue: CalcitValue, tag: CalcitValue) => CalcitValue;
130
+ export declare let _$n_enum_$o_validate: (enumValue: CalcitValue, tag: CalcitValue) => void;
123
131
  export declare let _$n_struct_$o_get: (xs: CalcitValue, k: CalcitTag) => CalcitValue;
124
132
  export declare let _$n_list_$o_assoc: (xs: CalcitValue, k: CalcitValue, v: CalcitValue) => CalcitList;
125
133
  export declare let _$n_enum_$o_assoc: (xs: CalcitValue, k: CalcitValue, v: CalcitValue) => CalcitEnumValue;
@@ -136,9 +144,9 @@ export declare let _$n_list_$o_assoc_before: (xs: CalcitList | CalcitSliceList,
136
144
  export declare let _$n_list_$o_assoc_after: (xs: CalcitSliceList, k: number, v: CalcitValue) => CalcitList | CalcitSliceList;
137
145
  export declare let _$n_list_$o_dissoc: (xs: CalcitValue | CalcitSliceList, k: CalcitValue) => CalcitList | CalcitSliceList;
138
146
  export declare let _$n_map_$o_dissoc: (xs: CalcitValue, ...args: CalcitValue[]) => CalcitMap | CalcitSliceMap;
139
- export declare let reset_$x_: (a: CalcitRef, v: CalcitValue) => null;
140
- export declare let add_watch: (a: CalcitRef, k: CalcitTag, f: CalcitFn) => null;
141
- export declare let remove_watch: (a: CalcitRef, k: CalcitTag) => null;
147
+ export declare let reset_$x_: (a: CalcitRef, v: CalcitValue) => CalcitValue;
148
+ export declare let add_watch: (a: CalcitRef, k: CalcitTag, f: CalcitFn) => void;
149
+ export declare let remove_watch: (a: CalcitRef, k: CalcitTag) => void;
142
150
  export declare let range: (n: number, m?: number, step?: number) => CalcitSliceList;
143
151
  export declare function _$n_list_$o_empty_$q_(xs: CalcitValue): boolean;
144
152
  export declare function _$n_str_$o_empty_$q_(xs: CalcitValue): boolean;
@@ -149,7 +157,7 @@ export declare let _$n_list_$o_last: (xs: CalcitValue) => CalcitValue;
149
157
  export declare let _$n_str_$o_first: (xs: CalcitValue) => CalcitValue;
150
158
  export declare let _$n_map_$o_destruct: (xs: CalcitValue) => CalcitValue;
151
159
  export declare let _$n_set_$o_destruct: (xs: CalcitValue) => CalcitValue;
152
- export declare let timeout_call: (duration: number, f: CalcitFn) => null;
160
+ export declare let timeout_call: (duration: number, f: CalcitFn) => void;
153
161
  export declare let _$n_list_$o_rest: (xs: CalcitValue) => CalcitList | CalcitSliceList;
154
162
  export declare let _$n_str_$o_rest: (xs: CalcitValue) => CalcitValue;
155
163
  export declare let recur: (...xs: CalcitValue[]) => CalcitRecur;
@@ -162,7 +170,7 @@ export declare let butlast: (xs: CalcitValue) => CalcitList | CalcitSliceList |
162
170
  export declare let initCrTernary: (x: string) => CalcitValue;
163
171
  export declare let _SHA__$M_: (...xs: CalcitValue[]) => CalcitValue;
164
172
  export declare let generate_id_$x_: () => string;
165
- export declare let _$n_display_stack: () => null;
173
+ export declare let _$n_display_stack: () => void;
166
174
  export declare let _$n_list_$o_slice: (xs: CalcitList, from: number, to: number) => CalcitSliceList | CalcitList;
167
175
  export declare let _$n_list_$o_concat: (...lists: (CalcitList | CalcitSliceList)[]) => CalcitList | CalcitSliceList;
168
176
  export declare let _$n_list_$o_reverse: (xs: CalcitList) => CalcitList;
@@ -247,7 +255,7 @@ export declare let parse_cirru: (code: string) => CalcitCirruQuote;
247
255
  export declare let parse_cirru_list: (code: string) => CalcitList;
248
256
  export declare let parse_cirru_edn: (code: string, options: CalcitValue) => CalcitValue;
249
257
  type DataShapeNode = {
250
- kind: "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" | "dynamic";
258
+ kind: "nil" | "unit" | "bool" | "number" | "string" | "symbol" | "tag" | "buffer" | "cirru-quote" | "dynamic";
251
259
  } | {
252
260
  kind: "optional" | "list" | "set" | "ref";
253
261
  inner: number;