From 683281363dc4a016b0d986c7126c161c8ae6fe36 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Sun, 29 Mar 2026 22:14:53 +0200 Subject: [PATCH] Initial commit: WAFER (WebAssembly Forth Engine in Rust) Optimizing Forth 2012 compiler targeting WebAssembly with IR-based compilation pipeline, multi-typed stack inference, subroutine threading, and JIT/consolidation modes. Rust kernel with ~35 primitives and Forth standard library for core/core-ext word sets. --- .github/workflows/ci.yml | 40 + .gitignore | 5 + .gitmodules | 3 + CLAUDE.md | 40 + Cargo.lock | 3147 +++++++++++++++++++++++++++++++ Cargo.toml | 19 + Justfile | 45 + LICENSE | 21 + README.md | 92 + crates/cli/Cargo.toml | 14 + crates/cli/src/main.rs | 41 + crates/core/Cargo.toml | 17 + crates/core/src/codegen.rs | 21 + crates/core/src/compiler.rs | 21 + crates/core/src/consolidate.rs | 16 + crates/core/src/dictionary.rs | 751 ++++++++ crates/core/src/error.rs | 84 + crates/core/src/ir.rs | 159 ++ crates/core/src/lib.rs | 30 + crates/core/src/memory.rs | 134 ++ crates/core/src/optimizer.rs | 19 + crates/core/src/outer.rs | 24 + crates/core/src/primitives.rs | 19 + crates/core/src/types.rs | 106 ++ crates/core/src/words/mod.rs | 19 + crates/core/tests/compliance.rs | 91 + crates/web/Cargo.toml | 9 + crates/web/src/lib.rs | 6 + forth/boot.fth | 23 + forth/core.fth | 48 + forth/core_ext.fth | 11 + forth/prelude.fth | 8 + tests/forth2012-test-suite | 1 + 33 files changed, 5084 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CLAUDE.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Justfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 crates/cli/Cargo.toml create mode 100644 crates/cli/src/main.rs create mode 100644 crates/core/Cargo.toml create mode 100644 crates/core/src/codegen.rs create mode 100644 crates/core/src/compiler.rs create mode 100644 crates/core/src/consolidate.rs create mode 100644 crates/core/src/dictionary.rs create mode 100644 crates/core/src/error.rs create mode 100644 crates/core/src/ir.rs create mode 100644 crates/core/src/lib.rs create mode 100644 crates/core/src/memory.rs create mode 100644 crates/core/src/optimizer.rs create mode 100644 crates/core/src/outer.rs create mode 100644 crates/core/src/primitives.rs create mode 100644 crates/core/src/types.rs create mode 100644 crates/core/src/words/mod.rs create mode 100644 crates/core/tests/compliance.rs create mode 100644 crates/web/Cargo.toml create mode 100644 crates/web/src/lib.rs create mode 100644 forth/boot.fth create mode 100644 forth/core.fth create mode 100644 forth/core_ext.fth create mode 100644 forth/prelude.fth create mode 160000 tests/forth2012-test-suite diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..42086af --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - uses: Swatinem/rust-cache@v2 + + - name: Check formatting + run: cargo fmt --all --check + + - name: Clippy + run: cargo clippy --workspace -- -D warnings + + - name: Build + run: cargo build --workspace + + - name: Test + run: cargo test --workspace + + - name: Compliance tests + run: cargo test --test compliance -- --nocapture + continue-on-error: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f85b5d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target +*.wasm +*.swp +.DS_Store +*.bk diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..72fdd57 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/forth2012-test-suite"] + path = tests/forth2012-test-suite + url = https://github.com/gerryjackson/forth2012-test-suite.git diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..3846c48 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,40 @@ +# WAFER Project Conventions + +## What is WAFER? +WAFER (WebAssembly Forth Engine in Rust) is an optimizing Forth 2012 compiler targeting WebAssembly. + +## Architecture +- Rust kernel (~35 primitives) + Forth standard library (everything else in .fth files) +- IR-based compilation pipeline: Forth -> IR -> type inference -> optimize -> WASM codegen +- Multi-typed stack: use WASM's native typed stack when types are known via inference, fall back to linear memory for dynamic/polymorphic cases +- Subroutine threading via WASM function tables +- JIT mode: per-word WASM modules + shared function table +- Consolidation mode: recompile all words into single optimized WASM module + +## Code Style +- `cargo fmt` and `cargo clippy` must pass with no warnings +- Every public function needs a doc comment +- Every module needs unit tests +- Use `thiserror` for error types in core crate, `anyhow` for CLI crate +- Prefer returning `Result` over panicking + +## Testing (Critical) +- **Specs-driven TDD**: Every feature starts with its failing test, then implementation +- Run `cargo test --workspace` before committing +- Forth 2012 compliance: `cargo test --test compliance` +- Property-based tests with `proptest` for numeric operations and optimizer correctness +- Snapshot tests with `insta` for IR and WASM output +- 100% compliance is mandatory for each implemented word set before moving on +- Never break existing compliance tests + +## Forth Source (.fth files) +- One file per word set in `forth/` +- Document each word with standard stack effect notation: `( before -- after )` +- Maximize words written in Forth, minimize Rust primitives +- Boot order: boot.fth -> core.fth -> core_ext.fth -> ... -> prelude.fth + +## Key Principles +1. Maximize Forth, minimize Rust (self-hosting goal) +2. Correctness first, performance second +3. Test-driven: if it's not tested, it doesn't work +4. Every word set at 100% compliance before moving to the next diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4cb12a3 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3147 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ar_archive_writer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +dependencies = [ + "object 0.37.3", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cap-fs-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.59.0", +] + +[[package]] +name = "cap-net-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix 1.1.4", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix 1.1.4", + "rustix-linux-procfs", + "windows-sys 0.59.0", + "winx", +] + +[[package]] +name = "cap-rand" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8144c22e24bbcf26ade86cb6501a0916c46b7e4787abdb0045a467eb1645a1d" +dependencies = [ + "ambient-authority", + "rand 0.8.5", +] + +[[package]] +name = "cap-std" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6dc3090992a735d23219de5c204927163d922f42f575a0189b005c62d37549a" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix 1.1.4", +] + +[[package]] +name = "cap-time-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def102506ce40c11710a9b16e614af0cde8e76ae51b1f48c04b8d79f4b671a80" +dependencies = [ + "ambient-authority", + "cap-primitives", + "iana-time-zone", + "once_cell", + "rustix 1.1.4", + "winx", +] + +[[package]] +name = "cc" +version = "1.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpp_demangle" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-assembler-x64" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4b56ebe316895d3fa37775d0a87b0c889cc933f5c8b253dbcc7c7bcb7fe7e4" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cabbc01dfbd7dcd6c329ca44f0212910309c221797ac736a67a5bc8857fe1b" + +[[package]] +name = "cranelift-bforest" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ffe46df300a45f1dc6f609dc808ce963f0e3a2e971682c479a2d13e3b9b8ef" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e606230a7e3a6897d603761baee0d19f88d077f17b996bb5089488a29ae96e41" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.15.5", + "log", + "pulley-interpreter", + "regalloc2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a63bffafc23bc60969ad528e138788495999d935f0adcfd6543cb151ca8637d" +dependencies = [ + "cranelift-assembler-x64", + "cranelift-codegen-shared", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af50281b67324b58e843170a6a5943cf6d387c06f7eeacc9f5696e4ab7ae7d7e" + +[[package]] +name = "cranelift-control" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c20c1b38d1abfbcebb0032e497e71156c0e3b8dcb3f0a92b9863b7bcaec290c" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e002691cc69c38b54fc7ec93e5be5b744f627d027031d991cc845d1d512d0ce" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93588ed1796cbcb0e2ad160403509e2c5d330d80dd6e0014ac6774c7ebac496" + +[[package]] +name = "cranelift-native" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5b09bdd6407bf5d89661b80cf926ce731c9e8cc184bf49102267a2369a8358e" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if", + "rustix 1.1.4", + "windows-sys 0.59.0", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes", + "rustix 1.1.4", + "windows-sys 0.59.0", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "fxprof-processed-profile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +dependencies = [ + "bitflags", + "debugid", + "fxhash", + "serde", + "serde_json", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "insta" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99322078b2c076829a1db959d49da554fabc4342257fc0ba5a070a1eb3a01cd8" +dependencies = [ + "console", + "once_cell", + "similar", + "tempfile", +] + +[[package]] +name = "io-extras" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" +dependencies = [ + "io-lifetimes", + "windows-sys 0.59.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "ittapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] + +[[package]] +name = "ittapi-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" +dependencies = [ + "cc", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memfd" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" +dependencies = [ + "rustix 1.1.4", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "crc32fast", + "hashbrown 0.15.5", + "indexmap", + "memchr", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "psm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "pulley-interpreter" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3325791708ad50580aeacfcce06cb5e462c9ba7a2368e109cb2012b944b70e" +dependencies = [ + "cranelift-bitset", + "log", + "wasmtime-math", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regalloc2" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc06e6b318142614e4a48bc725abbf08ff166694835c43c9dae5a9009704639a" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.5", + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix 1.1.4", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "rustyline" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1e066dc922e513bda599c6ccb5f3bb2b0ea5870a579448f2622993f0a9a2f" +dependencies = [ + "bitflags", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "windows-sys 0.59.0", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shellexpand" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" +dependencies = [ + "dirs", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-interface" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" +dependencies = [ + "bitflags", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes", + "rustix 0.38.44", + "windows-sys 0.59.0", + "winx", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wafer" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "rustyline", + "wafer-core", + "wasmtime", + "wasmtime-wasi", +] + +[[package]] +name = "wafer-core" +version = "0.1.0" +dependencies = [ + "anyhow", + "insta", + "proptest", + "thiserror 2.0.18", + "wasm-encoder 0.228.0", + "wasmparser 0.228.0", + "wasmtime", +] + +[[package]] +name = "wafer-web" +version = "0.1.0" +dependencies = [ + "wafer-core", +] + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.226.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d81b727619aec227dce83e7f7420d4e56c79acd044642a356ea045b98d4e13" +dependencies = [ + "leb128fmt", + "wasmparser 0.226.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.228.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" +dependencies = [ + "leb128fmt", + "wasmparser 0.228.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" +dependencies = [ + "leb128fmt", + "wasmparser 0.245.1", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder 0.244.0", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasmparser" +version = "0.226.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc28600dcb2ba68d7e5f1c3ba4195c2bddc918c0243fd702d0b6dbd05689b681" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wasmparser" +version = "0.228.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wasmparser" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + +[[package]] +name = "wasmprinter" +version = "0.226.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "753a0516fa6c01756ee861f36878dfd9875f273aea9409d9ea390a333c5bcdc2" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.226.0", +] + +[[package]] +name = "wasmtime" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fe78033c72da8741e724d763daf1375c93a38bfcea99c873ee4415f6098c3f" +dependencies = [ + "addr2line", + "anyhow", + "async-trait", + "bitflags", + "bumpalo", + "cc", + "cfg-if", + "encoding_rs", + "fxprof-processed-profile", + "gimli", + "hashbrown 0.15.5", + "indexmap", + "ittapi", + "libc", + "log", + "mach2", + "memfd", + "object 0.36.7", + "once_cell", + "paste", + "postcard", + "psm", + "pulley-interpreter", + "rayon", + "rustix 0.38.44", + "semver", + "serde", + "serde_derive", + "serde_json", + "smallvec", + "sptr", + "target-lexicon", + "trait-variant", + "wasm-encoder 0.226.0", + "wasmparser 0.226.0", + "wasmtime-asm-macros", + "wasmtime-cache", + "wasmtime-component-macro", + "wasmtime-component-util", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-math", + "wasmtime-slab", + "wasmtime-versioned-export-macros", + "wasmtime-winch", + "wat", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f3d44ae977d70ccf80938b371d5ec60b6adedf60800b9e8dd1223bb69f4cbc" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e209505770c7f38725513dba37246265fa6f724c30969de1e9d2a9e6c8f55099" +dependencies = [ + "anyhow", + "base64", + "directories-next", + "log", + "postcard", + "rustix 0.38.44", + "serde", + "serde_derive", + "sha2", + "toml", + "windows-sys 0.59.0", + "zstd", +] + +[[package]] +name = "wasmtime-component-macro" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397e68ee29eb072d8d8741c9d2c971a284cd1bc960ebf2c1f6a33ea6ba16d6e1" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wasmtime-component-util", + "wasmtime-wit-bindgen", + "wit-parser 0.226.0", +] + +[[package]] +name = "wasmtime-component-util" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f292ef5eb2cf3d414c2bde59c7fa0feeba799c8db9a8c5a656ad1d1a1d05e10b" + +[[package]] +name = "wasmtime-cranelift" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52fc12eb8ea695a30007a4849a5fd56209dd86a15579e92e0c27c27122818505" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "gimli", + "itertools", + "log", + "object 0.36.7", + "pulley-interpreter", + "smallvec", + "target-lexicon", + "thiserror 1.0.69", + "wasmparser 0.226.0", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-environ" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b6b4bf08e371edf262cccb62de10e214bd4aaafaa069f1cd49c9c1c3a5ae8e4" +dependencies = [ + "anyhow", + "cpp_demangle", + "cranelift-bitset", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "object 0.36.7", + "postcard", + "rustc-demangle", + "semver", + "serde", + "serde_derive", + "smallvec", + "target-lexicon", + "wasm-encoder 0.226.0", + "wasmparser 0.226.0", + "wasmprinter", + "wasmtime-component-util", +] + +[[package]] +name = "wasmtime-fiber" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8828d7d8fbe90d087a9edea9223315caf7eb434848896667e5d27889f1173" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "rustix 0.38.44", + "wasmtime-asm-macros", + "wasmtime-versioned-export-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9eff86dedd48b023199de2d266f5d3e37bc7c5bafdc1e3e3057214649ecf5a" +dependencies = [ + "cc", + "object 0.36.7", + "rustix 0.38.44", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a54f6c6c7e9d7eeee32dfcc10db7f29d505ee7dd28d00593ea241d5f70698e64" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-math" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1108aad2e6965698f9207ea79b80eda2b3dcc57dcb69f4258296d4664ae32cd" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmtime-slab" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d6a321317281b721c5530ef733e8596ecc6065035f286ccd155b3fa8e0ab2f" + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5732a5c86efce7bca121a61d8c07875f6b85c1607aa86753b40f7f8bd9d3a780" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasmtime-wasi" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b425ede2633fade96bd624b6f35cea5f8be1995d149530882dbc35efbf1e31f" +dependencies = [ + "anyhow", + "async-trait", + "bitflags", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "rustix 0.38.44", + "system-interface", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", + "wasmtime", + "wasmtime-wasi-io", + "wiggle", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-wasi-io" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ec650d8891ec5ff823bdcefe3b370278becd1f33125bcfdcf628943dcde676" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "futures", + "wasmtime", +] + +[[package]] +name = "wasmtime-winch" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa4741ee66a52e2f0ec5f79040017123ba47d2dff9d994b35879cc2b7f468d4" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object 0.36.7", + "target-lexicon", + "wasmparser 0.226.0", + "wasmtime-cranelift", + "wasmtime-environ", + "winch-codegen", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505c13fa0cac6c43e805347acf1e916c8de54e3790f2c22873c5692964b09b62" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "wit-parser 0.226.0", +] + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + +[[package]] +name = "wast" +version = "245.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width", + "wasm-encoder 0.245.1", +] + +[[package]] +name = "wat" +version = "1.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be" +dependencies = [ + "wast 245.0.1", +] + +[[package]] +name = "wiggle" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc9a83fe01faa51423fc84941cdbe0ec33ba1e9a75524a560a27a4ad1ff2c3b" +dependencies = [ + "anyhow", + "async-trait", + "bitflags", + "thiserror 1.0.69", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d250c01cd52cfdb40aad167fad579af55acbeccb85a54827099d31dc1b90cbd7" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "shellexpand", + "syn", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35be0aee84be808a5e17f6b732e110eb75703d9d6e66e22c7464d841aa2600c5" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wiggle-generate", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winch-codegen" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f05457f74ec3c94d5c5caac06b84fd8d9d4d7fa21419189845ed245a53477" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "thiserror 1.0.69", + "wasmparser 0.226.0", + "wasmtime-cranelift", + "wasmtime-environ", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser 0.244.0", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.244.0", + "wasm-metadata", + "wasmparser 0.244.0", + "wit-parser 0.244.0", +] + +[[package]] +name = "wit-parser" +version = "0.226.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f007722bfd43a2978c5b8b90f02c927dddf0f11c5f5b50929816b3358718cd" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.226.0", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.244.0", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror 1.0.69", + "wast 35.0.2", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..28f85b9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[workspace] +members = ["crates/*"] +resolver = "2" + +[workspace.package] +version = "0.1.0" +edition = "2024" +license = "MIT OR Apache-2.0" +repository = "https://github.com/nickvonkaenel/wafer" + +[workspace.dependencies] +wasm-encoder = "0.228" +wasmparser = "0.228" +wasmtime = "31" +wasmtime-wasi = "31" +anyhow = "1" +thiserror = "2" +proptest = "1" +insta = "1" diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..cf20230 --- /dev/null +++ b/Justfile @@ -0,0 +1,45 @@ +default: + just --list + +# Build everything +build: + cargo build --workspace + +# Run all tests +test: + cargo test --workspace + +# Run Forth 2012 compliance tests +compliance: + cargo test --test compliance -- --nocapture + +# Run clippy lints +clippy: + cargo clippy --workspace -- -D warnings + +# Check formatting +fmt: + cargo fmt --all --check + +# Format code +fmt-fix: + cargo fmt --all + +# Run the REPL +repl: + cargo run -p wafer + +# Run a Forth file +run file: + cargo run -p wafer -- {{file}} + +# Run benchmarks +bench: + cargo bench --workspace + +# Full CI check (what CI runs) +ci: fmt clippy test + +# Check compilation without running +check: + cargo check --workspace diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d7bada8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 WAFER Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9441ccf --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# WAFER + +**WebAssembly Forth Engine in Rust** + +An optimizing Forth 2012 compiler targeting WebAssembly. + +## Goals + +- **Full Forth 2012 compliance** -- all word sets, 100% test suite pass rate +- **Optimizing compiler** -- constant folding, inlining, peephole optimization, stack-to-local promotion +- **Multi-typed stack** -- type inference uses WASM's native typed stack when possible, memory fallback for dynamic cases +- **Self-hosting** -- minimal Rust kernel (~35 primitives), everything else written in WAFER Forth +- **Dual mode** -- JIT for interactive development, consolidation recompilation into a single optimized WASM module + +## Architecture + +``` +Forth Source -> Outer Interpreter -> IR (with type inference) -> Optimization -> WASM Codegen +``` + +- **Subroutine threading** via WASM function tables +- **JIT mode**: each new word compiles to a separate WASM module +- **Consolidation mode**: recompile all words into a single module with direct calls +- **IR-based pipeline** enables optimization passes before WASM emission + +## Building + +```bash +cargo build --workspace +``` + +## Running + +```bash +# Interactive REPL +cargo run -p wafer + +# Run a Forth file +cargo run -p wafer -- file.fth + +# Compile to optimized WASM +cargo run -p wafer -- --consolidate file.fth -o output.wasm +``` + +## Testing + +```bash +# All tests +cargo test --workspace + +# Forth 2012 compliance dashboard +cargo test --test compliance + +# Benchmarks +cargo bench --workspace +``` + +## Project Structure + +``` +crates/ + core/ wafer-core: compiler, IR, optimizer, codegen + cli/ wafer: CLI REPL and AOT compiler + web/ wafer-web: browser bindings (planned) +forth/ Standard library written in WAFER Forth +tests/ Integration tests and Forth 2012 compliance suite +``` + +## Compliance Status + +Targeting 100% Forth 2012 compliance, tested with [Gerry Jackson's forth2012-test-suite](https://github.com/gerryjackson/forth2012-test-suite). + +| Word Set | Status | +|----------|--------| +| Core | Pending | +| Core Extensions | Pending | +| Block | N/A | +| Double-Number | Pending | +| Exception | Pending | +| Facility | Pending | +| File-Access | Pending | +| Floating-Point | Pending | +| Locals | Pending | +| Memory-Allocation | Pending | +| Programming-Tools | Pending | +| Search-Order | Pending | +| String | Pending | +| Extended-Character | Pending | + +## License + +MIT OR Apache-2.0 diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 0000000..6c95bdf --- /dev/null +++ b/crates/cli/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "wafer" +description = "WAFER: WebAssembly Forth Engine in Rust - CLI REPL and compiler" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +wafer-core = { path = "../core" } +wasmtime = { workspace = true } +wasmtime-wasi = { workspace = true } +anyhow = { workspace = true } +clap = { version = "4", features = ["derive"] } +rustyline = "15" diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs new file mode 100644 index 0000000..0104c31 --- /dev/null +++ b/crates/cli/src/main.rs @@ -0,0 +1,41 @@ +//! WAFER CLI: Interactive REPL and AOT compiler for WAFER Forth. + +use clap::Parser; + +/// WAFER: WebAssembly Forth Engine in Rust +#[derive(Parser, Debug)] +#[command(name = "wafer", version, about)] +struct Cli { + /// Forth source file to execute + file: Option, + + /// Compile all words into a single optimized WASM module + #[arg(long)] + consolidate: bool, + + /// Output file for consolidated WASM (requires --consolidate) + #[arg(short, long)] + output: Option, +} + +fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + + match cli.file { + Some(ref _file) => { + // TODO: Step 9 - Load and execute Forth file + eprintln!("WAFER: file execution not yet implemented"); + } + None => { + // TODO: Step 9 - Interactive REPL + println!( + "WAFER v{} - WebAssembly Forth Engine in Rust", + env!("CARGO_PKG_VERSION") + ); + println!("Type BYE to exit."); + eprintln!("REPL not yet implemented"); + } + } + + Ok(()) +} diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml new file mode 100644 index 0000000..a51589b --- /dev/null +++ b/crates/core/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wafer-core" +description = "WAFER: WebAssembly Forth Engine in Rust - core compiler and runtime" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +wasm-encoder = { workspace = true } +wasmparser = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } + +[dev-dependencies] +proptest = { workspace = true } +insta = { workspace = true } +wasmtime = { workspace = true } diff --git a/crates/core/src/codegen.rs b/crates/core/src/codegen.rs new file mode 100644 index 0000000..f53a4db --- /dev/null +++ b/crates/core/src/codegen.rs @@ -0,0 +1,21 @@ +//! WASM code generation from IR. +//! +//! Translates optimized IR into WASM bytecode using the `wasm-encoder` crate. +//! Supports two modes: +//! - **Typed mode**: when type inference succeeds, values stay in WASM locals +//! - **Fallback mode**: load/store against stack pointer globals in linear memory + +// TODO: Step 5 - Full codegen implementation +// - IR -> WASM function body translation +// - Single-word module generation (JIT mode) +// - Multi-word module generation (AOT/consolidation mode) +// - Typed vs fallback mode selection +// - Function table management + +#[cfg(test)] +mod tests { + #[test] + fn placeholder() { + // Codegen tests will be added in Step 5 + } +} diff --git a/crates/core/src/compiler.rs b/crates/core/src/compiler.rs new file mode 100644 index 0000000..c783c9d --- /dev/null +++ b/crates/core/src/compiler.rs @@ -0,0 +1,21 @@ +//! Forth compile mode: builds IR from word definitions. +//! +//! When the outer interpreter encounters `:`, it switches to compile mode. +//! The compiler collects tokens and builds an IR representation until `;`. +//! IMMEDIATE words are executed during compilation (e.g., IF, ELSE, THEN). + +// TODO: Step 7 - Compiler implementation +// - : (colon) starts compilation, ; (semicolon) ends it +// - Build Vec for the word body +// - Handle IMMEDIATE words +// - Handle control structures (IF/ELSE/THEN, DO/LOOP, BEGIN/UNTIL) +// - LITERAL, POSTPONE, ['], [CHAR] +// - Defining words: VARIABLE, CONSTANT, CREATE, DOES> + +#[cfg(test)] +mod tests { + #[test] + fn placeholder() { + // Compiler tests will be added in Step 7 + } +} diff --git a/crates/core/src/consolidate.rs b/crates/core/src/consolidate.rs new file mode 100644 index 0000000..c9e677a --- /dev/null +++ b/crates/core/src/consolidate.rs @@ -0,0 +1,16 @@ +//! Consolidation recompiler: merge all JIT-compiled words into a single WASM module. +//! +//! After interactive development, `CONSOLIDATE` recompiles everything: +//! - All `call_indirect` replaced with direct `call` +//! - Cross-word optimizations (inlining, constant propagation) +//! - Single WASM module output for maximum performance + +// TODO: Step 12 - Consolidation recompiler implementation + +#[cfg(test)] +mod tests { + #[test] + fn placeholder() { + // Consolidation tests will be added in Step 12 + } +} diff --git a/crates/core/src/dictionary.rs b/crates/core/src/dictionary.rs new file mode 100644 index 0000000..a367efd --- /dev/null +++ b/crates/core/src/dictionary.rs @@ -0,0 +1,751 @@ +//! Forth dictionary: word headers, lookup, and creation. +//! +//! The dictionary is a linked list in linear memory. Each entry contains: +//! - Link to previous entry (4 bytes) +//! - Flags + name length (1 byte) +//! - Name string (N bytes, padded to cell alignment) +//! - Code field: function table index (4 bytes) +//! - Parameter field: data for CREATEd words, DOES> action, etc. + +use crate::error::{WaferError, WaferResult}; +use crate::memory::{DICTIONARY_BASE, INITIAL_PAGES, PAGE_SIZE}; + +/// Flags stored in the dictionary entry header. +pub mod flags { + /// Word executes during compilation. + pub const IMMEDIATE: u8 = 0x80; + /// Word is hidden (being compiled, not yet findable). + pub const HIDDEN: u8 = 0x40; + /// Mask for the name length (lower 5 bits). + pub const LENGTH_MASK: u8 = 0x1F; + /// Maximum word name length. + pub const MAX_NAME_LEN: usize = 31; +} + +/// Unique identifier for a word in the dictionary. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WordId(pub u32); + +/// The dictionary manages word entries in a simulated linear memory buffer. +pub struct Dictionary { + /// The memory buffer (simulates WASM linear memory). + memory: Vec, + /// Address of the most recently defined word (LATEST). + latest: u32, + /// Next free address in the dictionary (HERE). + here: u32, + /// Next available function table index. + next_fn_index: u32, +} + +/// Align an address upward to a 4-byte boundary. +fn align4(addr: u32) -> u32 { + (addr + 3) & !3 +} + +impl Dictionary { + /// Create a new dictionary with the given memory buffer. + /// `here` is initialized to `DICTIONARY_BASE` from memory.rs. + pub fn new() -> Self { + let size = (INITIAL_PAGES * PAGE_SIZE) as usize; + Self { + memory: vec![0u8; size], + latest: 0, + here: DICTIONARY_BASE, + next_fn_index: 0, + } + } + + /// Create a new dictionary entry (like Forth's CREATE). + /// Returns the WordId (function table index) assigned to this word. + /// The word starts HIDDEN (will be revealed when compilation completes). + pub fn create(&mut self, name: &str, immediate: bool) -> WaferResult { + let name_upper = name.to_ascii_uppercase(); + let name_bytes = name_upper.as_bytes(); + let name_len = name_bytes.len(); + + if name_len == 0 || name_len > flags::MAX_NAME_LEN { + return Err(WaferError::NameTooLong(name.to_string())); + } + + // Calculate the total space needed: + // 4 (link) + 1 (flags) + name_len + padding + 4 (code field) + let entry_start = self.here; + let name_end = entry_start + 4 + 1 + name_len as u32; + let code_field_addr = align4(name_end); + let after_code = code_field_addr + 4; + + // Check bounds + if after_code as usize > self.memory.len() { + return Err(WaferError::DictionaryOverflow); + } + + // Write link field (points to previous LATEST) + self.write_u32_unchecked(entry_start, self.latest); + + // Write flags byte: HIDDEN | length, optionally IMMEDIATE + let mut flag_byte = flags::HIDDEN | (name_len as u8 & flags::LENGTH_MASK); + if immediate { + flag_byte |= flags::IMMEDIATE; + } + self.memory[(entry_start + 4) as usize] = flag_byte; + + // Write name bytes + let name_start = (entry_start + 5) as usize; + self.memory[name_start..name_start + name_len].copy_from_slice(name_bytes); + + // Zero padding bytes between name end and code field + for i in (name_end as usize)..(code_field_addr as usize) { + self.memory[i] = 0; + } + + // Write code field (function table index) + let fn_index = self.next_fn_index; + self.write_u32_unchecked(code_field_addr, fn_index); + self.next_fn_index += 1; + + // Update LATEST and HERE + self.latest = entry_start; + self.here = after_code; + + Ok(WordId(fn_index)) + } + + /// Reveal the most recent word (remove HIDDEN flag). + /// Called after `: ... ;` completes compilation. + pub fn reveal(&mut self) { + if self.latest == 0 && self.here == DICTIONARY_BASE { + // No words defined yet + return; + } + let flags_addr = (self.latest + 4) as usize; + if flags_addr < self.memory.len() { + self.memory[flags_addr] &= !flags::HIDDEN; + } + } + + /// Set the code field of the most recent word. + pub fn set_code_field(&mut self, word_addr: u32, fn_index: u32) { + if let Ok(code_addr) = self.code_field_addr(word_addr) { + self.write_u32_unchecked(code_addr, fn_index); + } + } + + /// Look up a word by name. Returns (word_address, word_id, is_immediate). + /// Searches from LATEST backward through the linked list. + /// Skips HIDDEN words. + pub fn find(&self, name: &str) -> Option<(u32, WordId, bool)> { + let search_name = name.to_ascii_uppercase(); + let search_bytes = search_name.as_bytes(); + let search_len = search_bytes.len(); + + let mut addr = self.latest; + while addr != 0 || (addr == self.latest && self.latest != 0) { + let flags_byte = self.memory[(addr + 4) as usize]; + + // Skip hidden words + if flags_byte & flags::HIDDEN == 0 { + let entry_len = (flags_byte & flags::LENGTH_MASK) as usize; + + if entry_len == search_len { + let name_start = (addr + 5) as usize; + let entry_name = &self.memory[name_start..name_start + entry_len]; + + if entry_name == search_bytes { + let is_immediate = flags_byte & flags::IMMEDIATE != 0; + let code_addr = align4(addr + 5 + entry_len as u32); + let fn_index = self.read_u32_unchecked(code_addr); + return Some((addr, WordId(fn_index), is_immediate)); + } + } + } + + // Follow link to previous entry + let link = self.read_u32_unchecked(addr); + if link == addr { + // Safety: prevent infinite loops + break; + } + addr = link; + if addr == 0 { + break; + } + } + + None + } + + /// Get the current HERE pointer. + pub fn here(&self) -> u32 { + self.here + } + + /// Get the current LATEST pointer. + pub fn latest(&self) -> u32 { + self.latest + } + + /// Allocate n bytes at HERE (like Forth's ALLOT). + pub fn allot(&mut self, n: u32) -> WaferResult { + let new_here = self + .here + .checked_add(n) + .ok_or(WaferError::DictionaryOverflow)?; + if new_here as usize > self.memory.len() { + return Err(WaferError::DictionaryOverflow); + } + let old_here = self.here; + self.here = new_here; + Ok(old_here) + } + + /// Store a cell (u32) at HERE and advance HERE by 4 (like Forth's `,`). + pub fn comma(&mut self, value: u32) -> WaferResult<()> { + let addr = self.here; + if (addr + 4) as usize > self.memory.len() { + return Err(WaferError::DictionaryOverflow); + } + self.write_u32_unchecked(addr, value); + self.here += 4; + Ok(()) + } + + /// Store a byte at HERE and advance HERE by 1 (like Forth's `C,`). + pub fn c_comma(&mut self, value: u8) -> WaferResult<()> { + let addr = self.here as usize; + if addr >= self.memory.len() { + return Err(WaferError::DictionaryOverflow); + } + self.memory[addr] = value; + self.here += 1; + Ok(()) + } + + /// Read a cell (u32) from the given address. + pub fn read_u32(&self, addr: u32) -> WaferResult { + let a = addr as usize; + if a + 4 > self.memory.len() { + return Err(WaferError::InvalidAddress(addr)); + } + Ok(u32::from_le_bytes([ + self.memory[a], + self.memory[a + 1], + self.memory[a + 2], + self.memory[a + 3], + ])) + } + + /// Write a cell (u32) to the given address. + pub fn write_u32(&mut self, addr: u32, value: u32) -> WaferResult<()> { + let a = addr as usize; + if a + 4 > self.memory.len() { + return Err(WaferError::InvalidAddress(addr)); + } + let bytes = value.to_le_bytes(); + self.memory[a..a + 4].copy_from_slice(&bytes); + Ok(()) + } + + /// Read a byte from the given address. + pub fn read_u8(&self, addr: u32) -> WaferResult { + let a = addr as usize; + if a >= self.memory.len() { + return Err(WaferError::InvalidAddress(addr)); + } + Ok(self.memory[a]) + } + + /// Write a byte to the given address. + pub fn write_u8(&mut self, addr: u32, value: u8) -> WaferResult<()> { + let a = addr as usize; + if a >= self.memory.len() { + return Err(WaferError::InvalidAddress(addr)); + } + self.memory[a] = value; + Ok(()) + } + + /// Get the name of the word at the given address. + pub fn word_name(&self, word_addr: u32) -> WaferResult { + let flags_addr = (word_addr + 4) as usize; + if flags_addr >= self.memory.len() { + return Err(WaferError::InvalidAddress(word_addr)); + } + let flags_byte = self.memory[flags_addr]; + let name_len = (flags_byte & flags::LENGTH_MASK) as usize; + let name_start = (word_addr + 5) as usize; + let name_end = name_start + name_len; + if name_end > self.memory.len() { + return Err(WaferError::InvalidAddress(word_addr)); + } + let name_bytes = &self.memory[name_start..name_end]; + Ok(String::from_utf8_lossy(name_bytes).to_string()) + } + + /// Get the code field (function index) of the word at the given address. + pub fn code_field(&self, word_addr: u32) -> WaferResult { + let code_addr = self.code_field_addr(word_addr)?; + self.read_u32(code_addr) + } + + /// Get the parameter field address of the word at the given address. + pub fn param_field_addr(&self, word_addr: u32) -> WaferResult { + let code_addr = self.code_field_addr(word_addr)?; + Ok(code_addr + 4) + } + + /// Toggle the IMMEDIATE flag on the most recent word. + pub fn toggle_immediate(&mut self) -> WaferResult<()> { + if self.latest == 0 && self.here == DICTIONARY_BASE { + return Err(WaferError::CompileError( + "no word defined yet".to_string(), + )); + } + let flags_addr = (self.latest + 4) as usize; + if flags_addr >= self.memory.len() { + return Err(WaferError::InvalidAddress(self.latest + 4)); + } + self.memory[flags_addr] ^= flags::IMMEDIATE; + Ok(()) + } + + /// Get a reference to the raw memory buffer. + pub fn memory(&self) -> &[u8] { + &self.memory + } + + /// Get a mutable reference to the raw memory buffer. + pub fn memory_mut(&mut self) -> &mut Vec { + &mut self.memory + } + + // -- Private helpers -- + + /// Compute the address of the code field for the word at `word_addr`. + fn code_field_addr(&self, word_addr: u32) -> WaferResult { + let flags_addr = (word_addr + 4) as usize; + if flags_addr >= self.memory.len() { + return Err(WaferError::InvalidAddress(word_addr)); + } + let flags_byte = self.memory[flags_addr]; + let name_len = (flags_byte & flags::LENGTH_MASK) as u32; + Ok(align4(word_addr + 5 + name_len)) + } + + /// Write a u32 in little-endian without bounds checking. + /// Caller must ensure addr + 4 <= memory.len(). + fn write_u32_unchecked(&mut self, addr: u32, value: u32) { + let a = addr as usize; + let bytes = value.to_le_bytes(); + self.memory[a..a + 4].copy_from_slice(&bytes); + } + + /// Read a u32 in little-endian without bounds checking. + /// Caller must ensure addr + 4 <= memory.len(). + fn read_u32_unchecked(&self, addr: u32) -> u32 { + let a = addr as usize; + u32::from_le_bytes([ + self.memory[a], + self.memory[a + 1], + self.memory[a + 2], + self.memory[a + 3], + ]) + } +} + +impl Default for Dictionary { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::DICTIONARY_BASE; + + #[test] + fn flag_constants() { + // Flags should not overlap with name length + assert_eq!(flags::IMMEDIATE & flags::LENGTH_MASK, 0); + assert_eq!(flags::HIDDEN & flags::LENGTH_MASK, 0); + // Max name length fits in the length mask + assert!(flags::MAX_NAME_LEN <= flags::LENGTH_MASK as usize); + } + + #[test] + fn create_and_find_word() { + let mut dict = Dictionary::new(); + let word_id = dict.create("dup", false).unwrap(); + dict.reveal(); + + let result = dict.find("DUP"); + assert!(result.is_some()); + let (addr, found_id, is_imm) = result.unwrap(); + assert_eq!(found_id, word_id); + assert!(!is_imm); + assert_eq!(addr, DICTIONARY_BASE); + } + + #[test] + fn create_multiple_words_and_find_each() { + let mut dict = Dictionary::new(); + + let id_a = dict.create("ALPHA", false).unwrap(); + dict.reveal(); + let id_b = dict.create("BETA", false).unwrap(); + dict.reveal(); + let id_c = dict.create("GAMMA", false).unwrap(); + dict.reveal(); + + let (_, fid_a, _) = dict.find("ALPHA").unwrap(); + let (_, fid_b, _) = dict.find("BETA").unwrap(); + let (_, fid_c, _) = dict.find("GAMMA").unwrap(); + + assert_eq!(fid_a, id_a); + assert_eq!(fid_b, id_b); + assert_eq!(fid_c, id_c); + } + + #[test] + fn case_insensitive_lookup() { + let mut dict = Dictionary::new(); + dict.create("Hello", false).unwrap(); + dict.reveal(); + + // All case variants should find the same word + assert!(dict.find("HELLO").is_some()); + assert!(dict.find("hello").is_some()); + assert!(dict.find("hElLo").is_some()); + } + + #[test] + fn hidden_words_not_found() { + let mut dict = Dictionary::new(); + dict.create("SECRET", false).unwrap(); + // Don't reveal + + assert!(dict.find("SECRET").is_none()); + } + + #[test] + fn reveal_makes_hidden_word_findable() { + let mut dict = Dictionary::new(); + dict.create("HIDDEN", false).unwrap(); + assert!(dict.find("HIDDEN").is_none()); + + dict.reveal(); + assert!(dict.find("HIDDEN").is_some()); + } + + #[test] + fn immediate_flag_works() { + let mut dict = Dictionary::new(); + let word_id = dict.create("IF", true).unwrap(); + dict.reveal(); + + let (_, found_id, is_imm) = dict.find("IF").unwrap(); + assert_eq!(found_id, word_id); + assert!(is_imm); + } + + #[test] + fn toggle_immediate() { + let mut dict = Dictionary::new(); + dict.create("MYWORD", false).unwrap(); + dict.reveal(); + + // Initially not immediate + let (_, _, is_imm) = dict.find("MYWORD").unwrap(); + assert!(!is_imm); + + // Toggle to immediate + dict.toggle_immediate().unwrap(); + let (_, _, is_imm) = dict.find("MYWORD").unwrap(); + assert!(is_imm); + + // Toggle back + dict.toggle_immediate().unwrap(); + let (_, _, is_imm) = dict.find("MYWORD").unwrap(); + assert!(!is_imm); + } + + #[test] + fn comma_advances_here() { + let mut dict = Dictionary::new(); + let h0 = dict.here(); + dict.comma(42).unwrap(); + assert_eq!(dict.here(), h0 + 4); + + // Verify the value was stored + let val = dict.read_u32(h0).unwrap(); + assert_eq!(val, 42); + } + + #[test] + fn c_comma_advances_here() { + let mut dict = Dictionary::new(); + let h0 = dict.here(); + dict.c_comma(0xAB).unwrap(); + assert_eq!(dict.here(), h0 + 1); + + // Verify the value was stored + let val = dict.read_u8(h0).unwrap(); + assert_eq!(val, 0xAB); + } + + #[test] + fn allot_advances_here() { + let mut dict = Dictionary::new(); + let h0 = dict.here(); + let old = dict.allot(100).unwrap(); + assert_eq!(old, h0); + assert_eq!(dict.here(), h0 + 100); + } + + #[test] + fn memory_read_write_u32() { + let mut dict = Dictionary::new(); + let addr = DICTIONARY_BASE; + dict.write_u32(addr, 0xDEADBEEF).unwrap(); + let val = dict.read_u32(addr).unwrap(); + assert_eq!(val, 0xDEADBEEF); + } + + #[test] + fn memory_read_write_u8() { + let mut dict = Dictionary::new(); + let addr = DICTIONARY_BASE; + dict.write_u8(addr, 0x42).unwrap(); + let val = dict.read_u8(addr).unwrap(); + assert_eq!(val, 0x42); + } + + #[test] + fn max_name_length() { + let mut dict = Dictionary::new(); + let name = "A".repeat(31); // MAX_NAME_LEN = 31 + let result = dict.create(&name, false); + assert!(result.is_ok()); + dict.reveal(); + + let found = dict.find(&name); + assert!(found.is_some()); + let (_, _, _) = found.unwrap(); + + // Verify the name stored correctly + let word_name = dict.word_name(dict.latest()).unwrap(); + assert_eq!(word_name, name); + } + + #[test] + fn name_too_long_rejected() { + let mut dict = Dictionary::new(); + let name = "A".repeat(32); // Exceeds MAX_NAME_LEN + let result = dict.create(&name, false); + assert!(result.is_err()); + } + + #[test] + fn empty_name_rejected() { + let mut dict = Dictionary::new(); + let result = dict.create("", false); + assert!(result.is_err()); + } + + #[test] + fn unknown_word_returns_none() { + let mut dict = Dictionary::new(); + dict.create("EXISTS", false).unwrap(); + dict.reveal(); + + assert!(dict.find("DOESNOTEXIST").is_none()); + } + + #[test] + fn param_field_addr_calculation() { + let mut dict = Dictionary::new(); + dict.create("VAR", false).unwrap(); + dict.reveal(); + + let word_addr = dict.latest(); + let pfa = dict.param_field_addr(word_addr).unwrap(); + let cfa_addr = align4(word_addr + 5 + 3); // "VAR" is 3 bytes + assert_eq!(pfa, cfa_addr + 4); + + // HERE should equal the parameter field address right after create + assert_eq!(dict.here(), pfa); + } + + #[test] + fn dictionary_overflow_detection() { + let mut dict = Dictionary::new(); + let mem_size = dict.memory().len() as u32; + + // Try to allot beyond memory + let result = dict.allot(mem_size + 1); + assert!(result.is_err()); + } + + #[test] + fn invalid_address_read() { + let dict = Dictionary::new(); + let mem_size = dict.memory().len() as u32; + + // Reading beyond the end should fail + assert!(dict.read_u32(mem_size).is_err()); + assert!(dict.read_u8(mem_size).is_err()); + } + + #[test] + fn invalid_address_write() { + let mut dict = Dictionary::new(); + let mem_size = dict.memory().len() as u32; + + // Writing beyond the end should fail + assert!(dict.write_u32(mem_size, 0).is_err()); + assert!(dict.write_u8(mem_size, 0).is_err()); + } + + #[test] + fn set_code_field_updates_function_index() { + let mut dict = Dictionary::new(); + dict.create("TEST", false).unwrap(); + dict.reveal(); + + let word_addr = dict.latest(); + dict.set_code_field(word_addr, 999); + + let code = dict.code_field(word_addr).unwrap(); + assert_eq!(code, 999); + } + + #[test] + fn word_name_retrieval() { + let mut dict = Dictionary::new(); + dict.create("HELLO", false).unwrap(); + dict.reveal(); + + let name = dict.word_name(dict.latest()).unwrap(); + assert_eq!(name, "HELLO"); + } + + #[test] + fn linked_list_traversal() { + // Verify that the linked list structure is correct + let mut dict = Dictionary::new(); + + let addr0 = dict.here(); + dict.create("FIRST", false).unwrap(); + dict.reveal(); + assert_eq!(dict.latest(), addr0); + + let addr1 = dict.here(); + dict.create("SECOND", false).unwrap(); + dict.reveal(); + assert_eq!(dict.latest(), addr1); + + // Second word's link should point to first word + let link = dict.read_u32(addr1).unwrap(); + assert_eq!(link, addr0); + + // First word's link should be 0 (end of list) + let link = dict.read_u32(addr0).unwrap(); + assert_eq!(link, 0); + } + + #[test] + fn later_definition_shadows_earlier() { + let mut dict = Dictionary::new(); + + let id1 = dict.create("DUP", false).unwrap(); + dict.reveal(); + let id2 = dict.create("DUP", false).unwrap(); + dict.reveal(); + + // find should return the later (most recent) definition + let (_, found_id, _) = dict.find("DUP").unwrap(); + assert_eq!(found_id, id2); + assert_ne!(id1, id2); + } + + #[test] + fn alignment_padding() { + let mut dict = Dictionary::new(); + + // "AB" is 2 bytes at offset 5 => name_end = base + 4 + 1 + 2 = base + 7 + // align4(base + 7) should round up properly + dict.create("AB", false).unwrap(); + dict.reveal(); + + let word_addr = dict.latest(); + let pfa = dict.param_field_addr(word_addr).unwrap(); + // code field should be at align4(word_addr + 5 + 2) = align4(word_addr + 7) + let expected_code = align4(word_addr + 7); + assert_eq!(pfa, expected_code + 4); + // HERE should be 4-byte aligned + assert_eq!(dict.here() % 4, 0); + } + + #[test] + fn memory_access() { + let mut dict = Dictionary::new(); + + // Test raw memory access + let mem = dict.memory(); + assert_eq!(mem.len(), (INITIAL_PAGES * PAGE_SIZE) as usize); + + // Test mutable access + let mem = dict.memory_mut(); + mem[0] = 0xFF; + assert_eq!(dict.memory()[0], 0xFF); + } + + #[test] + fn default_trait() { + let dict = Dictionary::default(); + assert_eq!(dict.here(), DICTIONARY_BASE); + assert_eq!(dict.latest(), 0); + } + + #[test] + fn comma_overflow() { + let mut dict = Dictionary::new(); + // Move HERE to near the end of memory + let mem_size = dict.memory().len() as u32; + dict.here = mem_size - 2; // Only 2 bytes left + let result = dict.comma(42); + assert!(result.is_err()); + } + + #[test] + fn c_comma_overflow() { + let mut dict = Dictionary::new(); + let mem_size = dict.memory().len() as u32; + dict.here = mem_size; // No space left + let result = dict.c_comma(42); + assert!(result.is_err()); + } + + #[test] + fn word_ids_are_sequential() { + let mut dict = Dictionary::new(); + let id0 = dict.create("A", false).unwrap(); + dict.reveal(); + let id1 = dict.create("B", false).unwrap(); + dict.reveal(); + let id2 = dict.create("C", false).unwrap(); + dict.reveal(); + + assert_eq!(id0, WordId(0)); + assert_eq!(id1, WordId(1)); + assert_eq!(id2, WordId(2)); + } + + #[test] + fn toggle_immediate_no_word_errors() { + let mut dict = Dictionary::new(); + let result = dict.toggle_immediate(); + assert!(result.is_err()); + } +} diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs new file mode 100644 index 0000000..7af7187 --- /dev/null +++ b/crates/core/src/error.rs @@ -0,0 +1,84 @@ +//! Error types for the WAFER compiler and runtime. + +use thiserror::Error; + +/// Errors that can occur during WAFER compilation and execution. +#[derive(Debug, Error)] +pub enum WaferError { + #[error("stack underflow")] + StackUnderflow, + + #[error("stack overflow")] + StackOverflow, + + #[error("return stack underflow")] + ReturnStackUnderflow, + + #[error("return stack overflow")] + ReturnStackOverflow, + + #[error("float stack underflow")] + FloatStackUnderflow, + + #[error("float stack overflow")] + FloatStackOverflow, + + #[error("unknown word: {0}")] + UnknownWord(String), + + #[error("division by zero")] + DivisionByZero, + + #[error("invalid memory address: {0:#x}")] + InvalidAddress(u32), + + #[error("dictionary overflow")] + DictionaryOverflow, + + #[error("compilation error: {0}")] + CompileError(String), + + #[error("invalid number: {0}")] + InvalidNumber(String), + + #[error("word name too long: {0}")] + NameTooLong(String), + + #[error("control structure mismatch: {0}")] + ControlMismatch(String), + + #[error("WASM codegen error: {0}")] + CodegenError(String), + + #[error("WASM validation error: {0}")] + ValidationError(String), + + #[error("I/O error: {0}")] + IoError(String), + + #[error("THROW code {0}")] + Throw(i32), + + #[error("{0}")] + Abort(String), +} + +/// Result type alias for WAFER operations. +pub type WaferResult = Result; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn error_display() { + let err = WaferError::UnknownWord("FOO".to_string()); + assert_eq!(err.to_string(), "unknown word: FOO"); + } + + #[test] + fn error_throw_code() { + let err = WaferError::Throw(-1); + assert_eq!(err.to_string(), "THROW code -1"); + } +} diff --git a/crates/core/src/ir.rs b/crates/core/src/ir.rs new file mode 100644 index 0000000..3a79250 --- /dev/null +++ b/crates/core/src/ir.rs @@ -0,0 +1,159 @@ +//! Intermediate representation for WAFER's compilation pipeline. +//! +//! The IR sits between parsing/compilation and WASM codegen. +//! Optimization passes transform IR before it reaches codegen. + +use crate::dictionary::WordId; + +/// A single IR operation. +#[derive(Debug, Clone, PartialEq)] +pub enum IrOp { + // -- Literals -- + /// Push a 32-bit integer constant. + PushI32(i32), + /// Push a 64-bit integer constant (double-cell). + PushI64(i64), + /// Push a 64-bit float constant. + PushF64(f64), + + // -- Stack manipulation -- + Drop, + Dup, + Swap, + Over, + Rot, + Nip, + Tuck, + + // -- Arithmetic -- + Add, + Sub, + Mul, + /// Combined division and modulus: ( n1 n2 -- rem quot ) + DivMod, + Negate, + Abs, + + // -- Comparison -- + Eq, + NotEq, + Lt, + Gt, + LtUnsigned, + ZeroEq, + ZeroLt, + + // -- Logic -- + And, + Or, + Xor, + Invert, + Lshift, + Rshift, + + // -- Memory -- + /// Fetch cell from address: ( addr -- x ) + Fetch, + /// Store cell to address: ( x addr -- ) + Store, + /// Fetch byte: ( addr -- char ) + CFetch, + /// Store byte: ( char addr -- ) + CStore, + /// Add to cell at address: ( n addr -- ) + PlusStore, + + // -- Control flow -- + /// Call another word. + Call(WordId), + /// Tail-call optimization. + TailCall(WordId), + /// IF ... ELSE ... THEN + If { + then_body: Vec, + else_body: Option>, + }, + /// DO ... LOOP + DoLoop { + body: Vec, + is_plus_loop: bool, + }, + /// BEGIN ... UNTIL + BeginUntil { + body: Vec, + }, + /// BEGIN ... WHILE ... REPEAT + BeginWhileRepeat { + test: Vec, + body: Vec, + }, + /// Return from current word. + Exit, + + // -- Return stack -- + /// Move to return stack: ( x -- ) ( R: -- x ) + ToR, + /// Move from return stack: ( -- x ) ( R: x -- ) + FromR, + /// Copy from return stack: ( -- x ) ( R: x -- x ) + RFetch, + + // -- I/O -- + /// Output character: ( char -- ) + Emit, + /// Print number: ( n -- ) + Dot, + /// Output newline. + Cr, + /// Output string: ( c-addr u -- ) + Type, + + // -- System -- + /// Execute word by function table index: ( xt -- ) + Execute, +} + +/// A compiled word definition as IR. +#[derive(Debug, Clone)] +pub struct IrWord { + /// Word name. + pub name: String, + /// The word's body as IR operations. + pub body: Vec, + /// Whether this word has the IMMEDIATE flag. + pub is_immediate: bool, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ir_word_construction() { + let word = IrWord { + name: "SQUARE".to_string(), + body: vec![IrOp::Dup, IrOp::Mul], + is_immediate: false, + }; + assert_eq!(word.name, "SQUARE"); + assert_eq!(word.body.len(), 2); + } + + #[test] + fn ir_control_flow() { + // : ABS DUP 0< IF NEGATE THEN ; + let abs_word = IrWord { + name: "ABS".to_string(), + body: vec![ + IrOp::Dup, + IrOp::ZeroLt, + IrOp::If { + then_body: vec![IrOp::Negate], + else_body: None, + }, + ], + is_immediate: false, + }; + assert_eq!(abs_word.body.len(), 3); + } +} diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs new file mode 100644 index 0000000..299da60 --- /dev/null +++ b/crates/core/src/lib.rs @@ -0,0 +1,30 @@ +//! WAFER Core: WebAssembly Forth Engine in Rust +//! +//! This crate provides the core compiler and runtime for WAFER, +//! an optimizing Forth 2012 compiler targeting WebAssembly. +//! +//! # Architecture +//! +//! ```text +//! Forth Source -> Outer Interpreter -> IR -> Optimize -> WASM Codegen +//! ``` +//! +//! The compilation pipeline: +//! 1. **Outer interpreter** tokenizes input and dispatches to interpret/compile mode +//! 2. **Compiler** builds an intermediate representation (IR) for each word definition +//! 3. **Type inference** annotates the IR with stack types +//! 4. **Optimizer** applies transformation passes (constant folding, inlining, etc.) +//! 5. **Codegen** translates optimized IR to WASM bytecode via `wasm-encoder` + +pub mod codegen; +pub mod compiler; +pub mod consolidate; +pub mod dictionary; +pub mod error; +pub mod ir; +pub mod memory; +pub mod optimizer; +pub mod outer; +pub mod primitives; +pub mod types; +pub mod words; diff --git a/crates/core/src/memory.rs b/crates/core/src/memory.rs new file mode 100644 index 0000000..1f87a77 --- /dev/null +++ b/crates/core/src/memory.rs @@ -0,0 +1,134 @@ +//! Linear memory layout and stack operations for WAFER. +//! +//! WAFER uses WASM linear memory for the dictionary, return stack, +//! and as a fallback for the data and float stacks when types are unknown. +//! When type inference succeeds, values stay in WASM locals/operand stack instead. + +/// Size of one memory page in WASM (64 KiB). +pub const PAGE_SIZE: u32 = 65536; + +/// Initial number of memory pages. +pub const INITIAL_PAGES: u32 = 16; // 1 MiB + +/// Maximum number of memory pages. +pub const MAX_PAGES: u32 = 256; // 16 MiB + +// Memory region layout +// All offsets are byte addresses in linear memory. + +/// System variables region (STATE, BASE, >IN, HLD, etc.) +pub const SYSVAR_BASE: u32 = 0x0000; +/// Size of system variables region. +pub const SYSVAR_SIZE: u32 = 64; + +/// Input buffer for source parsing. +pub const INPUT_BUFFER_BASE: u32 = SYSVAR_BASE + SYSVAR_SIZE; // 0x0040 +/// Size of input buffer. +pub const INPUT_BUFFER_SIZE: u32 = 1024; + +/// PAD - scratch area for string formatting. +pub const PAD_BASE: u32 = INPUT_BUFFER_BASE + INPUT_BUFFER_SIZE; // 0x0440 +/// Size of PAD. +pub const PAD_SIZE: u32 = 256; + +/// Data stack region (fallback when types are unknown). +/// Grows downward from the top of this region. +pub const DATA_STACK_BASE: u32 = PAD_BASE + PAD_SIZE; // 0x0540 +/// Size of data stack region. +pub const DATA_STACK_SIZE: u32 = 4096; // 1024 cells + +/// Return stack region. Grows downward. +pub const RETURN_STACK_BASE: u32 = DATA_STACK_BASE + DATA_STACK_SIZE; // 0x1540 +/// Size of return stack region. +pub const RETURN_STACK_SIZE: u32 = 4096; + +/// Floating-point stack region (fallback). Grows downward. +pub const FLOAT_STACK_BASE: u32 = RETURN_STACK_BASE + RETURN_STACK_SIZE; // 0x2540 +/// Size of float stack region. +pub const FLOAT_STACK_SIZE: u32 = 2048; // 256 doubles + +/// Dictionary region start. Grows upward. +pub const DICTIONARY_BASE: u32 = FLOAT_STACK_BASE + FLOAT_STACK_SIZE; // 0x2D40 + +/// Initial top of data stack (grows down from here). +pub const DATA_STACK_TOP: u32 = DATA_STACK_BASE + DATA_STACK_SIZE; + +/// Initial top of return stack (grows down from here). +pub const RETURN_STACK_TOP: u32 = RETURN_STACK_BASE + RETURN_STACK_SIZE; + +/// Initial top of float stack (grows down from here). +pub const FLOAT_STACK_TOP: u32 = FLOAT_STACK_BASE + FLOAT_STACK_SIZE; + +/// Size of one cell (4 bytes for i32). +pub const CELL_SIZE: u32 = 4; + +/// Size of one double-cell (8 bytes). +pub const DOUBLE_CELL_SIZE: u32 = 8; + +/// Size of one float (8 bytes for f64). +pub const FLOAT_SIZE: u32 = 8; + +// System variable offsets within SYSVAR region + +/// STATE: 0 = interpreting, -1 (0xFFFFFFFF) = compiling. +pub const SYSVAR_STATE: u32 = SYSVAR_BASE; +/// BASE: current number base (default 10). +pub const SYSVAR_BASE_VAR: u32 = SYSVAR_BASE + 4; +/// >IN: offset into the input buffer. +pub const SYSVAR_TO_IN: u32 = SYSVAR_BASE + 8; +/// HERE: next free dictionary address. +pub const SYSVAR_HERE: u32 = SYSVAR_BASE + 12; +/// LATEST: pointer to the most recent dictionary entry. +pub const SYSVAR_LATEST: u32 = SYSVAR_BASE + 16; +/// SOURCE-ID: current input source (0 = user input, -1 = string). +pub const SYSVAR_SOURCE_ID: u32 = SYSVAR_BASE + 20; +/// #TIB: length of current input. +pub const SYSVAR_NUM_TIB: u32 = SYSVAR_BASE + 24; +/// HLD: pointer for pictured numeric output. +pub const SYSVAR_HLD: u32 = SYSVAR_BASE + 28; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn memory_regions_dont_overlap() { + // Each region should start after the previous one ends + assert!(INPUT_BUFFER_BASE >= SYSVAR_BASE + SYSVAR_SIZE); + assert!(PAD_BASE >= INPUT_BUFFER_BASE + INPUT_BUFFER_SIZE); + assert!(DATA_STACK_BASE >= PAD_BASE + PAD_SIZE); + assert!(RETURN_STACK_BASE >= DATA_STACK_BASE + DATA_STACK_SIZE); + assert!(FLOAT_STACK_BASE >= RETURN_STACK_BASE + RETURN_STACK_SIZE); + assert!(DICTIONARY_BASE >= FLOAT_STACK_BASE + FLOAT_STACK_SIZE); + } + + #[test] + fn dictionary_starts_within_first_page() { + assert!(DICTIONARY_BASE < PAGE_SIZE); + } + + #[test] + fn stack_tops_are_correct() { + assert_eq!(DATA_STACK_TOP, DATA_STACK_BASE + DATA_STACK_SIZE); + assert_eq!(RETURN_STACK_TOP, RETURN_STACK_BASE + RETURN_STACK_SIZE); + assert_eq!(FLOAT_STACK_TOP, FLOAT_STACK_BASE + FLOAT_STACK_SIZE); + } + + #[test] + fn sysvar_offsets_are_within_region() { + let all_offsets = [ + SYSVAR_STATE, + SYSVAR_BASE_VAR, + SYSVAR_TO_IN, + SYSVAR_HERE, + SYSVAR_LATEST, + SYSVAR_SOURCE_ID, + SYSVAR_NUM_TIB, + SYSVAR_HLD, + ]; + for offset in all_offsets { + assert!(offset >= SYSVAR_BASE); + assert!(offset + CELL_SIZE <= SYSVAR_BASE + SYSVAR_SIZE); + } + } +} diff --git a/crates/core/src/optimizer.rs b/crates/core/src/optimizer.rs new file mode 100644 index 0000000..81abc25 --- /dev/null +++ b/crates/core/src/optimizer.rs @@ -0,0 +1,19 @@ +//! Optimization passes for WAFER's IR. +//! +//! Each pass is a function `Vec -> Vec`, composable in sequence: +//! 1. Constant folding +//! 2. Strength reduction +//! 3. Peephole optimization +//! 4. Inlining +//! 5. Dead code elimination +//! 6. Stack-to-local promotion + +// TODO: Step 11 - Optimization pass implementations + +#[cfg(test)] +mod tests { + #[test] + fn placeholder() { + // Optimizer tests will be added in Step 11 + } +} diff --git a/crates/core/src/outer.rs b/crates/core/src/outer.rs new file mode 100644 index 0000000..8cf19a1 --- /dev/null +++ b/crates/core/src/outer.rs @@ -0,0 +1,24 @@ +//! Outer interpreter: tokenizer, number parser, and interpret/compile dispatch. +//! +//! The outer interpreter is the main loop of Forth: +//! 1. Read a token (whitespace-delimited word) +//! 2. Look it up in the dictionary +//! 3. If found: execute (interpret mode) or compile (compile mode) +//! 4. If not found: try to parse as a number +//! 5. If number: push (interpret) or compile as literal (compile mode) +//! 6. If neither: error + +// TODO: Step 8 - Outer interpreter implementation +// - Tokenizer (whitespace splitting, string literals) +// - Number parsing (decimal, #decimal, $hex, %binary per Forth 2012) +// - Main interpret/compile dispatch loop +// - STATE management +// - EVALUATE support (nested interpretation) + +#[cfg(test)] +mod tests { + #[test] + fn placeholder() { + // Outer interpreter tests will be added in Step 8 + } +} diff --git a/crates/core/src/primitives.rs b/crates/core/src/primitives.rs new file mode 100644 index 0000000..39fa0a7 --- /dev/null +++ b/crates/core/src/primitives.rs @@ -0,0 +1,19 @@ +//! Built-in primitive words for WAFER. +//! +//! Primitives are the ~35 words that must be implemented in Rust because +//! they require direct WASM instructions or host interaction. +//! Everything else is defined in Forth (loaded from .fth files). + +// TODO: Step 6 - Primitive word implementations +// Each primitive provides: +// - Its StackEffect (type signature) +// - Its IR representation (for inlining by the optimizer) +// - Direct WASM instruction generation + +#[cfg(test)] +mod tests { + #[test] + fn placeholder() { + // Primitive tests will be added in Step 6 + } +} diff --git a/crates/core/src/types.rs b/crates/core/src/types.rs new file mode 100644 index 0000000..cf59730 --- /dev/null +++ b/crates/core/src/types.rs @@ -0,0 +1,106 @@ +//! Type inference engine for WAFER's multi-typed stack. +//! +//! WAFER uses type inference to determine when values on the stack have +//! statically known types. When types are known, codegen uses WASM's native +//! typed operand stack and locals instead of simulating stacks in linear memory. + +/// Types that can appear on WAFER's stack. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum StackType { + /// 32-bit integer (default Forth cell). + I32, + /// 64-bit integer (double-cell). + I64, + /// 32-bit float. + F32, + /// 64-bit float (Forth floating-point). + F64, + /// Boolean (result of comparisons). Represented as i32 at WASM level. + Bool, + /// Memory address. Represented as i32 at WASM level. + Addr, + /// Type is unknown or cannot be determined statically. + Unknown, +} + +impl StackType { + /// Returns the WASM value type for this stack type. + pub fn wasm_type(self) -> wasm_encoder::ValType { + match self { + StackType::I32 | StackType::Bool | StackType::Addr => wasm_encoder::ValType::I32, + StackType::I64 => wasm_encoder::ValType::I64, + StackType::F32 => wasm_encoder::ValType::F32, + StackType::F64 => wasm_encoder::ValType::F64, + StackType::Unknown => wasm_encoder::ValType::I32, // default to i32 + } + } + + /// Returns true if this type's WASM representation is i32. + pub fn is_i32_compatible(self) -> bool { + matches!( + self, + StackType::I32 | StackType::Bool | StackType::Addr | StackType::Unknown + ) + } +} + +/// Describes the stack effect of a Forth word. +/// +/// For example, `+` has effect `( I32 I32 -- I32 )`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StackEffect { + /// Types consumed from the stack (bottom to top). + pub inputs: Vec, + /// Types produced on the stack (bottom to top). + pub outputs: Vec, +} + +impl StackEffect { + /// Create a new stack effect. + pub fn new(inputs: Vec, outputs: Vec) -> Self { + Self { inputs, outputs } + } + + /// Number of items consumed. + pub fn input_count(&self) -> usize { + self.inputs.len() + } + + /// Number of items produced. + pub fn output_count(&self) -> usize { + self.outputs.len() + } + + /// Net stack depth change. + pub fn depth_change(&self) -> i32 { + self.outputs.len() as i32 - self.inputs.len() as i32 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stack_type_wasm_mapping() { + assert_eq!(StackType::I32.wasm_type(), wasm_encoder::ValType::I32); + assert_eq!(StackType::F64.wasm_type(), wasm_encoder::ValType::F64); + assert_eq!(StackType::Bool.wasm_type(), wasm_encoder::ValType::I32); + assert_eq!(StackType::Addr.wasm_type(), wasm_encoder::ValType::I32); + } + + #[test] + fn stack_effect_depth() { + // DUP ( x -- x x ) + let dup = StackEffect::new(vec![StackType::I32], vec![StackType::I32, StackType::I32]); + assert_eq!(dup.depth_change(), 1); + + // + ( x y -- z ) + let add = StackEffect::new(vec![StackType::I32, StackType::I32], vec![StackType::I32]); + assert_eq!(add.depth_change(), -1); + + // DROP ( x -- ) + let drop_e = StackEffect::new(vec![StackType::I32], vec![]); + assert_eq!(drop_e.depth_change(), -1); + } +} diff --git a/crates/core/src/words/mod.rs b/crates/core/src/words/mod.rs new file mode 100644 index 0000000..9f8828e --- /dev/null +++ b/crates/core/src/words/mod.rs @@ -0,0 +1,19 @@ +//! Forth 2012 word set implementations. +//! +//! Each submodule implements one word set from the Forth 2012 standard. +//! Words are implemented in Rust only when they require direct WASM instructions; +//! most words are defined in Forth source files under `forth/`. + +// Word set modules will be added as each set is implemented: +// pub mod core; +// pub mod core_ext; +// pub mod double; +// pub mod exception; +// pub mod floating; +// pub mod locals; +// pub mod string; +// pub mod tools; +// pub mod memory_alloc; +// pub mod search_order; +// pub mod file; +// pub mod facility; diff --git a/crates/core/tests/compliance.rs b/crates/core/tests/compliance.rs new file mode 100644 index 0000000..7664f4e --- /dev/null +++ b/crates/core/tests/compliance.rs @@ -0,0 +1,91 @@ +//! Forth 2012 compliance tests using Gerry Jackson's test suite. +//! +//! Each test function loads the corresponding test file from the +//! forth2012-test-suite submodule and runs it through WAFER. +//! Tests are initially `#[ignore]` and enabled as word sets are implemented. + +/// Path to the test suite source directory. +/// The submodule lives at the workspace root: tests/forth2012-test-suite/ +const _TEST_SUITE_DIR: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../tests/forth2012-test-suite/src" +); + +// TODO: Test harness that boots WAFER, loads tester.fr, and runs test files. +// For now, these are placeholder tests that document the compliance targets. + +#[test] +#[ignore = "Step 10: Core word set not yet implemented"] +fn compliance_core() { + // Will load: tester.fr, then core.fr + // Must pass with 0 failures + todo!("Boot WAFER, load tester.fr + core.fr, assert 0 failures"); +} + +#[test] +#[ignore = "Step 10: Core word set not yet implemented"] +fn compliance_core_plus() { + // Will load: tester.fr, then coreplustest.fth + todo!("Boot WAFER, load tester.fr + coreplustest.fth"); +} + +#[test] +#[ignore = "Step 13: Core extensions not yet implemented"] +fn compliance_core_ext() { + // Will load: tester.fr, utilities.fth, then coreexttest.fth + todo!("Boot WAFER, load coreexttest.fth"); +} + +#[test] +#[ignore = "Step 13: Double-number word set not yet implemented"] +fn compliance_double() { + todo!("Boot WAFER, load doubletest.fth"); +} + +#[test] +#[ignore = "Step 13: Exception word set not yet implemented"] +fn compliance_exception() { + todo!("Boot WAFER, load exceptiontest.fth"); +} + +#[test] +#[ignore = "Step 13: Facility word set not yet implemented"] +fn compliance_facility() { + todo!("Boot WAFER, load facilitytest.fth"); +} + +#[test] +#[ignore = "Step 13: File-access word set not yet implemented"] +fn compliance_file() { + todo!("Boot WAFER, load filetest.fth"); +} + +#[test] +#[ignore = "Step 13: Locals word set not yet implemented"] +fn compliance_locals() { + todo!("Boot WAFER, load localstest.fth"); +} + +#[test] +#[ignore = "Step 13: Memory-allocation word set not yet implemented"] +fn compliance_memory() { + todo!("Boot WAFER, load memorytest.fth"); +} + +#[test] +#[ignore = "Step 13: Search-order word set not yet implemented"] +fn compliance_search_order() { + todo!("Boot WAFER, load searchordertest.fth"); +} + +#[test] +#[ignore = "Step 13: String word set not yet implemented"] +fn compliance_string() { + todo!("Boot WAFER, load stringtest.fth"); +} + +#[test] +#[ignore = "Step 13: Programming-tools word set not yet implemented"] +fn compliance_tools() { + todo!("Boot WAFER, load toolstest.fth"); +} diff --git a/crates/web/Cargo.toml b/crates/web/Cargo.toml new file mode 100644 index 0000000..f5b4b5d --- /dev/null +++ b/crates/web/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "wafer-web" +description = "WAFER: WebAssembly Forth Engine in Rust - browser bindings" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +wafer-core = { path = "../core" } diff --git a/crates/web/src/lib.rs b/crates/web/src/lib.rs new file mode 100644 index 0000000..3a82bdb --- /dev/null +++ b/crates/web/src/lib.rs @@ -0,0 +1,6 @@ +//! WAFER Web: Browser bindings for WAFER Forth. +//! +//! This crate will provide wasm-bindgen bindings for running WAFER +//! in the browser with a web REPL. + +// TODO: Phase 5 - Browser target implementation diff --git a/forth/boot.fth b/forth/boot.fth new file mode 100644 index 0000000..c3e15d5 --- /dev/null +++ b/forth/boot.fth @@ -0,0 +1,23 @@ +\ WAFER Boot - Minimal bootstrap loaded first after primitives +\ This file defines the most fundamental derived words needed +\ before the rest of the standard library can load. + +\ These words are defined in terms of the ~35 Rust primitives. +\ They form the foundation for core.fth and all subsequent files. + +\ TODO: Step 7/8 - Populate with bootstrap definitions once +\ the compiler and outer interpreter are working. +\ For now this file documents what will go here: + +\ Derived stack operations: +\ : NIP ( x1 x2 -- x2 ) SWAP DROP ; +\ : TUCK ( x1 x2 -- x2 x1 x2 ) SWAP OVER ; +\ : 2DUP ( x1 x2 -- x1 x2 x1 x2 ) OVER OVER ; +\ : 2DROP ( x1 x2 -- ) DROP DROP ; +\ : ?DUP ( x -- 0 | x x ) DUP IF DUP THEN ; + +\ Basic arithmetic derived from primitives: +\ : 1+ ( n -- n+1 ) 1 + ; +\ : 1- ( n -- n-1 ) 1 - ; +\ : NEGATE ( n -- -n ) 0 SWAP - ; +\ : ABS ( n -- |n| ) DUP 0< IF NEGATE THEN ; diff --git a/forth/core.fth b/forth/core.fth new file mode 100644 index 0000000..44ddd6d --- /dev/null +++ b/forth/core.fth @@ -0,0 +1,48 @@ +\ WAFER Core Word Set - High-level words defined in Forth +\ These implement Forth 2012 Core words that can be expressed +\ in terms of primitives and boot words. + +\ TODO: Step 10 - Populate as Core compliance tests are run. +\ Each word here will be tested against forth2012-test-suite/src/core.fr + +\ -- Derived stack operations -- +\ : NIP ( x1 x2 -- x2 ) SWAP DROP ; +\ : TUCK ( x1 x2 -- x2 x1 x2 ) SWAP OVER ; +\ : 2DUP ( x1 x2 -- x1 x2 x1 x2 ) OVER OVER ; +\ : 2DROP ( x1 x2 -- ) DROP DROP ; +\ : 2SWAP ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) ROT >R ROT R> ; +\ : 2OVER ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) >R >R 2DUP R> R> 2SWAP ; + +\ -- Arithmetic -- +\ : 1+ 1 + ; +\ : 1- 1 - ; +\ : 2* 1 LSHIFT ; +\ : 2/ 1 RSHIFT ; +\ : NEGATE 0 SWAP - ; +\ : ABS DUP 0< IF NEGATE THEN ; +\ : MIN 2DUP > IF SWAP THEN DROP ; +\ : MAX 2DUP < IF SWAP THEN DROP ; +\ : MOD /MOD DROP ; +\ : / /MOD NIP ; + +\ -- Comparison -- +\ : 0= 0 = ; +\ : 0<> 0= 0= ; +\ : 0< 0 < ; +\ : 0> 0 SWAP < ; +\ : <> = 0= ; + +\ -- Memory -- +\ : +! DUP @ ROT + SWAP ! ; +\ : CELLS 4 * ; +\ : CELL+ 4 + ; +\ : CHARS ; +\ : CHAR+ 1+ ; + +\ -- Defining words -- +\ : VARIABLE CREATE 0 , ; +\ : CONSTANT CREATE , DOES> @ ; + +\ -- I/O -- +\ : SPACE BL EMIT ; +\ : SPACES 0 ?DO SPACE LOOP ; diff --git a/forth/core_ext.fth b/forth/core_ext.fth new file mode 100644 index 0000000..0a46310 --- /dev/null +++ b/forth/core_ext.fth @@ -0,0 +1,11 @@ +\ WAFER Core Extensions Word Set +\ Forth 2012 Section 6.2 + +\ TODO: Step 13 - Implement as compliance tests are enabled +\ : VALUE CREATE , DOES> @ ; +\ : TO ' >BODY ! ; +\ : DEFER CREATE ['] ABORT , DOES> @ EXECUTE ; +\ : DEFER! >BODY ! ; +\ : DEFER@ >BODY @ ; +\ : IS STATE @ IF POSTPONE ['] POSTPONE DEFER! ELSE ' DEFER! THEN ; IMMEDIATE +\ : ACTION-OF STATE @ IF POSTPONE ['] POSTPONE DEFER@ ELSE ' DEFER@ THEN ; IMMEDIATE diff --git a/forth/prelude.fth b/forth/prelude.fth new file mode 100644 index 0000000..4b6ef0f --- /dev/null +++ b/forth/prelude.fth @@ -0,0 +1,8 @@ +\ WAFER Prelude - Master loader for the standard library +\ This file is loaded at boot after primitives are registered. +\ It includes all word set files in dependency order. + +\ TODO: Enable includes as each word set is implemented +\ INCLUDE boot.fth +\ INCLUDE core.fth +\ INCLUDE core_ext.fth diff --git a/tests/forth2012-test-suite b/tests/forth2012-test-suite new file mode 160000 index 0000000..9773f84 --- /dev/null +++ b/tests/forth2012-test-suite @@ -0,0 +1 @@ +Subproject commit 9773f84dd12390f342d37195da8848b04e1f4a23