commit 7d9937d0d82493e0d00dfd44d493d646b0c323ab Author: Oleksandr Kozachuk Date: Sun Mar 29 22:14:53 2026 +0200 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. 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