From 9f176b09c73d54dc04495299f28760b1cf0e78bd Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 12:08:37 -0400 Subject: [PATCH 01/26] wip: add a websocket server --- Cargo.lock | 398 ++++++++++++++++++++++++++++++++++++------ stack-cli/Cargo.toml | 7 + stack-cli/src/main.rs | 47 ++++- 3 files changed, 395 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd93c797..33615600 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,8 +101,8 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "cfg-if", - "getrandom", + "cfg-if 1.0.0", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -312,7 +312,7 @@ checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock 2.8.0", "autocfg", - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "futures-lite 1.13.0", "log", @@ -331,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ "async-lock 3.4.0", - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "futures-io", "futures-lite 2.3.0", @@ -379,7 +379,7 @@ dependencies = [ "async-lock 2.8.0", "async-signal", "blocking", - "cfg-if", + "cfg-if 1.0.0", "event-listener 3.1.0", "futures-lite 1.13.0", "rustix 0.38.34", @@ -406,7 +406,7 @@ dependencies = [ "async-io 2.3.3", "async-lock 3.4.0", "atomic-waker", - "cfg-if", + "cfg-if 1.0.0", "futures-core", "futures-io", "rustix 0.38.34", @@ -528,13 +528,34 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -603,6 +624,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "bytemuck" version = "1.16.0" @@ -629,6 +656,16 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + [[package]] name = "bytes" version = "1.6.0" @@ -687,6 +724,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -859,7 +902,7 @@ version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "bytes", + "bytes 1.6.0", "memchr", ] @@ -870,7 +913,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a2dc81369dde6d31456eedbb4fd3d320f0b9713573dfe06e569e2bce7607f2" dependencies = [ "castaway", - "cfg-if", + "cfg-if 1.0.0", "itoa", "rustversion", "ryu", @@ -941,7 +984,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -968,12 +1011,12 @@ dependencies = [ "bitflags 2.5.0", "crossterm_winapi", "libc", - "mio", + "mio 0.8.11", "parking_lot", "serde", "signal-hook", "signal-hook-mio", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -982,7 +1025,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -991,7 +1034,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -1023,13 +1066,22 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "crypto-common", ] @@ -1113,7 +1165,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "web-time", - "winapi", + "winapi 0.3.9", "winit", ] @@ -1293,6 +1345,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fastrand" version = "1.9.0" @@ -1314,7 +1372,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "rustix 0.38.34", "windows-sys 0.52.0", ] @@ -1334,7 +1392,7 @@ version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.4.1", "windows-sys 0.52.0", @@ -1407,6 +1465,22 @@ dependencies = [ "libc", ] +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.3.2", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "futures-core" version = "0.3.30" @@ -1475,6 +1549,15 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1495,15 +1578,26 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -1622,7 +1716,7 @@ dependencies = [ "log", "presser", "thiserror", - "winapi", + "winapi 0.3.9", "windows 0.52.0", ] @@ -1668,7 +1762,7 @@ dependencies = [ "libloading 0.8.3", "thiserror", "widestring", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1704,6 +1798,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1917,7 +2017,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1941,6 +2041,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -1978,7 +2087,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", - "cfg-if", + "cfg-if 1.0.0", "combine", "jni-sys", "log", @@ -2011,6 +2120,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "khronos-egl" version = "6.0.0" @@ -2048,6 +2167,12 @@ dependencies = [ "libc", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.155" @@ -2060,8 +2185,8 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cfg-if", - "winapi", + "cfg-if 1.0.0", + "winapi 0.3.9", ] [[package]] @@ -2070,7 +2195,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-targets 0.52.5", ] @@ -2198,6 +2323,25 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + [[package]] name = "mio" version = "0.8.11" @@ -2206,10 +2350,34 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio 0.6.23", + "slab", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + [[package]] name = "naga" version = "0.19.2" @@ -2261,6 +2429,17 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "net2" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + [[package]] name = "nix" version = "0.26.4" @@ -2268,7 +2447,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", - "cfg-if", + "cfg-if 1.0.0", "libc", "memoffset 0.7.1", ] @@ -2280,7 +2459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.5.0", - "cfg-if", + "cfg-if 1.0.0", "cfg_aliases", "libc", ] @@ -2315,7 +2494,7 @@ dependencies = [ "kqueue", "libc", "log", - "mio", + "mio 0.8.11", "walkdir", "windows-sys 0.48.0", ] @@ -2525,6 +2704,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "orbclient" version = "0.3.47" @@ -2585,7 +2770,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.5.1", "smallvec", @@ -2664,7 +2849,7 @@ checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags 1.3.2", - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "libc", "log", @@ -2678,7 +2863,7 @@ version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "hermit-abi", "pin-project-lite", @@ -2751,6 +2936,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.5" @@ -2758,8 +2956,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -2769,7 +2977,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -2778,7 +2995,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -2957,18 +3183,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -2986,15 +3212,27 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug", +] + [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -3014,7 +3252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", - "mio", + "mio 0.8.11", "signal-hook", ] @@ -3109,7 +3347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3136,8 +3374,10 @@ dependencies = [ "crossterm", "notify", "reedline", + "serde", "stack-core", "stack-std", + "ws", ] [[package]] @@ -3258,7 +3498,7 @@ version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand 2.1.0", "rustix 0.38.34", "windows-sys 0.52.0", @@ -3288,7 +3528,7 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "proc-macro2", "quote", "syn 2.0.66", @@ -3335,7 +3575,7 @@ dependencies = [ "arrayref", "arrayvec", "bytemuck", - "cfg-if", + "cfg-if 1.0.0", "log", "tiny-skia-path", ] @@ -3463,7 +3703,7 @@ checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ "memoffset 0.9.1", "tempfile", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3561,6 +3801,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3573,7 +3819,7 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -3598,7 +3844,7 @@ version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -3786,7 +4032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01" dependencies = [ "arrayvec", - "cfg-if", + "cfg-if 1.0.0", "cfg_aliases", "js-sys", "log", @@ -3867,7 +4113,7 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3887,6 +4133,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -3897,6 +4149,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -4265,6 +4523,34 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "ws" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fe90c75f236a0a00247d5900226aea4f2d7b05ccc34da9e7a8880ff59b5848" +dependencies = [ + "byteorder", + "bytes 0.4.12", + "httparse", + "log", + "mio 0.6.23", + "mio-extras", + "rand 0.7.3", + "sha-1", + "slab", + "url", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -4395,14 +4681,14 @@ dependencies = [ "nix 0.26.4", "once_cell", "ordered-stream", - "rand", + "rand 0.8.5", "serde", "serde_repr", "sha1", "static_assertions", "tracing", "uds_windows", - "winapi", + "winapi 0.3.9", "xdg-home", "zbus_macros", "zbus_names", diff --git a/stack-cli/Cargo.toml b/stack-cli/Cargo.toml index 9d831234..ebb5be31 100644 --- a/stack-cli/Cargo.toml +++ b/stack-cli/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" [features] default = ["stack-std"] stack-std = ["dep:stack-std"] +serde = ["dep:serde"] +ws = ["dep:ws"] +server = ["dep:ws", "dep:serde"] [dependencies] clap.workspace = true @@ -17,6 +20,10 @@ stack-core = { path = "../stack-core" } stack-std = { path = "../stack-std", optional = true } codespan-reporting = "0.11.1" +# server +serde = { version = "1.0.204", features = ["derive"], optional = true } +ws = { version = "0.9.2", optional = true } + [[bin]] name = "stack" path = "src/main.rs" diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index b544dc59..594fb055 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -2,7 +2,7 @@ use core::fmt; use std::{ io::{self, prelude::Write, Read}, path::{Path, PathBuf}, - sync::Arc, + sync::{Arc, Mutex}, }; use clap::Parser; @@ -223,6 +223,48 @@ fn main() { } } } + Subcommand::Serve => { + #[cfg(feature = "server")] + { + use serde::{Deserialize, Serialize}; + use ws::listen; + + let engine = Mutex::new(Engine::new()); + let context = Mutex::new(Context::new()); + + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + )] + enum Incoming { + Run(String), + RunNew(String), + ClearStack, + ClearScope, + ClearAll, + } + + listen("127.0.0.1:5001", |out| { + move |msg| { + println!("msg: {msg:?}"); + Ok(()) + } + }) + .unwrap(); + } + + #[cfg(not(feature = "server"))] + { + eprintln!("Server feature is not enabled. Compile the Stack CLI with --features server"); + } + } } } @@ -329,4 +371,7 @@ enum Subcommand { #[arg(short, long)] watch: bool, }, + + // TODO: add host and port as options + Serve, } From e572833e5bf69d6d97a0b66379253f40b067eb67 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 12:33:31 -0400 Subject: [PATCH 02/26] implement serialize on Expressions --- Cargo.lock | 1 + Cargo.toml | 3 ++- stack-cli/Cargo.toml | 7 ++---- stack-core/Cargo.toml | 1 + stack-core/src/expr.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33615600..52ff5a34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3386,6 +3386,7 @@ version = "0.1.0" dependencies = [ "compact_str", "internment", + "serde", "test-case", "unicode-segmentation", "yansi", diff --git a/Cargo.toml b/Cargo.toml index ab0bfd9f..270b427f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ unicode-segmentation = "1" compact_str = "=0.8.0-beta" test-case = "3" -clap = { version = "4", features = ["derive"] } \ No newline at end of file +clap = { version = "4", features = ["derive"] } +serde = { version = "1.0.204", features = ["derive"] } diff --git a/stack-cli/Cargo.toml b/stack-cli/Cargo.toml index ebb5be31..bbee8825 100644 --- a/stack-cli/Cargo.toml +++ b/stack-cli/Cargo.toml @@ -6,9 +6,6 @@ edition = "2021" [features] default = ["stack-std"] stack-std = ["dep:stack-std"] -serde = ["dep:serde"] -ws = ["dep:ws"] -server = ["dep:ws", "dep:serde"] [dependencies] clap.workspace = true @@ -21,8 +18,8 @@ stack-std = { path = "../stack-std", optional = true } codespan-reporting = "0.11.1" # server -serde = { version = "1.0.204", features = ["derive"], optional = true } -ws = { version = "0.9.2", optional = true } +serde = { workspace = true } +ws = { version = "0.9.2" } [[bin]] name = "stack" diff --git a/stack-core/Cargo.toml b/stack-core/Cargo.toml index e4a7effb..111ddd4f 100644 --- a/stack-core/Cargo.toml +++ b/stack-core/Cargo.toml @@ -8,6 +8,7 @@ internment = "0.7.4" unicode-segmentation.workspace = true compact_str.workspace = true yansi = "1" +serde.workspace = true [dev-dependencies] test-case.workspace = true diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 989f303d..41ac6c89 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use compact_str::CompactString; use internment::Intern; +use serde::ser::{Serialize, SerializeMap, SerializeTuple}; use yansi::Paint; use crate::{lexer::Span, scope::Scope, source::Source, symbol::Symbol}; @@ -13,6 +14,15 @@ pub struct Expr { pub info: Option, } +impl Serialize for Expr { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.kind.serialize(serializer) + } +} + impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Expr {{ kind: ExprKind::{:?} }}", self.kind) @@ -136,6 +146,45 @@ pub enum ExprKind { Underscore, } +impl Serialize for ExprKind { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + ExprKind::Nil => serializer.serialize_unit(), + ExprKind::Boolean(v) => serializer.serialize_bool(*v), + ExprKind::Integer(v) => serializer.serialize_i64(*v), + ExprKind::Float(v) => serializer.serialize_f64(*v), + ExprKind::String(v) => serializer.serialize_str(v.as_str()), + // TODO: Symbol serialization isn't 1:1, as it's turned into a str here. + // Is that what we want? + ExprKind::Symbol(v) => serializer.serialize_str(v.as_str()), + ExprKind::Lazy(inner) => inner.kind.serialize(serializer), + ExprKind::List(v) => { + let mut tup = serializer.serialize_tuple(v.len())?; + for item in v.iter() { + tup.serialize_element(&item.kind)?; + } + tup.end() + } + ExprKind::Record(v) => { + let mut record = serializer.serialize_map(Some(v.len()))?; + for (key, val) in v.iter() { + let key = key.as_str(); + record.serialize_entry(key, &val.kind)?; + } + record.end() + } + + // We won't serialize these for now since they aren't really datatypes. + ExprKind::Function { .. } => serializer.serialize_unit(), + ExprKind::SExpr { .. } => serializer.serialize_unit(), + ExprKind::Underscore => serializer.serialize_unit(), + } + } +} + impl ExprKind { #[inline] pub const fn is_nil(&self) -> bool { From a4bbf2ed1330ef3c8ebbf1513140719c72cbf147 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 13:00:16 -0400 Subject: [PATCH 03/26] implement running into the ws server --- Cargo.lock | 13 +++++ stack-cli/Cargo.toml | 1 + stack-cli/src/main.rs | 112 ++++++++++++++++++++++++++++-------------- 3 files changed, 88 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52ff5a34..10cc9713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3201,6 +3201,18 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "serde_json" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" @@ -3375,6 +3387,7 @@ dependencies = [ "notify", "reedline", "serde", + "serde_json", "stack-core", "stack-std", "ws", diff --git a/stack-cli/Cargo.toml b/stack-cli/Cargo.toml index bbee8825..b71542f1 100644 --- a/stack-cli/Cargo.toml +++ b/stack-cli/Cargo.toml @@ -20,6 +20,7 @@ codespan-reporting = "0.11.1" # server serde = { workspace = true } ws = { version = "0.9.2" } +serde_json = "1.0.121" [[bin]] name = "stack" diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index 594fb055..8806f569 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -1,7 +1,9 @@ use core::fmt; use std::{ io::{self, prelude::Write, Read}, + mem, path::{Path, PathBuf}, + rc::Rc, sync::{Arc, Mutex}, }; @@ -24,6 +26,7 @@ use notify::{ }; use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal}; use stack_core::prelude::*; +use ws::Message; fn main() { let cli = Cli::parse(); @@ -224,46 +227,79 @@ fn main() { } } Subcommand::Serve => { - #[cfg(feature = "server")] - { - use serde::{Deserialize, Serialize}; - use ws::listen; - - let engine = Mutex::new(Engine::new()); - let context = Mutex::new(Context::new()); - - #[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Serialize, - Deserialize, - )] - enum Incoming { - Run(String), - RunNew(String), - ClearStack, - ClearScope, - ClearAll, - } - - listen("127.0.0.1:5001", |out| { - move |msg| { - println!("msg: {msg:?}"); - Ok(()) - } - }) - .unwrap(); + use serde::{Deserialize, Serialize}; + use ws::listen; + + let eng_mutex = Rc::new(Mutex::new(Engine::new())); + let ctx_mutex = Rc::new(Mutex::new(Context::new())); + + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + )] + enum Incoming { + Run(String), + RunNew(String), + ClearStack, + ClearScope, + ClearAll, } - #[cfg(not(feature = "server"))] - { - eprintln!("Server feature is not enabled. Compile the Stack CLI with --features server"); - } + listen("127.0.0.1:5001", |out| { + let eng_mutex = eng_mutex.clone(); + let ctx_mutex = ctx_mutex.clone(); + + move |msg| { + if let Message::Text(string) = msg { + let source = Source::new("runner", string); + let mut lexer = Lexer::new(source); + let exprs = parse(&mut lexer).unwrap(); + + match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { + (Ok(engine), Ok(mut guard)) => { + let context = mem::take(&mut *guard); + drop(guard); + + let result = engine.run(context, exprs); + let guard = ctx_mutex.try_lock(); + if let Ok(mut guard) = guard { + match result { + Ok(ctx) => { + *guard = ctx; + + if let Some(expr) = guard.stack().last() { + if let Ok(string) = serde_json::to_string(expr) { + println!("sending: {string:?}"); + + out.send(string) + } else { + todo!("failed serde json") + } + } else { + todo!("no last item") + } + } + Err(_) => todo!(), + } + } else { + todo!("mutex no lock 2"); + } + } + _ => todo!("mutex not lock"), + } + } else { + todo!("message not text") + } + } + }) + .unwrap(); } } } From 493bde9c24f0cbb12be95c990b1f10471be9f166 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 13:02:25 -0400 Subject: [PATCH 04/26] remove unnecessary code --- stack-cli/src/main.rs | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index 8806f569..56a28d0b 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -265,31 +265,25 @@ fn main() { match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { (Ok(engine), Ok(mut guard)) => { let context = mem::take(&mut *guard); - drop(guard); - let result = engine.run(context, exprs); - let guard = ctx_mutex.try_lock(); - if let Ok(mut guard) = guard { - match result { - Ok(ctx) => { - *guard = ctx; - - if let Some(expr) = guard.stack().last() { - if let Ok(string) = serde_json::to_string(expr) { - println!("sending: {string:?}"); - - out.send(string) - } else { - todo!("failed serde json") - } + + match result { + Ok(ctx) => { + *guard = ctx; + + if let Some(expr) = guard.stack().last() { + if let Ok(string) = serde_json::to_string(expr) { + println!("sending: {string:?}"); + + out.send(string) } else { - todo!("no last item") + todo!("failed serde json") } + } else { + todo!("no last item") } - Err(_) => todo!(), } - } else { - todo!("mutex no lock 2"); + Err(_) => todo!(), } } _ => todo!("mutex not lock"), From 6edc55dd8958033cd1860e0dea68eefc49dbbfec Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 15:10:26 -0400 Subject: [PATCH 05/26] wip: parse incoming JSON --- stack-cli/src/main.rs | 88 +++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index 56a28d0b..efa5e7df 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -233,22 +233,23 @@ fn main() { let eng_mutex = Rc::new(Mutex::new(Engine::new())); let ctx_mutex = Rc::new(Mutex::new(Context::new())); - #[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Serialize, - Deserialize, - )] + #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] + #[serde(tag = "type", content = "code", rename_all = "lowercase")] enum Incoming { - Run(String), + /// Run code within a new engine + #[serde(rename = "run_new")] RunNew(String), + /// Run code within the existing engine + Run(String), + + /// Clear the stack + #[serde(rename = "clear_stack")] ClearStack, + /// Clear the scope + #[serde(rename = "clear_scope")] ClearScope, + /// Clear everything + #[serde(rename = "clear")] ClearAll, } @@ -258,35 +259,48 @@ fn main() { move |msg| { if let Message::Text(string) = msg { - let source = Source::new("runner", string); - let mut lexer = Lexer::new(source); - let exprs = parse(&mut lexer).unwrap(); - - match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { - (Ok(engine), Ok(mut guard)) => { - let context = mem::take(&mut *guard); - let result = engine.run(context, exprs); - - match result { - Ok(ctx) => { - *guard = ctx; - - if let Some(expr) = guard.stack().last() { - if let Ok(string) = serde_json::to_string(expr) { - println!("sending: {string:?}"); - - out.send(string) - } else { - todo!("failed serde json") + let request = serde_json::from_str::(&string); + + match request { + Ok(incoming) => match incoming { + Incoming::RunNew(_) => todo!(), + Incoming::Run(code) => { + let source = Source::new("runner", code); + let mut lexer = Lexer::new(source); + let exprs = parse(&mut lexer).unwrap(); + + match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { + (Ok(engine), Ok(mut guard)) => { + let context = mem::take(&mut *guard); + let result = engine.run(context, exprs); + + match result { + Ok(ctx) => { + *guard = ctx; + + if let Some(expr) = guard.stack().last() { + if let Ok(string) = serde_json::to_string(expr) { + println!("sending: {string:?}"); + + out.send(string) + } else { + todo!("failed serde json") + } + } else { + todo!("no last item") + } + } + Err(_) => todo!(), } - } else { - todo!("no last item") } + _ => todo!("mutex not lock"), } - Err(_) => todo!(), } - } - _ => todo!("mutex not lock"), + Incoming::ClearStack => todo!(), + Incoming::ClearScope => todo!(), + Incoming::ClearAll => todo!(), + }, + Err(parse_error) => todo!("parse error"), } } else { todo!("message not text") From 0d32a86935538abc9865ffe061a28b94551c56d5 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 15:19:19 -0400 Subject: [PATCH 06/26] implement run_new --- stack-cli/src/main.rs | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index efa5e7df..abbbd8a6 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -263,7 +263,40 @@ fn main() { match request { Ok(incoming) => match incoming { - Incoming::RunNew(_) => todo!(), + Incoming::RunNew(code) => { + let source = Source::new("runner", code); + let mut lexer = Lexer::new(source); + let exprs = parse(&mut lexer).unwrap(); + + match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { + (Ok(engine), Ok(mut guard)) => { + mem::replace(&mut *guard, Context::new()); + + let context = mem::take(&mut *guard); + let result = engine.run(context, exprs); + + match result { + Ok(ctx) => { + *guard = ctx; + + if let Some(expr) = guard.stack().last() { + if let Ok(string) = serde_json::to_string(expr) { + println!("sending: {string:?}"); + + out.send(string) + } else { + todo!("failed serde json") + } + } else { + todo!("no last item") + } + } + Err(_) => todo!("run error"), + } + } + _ => todo!("mutex not lock"), + } + } Incoming::Run(code) => { let source = Source::new("runner", code); let mut lexer = Lexer::new(source); @@ -290,7 +323,7 @@ fn main() { todo!("no last item") } } - Err(_) => todo!(), + Err(_) => todo!("run error"), } } _ => todo!("mutex not lock"), From 3ae900963aa99351c3bee17090fad3c11be23a16 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 15:28:31 -0400 Subject: [PATCH 07/26] serialize all things errors --- stack-cli/src/main.rs | 16 +++++++++------- stack-core/src/context.rs | 13 +++++++++++++ stack-core/src/engine.rs | 6 ++++-- stack-core/src/expr.rs | 18 ++++++------------ stack-core/src/lexer.rs | 4 +++- stack-core/src/source.rs | 12 +++++++++++- 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index abbbd8a6..2d2078b9 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -270,7 +270,7 @@ fn main() { match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { (Ok(engine), Ok(mut guard)) => { - mem::replace(&mut *guard, Context::new()); + let _ = mem::replace(&mut *guard, Context::new()); let context = mem::take(&mut *guard); let result = engine.run(context, exprs); @@ -281,8 +281,6 @@ fn main() { if let Some(expr) = guard.stack().last() { if let Ok(string) = serde_json::to_string(expr) { - println!("sending: {string:?}"); - out.send(string) } else { todo!("failed serde json") @@ -291,7 +289,10 @@ fn main() { todo!("no last item") } } - Err(_) => todo!("run error"), + Err(error) => match serde_json::to_string(&error) { + Ok(string) => out.send(string), + Err(_) => todo!(), + }, } } _ => todo!("mutex not lock"), @@ -313,8 +314,6 @@ fn main() { if let Some(expr) = guard.stack().last() { if let Ok(string) = serde_json::to_string(expr) { - println!("sending: {string:?}"); - out.send(string) } else { todo!("failed serde json") @@ -323,7 +322,10 @@ fn main() { todo!("no last item") } } - Err(_) => todo!("run error"), + Err(error) => match serde_json::to_string(&error) { + Ok(string) => out.send(string), + Err(_) => todo!(), + }, } } _ => todo!("mutex not lock"), diff --git a/stack-core/src/context.rs b/stack-core/src/context.rs index 13434577..1ee7b132 100644 --- a/stack-core/src/context.rs +++ b/stack-core/src/context.rs @@ -1,5 +1,7 @@ use std::{cell::RefCell, collections::HashMap, sync::Arc}; +use serde::ser::{Serialize, SerializeMap}; + use crate::{ chain::Chain, engine::{RunError, RunErrorReason}, @@ -20,6 +22,17 @@ pub struct Context { sources: HashMap, } +impl Serialize for Context { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut record = serializer.serialize_map(Some(1))?; + record.serialize_entry("stack", &self.stack)?; + record.end() + } +} + impl Context { #[inline] pub fn new() -> Self { diff --git a/stack-core/src/engine.rs b/stack-core/src/engine.rs index 8c0382a5..74f09224 100644 --- a/stack-core/src/engine.rs +++ b/stack-core/src/engine.rs @@ -5,6 +5,8 @@ use std::{ time::{Duration, Instant}, }; +use serde::Serialize; + use crate::{ context::Context, expr::{Expr, ExprKind, FnScope}, @@ -350,7 +352,7 @@ impl Engine { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize)] pub struct RunError { pub reason: RunErrorReason, pub context: Context, @@ -371,7 +373,7 @@ impl fmt::Display for RunError { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub enum RunErrorReason { StackUnderflow, DoubleError, diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 41ac6c89..00dadf6f 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -3,26 +3,20 @@ use std::collections::HashMap; use compact_str::CompactString; use internment::Intern; -use serde::ser::{Serialize, SerializeMap, SerializeTuple}; +use serde::{ + ser::{SerializeMap, SerializeTuple}, + Serialize, +}; use yansi::Paint; use crate::{lexer::Span, scope::Scope, source::Source, symbol::Symbol}; -#[derive(Clone)] +#[derive(Clone, Serialize)] pub struct Expr { pub kind: ExprKind, pub info: Option, } -impl Serialize for Expr { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.kind.serialize(serializer) - } -} - impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Expr {{ kind: ExprKind::{:?} }}", self.kind) @@ -560,7 +554,7 @@ impl fmt::Display for ErrorInner { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct ExprInfo { pub source: Source, pub span: Span, diff --git a/stack-core/src/lexer.rs b/stack-core/src/lexer.rs index 56e9f563..d6894ad4 100644 --- a/stack-core/src/lexer.rs +++ b/stack-core/src/lexer.rs @@ -1,5 +1,7 @@ use core::{fmt, ops::Range}; +use serde::Serialize; + use crate::source::Source; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -14,7 +16,7 @@ impl fmt::Display for Token { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct Span { /// The lower byte bound (inclusive). pub start: usize, diff --git a/stack-core/src/source.rs b/stack-core/src/source.rs index 5e96f3b8..7cfed526 100644 --- a/stack-core/src/source.rs +++ b/stack-core/src/source.rs @@ -3,6 +3,7 @@ use core::{fmt, num::NonZeroUsize}; use std::{fs, io, path::Path, sync::Arc}; +use serde::Serialize; use unicode_segmentation::UnicodeSegmentation; /// Contains metadata for a source. @@ -11,6 +12,15 @@ use unicode_segmentation::UnicodeSegmentation; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Source(Arc); +impl Serialize for Source { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } +} + impl Source { /// Creates a new [`Source`]. pub fn new(name: N, source: S) -> Self @@ -126,7 +136,7 @@ impl fmt::Display for Location { } } -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Serialize)] struct SourceInner { name: String, source: String, From 38e6c586ad57b5be849608161ecf5afdca06e1d2 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 15:41:11 -0400 Subject: [PATCH 08/26] update serialization of the API response --- stack-cli/src/main.rs | 89 +++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index 2d2078b9..c16af850 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -233,14 +233,19 @@ fn main() { let eng_mutex = Rc::new(Mutex::new(Engine::new())); let ctx_mutex = Rc::new(Mutex::new(Context::new())); - #[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] + #[derive(Debug, Clone, Deserialize)] #[serde(tag = "type", content = "code", rename_all = "lowercase")] enum Incoming { + /// Run code within the existing engine + Run(String), /// Run code within a new engine #[serde(rename = "run_new")] RunNew(String), - /// Run code within the existing engine - Run(String), + + /// Exports the stack + Stack, + /// Exports the current scope + Scope, /// Clear the stack #[serde(rename = "clear_stack")] @@ -253,6 +258,24 @@ fn main() { ClearAll, } + #[derive(Debug, Clone, Serialize)] + #[serde(tag = "error", content = "value", rename_all = "lowercase")] + enum OutgoingError { + /// Error from the Engine + #[serde(rename = "run_error")] + RunError(RunError), + } + + #[derive(Debug, Clone, Serialize)] + #[serde(tag = "type", content = "value", rename_all = "lowercase")] + enum Outgoing { + /// The last item of the stack + Ok(Expr), + + /// An error + Error(OutgoingError), + } + listen("127.0.0.1:5001", |out| { let eng_mutex = eng_mutex.clone(); let ctx_mutex = ctx_mutex.clone(); @@ -279,20 +302,22 @@ fn main() { Ok(ctx) => { *guard = ctx; - if let Some(expr) = guard.stack().last() { - if let Ok(string) = serde_json::to_string(expr) { - out.send(string) - } else { - todo!("failed serde json") - } - } else { - todo!("no last item") - } + let expr = guard + .stack() + .last() + .cloned() + .unwrap_or_else(|| ExprKind::Nil.into()); + + out.send( + serde_json::to_string(&Outgoing::Ok(expr)).unwrap(), + ) } - Err(error) => match serde_json::to_string(&error) { - Ok(string) => out.send(string), - Err(_) => todo!(), - }, + Err(error) => out.send( + serde_json::to_string(&Outgoing::Error( + OutgoingError::RunError(error), + )) + .unwrap(), + ), } } _ => todo!("mutex not lock"), @@ -312,25 +337,31 @@ fn main() { Ok(ctx) => { *guard = ctx; - if let Some(expr) = guard.stack().last() { - if let Ok(string) = serde_json::to_string(expr) { - out.send(string) - } else { - todo!("failed serde json") - } - } else { - todo!("no last item") - } + let expr = guard + .stack() + .last() + .cloned() + .unwrap_or_else(|| ExprKind::Nil.into()); + + out.send( + serde_json::to_string(&Outgoing::Ok(expr)).unwrap(), + ) } - Err(error) => match serde_json::to_string(&error) { - Ok(string) => out.send(string), - Err(_) => todo!(), - }, + Err(error) => out.send( + serde_json::to_string(&Outgoing::Error( + OutgoingError::RunError(error), + )) + .unwrap(), + ), } } _ => todo!("mutex not lock"), } } + + Incoming::Stack => todo!(), + Incoming::Scope => todo!(), + Incoming::ClearStack => todo!(), Incoming::ClearScope => todo!(), Incoming::ClearAll => todo!(), From 6c8b406330f9051564fc98bc5f896bea4e556ee9 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 16:03:20 -0400 Subject: [PATCH 09/26] update incoming and outgoing responses --- stack-cli/src/main.rs | 82 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index c16af850..530739b8 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -1,5 +1,6 @@ use core::fmt; use std::{ + collections::HashMap, io::{self, prelude::Write, Read}, mem, path::{Path, PathBuf}, @@ -264,15 +265,32 @@ fn main() { /// Error from the Engine #[serde(rename = "run_error")] RunError(RunError), + + /// Error from the command reader + #[serde(rename = "command_error")] + CommandError(String), } #[derive(Debug, Clone, Serialize)] - #[serde(tag = "type", content = "value", rename_all = "lowercase")] + #[serde(tag = "status", content = "value", rename_all = "lowercase")] enum Outgoing { - /// The last item of the stack - Ok(Expr), + /// A Expr + #[serde(rename = "ok")] + Single(Expr), + + /// A Null Response + #[serde(rename = "ok")] + Null(()), + + /// A Vec of Exprs + #[serde(rename = "ok")] + Many(Vec), + + /// A Map of Exprs + #[serde(rename = "ok")] + Map(HashMap), - /// An error + /// An Error Error(OutgoingError), } @@ -302,15 +320,16 @@ fn main() { Ok(ctx) => { *guard = ctx; - let expr = guard - .stack() - .last() - .cloned() - .unwrap_or_else(|| ExprKind::Nil.into()); - - out.send( - serde_json::to_string(&Outgoing::Ok(expr)).unwrap(), - ) + match guard.stack().last().cloned() { + Some(expr) => out.send( + serde_json::to_string(&Outgoing::Single(expr)) + .unwrap(), + ), + None => out.send( + serde_json::to_string(&Outgoing::Null(())) + .unwrap(), + ), + } } Err(error) => out.send( serde_json::to_string(&Outgoing::Error( @@ -344,7 +363,8 @@ fn main() { .unwrap_or_else(|| ExprKind::Nil.into()); out.send( - serde_json::to_string(&Outgoing::Ok(expr)).unwrap(), + serde_json::to_string(&Outgoing::Single(expr)) + .unwrap(), ) } Err(error) => out.send( @@ -359,14 +379,42 @@ fn main() { } } - Incoming::Stack => todo!(), - Incoming::Scope => todo!(), + Incoming::Stack => match ctx_mutex.try_lock() { + Ok(context) => out.send( + serde_json::to_string(&Outgoing::Many( + context.stack().to_vec(), + )) + .unwrap(), + ), + Err(_) => todo!(), + }, + Incoming::Scope => match ctx_mutex.try_lock() { + Ok(context) => { + let mut scope: HashMap = HashMap::new(); + for (k, v) in context.scope().items.iter() { + scope.insert( + k.to_string(), + v.borrow().val().clone().unwrap(), + ); + } + + out.send( + serde_json::to_string(&Outgoing::Map(scope)).unwrap(), + ) + } + Err(_) => todo!(), + }, Incoming::ClearStack => todo!(), Incoming::ClearScope => todo!(), Incoming::ClearAll => todo!(), }, - Err(parse_error) => todo!("parse error"), + Err(parse_error) => out.send( + serde_json::to_string(&Outgoing::Error( + OutgoingError::CommandError(parse_error.to_string()), + )) + .unwrap(), + ), } } else { todo!("message not text") From d6110dcd0fc591607ff4ef3096220f4b8191d313 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 16:14:16 -0400 Subject: [PATCH 10/26] code splitting and refactoring --- stack-cli/src/lib.rs | 1 + stack-cli/src/main.rs | 204 +--------------------------------------- stack-cli/src/server.rs | 204 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 201 deletions(-) create mode 100644 stack-cli/src/lib.rs create mode 100644 stack-cli/src/server.rs diff --git a/stack-cli/src/lib.rs b/stack-cli/src/lib.rs new file mode 100644 index 00000000..74f47ad3 --- /dev/null +++ b/stack-cli/src/lib.rs @@ -0,0 +1 @@ +pub mod server; diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index 530739b8..e5c0b8a0 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -1,11 +1,8 @@ use core::fmt; use std::{ - collections::HashMap, io::{self, prelude::Write, Read}, - mem, path::{Path, PathBuf}, - rc::Rc, - sync::{Arc, Mutex}, + sync::Arc, }; use clap::Parser; @@ -26,8 +23,8 @@ use notify::{ Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher, }; use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal}; +use stack_cli::server::listen; use stack_core::prelude::*; -use ws::Message; fn main() { let cli = Cli::parse(); @@ -227,202 +224,7 @@ fn main() { } } } - Subcommand::Serve => { - use serde::{Deserialize, Serialize}; - use ws::listen; - - let eng_mutex = Rc::new(Mutex::new(Engine::new())); - let ctx_mutex = Rc::new(Mutex::new(Context::new())); - - #[derive(Debug, Clone, Deserialize)] - #[serde(tag = "type", content = "code", rename_all = "lowercase")] - enum Incoming { - /// Run code within the existing engine - Run(String), - /// Run code within a new engine - #[serde(rename = "run_new")] - RunNew(String), - - /// Exports the stack - Stack, - /// Exports the current scope - Scope, - - /// Clear the stack - #[serde(rename = "clear_stack")] - ClearStack, - /// Clear the scope - #[serde(rename = "clear_scope")] - ClearScope, - /// Clear everything - #[serde(rename = "clear")] - ClearAll, - } - - #[derive(Debug, Clone, Serialize)] - #[serde(tag = "error", content = "value", rename_all = "lowercase")] - enum OutgoingError { - /// Error from the Engine - #[serde(rename = "run_error")] - RunError(RunError), - - /// Error from the command reader - #[serde(rename = "command_error")] - CommandError(String), - } - - #[derive(Debug, Clone, Serialize)] - #[serde(tag = "status", content = "value", rename_all = "lowercase")] - enum Outgoing { - /// A Expr - #[serde(rename = "ok")] - Single(Expr), - - /// A Null Response - #[serde(rename = "ok")] - Null(()), - - /// A Vec of Exprs - #[serde(rename = "ok")] - Many(Vec), - - /// A Map of Exprs - #[serde(rename = "ok")] - Map(HashMap), - - /// An Error - Error(OutgoingError), - } - - listen("127.0.0.1:5001", |out| { - let eng_mutex = eng_mutex.clone(); - let ctx_mutex = ctx_mutex.clone(); - - move |msg| { - if let Message::Text(string) = msg { - let request = serde_json::from_str::(&string); - - match request { - Ok(incoming) => match incoming { - Incoming::RunNew(code) => { - let source = Source::new("runner", code); - let mut lexer = Lexer::new(source); - let exprs = parse(&mut lexer).unwrap(); - - match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { - (Ok(engine), Ok(mut guard)) => { - let _ = mem::replace(&mut *guard, Context::new()); - - let context = mem::take(&mut *guard); - let result = engine.run(context, exprs); - - match result { - Ok(ctx) => { - *guard = ctx; - - match guard.stack().last().cloned() { - Some(expr) => out.send( - serde_json::to_string(&Outgoing::Single(expr)) - .unwrap(), - ), - None => out.send( - serde_json::to_string(&Outgoing::Null(())) - .unwrap(), - ), - } - } - Err(error) => out.send( - serde_json::to_string(&Outgoing::Error( - OutgoingError::RunError(error), - )) - .unwrap(), - ), - } - } - _ => todo!("mutex not lock"), - } - } - Incoming::Run(code) => { - let source = Source::new("runner", code); - let mut lexer = Lexer::new(source); - let exprs = parse(&mut lexer).unwrap(); - - match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { - (Ok(engine), Ok(mut guard)) => { - let context = mem::take(&mut *guard); - let result = engine.run(context, exprs); - - match result { - Ok(ctx) => { - *guard = ctx; - - let expr = guard - .stack() - .last() - .cloned() - .unwrap_or_else(|| ExprKind::Nil.into()); - - out.send( - serde_json::to_string(&Outgoing::Single(expr)) - .unwrap(), - ) - } - Err(error) => out.send( - serde_json::to_string(&Outgoing::Error( - OutgoingError::RunError(error), - )) - .unwrap(), - ), - } - } - _ => todo!("mutex not lock"), - } - } - - Incoming::Stack => match ctx_mutex.try_lock() { - Ok(context) => out.send( - serde_json::to_string(&Outgoing::Many( - context.stack().to_vec(), - )) - .unwrap(), - ), - Err(_) => todo!(), - }, - Incoming::Scope => match ctx_mutex.try_lock() { - Ok(context) => { - let mut scope: HashMap = HashMap::new(); - for (k, v) in context.scope().items.iter() { - scope.insert( - k.to_string(), - v.borrow().val().clone().unwrap(), - ); - } - - out.send( - serde_json::to_string(&Outgoing::Map(scope)).unwrap(), - ) - } - Err(_) => todo!(), - }, - - Incoming::ClearStack => todo!(), - Incoming::ClearScope => todo!(), - Incoming::ClearAll => todo!(), - }, - Err(parse_error) => out.send( - serde_json::to_string(&Outgoing::Error( - OutgoingError::CommandError(parse_error.to_string()), - )) - .unwrap(), - ), - } - } else { - todo!("message not text") - } - } - }) - .unwrap(); - } + Subcommand::Serve => listen(), } } diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs new file mode 100644 index 00000000..d87049ec --- /dev/null +++ b/stack-cli/src/server.rs @@ -0,0 +1,204 @@ +use stack_core::prelude::*; +use std::{collections::HashMap, mem, rc::Rc, sync::Mutex}; + +use serde::{Deserialize, Serialize}; +use ws::Message; + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum Incoming { + Run(RunPayload), + RunNew(RunPayload), + Stack(BasePayload), + Scope(BasePayload), + ClearStack(BasePayload), + ClearScope(BasePayload), + Clear(BasePayload), +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RunPayload { + pub id: u32, + pub code: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct BasePayload { + pub id: u32, +} + +impl Incoming { + pub fn id(&self) -> u32 { + match self { + Incoming::Run(payload) | Incoming::RunNew(payload) => payload.id, + Incoming::Stack(payload) + | Incoming::Scope(payload) + | Incoming::ClearStack(payload) + | Incoming::ClearScope(payload) + | Incoming::Clear(payload) => payload.id, + } + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "error", content = "value", rename_all = "lowercase")] +pub enum OutgoingError { + /// Error from the Engine + #[serde(rename = "run_error")] + RunError(RunError), + + /// Error from the command reader + #[serde(rename = "command_error")] + CommandError(String), +} + +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "status", content = "value", rename_all = "lowercase")] +pub enum Outgoing { + /// A Expr + #[serde(rename = "ok")] + Single(Expr), + + /// A Null Response + #[serde(rename = "ok")] + Null(()), + + /// A Vec of Exprs + #[serde(rename = "ok")] + Many(Vec), + + /// A Map of Exprs + #[serde(rename = "ok")] + Map(HashMap), + + /// An Error + Error(OutgoingError), +} + +pub fn listen() { + let eng_mutex = Rc::new(Mutex::new(Engine::new())); + let ctx_mutex = Rc::new(Mutex::new(Context::new())); + + ws::listen("127.0.0.1:5001", |out| { + let eng_mutex = eng_mutex.clone(); + let ctx_mutex = ctx_mutex.clone(); + + move |msg| { + if let Message::Text(string) = msg { + let request = serde_json::from_str::(&string); + + match request { + Ok(incoming) => match incoming { + Incoming::RunNew(RunPayload { id, code }) => { + let source = Source::new("runner", code); + let mut lexer = Lexer::new(source); + let exprs = parse(&mut lexer).unwrap(); + + match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { + (Ok(engine), Ok(mut guard)) => { + let _ = mem::replace(&mut *guard, Context::new()); + + let context = mem::take(&mut *guard); + let result = engine.run(context, exprs); + + match result { + Ok(ctx) => { + *guard = ctx; + + match guard.stack().last().cloned() { + Some(expr) => out.send( + serde_json::to_string(&Outgoing::Single(expr)) + .unwrap(), + ), + None => out.send( + serde_json::to_string(&Outgoing::Null(())).unwrap(), + ), + } + } + Err(error) => out.send( + serde_json::to_string(&Outgoing::Error( + OutgoingError::RunError(error), + )) + .unwrap(), + ), + } + } + _ => todo!("mutex not lock"), + } + } + Incoming::Run(RunPayload { id, code }) => { + let source = Source::new("runner", code); + let mut lexer = Lexer::new(source); + let exprs = parse(&mut lexer).unwrap(); + + match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { + (Ok(engine), Ok(mut guard)) => { + let context = mem::take(&mut *guard); + let result = engine.run(context, exprs); + + match result { + Ok(ctx) => { + *guard = ctx; + + let expr = guard + .stack() + .last() + .cloned() + .unwrap_or_else(|| ExprKind::Nil.into()); + + out.send( + serde_json::to_string(&Outgoing::Single(expr)).unwrap(), + ) + } + Err(error) => out.send( + serde_json::to_string(&Outgoing::Error( + OutgoingError::RunError(error), + )) + .unwrap(), + ), + } + } + _ => todo!("mutex not lock"), + } + } + + Incoming::Stack(BasePayload { id }) => match ctx_mutex.try_lock() { + Ok(context) => out.send( + serde_json::to_string(&Outgoing::Many( + context.stack().to_vec(), + )) + .unwrap(), + ), + Err(_) => todo!(), + }, + Incoming::Scope(BasePayload { id }) => match ctx_mutex.try_lock() { + Ok(context) => { + let mut scope: HashMap = HashMap::new(); + for (k, v) in context.scope().items.iter() { + scope + .insert(k.to_string(), v.borrow().val().clone().unwrap()); + } + + out.send(serde_json::to_string(&Outgoing::Map(scope)).unwrap()) + } + Err(_) => todo!(), + }, + + Incoming::ClearStack(BasePayload { id }) => todo!(), + Incoming::ClearScope(BasePayload { id }) => todo!(), + Incoming::Clear(BasePayload { id }) => todo!(), + }, + Err(parse_error) => out.send( + serde_json::to_string(&Outgoing::Error( + OutgoingError::CommandError(parse_error.to_string()), + )) + .unwrap(), + ), + } + } else { + todo!("message not text") + } + } + }) + .unwrap(); +} From 1915e961e4b78c8797f05d50718c64922a8767c1 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 16:32:14 -0400 Subject: [PATCH 11/26] refactor outgoing messages --- stack-cli/src/server.rs | 183 ++++++++++++++++++++++++++++++--------- stack-core/src/engine.rs | 4 +- stack-core/src/expr.rs | 2 +- 3 files changed, 145 insertions(+), 44 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index d87049ec..c337f571 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -41,40 +41,104 @@ impl Incoming { } #[derive(Debug, Clone, Serialize)] -#[serde(tag = "error", content = "value", rename_all = "lowercase")] +#[serde(tag = "error", rename_all = "snake_case")] pub enum OutgoingError { - /// Error from the Engine - #[serde(rename = "run_error")] - RunError(RunError), + RunError(RunErrorPayload), + CommandError(CommandErrorPayload), +} - /// Error from the command reader - #[serde(rename = "command_error")] - CommandError(String), +#[derive(Debug, Clone, Serialize)] +pub struct PublicContext { + pub stack: Vec, + pub scopes: Vec>, + pub sources: HashMap, } #[derive(Debug, Clone, Serialize)] -#[serde(tag = "status", content = "value", rename_all = "lowercase")] -pub enum Outgoing { - /// A Expr - #[serde(rename = "ok")] - Single(Expr), +pub struct PublicRunError { + pub reason: RunErrorReason, + pub context: Vec, + pub expr: Expr, +} - /// A Null Response - #[serde(rename = "ok")] - Null(()), +impl From for PublicRunError { + fn from(value: RunError) -> Self { + Self { + reason: value.reason, + context: value.context.stack().to_vec(), + expr: value.expr, + } + } +} - /// A Vec of Exprs - #[serde(rename = "ok")] - Many(Vec), +#[derive(Debug, Clone, Serialize)] +pub struct RunErrorPayload { + pub for_id: u32, + pub value: PublicRunError, +} - /// A Map of Exprs - #[serde(rename = "ok")] - Map(HashMap), +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CommandErrorPayload { + pub for_id: u32, + pub value: String, +} - /// An Error +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "status", rename_all = "snake_case")] +pub enum Outgoing { + Ok(OkPayload), Error(OutgoingError), } +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum OkPayload { + Single(SinglePayload), + Null(NullPayload), + Many(ManyPayload), + Map(MapPayload), +} + +#[derive(Debug, Clone, Serialize)] +pub struct SinglePayload { + pub for_id: u32, + pub value: Expr, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NullPayload { + pub for_id: u32, +} + +#[derive(Debug, Clone, Serialize)] +pub struct ManyPayload { + pub for_id: u32, + pub value: Vec, +} + +#[derive(Debug, Clone, Serialize)] +pub struct MapPayload { + pub for_id: u32, + pub value: HashMap, +} + +impl Outgoing { + pub fn for_id(&self) -> u32 { + match self { + Outgoing::Ok(payload) => match payload { + OkPayload::Single(p) => p.for_id, + OkPayload::Null(p) => p.for_id, + OkPayload::Many(p) => p.for_id, + OkPayload::Map(p) => p.for_id, + }, + Outgoing::Error(error) => match error { + OutgoingError::RunError(p) => p.for_id, + OutgoingError::CommandError(p) => p.for_id, + }, + } + } +} + pub fn listen() { let eng_mutex = Rc::new(Mutex::new(Engine::new())); let ctx_mutex = Rc::new(Mutex::new(Context::new())); @@ -107,17 +171,28 @@ pub fn listen() { match guard.stack().last().cloned() { Some(expr) => out.send( - serde_json::to_string(&Outgoing::Single(expr)) - .unwrap(), + serde_json::to_string(&Outgoing::Ok( + OkPayload::Single(SinglePayload { + for_id: id, + value: expr, + }), + )) + .unwrap(), ), None => out.send( - serde_json::to_string(&Outgoing::Null(())).unwrap(), + serde_json::to_string(&Outgoing::Ok( + OkPayload::Null(NullPayload { for_id: id }), + )) + .unwrap(), ), } } Err(error) => out.send( serde_json::to_string(&Outgoing::Error( - OutgoingError::RunError(error), + OutgoingError::RunError(RunErrorPayload { + for_id: id, + value: error.into(), + }), )) .unwrap(), ), @@ -140,19 +215,30 @@ pub fn listen() { Ok(ctx) => { *guard = ctx; - let expr = guard - .stack() - .last() - .cloned() - .unwrap_or_else(|| ExprKind::Nil.into()); - - out.send( - serde_json::to_string(&Outgoing::Single(expr)).unwrap(), - ) + match guard.stack().last().cloned() { + Some(expr) => out.send( + serde_json::to_string(&Outgoing::Ok( + OkPayload::Single(SinglePayload { + for_id: id, + value: expr, + }), + )) + .unwrap(), + ), + None => out.send( + serde_json::to_string(&Outgoing::Ok( + OkPayload::Null(NullPayload { for_id: id }), + )) + .unwrap(), + ), + } } Err(error) => out.send( serde_json::to_string(&Outgoing::Error( - OutgoingError::RunError(error), + OutgoingError::RunError(RunErrorPayload { + for_id: id, + value: error.into(), + }), )) .unwrap(), ), @@ -164,9 +250,12 @@ pub fn listen() { Incoming::Stack(BasePayload { id }) => match ctx_mutex.try_lock() { Ok(context) => out.send( - serde_json::to_string(&Outgoing::Many( - context.stack().to_vec(), - )) + serde_json::to_string(&Outgoing::Ok(OkPayload::Many( + ManyPayload { + for_id: id, + value: context.stack().to_vec(), + }, + ))) .unwrap(), ), Err(_) => todo!(), @@ -179,7 +268,15 @@ pub fn listen() { .insert(k.to_string(), v.borrow().val().clone().unwrap()); } - out.send(serde_json::to_string(&Outgoing::Map(scope)).unwrap()) + out.send( + serde_json::to_string(&Outgoing::Ok(OkPayload::Map( + MapPayload { + for_id: id, + value: scope, + }, + ))) + .unwrap(), + ) } Err(_) => todo!(), }, @@ -190,7 +287,11 @@ pub fn listen() { }, Err(parse_error) => out.send( serde_json::to_string(&Outgoing::Error( - OutgoingError::CommandError(parse_error.to_string()), + OutgoingError::CommandError(CommandErrorPayload { + // TODO: we don't get an ID here so this is a special case + for_id: 0, + value: parse_error.to_string(), + }), )) .unwrap(), ), diff --git a/stack-core/src/engine.rs b/stack-core/src/engine.rs index 74f09224..24b916a2 100644 --- a/stack-core/src/engine.rs +++ b/stack-core/src/engine.rs @@ -5,7 +5,7 @@ use std::{ time::{Duration, Instant}, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::{ context::Context, @@ -373,7 +373,7 @@ impl fmt::Display for RunError { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum RunErrorReason { StackUnderflow, DoubleError, diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 00dadf6f..7c282ff4 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -5,7 +5,7 @@ use compact_str::CompactString; use internment::Intern; use serde::{ ser::{SerializeMap, SerializeTuple}, - Serialize, + Deserialize, Serialize, }; use yansi::Paint; From d44b66a84dbafd80e8f715659590edc467a36c8b Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 16:33:43 -0400 Subject: [PATCH 12/26] remove unused declarations --- stack-cli/src/server.rs | 13 +------------ stack-core/src/expr.rs | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index c337f571..902b0147 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -11,9 +11,6 @@ pub enum Incoming { RunNew(RunPayload), Stack(BasePayload), Scope(BasePayload), - ClearStack(BasePayload), - ClearScope(BasePayload), - Clear(BasePayload), } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -31,11 +28,7 @@ impl Incoming { pub fn id(&self) -> u32 { match self { Incoming::Run(payload) | Incoming::RunNew(payload) => payload.id, - Incoming::Stack(payload) - | Incoming::Scope(payload) - | Incoming::ClearStack(payload) - | Incoming::ClearScope(payload) - | Incoming::Clear(payload) => payload.id, + Incoming::Stack(payload) | Incoming::Scope(payload) => payload.id, } } } @@ -280,10 +273,6 @@ pub fn listen() { } Err(_) => todo!(), }, - - Incoming::ClearStack(BasePayload { id }) => todo!(), - Incoming::ClearScope(BasePayload { id }) => todo!(), - Incoming::Clear(BasePayload { id }) => todo!(), }, Err(parse_error) => out.send( serde_json::to_string(&Outgoing::Error( diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 7c282ff4..00dadf6f 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -5,7 +5,7 @@ use compact_str::CompactString; use internment::Intern; use serde::{ ser::{SerializeMap, SerializeTuple}, - Deserialize, Serialize, + Serialize, }; use yansi::Paint; From 2845b692b9873018149cc720ddc309bb96335002 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 17:21:38 -0400 Subject: [PATCH 13/26] wip: implement deserialize for everything --- stack-cli/src/server.rs | 30 +-------- stack-core/src/expr.rs | 133 +++++++++++++++++++++++++++++++++++++-- stack-core/src/lexer.rs | 4 +- stack-core/src/scope.rs | 50 +++++++++++++++ stack-core/src/source.rs | 18 +++++- stack-core/src/symbol.rs | 41 ++++++++++++ 6 files changed, 241 insertions(+), 35 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index 902b0147..fdf7351c 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -40,34 +40,10 @@ pub enum OutgoingError { CommandError(CommandErrorPayload), } -#[derive(Debug, Clone, Serialize)] -pub struct PublicContext { - pub stack: Vec, - pub scopes: Vec>, - pub sources: HashMap, -} - -#[derive(Debug, Clone, Serialize)] -pub struct PublicRunError { - pub reason: RunErrorReason, - pub context: Vec, - pub expr: Expr, -} - -impl From for PublicRunError { - fn from(value: RunError) -> Self { - Self { - reason: value.reason, - context: value.context.stack().to_vec(), - expr: value.expr, - } - } -} - #[derive(Debug, Clone, Serialize)] pub struct RunErrorPayload { pub for_id: u32, - pub value: PublicRunError, + pub value: RunError, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -184,7 +160,7 @@ pub fn listen() { serde_json::to_string(&Outgoing::Error( OutgoingError::RunError(RunErrorPayload { for_id: id, - value: error.into(), + value: error, }), )) .unwrap(), @@ -230,7 +206,7 @@ pub fn listen() { serde_json::to_string(&Outgoing::Error( OutgoingError::RunError(RunErrorPayload { for_id: id, - value: error.into(), + value: error, }), )) .unwrap(), diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 00dadf6f..2ee2a0c3 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -1,17 +1,19 @@ use core::{cmp::Ordering, fmt, hash::Hash, ops}; use std::collections::HashMap; +use std::str::FromStr; use compact_str::CompactString; use internment::Intern; +use serde::de::{self, Deserializer, MapAccess, Visitor}; +use serde::Deserialize; use serde::{ ser::{SerializeMap, SerializeTuple}, Serialize, }; -use yansi::Paint; use crate::{lexer::Span, scope::Scope, source::Source, symbol::Symbol}; -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct Expr { pub kind: ExprKind, pub info: Option, @@ -102,7 +104,7 @@ pub fn display_fn_scope(scope: &FnScope) -> String { .into() } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Deserialize)] pub enum FnScope { Scoped(Scope), Scopeless, @@ -179,6 +181,127 @@ impl Serialize for ExprKind { } } +impl<'de> Deserialize<'de> for ExprKind { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ExprKindVisitor; + + impl<'de> Visitor<'de> for ExprKindVisitor { + type Value = ExprKind; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an ExprKind variant") + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let variant = map.next_key::()?.ok_or_else(|| { + de::Error::invalid_value(de::Unexpected::Map, &"variant name") + })?; + + match variant.as_str() { + "Nil" => Ok(ExprKind::Nil), + "Boolean" => { + let value = map.next_value()?; + Ok(ExprKind::Boolean(value)) + } + "Integer" => { + let value = map.next_value()?; + Ok(ExprKind::Integer(value)) + } + "Float" => { + let value = map.next_value()?; + Ok(ExprKind::Float(value)) + } + "String" => { + let value: String = map.next_value()?; + Ok(ExprKind::String( + CompactString::from_str(value.as_str()).unwrap(), + )) + } + "Symbol" => { + let value: String = map.next_value()?; + Ok(ExprKind::Symbol(Symbol::from_ref(value.as_str()))) + } + "Lazy" => { + let value: Expr = map.next_value()?; + Ok(ExprKind::Lazy(Box::new(value.into()))) + } + "List" => { + let value: Vec = map.next_value()?; + Ok(ExprKind::List(value)) + } + "Record" => { + let mut value: HashMap = map.next_value()?; + let mut map: HashMap = HashMap::new(); + for (k, v) in value.drain() { + map.insert(Symbol::from_ref(k.as_str()), v); + } + + Ok(ExprKind::Record(map)) + } + "Function" => { + let mut scope = todo!("Deserialize FnScope"); + let mut body = Vec::new(); + while let Some(key) = map.next_key::()? { + match key.as_str() { + "scope" => scope = map.next_value()?, + "body" => body = map.next_value()?, + _ => { + return Err(de::Error::unknown_field( + &key, + &["scope", "body"], + )) + } + } + } + Ok(ExprKind::Function { scope, body }) + } + "SExpr" => { + let mut call = todo!("Deserialize Symbol"); + let mut body = Vec::new(); + while let Some(key) = map.next_key::()? { + match key.as_str() { + "call" => call = map.next_value()?, + "body" => body = map.next_value()?, + _ => { + return Err(de::Error::unknown_field(&key, &["call", "body"])) + } + } + } + Ok(ExprKind::SExpr { call, body }) + } + "Underscore" => Ok(ExprKind::Underscore), + _ => Err(de::Error::unknown_variant( + &variant, + &[ + "Nil", + "Boolean", + "Integer", + "Float", + "String", + "Symbol", + "Lazy", + "List", + "Record", + "Function", + "SExpr", + "Underscore", + ], + )), + } + } + } + + const FIELDS: &[&str] = &["type", "value"]; + deserializer.deserialize_struct("ExprKind", FIELDS, ExprKindVisitor) + } +} + impl ExprKind { #[inline] pub const fn is_nil(&self) -> bool { @@ -380,6 +503,8 @@ impl ops::Rem for ExprKind { impl fmt::Display for ExprKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use yansi::Paint; + // TODO: Is there a nicer way to do this that avoids the duplication? if f.alternate() { match self { @@ -554,7 +679,7 @@ impl fmt::Display for ErrorInner { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ExprInfo { pub source: Source, pub span: Span, diff --git a/stack-core/src/lexer.rs b/stack-core/src/lexer.rs index d6894ad4..770f47a6 100644 --- a/stack-core/src/lexer.rs +++ b/stack-core/src/lexer.rs @@ -1,6 +1,6 @@ use core::{fmt, ops::Range}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::source::Source; @@ -16,7 +16,7 @@ impl fmt::Display for Token { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { /// The lower byte bound (inclusive). pub start: usize, diff --git a/stack-core/src/scope.rs b/stack-core/src/scope.rs index 11b7cc23..64a62dab 100644 --- a/stack-core/src/scope.rs +++ b/stack-core/src/scope.rs @@ -1,6 +1,11 @@ use core::fmt; use std::{cell::RefCell, collections::HashMap, fmt::Formatter, sync::Arc}; +use serde::{ + de::{MapAccess, Visitor}, + Deserialize, Deserializer, +}; + use crate::{chain::Chain, expr::FnScope, prelude::*}; pub type Val = Arc>>>; @@ -10,6 +15,51 @@ pub struct Scope { pub items: HashMap, } +impl<'de> Deserialize<'de> for Scope { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Helper struct to deserialize the items + #[derive(Deserialize)] + struct ScopeHelper { + items: HashMap, + } + + // Helper enum to deserialize Val + #[derive(Deserialize)] + #[serde(untagged)] + enum DeserializeVal { + Some(Expr), + None, + } + + // Deserialize into the helper struct + let helper = ScopeHelper::deserialize(deserializer)?; + + // Convert DeserializeVal to Val + let mut items: HashMap = helper + .items + .into_iter() + .map(|(k, v)| { + let val = match v { + DeserializeVal::Some(expr) => { + Arc::new(RefCell::new(Chain::new(Some(expr)))) + } + DeserializeVal::None => Arc::new(RefCell::new(Chain::new(None))), + }; + (k, val) + }) + .collect(); + let mut scope: HashMap = HashMap::new(); + for (k, v) in items.drain() { + scope.insert(Symbol::from_ref(k.as_str()), v); + } + + Ok(Scope { items: scope }) + } +} + impl fmt::Debug for Scope { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let iter = self.items.iter().map(|(name, item)| (name.as_str(), item)); diff --git a/stack-core/src/source.rs b/stack-core/src/source.rs index 7cfed526..0b1eae4e 100644 --- a/stack-core/src/source.rs +++ b/stack-core/src/source.rs @@ -3,7 +3,7 @@ use core::{fmt, num::NonZeroUsize}; use std::{fs, io, path::Path, sync::Arc}; -use serde::Serialize; +use serde::{Deserialize, Deserializer, Serialize}; use unicode_segmentation::UnicodeSegmentation; /// Contains metadata for a source. @@ -21,6 +21,19 @@ impl Serialize for Source { } } +impl<'de> Deserialize<'de> for Source { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // First, deserialize SourceInner + let inner = SourceInner::deserialize(deserializer)?; + + // Then wrap it in an Arc and return Source + Ok(Source(Arc::new(inner))) + } +} + impl Source { /// Creates a new [`Source`]. pub fn new(name: N, source: S) -> Self @@ -136,7 +149,8 @@ impl fmt::Display for Location { } } -#[derive(Debug, Clone, Eq, Serialize)] +#[derive(Debug, Clone, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] struct SourceInner { name: String, source: String, diff --git a/stack-core/src/symbol.rs b/stack-core/src/symbol.rs index 56b66fe2..9a7671fc 100644 --- a/stack-core/src/symbol.rs +++ b/stack-core/src/symbol.rs @@ -2,6 +2,10 @@ use core::{borrow::Borrow, fmt, hash::Hash}; use compact_str::{CompactString, ToCompactString}; use internment::Intern; +use serde::{ + de::{self, Visitor}, + Deserialize, Deserializer, +}; use crate::expr::ExprKind; @@ -9,6 +13,43 @@ use crate::expr::ExprKind; #[repr(transparent)] pub struct Symbol(Intern); +impl<'de> Deserialize<'de> for Symbol { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SymbolVisitor; + + impl<'de> Visitor<'de> for SymbolVisitor { + type Value = Symbol; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + // Convert the &str to CompactString and intern it + let compact_string = CompactString::new(value); + Ok(Symbol(Intern::new(compact_string))) + } + + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + // Convert the String to CompactString and intern it + let compact_string = CompactString::new(value); + Ok(Symbol(Intern::new(compact_string))) + } + } + + deserializer.deserialize_str(SymbolVisitor) + } +} + impl Symbol { /// Creates a [`Symbol`]. #[inline] From 744e45921cf38791101fa895597ea16ca8bad95e Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 17:24:59 -0400 Subject: [PATCH 14/26] clear warnings --- stack-core/src/expr.rs | 6 +++--- stack-core/src/journal.rs | 8 +++++--- stack-core/src/scope.rs | 5 +---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 2ee2a0c3..4158b399 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -229,7 +229,7 @@ impl<'de> Deserialize<'de> for ExprKind { } "Lazy" => { let value: Expr = map.next_value()?; - Ok(ExprKind::Lazy(Box::new(value.into()))) + Ok(ExprKind::Lazy(Box::new(value))) } "List" => { let value: Vec = map.next_value()?; @@ -245,7 +245,7 @@ impl<'de> Deserialize<'de> for ExprKind { Ok(ExprKind::Record(map)) } "Function" => { - let mut scope = todo!("Deserialize FnScope"); + let mut scope: FnScope = map.next_value()?; let mut body = Vec::new(); while let Some(key) = map.next_key::()? { match key.as_str() { @@ -262,7 +262,7 @@ impl<'de> Deserialize<'de> for ExprKind { Ok(ExprKind::Function { scope, body }) } "SExpr" => { - let mut call = todo!("Deserialize Symbol"); + let mut call: Symbol = map.next_value()?; let mut body = Vec::new(); while let Some(key) = map.next_key::()? { match key.as_str() { diff --git a/stack-core/src/journal.rs b/stack-core/src/journal.rs index deb372a0..f7793488 100644 --- a/stack-core/src/journal.rs +++ b/stack-core/src/journal.rs @@ -1,13 +1,15 @@ use core::fmt; use std::collections::HashMap; +use serde::Deserialize; + use crate::{ expr::{Expr, ExprInfo, ExprKind}, scope::Scope, symbol::Symbol, }; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Deserialize)] pub struct JournalEntry { pub ops: Vec, pub scope_level: usize, @@ -39,7 +41,7 @@ impl JournalEntry { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Deserialize)] pub enum JournalOp { Call(Expr), SCall(Expr), @@ -123,7 +125,7 @@ impl From for JournalScope { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Deserialize)] // TODO: implement this as a ring buffer with max_commits so we never go over pub struct Journal { ops: Vec, diff --git a/stack-core/src/scope.rs b/stack-core/src/scope.rs index 64a62dab..11de5517 100644 --- a/stack-core/src/scope.rs +++ b/stack-core/src/scope.rs @@ -1,10 +1,7 @@ use core::fmt; use std::{cell::RefCell, collections::HashMap, fmt::Formatter, sync::Arc}; -use serde::{ - de::{MapAccess, Visitor}, - Deserialize, Deserializer, -}; +use serde::{Deserialize, Deserializer}; use crate::{chain::Chain, expr::FnScope, prelude::*}; From 61f71be3028667c34d4f8b671421c4fab0e32ea6 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 17:26:48 -0400 Subject: [PATCH 15/26] use Rc's instead of Arc's --- stack-core/src/chain.rs | 18 +++++++++--------- stack-core/src/context.rs | 4 ++-- stack-core/src/scope.rs | 14 +++++++------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/stack-core/src/chain.rs b/stack-core/src/chain.rs index f34a390f..1d57a950 100644 --- a/stack-core/src/chain.rs +++ b/stack-core/src/chain.rs @@ -1,10 +1,10 @@ use core::{cell::RefCell, fmt}; -use std::{borrow::BorrowMut, sync::Arc}; +use std::{borrow::BorrowMut, rc::Rc}; #[derive(PartialEq, Clone)] pub struct Chain { - value: Arc>, - child: Option>>>, + value: Rc>, + child: Option>>>, root: bool, } @@ -20,14 +20,14 @@ where impl Chain { pub fn new(value: T) -> Self { Self { - value: Arc::new(RefCell::new(value)), + value: Rc::new(RefCell::new(value)), child: None, root: true, } } - pub fn link(&mut self) -> Arc> { - let child = Arc::new(RefCell::new(Self { + pub fn link(&mut self) -> Rc> { + let child = Rc::new(RefCell::new(Self { value: self.value.clone(), child: None, root: false, @@ -37,7 +37,7 @@ impl Chain { child } - pub fn root(&self) -> Arc> { + pub fn root(&self) -> Rc> { self.value.clone() } @@ -54,7 +54,7 @@ where self.value.borrow().clone() } - fn unlink_with_rc(&mut self, value: Arc>, new_root: bool) { + fn unlink_with_rc(&mut self, value: Rc>, new_root: bool) { let mut new_root = new_root; if new_root { @@ -70,7 +70,7 @@ where } pub fn unlink_with(&mut self, val: T) { - self.unlink_with_rc(Arc::new(RefCell::new(val)), true); + self.unlink_with_rc(Rc::new(RefCell::new(val)), true); } pub fn set(&mut self, val: T) { diff --git a/stack-core/src/context.rs b/stack-core/src/context.rs index 1ee7b132..a5bcb350 100644 --- a/stack-core/src/context.rs +++ b/stack-core/src/context.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, sync::Arc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; use serde::ser::{Serialize, SerializeMap}; @@ -175,7 +175,7 @@ impl Context { #[inline] pub fn scope_items( &self, - ) -> impl Iterator>>>)> { + ) -> impl Iterator>>>)> { self.scopes.last().items.iter() } diff --git a/stack-core/src/scope.rs b/stack-core/src/scope.rs index 11de5517..bdf93aa5 100644 --- a/stack-core/src/scope.rs +++ b/stack-core/src/scope.rs @@ -1,11 +1,11 @@ use core::fmt; -use std::{cell::RefCell, collections::HashMap, fmt::Formatter, sync::Arc}; +use std::{cell::RefCell, collections::HashMap, fmt::Formatter, rc::Rc}; use serde::{Deserialize, Deserializer}; use crate::{chain::Chain, expr::FnScope, prelude::*}; -pub type Val = Arc>>>; +pub type Val = Rc>>>; #[derive(Default, PartialEq)] pub struct Scope { @@ -41,9 +41,9 @@ impl<'de> Deserialize<'de> for Scope { .map(|(k, v)| { let val = match v { DeserializeVal::Some(expr) => { - Arc::new(RefCell::new(Chain::new(Some(expr)))) + Rc::new(RefCell::new(Chain::new(Some(expr)))) } - DeserializeVal::None => Arc::new(RefCell::new(Chain::new(None))), + DeserializeVal::None => Rc::new(RefCell::new(Chain::new(None))), }; (k, val) }) @@ -65,7 +65,7 @@ impl fmt::Debug for Scope { } impl Clone for Scope { - /// Clones the scope, using the same Arc's as self + /// Clones the scope, using the same Rc's as self fn clone(&self) -> Self { let mut items = HashMap::new(); @@ -100,7 +100,7 @@ impl Scope { c.clone() } else { - let val = Arc::new(RefCell::new(Chain::new(Some(item)))); + let val = Rc::new(RefCell::new(Chain::new(Some(item)))); self.items.insert(name, val.clone()); val @@ -111,7 +111,7 @@ impl Scope { self .items .entry(name) - .or_insert_with(|| Arc::new(RefCell::new(Chain::new(None)))); + .or_insert_with(|| Rc::new(RefCell::new(Chain::new(None)))); } pub fn set( From 1dac9082df5fec7df262c45e2bd912a7d0172f09 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 17:32:53 -0400 Subject: [PATCH 16/26] implement sending context over the wire --- stack-cli/src/server.rs | 44 ++++++++++++++++++++++++++++++++------- stack-core/src/context.rs | 7 +++++-- stack-core/src/engine.rs | 2 +- stack-core/src/vec_one.rs | 6 +++++- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index fdf7351c..c3e98ffc 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -7,10 +7,14 @@ use ws::Message; #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum Incoming { + // Execution Run(RunPayload), RunNew(RunPayload), + + // Querying Stack(BasePayload), Scope(BasePayload), + Context(BasePayload), } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -28,19 +32,21 @@ impl Incoming { pub fn id(&self) -> u32 { match self { Incoming::Run(payload) | Incoming::RunNew(payload) => payload.id, - Incoming::Stack(payload) | Incoming::Scope(payload) => payload.id, + Incoming::Stack(payload) + | Incoming::Scope(payload) + | Incoming::Context(payload) => payload.id, } } } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "error", rename_all = "snake_case")] pub enum OutgoingError { RunError(RunErrorPayload), CommandError(CommandErrorPayload), } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct RunErrorPayload { pub for_id: u32, pub value: RunError, @@ -52,23 +58,24 @@ pub struct CommandErrorPayload { pub value: String, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "status", rename_all = "snake_case")] pub enum Outgoing { Ok(OkPayload), Error(OutgoingError), } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum OkPayload { Single(SinglePayload), Null(NullPayload), Many(ManyPayload), Map(MapPayload), + Context(ContextPayload), } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct SinglePayload { pub for_id: u32, pub value: Expr, @@ -79,18 +86,24 @@ pub struct NullPayload { pub for_id: u32, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ManyPayload { pub for_id: u32, pub value: Vec, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct MapPayload { pub for_id: u32, pub value: HashMap, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ContextPayload { + pub for_id: u32, + pub value: Context, +} + impl Outgoing { pub fn for_id(&self) -> u32 { match self { @@ -99,6 +112,7 @@ impl Outgoing { OkPayload::Null(p) => p.for_id, OkPayload::Many(p) => p.for_id, OkPayload::Map(p) => p.for_id, + OkPayload::Context(p) => p.for_id, }, Outgoing::Error(error) => match error { OutgoingError::RunError(p) => p.for_id, @@ -249,6 +263,20 @@ pub fn listen() { } Err(_) => todo!(), }, + Incoming::Context(BasePayload { id }) => { + match ctx_mutex.try_lock() { + Ok(context) => out.send( + serde_json::to_string(&Outgoing::Ok(OkPayload::Context( + ContextPayload { + for_id: id, + value: context.clone(), + }, + ))) + .unwrap(), + ), + Err(_) => todo!(), + } + } }, Err(parse_error) => out.send( serde_json::to_string(&Outgoing::Error( diff --git a/stack-core/src/context.rs b/stack-core/src/context.rs index a5bcb350..1cebd983 100644 --- a/stack-core/src/context.rs +++ b/stack-core/src/context.rs @@ -1,6 +1,9 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use serde::ser::{Serialize, SerializeMap}; +use serde::{ + ser::{Serialize, SerializeMap}, + Deserialize, +}; use crate::{ chain::Chain, @@ -14,7 +17,7 @@ use crate::{ }; // TODO: This API could be a lot nicer. -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Deserialize)] pub struct Context { stack: Vec, scopes: VecOne, diff --git a/stack-core/src/engine.rs b/stack-core/src/engine.rs index 24b916a2..3080e5a7 100644 --- a/stack-core/src/engine.rs +++ b/stack-core/src/engine.rs @@ -352,7 +352,7 @@ impl Engine { } } -#[derive(Debug, Clone, PartialEq, Serialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct RunError { pub reason: RunErrorReason, pub context: Context, diff --git a/stack-core/src/vec_one.rs b/stack-core/src/vec_one.rs index 3d55cc48..9462ee36 100644 --- a/stack-core/src/vec_one.rs +++ b/stack-core/src/vec_one.rs @@ -3,8 +3,12 @@ use core::slice::{Iter, IterMut, SliceIndex}; use std::vec::IntoIter; +use serde::Deserialize; + /// A [`Vec`] with at least one element. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[derive( + Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Deserialize, +)] pub(crate) struct VecOne { vec: Vec, } From 791f70d91c8183fc7cfab3389ff12a922cc515ac Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 17:48:44 -0400 Subject: [PATCH 17/26] implement serialization for context-related types --- stack-cli/src/server.rs | 25 +------------------------ stack-core/src/context.rs | 18 ++---------------- stack-core/src/journal.rs | 8 ++++---- stack-core/src/scope.rs | 20 +++++++++++++++++++- stack-core/src/symbol.rs | 12 +++++++++++- stack-core/src/vec_one.rs | 13 +++++++++++-- 6 files changed, 48 insertions(+), 48 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index c3e98ffc..0198e19a 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -13,7 +13,6 @@ pub enum Incoming { // Querying Stack(BasePayload), - Scope(BasePayload), Context(BasePayload), } @@ -32,9 +31,7 @@ impl Incoming { pub fn id(&self) -> u32 { match self { Incoming::Run(payload) | Incoming::RunNew(payload) => payload.id, - Incoming::Stack(payload) - | Incoming::Scope(payload) - | Incoming::Context(payload) => payload.id, + Incoming::Stack(payload) | Incoming::Context(payload) => payload.id, } } } @@ -243,26 +240,6 @@ pub fn listen() { ), Err(_) => todo!(), }, - Incoming::Scope(BasePayload { id }) => match ctx_mutex.try_lock() { - Ok(context) => { - let mut scope: HashMap = HashMap::new(); - for (k, v) in context.scope().items.iter() { - scope - .insert(k.to_string(), v.borrow().val().clone().unwrap()); - } - - out.send( - serde_json::to_string(&Outgoing::Ok(OkPayload::Map( - MapPayload { - for_id: id, - value: scope, - }, - ))) - .unwrap(), - ) - } - Err(_) => todo!(), - }, Incoming::Context(BasePayload { id }) => { match ctx_mutex.try_lock() { Ok(context) => out.send( diff --git a/stack-core/src/context.rs b/stack-core/src/context.rs index 1cebd983..93b72ea8 100644 --- a/stack-core/src/context.rs +++ b/stack-core/src/context.rs @@ -1,9 +1,6 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use serde::{ - ser::{Serialize, SerializeMap}, - Deserialize, -}; +use serde::{Deserialize, Serialize}; use crate::{ chain::Chain, @@ -17,7 +14,7 @@ use crate::{ }; // TODO: This API could be a lot nicer. -#[derive(Debug, Clone, PartialEq, Default, Deserialize)] +#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] pub struct Context { stack: Vec, scopes: VecOne, @@ -25,17 +22,6 @@ pub struct Context { sources: HashMap, } -impl Serialize for Context { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut record = serializer.serialize_map(Some(1))?; - record.serialize_entry("stack", &self.stack)?; - record.end() - } -} - impl Context { #[inline] pub fn new() -> Self { diff --git a/stack-core/src/journal.rs b/stack-core/src/journal.rs index f7793488..dff6ea7a 100644 --- a/stack-core/src/journal.rs +++ b/stack-core/src/journal.rs @@ -1,7 +1,7 @@ use core::fmt; use std::collections::HashMap; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use crate::{ expr::{Expr, ExprInfo, ExprKind}, @@ -9,7 +9,7 @@ use crate::{ symbol::Symbol, }; -#[derive(Debug, Clone, PartialEq, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct JournalEntry { pub ops: Vec, pub scope_level: usize, @@ -41,7 +41,7 @@ impl JournalEntry { } } -#[derive(Debug, Clone, PartialEq, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum JournalOp { Call(Expr), SCall(Expr), @@ -125,7 +125,7 @@ impl From for JournalScope { } } -#[derive(Debug, Clone, PartialEq, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] // TODO: implement this as a ring buffer with max_commits so we never go over pub struct Journal { ops: Vec, diff --git a/stack-core/src/scope.rs b/stack-core/src/scope.rs index bdf93aa5..1fad6138 100644 --- a/stack-core/src/scope.rs +++ b/stack-core/src/scope.rs @@ -1,7 +1,10 @@ use core::fmt; use std::{cell::RefCell, collections::HashMap, fmt::Formatter, rc::Rc}; -use serde::{Deserialize, Deserializer}; +use serde::{ + ser::{Serialize, SerializeMap}, + Deserialize, Deserializer, +}; use crate::{chain::Chain, expr::FnScope, prelude::*}; @@ -12,6 +15,21 @@ pub struct Scope { pub items: HashMap, } +impl Serialize for Scope { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut map = serializer.serialize_map(Some(self.items.len()))?; + for (k, v) in self.items.iter() { + // TODO: don't unwrap and handle the error somehow + let expr: Expr = v.borrow().val().unwrap(); + map.serialize_entry(k, &expr)?; + } + map.end() + } +} + impl<'de> Deserialize<'de> for Scope { fn deserialize(deserializer: D) -> Result where diff --git a/stack-core/src/symbol.rs b/stack-core/src/symbol.rs index 9a7671fc..0db01b92 100644 --- a/stack-core/src/symbol.rs +++ b/stack-core/src/symbol.rs @@ -4,7 +4,7 @@ use compact_str::{CompactString, ToCompactString}; use internment::Intern; use serde::{ de::{self, Visitor}, - Deserialize, Deserializer, + Deserialize, Deserializer, Serialize, }; use crate::expr::ExprKind; @@ -13,6 +13,16 @@ use crate::expr::ExprKind; #[repr(transparent)] pub struct Symbol(Intern); +impl Serialize for Symbol { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + // TODO: is this okay to make Symbol transparently a string? + serializer.serialize_str(self.as_str()) + } +} + impl<'de> Deserialize<'de> for Symbol { fn deserialize(deserializer: D) -> Result where diff --git a/stack-core/src/vec_one.rs b/stack-core/src/vec_one.rs index 9462ee36..f72717b5 100644 --- a/stack-core/src/vec_one.rs +++ b/stack-core/src/vec_one.rs @@ -3,11 +3,20 @@ use core::slice::{Iter, IterMut, SliceIndex}; use std::vec::IntoIter; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; /// A [`Vec`] with at least one element. #[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Deserialize, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Default, + Serialize, + Deserialize, )] pub(crate) struct VecOne { vec: Vec, From aee9a8df6534a58dcb97295098e5f30e179e0ab0 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 18:39:33 -0400 Subject: [PATCH 18/26] add test for serialization --- Cargo.lock | 2 ++ Cargo.toml | 3 ++- stack-cli/Cargo.toml | 2 +- stack-core/src/context.rs | 20 ++++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10cc9713..7cd49507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -917,6 +917,7 @@ dependencies = [ "itoa", "rustversion", "ryu", + "serde", "static_assertions", ] @@ -3400,6 +3401,7 @@ dependencies = [ "compact_str", "internment", "serde", + "serde_json", "test-case", "unicode-segmentation", "yansi", diff --git a/Cargo.toml b/Cargo.toml index 270b427f..2591731a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,9 @@ members = ["stack-core", "stack-std", "stack-cli", "stack-debugger"] [workspace.dependencies] unicode-segmentation = "1" -compact_str = "=0.8.0-beta" +compact_str = { version = "=0.8.0-beta", features = ["serde"] } test-case = "3" clap = { version = "4", features = ["derive"] } serde = { version = "1.0.204", features = ["derive"] } +serde_json = "1.0.121" diff --git a/stack-cli/Cargo.toml b/stack-cli/Cargo.toml index b71542f1..a41a874a 100644 --- a/stack-cli/Cargo.toml +++ b/stack-cli/Cargo.toml @@ -20,7 +20,7 @@ codespan-reporting = "0.11.1" # server serde = { workspace = true } ws = { version = "0.9.2" } -serde_json = "1.0.121" +serde_json.workspace = true [[bin]] name = "stack" diff --git a/stack-core/src/context.rs b/stack-core/src/context.rs index 93b72ea8..a1318521 100644 --- a/stack-core/src/context.rs +++ b/stack-core/src/context.rs @@ -241,3 +241,23 @@ impl Context { self.scopes.try_pop(); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ser_and_de() { + let mut context = Context::new(); + context.stack_push(ExprKind::Integer(2).into()).unwrap(); + context.def_scope_item( + Symbol::from_ref("foo"), + ExprKind::Symbol(Symbol::from_ref("bar")).into(), + ); + + let json = serde_json::to_string(&context).unwrap(); + let ser_context: Context = serde_json::from_str(json.as_str()).unwrap(); + + assert_eq!(context, ser_context); + } +} From 442f0a45a6f69fe792be378d233625a837fcb671 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 18:39:51 -0400 Subject: [PATCH 19/26] use derived serialization for expr --- stack-core/src/expr.rs | 171 +---------------------------------------- 1 file changed, 3 insertions(+), 168 deletions(-) diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 4158b399..52124125 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -1,15 +1,10 @@ use core::{cmp::Ordering, fmt, hash::Hash, ops}; use std::collections::HashMap; -use std::str::FromStr; use compact_str::CompactString; use internment::Intern; -use serde::de::{self, Deserializer, MapAccess, Visitor}; use serde::Deserialize; -use serde::{ - ser::{SerializeMap, SerializeTuple}, - Serialize, -}; +use serde::Serialize; use crate::{lexer::Span, scope::Scope, source::Source, symbol::Symbol}; @@ -104,7 +99,7 @@ pub fn display_fn_scope(scope: &FnScope) -> String { .into() } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum FnScope { Scoped(Scope), Scopeless, @@ -122,7 +117,7 @@ impl FnScope { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum ExprKind { Nil, @@ -142,166 +137,6 @@ pub enum ExprKind { Underscore, } -impl Serialize for ExprKind { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - ExprKind::Nil => serializer.serialize_unit(), - ExprKind::Boolean(v) => serializer.serialize_bool(*v), - ExprKind::Integer(v) => serializer.serialize_i64(*v), - ExprKind::Float(v) => serializer.serialize_f64(*v), - ExprKind::String(v) => serializer.serialize_str(v.as_str()), - // TODO: Symbol serialization isn't 1:1, as it's turned into a str here. - // Is that what we want? - ExprKind::Symbol(v) => serializer.serialize_str(v.as_str()), - ExprKind::Lazy(inner) => inner.kind.serialize(serializer), - ExprKind::List(v) => { - let mut tup = serializer.serialize_tuple(v.len())?; - for item in v.iter() { - tup.serialize_element(&item.kind)?; - } - tup.end() - } - ExprKind::Record(v) => { - let mut record = serializer.serialize_map(Some(v.len()))?; - for (key, val) in v.iter() { - let key = key.as_str(); - record.serialize_entry(key, &val.kind)?; - } - record.end() - } - - // We won't serialize these for now since they aren't really datatypes. - ExprKind::Function { .. } => serializer.serialize_unit(), - ExprKind::SExpr { .. } => serializer.serialize_unit(), - ExprKind::Underscore => serializer.serialize_unit(), - } - } -} - -impl<'de> Deserialize<'de> for ExprKind { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct ExprKindVisitor; - - impl<'de> Visitor<'de> for ExprKindVisitor { - type Value = ExprKind; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("an ExprKind variant") - } - - fn visit_map(self, mut map: V) -> Result - where - V: MapAccess<'de>, - { - let variant = map.next_key::()?.ok_or_else(|| { - de::Error::invalid_value(de::Unexpected::Map, &"variant name") - })?; - - match variant.as_str() { - "Nil" => Ok(ExprKind::Nil), - "Boolean" => { - let value = map.next_value()?; - Ok(ExprKind::Boolean(value)) - } - "Integer" => { - let value = map.next_value()?; - Ok(ExprKind::Integer(value)) - } - "Float" => { - let value = map.next_value()?; - Ok(ExprKind::Float(value)) - } - "String" => { - let value: String = map.next_value()?; - Ok(ExprKind::String( - CompactString::from_str(value.as_str()).unwrap(), - )) - } - "Symbol" => { - let value: String = map.next_value()?; - Ok(ExprKind::Symbol(Symbol::from_ref(value.as_str()))) - } - "Lazy" => { - let value: Expr = map.next_value()?; - Ok(ExprKind::Lazy(Box::new(value))) - } - "List" => { - let value: Vec = map.next_value()?; - Ok(ExprKind::List(value)) - } - "Record" => { - let mut value: HashMap = map.next_value()?; - let mut map: HashMap = HashMap::new(); - for (k, v) in value.drain() { - map.insert(Symbol::from_ref(k.as_str()), v); - } - - Ok(ExprKind::Record(map)) - } - "Function" => { - let mut scope: FnScope = map.next_value()?; - let mut body = Vec::new(); - while let Some(key) = map.next_key::()? { - match key.as_str() { - "scope" => scope = map.next_value()?, - "body" => body = map.next_value()?, - _ => { - return Err(de::Error::unknown_field( - &key, - &["scope", "body"], - )) - } - } - } - Ok(ExprKind::Function { scope, body }) - } - "SExpr" => { - let mut call: Symbol = map.next_value()?; - let mut body = Vec::new(); - while let Some(key) = map.next_key::()? { - match key.as_str() { - "call" => call = map.next_value()?, - "body" => body = map.next_value()?, - _ => { - return Err(de::Error::unknown_field(&key, &["call", "body"])) - } - } - } - Ok(ExprKind::SExpr { call, body }) - } - "Underscore" => Ok(ExprKind::Underscore), - _ => Err(de::Error::unknown_variant( - &variant, - &[ - "Nil", - "Boolean", - "Integer", - "Float", - "String", - "Symbol", - "Lazy", - "List", - "Record", - "Function", - "SExpr", - "Underscore", - ], - )), - } - } - } - - const FIELDS: &[&str] = &["type", "value"]; - deserializer.deserialize_struct("ExprKind", FIELDS, ExprKindVisitor) - } -} - impl ExprKind { #[inline] pub const fn is_nil(&self) -> bool { From 438f5fb94c510a54be429e7929261e381ed4b43d Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 21:05:21 -0400 Subject: [PATCH 20/26] add serialization test for engine (e2e) --- stack-core/Cargo.toml | 1 + stack-core/src/engine.rs | 16 ++++++++++++++++ stack-core/src/expr.rs | 11 +++++++++++ stack-core/src/scope.rs | 23 ++++++++++++++++++++++- 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/stack-core/Cargo.toml b/stack-core/Cargo.toml index 111ddd4f..87f19513 100644 --- a/stack-core/Cargo.toml +++ b/stack-core/Cargo.toml @@ -12,3 +12,4 @@ serde.workspace = true [dev-dependencies] test-case.workspace = true +serde_json.workspace = true diff --git a/stack-core/src/engine.rs b/stack-core/src/engine.rs index 3080e5a7..384424d7 100644 --- a/stack-core/src/engine.rs +++ b/stack-core/src/engine.rs @@ -615,4 +615,20 @@ mod tests { vec![&ExprKind::Integer(1), &ExprKind::Integer(2),] ); } + + #[test] + fn test_ser_and_de() { + let source = Source::new("", "0 'a def 2 2 + '(fn)"); + let mut lexer = Lexer::new(source); + let exprs = crate::parser::parse(&mut lexer).unwrap(); + + let engine = Engine::new(); + let mut context = Context::new().with_stack_capacity(32); + context = engine.run(context, exprs).unwrap(); + + let json = serde_json::to_string(&context).unwrap(); + let ser_context: Context = serde_json::from_str(json.as_str()).unwrap(); + + assert_eq!(context, ser_context); + } } diff --git a/stack-core/src/expr.rs b/stack-core/src/expr.rs index 52124125..b8636470 100644 --- a/stack-core/src/expr.rs +++ b/stack-core/src/expr.rs @@ -217,6 +217,17 @@ impl PartialEq for ExprKind { (Self::List(lhs), Self::List(rhs)) => lhs == rhs, (Self::Record(lhs), Self::Record(rhs)) => lhs == rhs, + ( + Self::Function { + scope: lhs_scope, + body: lhs_body, + }, + Self::Function { + scope: rhs_scope, + body: rhs_body, + }, + ) => lhs_scope == rhs_scope && lhs_body == rhs_body, + ( Self::SExpr { call: lhs_call, diff --git a/stack-core/src/scope.rs b/stack-core/src/scope.rs index 1fad6138..0f1c4b01 100644 --- a/stack-core/src/scope.rs +++ b/stack-core/src/scope.rs @@ -10,11 +10,31 @@ use crate::{chain::Chain, expr::FnScope, prelude::*}; pub type Val = Rc>>>; -#[derive(Default, PartialEq)] +#[derive(Default)] pub struct Scope { pub items: HashMap, } +impl PartialEq for Scope { + fn eq(&self, other: &Self) -> bool { + let a: HashMap = HashMap::from_iter( + self + .items + .iter() + .map(|(k, v)| (*k, v.borrow().val().clone().unwrap())), + ); + + let b: HashMap = HashMap::from_iter( + other + .items + .iter() + .map(|(k, v)| (*k, v.borrow().val().clone().unwrap())), + ); + + a == b + } +} + impl Serialize for Scope { fn serialize(&self, serializer: S) -> Result where @@ -37,6 +57,7 @@ impl<'de> Deserialize<'de> for Scope { { // Helper struct to deserialize the items #[derive(Deserialize)] + #[serde(transparent)] struct ScopeHelper { items: HashMap, } From e8eb19bb9830c94bdad68c72e840654c0a9a1597 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 31 Jul 2024 22:15:41 -0400 Subject: [PATCH 21/26] wip: print results to terminal --- stack-cli/src/lib.rs | 57 +++++++++ stack-cli/src/main.rs | 59 +-------- stack-cli/src/server.rs | 265 +++++++++++++++++++--------------------- 3 files changed, 185 insertions(+), 196 deletions(-) diff --git a/stack-cli/src/lib.rs b/stack-cli/src/lib.rs index 74f47ad3..87721235 100644 --- a/stack-cli/src/lib.rs +++ b/stack-cli/src/lib.rs @@ -1 +1,58 @@ +use core::fmt; +use std::io::{self, prelude::Write}; + +use crossterm::{ + cursor::{self, MoveTo}, + style::Print, + terminal, QueueableCommand, +}; +use stack_core::prelude::*; + pub mod server; + +pub fn ok_or_exit(result: Result) -> T +where + E: fmt::Display, +{ + match result { + Ok(x) => x, + Err(e) => { + eprintln!("error: {e}"); + std::process::exit(1); + } + } +} + +pub fn print_stack(context: &Context) { + print!("stack:"); + + core::iter::repeat(" ") + .zip(context.stack()) + .for_each(|(sep, x)| print!("{sep}{x:#}")); + + println!() +} + +pub fn eprint_stack(context: &Context) { + eprint!("stack:"); + + core::iter::repeat(" ") + .zip(context.stack()) + .for_each(|(sep, x)| eprint!("{sep}{x:#}")); + + eprintln!() +} + +pub fn clear_screen() -> io::Result<()> { + let mut stdout = std::io::stdout(); + + stdout.queue(cursor::Hide)?; + let (_, num_lines) = terminal::size()?; + for _ in 0..2 * num_lines { + stdout.queue(Print("\n"))?; + } + stdout.queue(MoveTo(0, 0))?; + stdout.queue(cursor::Show)?; + + stdout.flush() +} diff --git a/stack-cli/src/main.rs b/stack-cli/src/main.rs index e5c0b8a0..3f90ca8c 100644 --- a/stack-cli/src/main.rs +++ b/stack-cli/src/main.rs @@ -1,6 +1,5 @@ -use core::fmt; use std::{ - io::{self, prelude::Write, Read}, + io::Read, path::{Path, PathBuf}, sync::Arc, }; @@ -14,16 +13,13 @@ use codespan_reporting::{ termcolor::{ColorChoice, StandardStream}, }, }; -use crossterm::{ - cursor::{self, MoveTo}, - style::Print, - terminal, QueueableCommand, -}; use notify::{ Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher, }; use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal}; -use stack_cli::server::listen; +use stack_cli::{ + clear_screen, eprint_stack, ok_or_exit, print_stack, server::listen, +}; use stack_core::prelude::*; fn main() { @@ -228,53 +224,6 @@ fn main() { } } -fn ok_or_exit(result: Result) -> T -where - E: fmt::Display, -{ - match result { - Ok(x) => x, - Err(e) => { - eprintln!("error: {e}"); - std::process::exit(1); - } - } -} - -fn print_stack(context: &Context) { - print!("stack:"); - - core::iter::repeat(" ") - .zip(context.stack()) - .for_each(|(sep, x)| print!("{sep}{x:#}")); - - println!() -} - -fn eprint_stack(context: &Context) { - eprint!("stack:"); - - core::iter::repeat(" ") - .zip(context.stack()) - .for_each(|(sep, x)| eprint!("{sep}{x:#}")); - - eprintln!() -} - -fn clear_screen() -> io::Result<()> { - let mut stdout = std::io::stdout(); - - stdout.queue(cursor::Hide)?; - let (_, num_lines) = terminal::size()?; - for _ in 0..2 * num_lines { - stdout.queue(Print("\n"))?; - } - stdout.queue(MoveTo(0, 0))?; - stdout.queue(cursor::Show)?; - - stdout.flush() -} - #[derive(Debug, Clone, PartialEq, Eq, Default, clap::Parser)] #[command(author, version, about, long_about = None)] #[command(propagate_version = true)] diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index 0198e19a..37b9cfb2 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -2,7 +2,9 @@ use stack_core::prelude::*; use std::{collections::HashMap, mem, rc::Rc, sync::Mutex}; use serde::{Deserialize, Serialize}; -use ws::Message; +use ws::{Message, Sender}; + +use crate::{eprint_stack, print_stack}; #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(tag = "type", rename_all = "snake_case")] @@ -119,157 +121,138 @@ impl Outgoing { } } -pub fn listen() { - let eng_mutex = Rc::new(Mutex::new(Engine::new())); - let ctx_mutex = Rc::new(Mutex::new(Context::new())); - - ws::listen("127.0.0.1:5001", |out| { - let eng_mutex = eng_mutex.clone(); - let ctx_mutex = ctx_mutex.clone(); - - move |msg| { - if let Message::Text(string) = msg { - let request = serde_json::from_str::(&string); - - match request { - Ok(incoming) => match incoming { - Incoming::RunNew(RunPayload { id, code }) => { - let source = Source::new("runner", code); - let mut lexer = Lexer::new(source); - let exprs = parse(&mut lexer).unwrap(); +fn run( + code: String, + eng_mutex: Rc>, + ctx_mutex: Rc>, + out: Sender, + id: u32, + reset: bool, +) -> ws::Result<()> { + let source = Source::new("runner", code); + let mut lexer = Lexer::new(source); + let exprs = parse(&mut lexer).unwrap(); - match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { - (Ok(engine), Ok(mut guard)) => { - let _ = mem::replace(&mut *guard, Context::new()); + match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { + (Ok(engine), Ok(mut guard)) => { + if reset { + let _ = mem::replace(&mut *guard, Context::new()); + } - let context = mem::take(&mut *guard); - let result = engine.run(context, exprs); + let context = mem::take(&mut *guard); + let result = engine.run(context, exprs); - match result { - Ok(ctx) => { - *guard = ctx; + match result { + Ok(ctx) => { + print_stack(&ctx); + *guard = ctx; - match guard.stack().last().cloned() { - Some(expr) => out.send( - serde_json::to_string(&Outgoing::Ok( - OkPayload::Single(SinglePayload { - for_id: id, - value: expr, - }), - )) - .unwrap(), - ), - None => out.send( - serde_json::to_string(&Outgoing::Ok( - OkPayload::Null(NullPayload { for_id: id }), - )) - .unwrap(), - ), - } - } - Err(error) => out.send( - serde_json::to_string(&Outgoing::Error( - OutgoingError::RunError(RunErrorPayload { - for_id: id, - value: error, - }), - )) - .unwrap(), - ), - } - } - _ => todo!("mutex not lock"), - } - } - Incoming::Run(RunPayload { id, code }) => { - let source = Source::new("runner", code); - let mut lexer = Lexer::new(source); - let exprs = parse(&mut lexer).unwrap(); + match guard.stack().last().cloned() { + Some(expr) => out.send( + serde_json::to_string(&Outgoing::Ok(OkPayload::Single( + SinglePayload { + for_id: id, + value: expr, + }, + ))) + .unwrap(), + ), + None => out.send( + serde_json::to_string(&Outgoing::Ok(OkPayload::Null( + NullPayload { for_id: id }, + ))) + .unwrap(), + ), + } + } + Err(e) => { + eprintln!("error: {e}"); + eprint_stack(&e.context); - match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { - (Ok(engine), Ok(mut guard)) => { - let context = mem::take(&mut *guard); - let result = engine.run(context, exprs); + out.send( + serde_json::to_string(&Outgoing::Error(OutgoingError::RunError( + RunErrorPayload { + for_id: id, + value: e, + }, + ))) + .unwrap(), + ) + } + } + } + _ => todo!("mutex not lock"), + } +} - match result { - Ok(ctx) => { - *guard = ctx; +pub fn handle( + out: Sender, + msg: Message, + eng_mutex: Rc>, + ctx_mutex: Rc>, +) -> ws::Result<()> { + if let Message::Text(string) = msg { + let request = serde_json::from_str::(&string); - match guard.stack().last().cloned() { - Some(expr) => out.send( - serde_json::to_string(&Outgoing::Ok( - OkPayload::Single(SinglePayload { - for_id: id, - value: expr, - }), - )) - .unwrap(), - ), - None => out.send( - serde_json::to_string(&Outgoing::Ok( - OkPayload::Null(NullPayload { for_id: id }), - )) - .unwrap(), - ), - } - } - Err(error) => out.send( - serde_json::to_string(&Outgoing::Error( - OutgoingError::RunError(RunErrorPayload { - for_id: id, - value: error, - }), - )) - .unwrap(), - ), - } - } - _ => todo!("mutex not lock"), - } - } + match request { + Ok(incoming) => match incoming { + Incoming::RunNew(RunPayload { id, code }) => { + run(code, eng_mutex, ctx_mutex, out, id, true) + } + Incoming::Run(RunPayload { id, code }) => { + run(code, eng_mutex, ctx_mutex, out, id, false) + } - Incoming::Stack(BasePayload { id }) => match ctx_mutex.try_lock() { - Ok(context) => out.send( - serde_json::to_string(&Outgoing::Ok(OkPayload::Many( - ManyPayload { - for_id: id, - value: context.stack().to_vec(), - }, - ))) - .unwrap(), - ), - Err(_) => todo!(), - }, - Incoming::Context(BasePayload { id }) => { - match ctx_mutex.try_lock() { - Ok(context) => out.send( - serde_json::to_string(&Outgoing::Ok(OkPayload::Context( - ContextPayload { - for_id: id, - value: context.clone(), - }, - ))) - .unwrap(), - ), - Err(_) => todo!(), - } - } - }, - Err(parse_error) => out.send( - serde_json::to_string(&Outgoing::Error( - OutgoingError::CommandError(CommandErrorPayload { - // TODO: we don't get an ID here so this is a special case - for_id: 0, - value: parse_error.to_string(), - }), - )) + Incoming::Stack(BasePayload { id }) => match ctx_mutex.try_lock() { + Ok(context) => out.send( + serde_json::to_string(&Outgoing::Ok(OkPayload::Many( + ManyPayload { + for_id: id, + value: context.stack().to_vec(), + }, + ))) .unwrap(), ), - } - } else { - todo!("message not text") - } + Err(_) => todo!(), + }, + Incoming::Context(BasePayload { id }) => match ctx_mutex.try_lock() { + Ok(context) => out.send( + serde_json::to_string(&Outgoing::Ok(OkPayload::Context( + ContextPayload { + for_id: id, + value: context.clone(), + }, + ))) + .unwrap(), + ), + Err(_) => todo!(), + }, + }, + Err(parse_error) => out.send( + serde_json::to_string(&Outgoing::Error(OutgoingError::CommandError( + CommandErrorPayload { + // TODO: we don't get an ID here so this is a special case + for_id: 0, + value: parse_error.to_string(), + }, + ))) + .unwrap(), + ), } + } else { + todo!("message not text") + } +} + +pub fn listen() { + let eng_mutex = Rc::new(Mutex::new(Engine::new())); + let ctx_mutex = Rc::new(Mutex::new(Context::new())); + + ws::listen("127.0.0.1:5001", |out| { + let eng_mutex = eng_mutex.clone(); + let ctx_mutex = ctx_mutex.clone(); + + |msg| handle(out, msg, eng_mutex, ctx_mutex) }) .unwrap(); } From 67f2433b1d366648b6ed7928c5ffafab99a325c3 Mon Sep 17 00:00:00 2001 From: Shane Date: Thu, 1 Aug 2024 16:00:44 -0400 Subject: [PATCH 22/26] fix closure handling --- stack-cli/src/server.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index 37b9cfb2..9ea6162d 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -125,12 +125,13 @@ fn run( code: String, eng_mutex: Rc>, ctx_mutex: Rc>, - out: Sender, + out: &Sender, id: u32, reset: bool, ) -> ws::Result<()> { let source = Source::new("runner", code); let mut lexer = Lexer::new(source); + // TODO: Don't unwrap on fail to parse let exprs = parse(&mut lexer).unwrap(); match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { @@ -186,8 +187,8 @@ fn run( } pub fn handle( - out: Sender, - msg: Message, + out: &Sender, + msg: &Message, eng_mutex: Rc>, ctx_mutex: Rc>, ) -> ws::Result<()> { @@ -252,7 +253,7 @@ pub fn listen() { let eng_mutex = eng_mutex.clone(); let ctx_mutex = ctx_mutex.clone(); - |msg| handle(out, msg, eng_mutex, ctx_mutex) + move |msg| handle(&out, &msg, eng_mutex.clone(), ctx_mutex.clone()) }) .unwrap(); } From 0d5399849aaf13f3929b100e8f793be66b796208 Mon Sep 17 00:00:00 2001 From: Shane Date: Thu, 1 Aug 2024 16:03:25 -0400 Subject: [PATCH 23/26] clear warnings --- stack-cli/src/server.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index 9ea6162d..fde1867e 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -121,6 +121,7 @@ impl Outgoing { } } +#[allow(clippy::result_large_err)] fn run( code: String, eng_mutex: Rc>, @@ -186,6 +187,7 @@ fn run( } } +#[allow(clippy::result_large_err)] pub fn handle( out: &Sender, msg: &Message, @@ -193,7 +195,7 @@ pub fn handle( ctx_mutex: Rc>, ) -> ws::Result<()> { if let Message::Text(string) = msg { - let request = serde_json::from_str::(&string); + let request = serde_json::from_str::(string); match request { Ok(incoming) => match incoming { From f9d4252015808d3971b573d1a898d3acf6a05803 Mon Sep 17 00:00:00 2001 From: Shane Date: Sat, 3 Aug 2024 12:06:26 -0400 Subject: [PATCH 24/26] transmit parse error --- stack-cli/src/server.rs | 24 ++++++++++++++++++++++-- stack-core/src/lexer.rs | 4 ++-- stack-core/src/parser.rs | 5 +++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index fde1867e..29e7b6aa 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -42,6 +42,7 @@ impl Incoming { #[serde(tag = "error", rename_all = "snake_case")] pub enum OutgoingError { RunError(RunErrorPayload), + ParseError(ParseErrorPayload), CommandError(CommandErrorPayload), } @@ -51,6 +52,12 @@ pub struct RunErrorPayload { pub value: RunError, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ParseErrorPayload { + pub for_id: u32, + pub value: ParseError, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CommandErrorPayload { pub for_id: u32, @@ -115,6 +122,7 @@ impl Outgoing { }, Outgoing::Error(error) => match error { OutgoingError::RunError(p) => p.for_id, + OutgoingError::ParseError(p) => p.for_id, OutgoingError::CommandError(p) => p.for_id, }, } @@ -132,8 +140,20 @@ fn run( ) -> ws::Result<()> { let source = Source::new("runner", code); let mut lexer = Lexer::new(source); - // TODO: Don't unwrap on fail to parse - let exprs = parse(&mut lexer).unwrap(); + let exprs = match parse(&mut lexer) { + Ok(e) => e, + Err(err) => { + return out.send( + serde_json::to_string(&Outgoing::Error(OutgoingError::ParseError( + ParseErrorPayload { + for_id: id, + value: err, + }, + ))) + .unwrap(), + ); + } + }; match (eng_mutex.try_lock(), ctx_mutex.try_lock()) { (Ok(engine), Ok(mut guard)) => { diff --git a/stack-core/src/lexer.rs b/stack-core/src/lexer.rs index 770f47a6..6256abaf 100644 --- a/stack-core/src/lexer.rs +++ b/stack-core/src/lexer.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::source::Source; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct Token { pub kind: TokenKind, pub span: Span, @@ -35,7 +35,7 @@ impl Span { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum TokenKind { Invalid, Eof, diff --git a/stack-core/src/parser.rs b/stack-core/src/parser.rs index bf241099..dd669e4f 100644 --- a/stack-core/src/parser.rs +++ b/stack-core/src/parser.rs @@ -1,5 +1,6 @@ use compact_str::ToCompactString; use core::fmt; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; use crate::{ @@ -256,7 +257,7 @@ fn parse_record( } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ParseError { pub source: Source, pub kind: ParseErrorKind, @@ -280,7 +281,7 @@ impl fmt::Display for ParseError { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum ParseErrorKind { UnexpectedToken(Token), InvalidLiteral(Token), From da9152115f201e3d3eb150416ad857f90a3ed44c Mon Sep 17 00:00:00 2001 From: Shane Date: Sat, 3 Aug 2024 12:11:22 -0400 Subject: [PATCH 25/26] update justfile --- justfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/justfile b/justfile index 549b8a02..2cb0f628 100644 --- a/justfile +++ b/justfile @@ -9,3 +9,9 @@ debug file: serve: cd docs; mdbook serve --open + +ws-serve: + cargo run -p stack-cli -- serve + +ws-connect: + rlwrap websocat ws://localhost:5001 From 5297ba62f67a8c44f3fdc4913064a468b54e8982 Mon Sep 17 00:00:00 2001 From: Shane Date: Sat, 3 Aug 2024 12:13:08 -0400 Subject: [PATCH 26/26] add info for server connection --- stack-cli/src/server.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stack-cli/src/server.rs b/stack-cli/src/server.rs index 29e7b6aa..103f6478 100644 --- a/stack-cli/src/server.rs +++ b/stack-cli/src/server.rs @@ -271,7 +271,8 @@ pub fn listen() { let eng_mutex = Rc::new(Mutex::new(Engine::new())); let ctx_mutex = Rc::new(Mutex::new(Context::new())); - ws::listen("127.0.0.1:5001", |out| { + println!("Websocket server running on ws://localhost:5501"); + ws::listen("localhost:5001", |out| { let eng_mutex = eng_mutex.clone(); let ctx_mutex = ctx_mutex.clone();