From ea1516fbd1eef6b6b01409bc71c13f20d8dc71c0 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 14 May 2023 23:50:27 -0400 Subject: [PATCH] Started new kv impl with support for mutable cells, just the basic interpreter. Going to add the lazy bytecode interperter next --- flake.lock | 98 ++--- flake.nix | 18 +- kv/Cargo.lock | 928 +++++++++++++++++++++++++++++++++++++++++ kv/Cargo.toml | 24 ++ kv/build.rs | 5 + kv/src/ast.rs | 350 ++++++++++++++++ kv/src/grammar.lalrpop | 31 ++ kv/src/main.rs | 17 + kv/src/test.rs | 566 +++++++++++++++++++++++++ 9 files changed, 1982 insertions(+), 55 deletions(-) create mode 100644 kv/Cargo.lock create mode 100644 kv/Cargo.toml create mode 100644 kv/build.rs create mode 100644 kv/src/ast.rs create mode 100644 kv/src/grammar.lalrpop create mode 100644 kv/src/main.rs create mode 100644 kv/src/test.rs diff --git a/flake.lock b/flake.lock index 52d0507..c4d3341 100644 --- a/flake.lock +++ b/flake.lock @@ -1,12 +1,15 @@ { "nodes": { "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1676283394, - "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -16,12 +19,15 @@ } }, "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -36,11 +42,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1678760344, - "narHash": "sha256-N8u9/O0NWt3PUQc9xmCeod1SFilOFicALjtYtslib2g=", + "lastModified": 1684117262, + "narHash": "sha256-ZSF4CZqeyk6QwTjal73KPMuTWiU6w/p8ygEimrPb7u4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "d907affef544f64bd6886fe6bcc5fa2495a82373", + "rev": "4679872d2dd3e94ffef75efcbf77ea11549d90a7", "type": "github" }, "original": { @@ -51,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1665296151, - "narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=", + "lastModified": 1681358109, + "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "14ccaaedd95a488dd7ae142757884d8e125b3363", + "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", "type": "github" }, "original": { @@ -65,43 +71,13 @@ "type": "github" } }, - "nixpkgs_stable_new": { - "locked": { - "lastModified": 1678703398, - "narHash": "sha256-Y1mW3dBsoWLHpYm+UIHb5VZ7rx024NNHaF16oZBx++o=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "67f26c1cfc5d5783628231e776a81c1ade623e0b", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "ref": "nixos-22.11", - "type": "indirect" - } - }, - "nixpkgs_stable_old": { - "locked": { - "lastModified": 1659446231, - "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "ref": "nixos-21.11", - "type": "indirect" - } - }, "nixpkgs_unstable": { "locked": { - "lastModified": 1678838343, - "narHash": "sha256-aA48yVAUyppdlVHhMStlWjB8u9uzA5iel3C47xlbkrw=", + "lastModified": 1684119138, + "narHash": "sha256-IqT3CR9pBL0Sh0Ysgs3E3j20gFUkzL8LKjN8/mIk1nc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b16f2a75619fe8e6adf4583f5fc6448bc967d482", + "rev": "44a082f3df95486b67da5609234d3c54f57ea5d0", "type": "github" }, "original": { @@ -114,10 +90,38 @@ "inputs": { "flake-utils": "flake-utils", "moz_overlay": "moz_overlay", - "nixpkgs_stable_new": "nixpkgs_stable_new", - "nixpkgs_stable_old": "nixpkgs_stable_old", "nixpkgs_unstable": "nixpkgs_unstable" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 830fe99..5dc9de8 100644 --- a/flake.nix +++ b/flake.nix @@ -2,23 +2,25 @@ description = "Env for Kraken and the extacted Koka bencmarks"; inputs = { # For some reason the newer one has broken koka/emscripten (probs same change) - nixpkgs_stable_new.url = "nixpkgs/nixos-22.11"; - nixpkgs_stable_old.url = "nixpkgs/nixos-21.11"; + #nixpkgs_stable_new.url = "nixpkgs/nixos-22.11"; + #nixpkgs_stable_old.url = "nixpkgs/nixos-21.11"; nixpkgs_unstable.url = "github:NixOS/nixpkgs"; moz_overlay.url = "github:oxalica/rust-overlay"; flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs_stable_new, nixpkgs_stable_old, nixpkgs_unstable, moz_overlay, flake-utils }: + outputs = { self, + #nixpkgs_stable_new, nixpkgs_stable_old, + nixpkgs_unstable, moz_overlay, flake-utils }: (flake-utils.lib.eachDefaultSystem (system: let pkgs_new = import nixpkgs_unstable { inherit system; overlays = [ moz_overlay.overlay ]; }; - pkgs_old = import nixpkgs_stable_old { - inherit system; - overlays = [ moz_overlay.overlay ]; - }; + #pkgs_old = import nixpkgs_stable_old { + # inherit system; + # overlays = [ moz_overlay.overlay ]; + #}; #newlisp = pkgs.stdenv.mkDerivation rec { #pname = "newLisp"; #version = "10.7.5"; @@ -102,7 +104,7 @@ #(rust-bin.stable.latest.default.override { targets = [ "wasm32-wasi" ]; }) #stack (haskellPackages.ghcWithPackages (p: [p.parallel])) koka - pkgs_old.emscripten + #pkgs_old.emscripten #picolisp #newlisp diff --git a/kv/Cargo.lock b/kv/Cargo.lock new file mode 100644 index 0000000..92edab8 --- /dev/null +++ b/kv/Cargo.lock @@ -0,0 +1,928 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cranelift" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50babaf4da30fd349e1b913760300266143535f15a0b7be7ce1ce9efafa8ff5e" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", +] + +[[package]] +name = "cranelift-bforest" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.13.2", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8" + +[[package]] +name = "cranelift-entity" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0" + +[[package]] +name = "cranelift-frontend" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba" + +[[package]] +name = "cranelift-jit" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ca96b05988aa057eda09a817a6e31915fabd7f476b513123aff08053cd193dd" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-module", + "cranelift-native", + "libc", + "log", + "region", + "target-lexicon", + "wasmtime-jit-icache-coherence", + "windows-sys 0.45.0", +] + +[[package]] +name = "cranelift-module" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5112c0be9cc5da064e0620570d67852f11ce44f2e572a58ecf7f11df73978b8" +dependencies = [ + "anyhow", + "cranelift-codegen", +] + +[[package]] +name = "cranelift-native" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "kv" +version = "0.1.0" +dependencies = [ + "anyhow", + "cranelift", + "cranelift-jit", + "cranelift-module", + "cranelift-native", + "lalrpop", + "lalrpop-util", + "once_cell", + "regex", +] + +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" +dependencies = [ + "regex", +] + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "linux-raw-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regalloc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.1", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + +[[package]] +name = "region" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/kv/Cargo.toml b/kv/Cargo.toml new file mode 100644 index 0000000..a13963b --- /dev/null +++ b/kv/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "kv" +version = "0.1.0" +edition = "2021" +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + +[profile.bench] +debug = true + +[dependencies] +lalrpop-util = {version="0.19.7", features=["lexer"]} +regex = "1" +once_cell = "1.17.0" +anyhow = "1" +cranelift = "0.95.1" +cranelift-module = "0.95.1" +cranelift-jit = "0.95.1" +cranelift-native = "0.95.1" + +[build-dependencies] +lalrpop = "0.19.7" diff --git a/kv/build.rs b/kv/build.rs new file mode 100644 index 0000000..23c7d3f --- /dev/null +++ b/kv/build.rs @@ -0,0 +1,5 @@ +extern crate lalrpop; + +fn main() { + lalrpop::process_root().unwrap(); +} diff --git a/kv/src/ast.rs b/kv/src/ast.rs new file mode 100644 index 0000000..fb1044f --- /dev/null +++ b/kv/src/ast.rs @@ -0,0 +1,350 @@ +use std::fmt; +use std::rc::Rc; +use std::cell::RefCell; +use std::convert::From; + +impl From for Form { fn from(item: i32) -> Self { Form::Int(item) } } +impl From for Form { fn from(item: bool) -> Self { Form::Bool(item) } } +// todo, strings not symbols? +impl From for Form { fn from(item: String) -> Self { Form::Symbol(item) } } +impl From<&str> for Form { fn from(item: &str) -> Self { Form::Symbol(item.to_owned()) } } + +impl, B: Into
> From<(A, B)> for Form { + fn from(item: (A, B)) -> Self { + Form::Pair(Rc::new(item.0.into()), Rc::new(item.1.into())) + } +} + +pub enum PossibleTailCall { + Result(Rc), + TailCall(Rc, Rc), +} +#[derive(Debug, Eq, PartialEq)] +pub enum Form { + Nil, + Int(i32), + Bool(bool), + Symbol(String), + Cell(RefCell>), + Pair(Rc,Rc), + PrimComb(String, fn(Rc, Rc) -> PossibleTailCall), + DeriComb { se: Rc, de: Option, params: String, body: Rc }, +} +impl Form { + pub fn truthy(&self) -> bool { + match self { + Form::Bool(b) => *b, + Form::Nil => false, + _ => true, + } + } + pub fn int(&self) -> Option { + match self { + Form::Int(i) => Some(*i), + _ => None, + } + } + pub fn sym(&self) -> Option<&str> { + match self { + Form::Symbol(s) => Some(s), + _ => None, + } + } + pub fn car(&self) -> Option> { + match self { + Form::Pair(car, _cdr) => Some(Rc::clone(car)), + _ => None, + } + } + pub fn cdr(&self) -> Option> { + match self { + Form::Pair(_car, cdr) => Some(Rc::clone(cdr)), + _ => None, + } + } + pub fn append(&self, x: Rc) -> Option { + match self { + Form::Pair(car, cdr) => cdr.append(x).map(|x| Form::Pair(Rc::clone(car), Rc::new(x))), + Form::Nil => Some(Form::Pair(x, Rc::new(Form::Nil))), + _ => None, + } + } +} +impl fmt::Display for Form { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Form::Nil => write!(f, "nil"), + Form::Int(i) => write!(f, "{i}"), + Form::Bool(b) => write!(f, "{b}"), + Form::Symbol(s) => write!(f, "{s}"), + Form::Cell(c) => write!(f, "@{}", c.borrow()), + Form::Pair(car, cdr) => { + write!(f, "({}", car)?; + let mut traverse: Rc = Rc::clone(cdr); + loop { + match &*traverse { + Form::Pair(ref carp, ref cdrp) => { + write!(f, " {}", carp)?; + traverse = Rc::clone(cdrp); + }, + Form::Nil => { + write!(f, ")")?; + return Ok(()); + }, + x => { + write!(f, ". {x})")?; + return Ok(()); + }, + } + } + }, + Form::PrimComb(name, _f) => write!(f, "<{name}>"), + Form::DeriComb { se, de, params, body } => { + write!(f, "<{} {} {}>", de.as_ref().unwrap_or(&"".to_string()), params, body) + }, + } + } +} + +pub fn eval(e: Rc, f: Rc) -> Rc { + let mut e = e; + let mut x = Option::Some(f); + loop { + let cur = x.take().unwrap(); + match *cur { + Form::Symbol(ref s) => { + let mut t = e; + while s != t.car().unwrap().car().unwrap().sym().unwrap() { + t = t.cdr().unwrap(); + } + return t.car().unwrap().cdr().unwrap(); + }, + Form::Pair(ref c, ref p) => { + let comb = eval(Rc::clone(&e), Rc::clone(c)); + match *comb { + Form::PrimComb(ref _n, ref f) => match f(e, Rc::clone(p)) { + PossibleTailCall::Result(r) => return r, + PossibleTailCall::TailCall(ne, nx) => { + e = ne; + x = Some(nx); + }, + }, + Form::DeriComb{ref se, ref de, ref params, ref body } => { + let mut new_e = Rc::clone(se); + if let Some(de) = de { + new_e = assoc(de, Rc::clone(&e), new_e); + } + new_e = assoc(params, Rc::clone(p), new_e); + // always a tail call + e = new_e; + x = Some(Rc::clone(body)); + }, + _ => panic!("Tried to call not a Prim/DeriComb {:?}", comb), + } + }, + _ => return cur, + } + } +} +fn assoc(k: &str, v: Rc, l: Rc) -> Rc { + Rc::new(Form::Pair( + Rc::new(Form::Pair( + Rc::new(Form::Symbol(k.to_owned())), + v)), + l)) +} +fn assoc_vec(kvs: Vec<(&str, Rc)>) -> Rc { + let mut to_ret = Rc::new(Form::Nil); + for (k, v) in kvs { + to_ret = assoc(k, v, to_ret); + } + to_ret +} + +pub fn root_env() -> Rc { + assoc_vec(vec![ + ("eval", Rc::new(Form::PrimComb("eval".to_owned(), |e, p| { + let b = eval(Rc::clone(&e), p.car().unwrap()); + let e = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::TailCall(e, b) + }))), + // (vau de params body) + ("vau", Rc::new(Form::PrimComb("vau".to_owned(), |e, p| { + let de = p.car().unwrap().sym().map(|s| s.to_owned()); + let params = p.cdr().unwrap().car().unwrap().sym().unwrap().to_owned(); + let body = p.cdr().unwrap().cdr().unwrap().car().unwrap(); + + PossibleTailCall::Result(Rc::new(Form::DeriComb { se: e, de, params, body })) + }))), + ("=", Rc::new(Form::PrimComb("=".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()); + let b = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Bool(a == b))) + }))), + ("<", Rc::new(Form::PrimComb("<".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()); + let b = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() < b.int().unwrap()))) + }))), + (">", Rc::new(Form::PrimComb(">".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()); + let b = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() > b.int().unwrap()))) + }))), + ("<=", Rc::new(Form::PrimComb("<=".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()); + let b = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() <= b.int().unwrap()))) + }))), + (">=", Rc::new(Form::PrimComb(">=".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()); + let b = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Bool(a.int().unwrap() >= b.int().unwrap()))) + }))), + ("if", Rc::new(Form::PrimComb("if".to_owned(), |e, p| { + if eval(Rc::clone(&e), p.car().unwrap()).truthy() { + PossibleTailCall::TailCall(e, p.cdr().unwrap().car().unwrap()) + } else { + PossibleTailCall::TailCall(e, p.cdr().unwrap().cdr().unwrap().car().unwrap()) + } + }))), + + ("cell", Rc::new(Form::PrimComb("cell".to_owned(), |e, p| { + let x = eval(Rc::clone(&e), p.car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Cell(RefCell::new(x)))) + }))), + ("set", Rc::new(Form::PrimComb("set".to_owned(), |e, p| { + match &*eval(Rc::clone(&e), p.car().unwrap()) { + Form::Cell(c) => PossibleTailCall::Result(c.replace(eval(Rc::clone(&e), p.cdr().unwrap().car().unwrap()))), + _ => panic!("set on not cell"), + } + }))), + ("get", Rc::new(Form::PrimComb("get".to_owned(), |e, p| { + match &*eval(Rc::clone(&e), p.car().unwrap()) { + Form::Cell(c) => PossibleTailCall::Result(Rc::clone(&c.borrow())), + _ => panic!("get on not cell"), + } + }))), + + ("cons", Rc::new(Form::PrimComb("cons".to_owned(), |e, p| { + let h = eval(Rc::clone(&e), p.car().unwrap()); + let t = eval(e, p.cdr().unwrap().car().unwrap()); + PossibleTailCall::Result(Rc::new(Form::Pair(h, t))) + }))), + ("car", Rc::new(Form::PrimComb("car".to_owned(), |e, p| { + PossibleTailCall::Result(eval(Rc::clone(&e), p.car().unwrap()).car().unwrap()) + }))), + ("cdr", Rc::new(Form::PrimComb("cdr".to_owned(), |e, p| { + PossibleTailCall::Result(eval(Rc::clone(&e), p.car().unwrap()).cdr().unwrap()) + }))), + ("quote", Rc::new(Form::PrimComb("quote".to_owned(), |_e, p| { + PossibleTailCall::Result(p.car().unwrap()) + }))), + + ("debug", Rc::new(Form::PrimComb("debug".to_owned(), |e, p| { + //println!("Debug: {:?}", eval(Rc::clone(&e), p.car().unwrap())); + println!("Debug: {}", eval(Rc::clone(&e), p.car().unwrap())); + PossibleTailCall::TailCall(e, p.cdr().unwrap().car().unwrap()) + }))), + ("assert", Rc::new(Form::PrimComb("assert".to_owned(), |e, p| { + let thing = eval(Rc::clone(&e), p.car().unwrap()); + if !thing.truthy() { + println!("Assert failed: {:?}", thing); + } + assert!(thing.truthy()); + PossibleTailCall::TailCall(e, p.cdr().unwrap().car().unwrap()) + }))), + + ("+", Rc::new(Form::PrimComb("+".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a + b))) + }))), + ("-", Rc::new(Form::PrimComb("-".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a - b))) + }))), + ("*", Rc::new(Form::PrimComb("*".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a * b))) + }))), + ("/", Rc::new(Form::PrimComb("/".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a / b))) + }))), + ("%", Rc::new(Form::PrimComb("%".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a % b))) + }))), + ("&", Rc::new(Form::PrimComb("&".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a & b))) + }))), + ("|", Rc::new(Form::PrimComb("|".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a | b))) + }))), + ("^", Rc::new(Form::PrimComb("^".to_owned(), |e, p| { + let a = eval(Rc::clone(&e), p.car().unwrap()).int().unwrap(); + let b = eval(e, p.cdr().unwrap().car().unwrap()).int().unwrap(); + PossibleTailCall::Result(Rc::new(Form::Int(a ^ b))) + }))), + + ("comb?", Rc::new(Form::PrimComb("comb?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::PrimComb(_n, _f) => true, + Form::DeriComb { .. } => true, + _ => false, + }))) + }))), + ("cell?", Rc::new(Form::PrimComb("cell?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::Cell(_c) => true, + _ => false, + }))) + }))), + ("pair?", Rc::new(Form::PrimComb("pair?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::Pair(_a,_b) => true, + _ => false, + }))) + }))), + ("symbol?", Rc::new(Form::PrimComb("symbol?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::Symbol(_) => true, + _ => false, + }))) + }))), + ("int?", Rc::new(Form::PrimComb("int?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::Int(_) => true, + _ => false, + }))) + }))), + // maybe bool? but also could be derived. Nil def + ("bool?", Rc::new(Form::PrimComb("bool?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::Bool(_) => true, + _ => false, + }))) + }))), + ("nil?", Rc::new(Form::PrimComb("nil?".to_owned(), |e, p| { + PossibleTailCall::Result(Rc::new(Form::Bool(match &*eval(e, p.car().unwrap()) { + Form::Nil => true, + _ => false, + }))) + }))), + + // consts + ("true", Rc::new(Form::Bool(true))), + ("false", Rc::new(Form::Bool(false))), + ("nil", Rc::new(Form::Nil)), + ]) +} + diff --git a/kv/src/grammar.lalrpop b/kv/src/grammar.lalrpop new file mode 100644 index 0000000..949ee1d --- /dev/null +++ b/kv/src/grammar.lalrpop @@ -0,0 +1,31 @@ +use std::str::FromStr; +use std::rc::Rc; +use crate::ast::Form; + +grammar; + +pub Term: Form = { + NUM => Form::Int(i32::from_str(<>).unwrap()), + SYM => Form::Symbol(<>.to_owned()), + "(" ")" => <>.unwrap_or(Form::Nil), + "'" => Form::Pair(Rc::new(Form::Symbol("quote".to_owned())), Rc::new(Form::Pair(Rc::new(<>), Rc::new(Form::Nil)))), + "!" => { + h.append(Rc::new(t)).unwrap() + }, +}; +ListInside: Form = { + => Form::Pair(Rc::new(<>), Rc::new(Form::Nil)), + => Form::Pair(Rc::new(h), Rc::new(t)), + "." => Form::Pair(Rc::new(a), Rc::new(d)), +} +match { + "(", + ")", + ".", + "'", + "!", + r"[0-9]+" => NUM, + r"[a-zA-Z+*/_=?%&|^<>-][\w+*/=_?%&|^<>-]*" => SYM, + r"(;[^\n]*\n)|\s+" => { } +} + diff --git a/kv/src/main.rs b/kv/src/main.rs new file mode 100644 index 0000000..a3c4bd7 --- /dev/null +++ b/kv/src/main.rs @@ -0,0 +1,17 @@ +#[macro_use] extern crate lalrpop_util; +lalrpop_mod!(pub grammar); + +use std::rc::Rc; + +mod ast; +use crate::ast::{eval,root_env}; +mod test; + +fn main() { + let input = "(= 17 ((vau d p (+ (eval (car p) d) 13)) (+ 1 3)))"; + let parsed_input = Rc::new(grammar::TermParser::new().parse(input).unwrap()); + println!("Parsed input is {} - {:?}", parsed_input, parsed_input); + let result = eval(root_env(), parsed_input); + println!("Result is {} - {:?}", result, result); +} + diff --git a/kv/src/test.rs b/kv/src/test.rs new file mode 100644 index 0000000..98054ba --- /dev/null +++ b/kv/src/test.rs @@ -0,0 +1,566 @@ +use std::rc::Rc; + +use crate::grammar; +use crate::ast::{eval,root_env,Form,PossibleTailCall}; + +#[test] +fn parse_test() { + let g = grammar::TermParser::new(); + for test in [ + "22", "(22)", "(((22)))", + "(22 )", "()", "( )", "( 44)", "(44 )", + "(22 44 (1) 33 (4 5 (6) 6))", "hello", + "-", "+", "(+ 1 ;hi + 3)", "'13", "hello-world", "_", + ] { + assert!(g.parse(test).is_ok()); + } + assert!(g.parse("((22)").is_err()); +} + +fn eval_test>(also_pe: bool, gram: &grammar::TermParser, e: &Rc, code: &str, expected: T) { + println!("Doing test {}", code); + let parsed = Rc::new(gram.parse(code).unwrap()); + let basic_result = eval(Rc::clone(e), Rc::clone(&parsed)); + assert_eq!(*basic_result, expected.into()); + if also_pe { + } +} + +#[test] +fn basic_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, "(+ 2 (car (cons 4 '(1 2))))", 6); + eval_test(true, &g, &e, "(= 17 ((vau d p (+ (eval (car p) d) 13)) (+ 1 3)))", true); + eval_test(true, &g, &e, "(if (= 2 2) (+ 1 2) (+ 3 4))", 3); + eval_test(true, &g, &e, "(quote a)", "a"); + eval_test(true, &g, &e, "'a", "a"); + eval_test(true, &g, &e, "'(1 . a)", (1, "a")); + eval_test(true, &g, &e, "'(1 a)", (1, ("a", Form::Nil))); + eval_test(true, &g, &e, "true", true); + eval_test(true, &g, &e, "false", false); + eval_test(true, &g, &e, "nil", Form::Nil); + + eval_test(true, &g, &e, "(+ 1 2)", 3); + eval_test(true, &g, &e, "(- 1 2)", -1); + eval_test(true, &g, &e, "(* 1 2)", 2); + eval_test(true, &g, &e, "(/ 4 2)", 2); + eval_test(true, &g, &e, "(% 3 2)", 1); + eval_test(true, &g, &e, "(& 3 2)", 2); + eval_test(true, &g, &e, "(| 2 1)", 3); + eval_test(true, &g, &e, "(^ 2 1)", 3); + eval_test(true, &g, &e, "(^ 3 1)", 2); + + eval_test(true, &g, &e, "(< 3 1)", false); + eval_test(true, &g, &e, "(<= 3 1)", false); + eval_test(true, &g, &e, "(> 3 1)", true); + eval_test(true, &g, &e, "(>= 3 1)", true); + + eval_test(true, &g, &e, "(comb? +)", true); + eval_test(true, &g, &e, "(comb? (vau d p 1))", true); + eval_test(true, &g, &e, "(comb? 1)", false); + eval_test(true, &g, &e, "(pair? '(a))", true); + //eval_test(true, &g, &e, "(pair? '())", true); + eval_test(true, &g, &e, "(nil? nil)", true); + eval_test(true, &g, &e, "(nil? 1)", false); + eval_test(true, &g, &e, "(pair? 1)", false); + eval_test(true, &g, &e, "(symbol? 'a)", true); + eval_test(true, &g, &e, "(symbol? 1)", false); + eval_test(true, &g, &e, "(int? 1)", true); + eval_test(true, &g, &e, "(int? true)", false); + eval_test(true, &g, &e, "(bool? true)", true); + eval_test(true, &g, &e, "(bool? 1)", false); + + eval_test(true, &g, &e, "!(bool?) 1", false); + eval_test(true, &g, &e, "!(bool?) true", true); + + eval_test(true, &g, &e, "((vau root_env _ (eval 'a (cons (cons 'a 2) root_env))))", 2); + eval_test(true, &g, &e, "'name-dash", "name-dash"); + + eval_test(true, &g, &e, "(get (cell 1))", 1); + eval_test(true, &g, &e, "(set (cell 1) 2)", 1); + eval_test(true, &g, &e, "(cell? (cell 1))", true); + eval_test(true, &g, &e, "((vau de p (eval (quote (cons (set a 2) (get a))) (cons (cons (quote a) (cell 1)) de))))", (1,2)); +} + + +use once_cell::sync::Lazy; +static LET: Lazy = Lazy::new(|| { + "!((vau root_env p (eval (car p) + (cons (cons 'let1 + (vau de p (eval (car (cdr (cdr p))) (cons (cons (car p) (eval (car (cdr p)) de)) de))) + ) root_env))))".to_owned() +}); + + +#[test] +fn fib_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (let1 x 10 (+ x 7))", *LET), 17); + let def_fib = " + !(let1 fib (vau de p + !(let1 self (eval (car p) de)) + !(let1 n (eval (car (cdr p)) de)) + !(if (= 0 n) 0) + !(if (= 1 n) 1) + (+ (self self (- n 1)) (self self (- n 2))) + ))"; + eval_test(false, &g, &e, &format!("{} {} (fib fib 6)", *LET, def_fib), 8); +} +#[test] +fn fact_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + let def_fact = " + !(let1 fact (vau de p + !(let1 self (eval (car p) de)) + !(let1 n (eval (car (cdr p)) de)) + !(if (= 0 n) 1) + (* n (self self (- n 1))) + ))"; + eval_test(true, &g, &e, &format!("{} {} (fact fact 6)", *LET, def_fact), 720); +} +static VAPPLY: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 vapply (vau de p + !(let1 f (eval (car p) de)) + !(let1 ip (eval (car (cdr p)) de)) + !(let1 nde (eval (car (cdr (cdr p))) de)) + (eval (cons f ip) nde) + ))", *LET) +}); +#[test] +fn vapply_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + // need the vapply to keep env in check because otherwise the env keeps growing + // and the Rc::drop will overflow the stack lol + let def_badid = format!(" + {} + !(let1 badid (vau de p + !(let1 inner (vau ide ip + !(let1 self (car ip)) + !(let1 n (car (cdr ip))) + !(let1 acc (car (cdr (cdr ip)))) + !(if (= 0 n) acc) + (vapply self (cons self (cons (- n 1) (cons (+ acc 1) nil))) de) + )) + (vapply inner (cons inner (cons (eval (car p) de) (cons 0 nil))) de) + ))", *VAPPLY); + // Won't work unless tail calls work + // so no PE? + eval_test(false, &g, &e, &format!("{} (badid 1000)", def_badid), 1000); +} + +static VMAP: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 vmap (vau de p + !(let1 vmap_inner (vau ide ip + !(let1 self (car ip)) + !(let1 f (car (cdr ip))) + !(let1 l (car (cdr (cdr ip)))) + !(if (= nil l) l) + (cons (vapply f (cons (car l) nil) de) (vapply self (cons self (cons f (cons (cdr l) nil))) de)) + )) + (vapply vmap_inner (cons vmap_inner (cons (eval (car p) de) (cons (eval (car (cdr p)) de) nil))) de) + ))", *VAPPLY) +}); +#[test] +fn vmap_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + // Maybe define in terms of a right fold? + //eval_test(true, &g, &e, &format!("{} (vmap (vau de p (+ 1 (car p))) '(1 2 3))", *VMAP), (2, (3, (4, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} (vmap (vau de p (+ 1 (car p))) '(1))", *VMAP), (2, Form::Nil)); +} + +static WRAP: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 wrap (vau de p + !(let1 f (eval (car p) de)) + (vau ide p (vapply f (vmap (vau _ xp (eval (car xp) ide)) p) ide)) + ))", *VMAP) +}); +#[test] +fn wrap_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + // Make sure (wrap (vau ...)) and internal style are optimized the same + eval_test(true, &g, &e, &format!("{} ((wrap (vau _ p (+ (car p) 1))) (+ 1 2))", *WRAP), 4); +} + +static UNWRAP: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 unwrap (vau de p + !(let1 f (eval (car p) de)) + (vau ide p (vapply f (vmap (vau _ xp (cons quote (cons (car xp) nil))) p) ide)) + ))", *WRAP) +}); +#[test] +fn unwrap_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + // Can't represent prims in tests :( - they do work though, uncommenting and checking the + // failed assert verifies + //eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (car p))) (+ 1 2))", def_unwrap), ("quote", (("+", (1, (2, Form::Nil))), Form::Nil))); + //eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (eval (car p) de))) (+ 1 2))", def_unwrap), (("+", (1, (2, Form::Nil))), Form::Nil)); + eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (eval (eval (car p) de) de))) (+ 1 2))", *UNWRAP), 3); + eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (+ (eval (eval (car p) de) de) 1))) (+ 1 2))", *UNWRAP), 4); +} + +static LAPPLY: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 lapply (vau de p + !(let1 f (eval (car p) de)) + !(let1 ip (eval (car (cdr p)) de)) + !(let1 nde (eval (car (cdr (cdr p))) de)) + (eval (cons (unwrap f) ip) nde) + ))", *UNWRAP) +}); +#[test] +fn lapply_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + // Should this allow envs at all? It technically can, but I feel like it kinda goes against the + // sensible deriviation + let def_lbadid = format!(" + {} + !(let1 lbadid (vau de p + !(let1 inner (wrap (vau ide ip + !(let1 self (car ip)) + !(let1 n (car (cdr ip))) + !(let1 acc (car (cdr (cdr ip)))) + !(if (= 0 n) acc) + (lapply self (cons self (cons (- n 1) (cons (+ acc 1) nil))) de) + ))) + (lapply inner (cons inner (cons (eval (car p) de) (cons 0 nil))) de) + ))", *LAPPLY); + // Won't work unless tail calls work + // takes a while though + eval_test(false, &g, &e, &format!("{} (lbadid 1000)", def_lbadid), 1000); +} + +static VFOLDL: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 vfoldl (vau de p + !(let1 vfoldl_inner (vau ide ip + !(let1 self (car ip)) + !(let1 f (car (cdr ip))) + !(let1 a (car (cdr (cdr ip)))) + !(let1 l (car (cdr (cdr (cdr ip))))) + !(if (= nil l) a) + (vapply self (cons self (cons f (cons (vapply f (cons a (cons (car l) nil)) de) (cons (cdr l) nil)))) de) + )) + (vapply vfoldl_inner (cons vfoldl_inner (cons (eval (car p) de) (cons (eval (car (cdr p)) de) (cons (eval (car (cdr (cdr p))) de) nil)))) de) + ))", *LAPPLY) +}); +#[test] +fn vfoldl_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (vfoldl (vau de p (+ (car p) (car (cdr p)))) 0 '(1 2 3))", *VFOLDL), 6); +} +static ZIPD: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 zipd (vau de p + !(let1 zipd_inner (vau ide ip + !(let1 self (car ip)) + !(let1 a (car (cdr ip))) + !(let1 b (car (cdr (cdr ip)))) + !(if (= nil a) a) + !(if (= nil b) b) + (cons (cons (car a) (car b)) (vapply self (cons self (cons (cdr a) (cons (cdr b) nil))) de)) + )) + (vapply zipd_inner (cons zipd_inner (cons (eval (car p) de) (cons (eval (car (cdr p)) de) nil))) de) + ))", *VFOLDL) +}); +#[test] +fn zipd_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (zipd '(1 2 3) '(4 5 6))", *ZIPD), ((1,4), ((2,5), ((3,6), Form::Nil)))); +} +static CONCAT: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 concat (vau de p + !(let1 concat_inner (vau ide ip + !(let1 self (car ip)) + !(let1 a (car (cdr ip))) + !(let1 b (car (cdr (cdr ip)))) + !(if (= nil a) b) + (cons (car a) (vapply self (cons self (cons (cdr a) (cons b nil))) de)) + )) + (vapply concat_inner (cons concat_inner (cons (eval (car p) de) (cons (eval (car (cdr p)) de) nil))) de) + ))", *ZIPD) +}); + +#[test] +fn concat_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (concat '(1 2 3) '(4 5 6))", *CONCAT), (1, (2, (3, (4, (5, (6, Form::Nil))))))); +} + +static BVAU: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 match_params (wrap (vau 0 p + !(let1 self (car p)) + !(let1 p_ls (car (cdr p))) + !(let1 dp (car (cdr (cdr p)))) + !(let1 e (car (cdr (cdr (cdr p))))) + !(if (= nil p_ls) (assert (= nil dp) e)) + !(if (symbol? p_ls) (cons (cons p_ls dp) e)) + (self self (cdr p_ls) (cdr dp) (self self (car p_ls) (car dp) e)) + ))) + !(let1 bvau (vau se p + (if (= nil (cdr (cdr p))) + ; No de case + !(let1 p_ls (car p)) + !(let1 b_v (car (cdr p))) + (vau 0 dp + (eval b_v (match_params match_params p_ls dp se)) + ) + + ; de case + !(let1 de_s (car p)) + !(let1 p_ls (car (cdr p))) + !(let1 b_v (car (cdr (cdr p)))) + (vau dde dp + (eval b_v (match_params match_params p_ls dp (cons (cons de_s dde) se))) + ) + ) + ))", *CONCAT) +}); +#[test] +fn bvau_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} ((bvau _ (a b c) (+ a (- b c))) 10 2 3)", *BVAU), 9); + eval_test(true, &g, &e, &format!("{} ((bvau (a b c) (+ a (- b c))) 10 2 3)", *BVAU), 9); + + eval_test(true, &g, &e, &format!("{} ((bvau (a b . c) c) 10 2 3)", *BVAU), (3, Form::Nil)); + eval_test(true, &g, &e, &format!("{} ((bvau (a b . c) c) 10 2)", *BVAU), Form::Nil); + eval_test(true, &g, &e, &format!("{} ((bvau (a b . c) c) 10 2 3 4 5)", *BVAU), (3, (4, (5, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} ((bvau c c) 3 4 5)", *BVAU), (3, (4, (5, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} ((bvau c c))", *BVAU), Form::Nil); + eval_test(true, &g, &e, &format!("{} ((bvau ((a b) . c) c) (10 2) 3 4 5)", *BVAU), (3, (4, (5, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} ((bvau ((a b) . c) a) (10 2) 3 4 5)", *BVAU), 10); + eval_test(true, &g, &e, &format!("{} ((bvau ((a b) . c) b) (10 2) 3 4 5)", *BVAU), 2); + + eval_test(true, &g, &e, &format!("{} ((wrap (bvau _ (a b c) (+ a (- b c)))) (+ 10 1) (+ 2 2) (+ 5 3))", *BVAU), 7); + eval_test(true, &g, &e, &format!("{} ((wrap (bvau (a b c) (+ a (- b c)))) (+ 10 1) (+ 2 2) (+ 5 3))", *BVAU), 7); +} + +static LAMBDA: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 lambda (vau de p + (wrap (vapply bvau p de)) + ))", *BVAU) +}); +#[test] +fn lambda_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} ((lambda (a b c) (+ a (- b c))) (+ 10 1) (+ 2 2) (+ 5 3))", *LAMBDA), 7); + eval_test(true, &g, &e, &format!("{} ((lambda (a b . c) c) 10 2 3)", *LAMBDA), (3, Form::Nil)); + eval_test(true, &g, &e, &format!("{} ((lambda (a b . c) c) 10 2)", *LAMBDA), Form::Nil); + eval_test(true, &g, &e, &format!("{} ((lambda (a b . c) c) 10 2 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} ((lambda c c) 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} ((lambda c c))", *LAMBDA), Form::Nil); + eval_test(true, &g, &e, &format!("{} ((lambda ((a b) . c) c) '(10 2) 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil)))); + eval_test(true, &g, &e, &format!("{} ((lambda ((a b) . c) a) '(10 2) 3 4 5)", *LAMBDA), 10); + eval_test(true, &g, &e, &format!("{} ((lambda ((a b) . c) b) '(10 2) 3 4 5)", *LAMBDA), 2); + eval_test(true, &g, &e, &format!("{} ((lambda ((a b . c) d) b) '(10 2 3 4) 3)", *LAMBDA), 2); + eval_test(true, &g, &e, &format!("{} ((lambda ((a b . c) d) c) '(10 2 3 4) 3)", *LAMBDA), (3, (4, Form::Nil))); + // should fail + //eval_test(true, &g, &e, &format!("{} ((lambda (a b c) c) 10 2 3 4)", *LAMBDA), 3); +} + +static LET2: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 let1 (bvau dp (s v b) + (eval b (match_params match_params s (eval v dp) dp)) + )) + ", *LAMBDA) +}); + +#[test] +fn let2_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + + eval_test(true, &g, &e, &format!("{} (let1 x (+ 10 1) (+ x 1))", *LET2), 12); + eval_test(true, &g, &e, &format!("{} (let1 x '(10 1) x)", *LET2), (10, (1, Form::Nil))); + eval_test(true, &g, &e, &format!("{} (let1 (a b) '(10 1) a)", *LET2), 10); + eval_test(true, &g, &e, &format!("{} (let1 (a b) '(10 1) b)", *LET2), 1); + eval_test(true, &g, &e, &format!("{} (let1 (a b . c) '(10 1) c)", *LET2), Form::Nil); + eval_test(true, &g, &e, &format!("{} (let1 (a b . c) '(10 1 2 3) c)", *LET2), (2, (3, Form::Nil))); + eval_test(true, &g, &e, &format!("{} (let1 ((a . b) . c) '((10 1) 2 3) a)", *LET2), 10); + eval_test(true, &g, &e, &format!("{} (let1 ((a . b) . c) '((10 1) 2 3) b)", *LET2), (1, Form::Nil)); + // should fail + //eval_test(true, &g, &e, &format!("{} (let1 (a b c) '(10 2 3 4) a)", *LET2), 10); +} + +static LIST: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 list (lambda args args)) + ", *LET2) +}); + +#[test] +fn list_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (list 1 2 (+ 3 4))", *LIST), (1, (2, (7, Form::Nil)))); +} + +static Y: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 Y (lambda (f3) + ((lambda (x1) (x1 x1)) + (lambda (x2) (f3 (wrap (vau app_env y (lapply (x2 x2) y app_env))))))) + ) + ", *LIST) +}); + +#[test] +fn y_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + + eval_test(true, &g, &e, &format!("{} ((Y (lambda (recurse) (lambda (n) (if (= 0 n) 1 (* n (recurse (- n 1))))))) 5)", *Y), 120); + +} + +static RLAMBDA: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 rlambda (bvau se (n p b) + (eval (list Y (list lambda (list n) (list lambda p b))) se) + )) + ", *Y) +}); + +#[test] +fn rlambda_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} ((rlambda recurse (n) (if (= 0 n) 1 (* n (recurse (- n 1))))) 5)", *RLAMBDA), 120); +} +static AND_OR: Lazy = Lazy::new(|| { + // need to extend for varidac + format!(" + {} + !(let1 and (bvau se (a b) + !(let1 ae (eval a se)) + (if ae (eval b se) ae) + )) + !(let1 or (bvau se (a b) + !(let1 ae (eval a se)) + (if ae ae (eval b se)) + )) + ", *RLAMBDA) +}); + +#[test] +fn and_or_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (and true true)", *AND_OR), true); + eval_test(true, &g, &e, &format!("{} (and false true)", *AND_OR), false); + eval_test(true, &g, &e, &format!("{} (and true false)", *AND_OR), false); + eval_test(true, &g, &e, &format!("{} (and false false)", *AND_OR), false); + + eval_test(true, &g, &e, &format!("{} (or true true)", *AND_OR), true); + eval_test(true, &g, &e, &format!("{} (or false true)", *AND_OR), true); + eval_test(true, &g, &e, &format!("{} (or true false)", *AND_OR), true); + eval_test(true, &g, &e, &format!("{} (or false false)", *AND_OR), false); +} +static LEN: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 len (lambda (l) + !(let1 len_helper (rlambda len_helper (l a) + (if (pair? l) (len_helper (cdr l) (+ 1 a)) + a) + )) + (len_helper l 0) + )) + ", *AND_OR) +}); + +#[test] +fn len_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (len '())", *LEN), 0); + eval_test(true, &g, &e, &format!("{} (len '(1))", *LEN), 1); + eval_test(true, &g, &e, &format!("{} (len '(1 2))", *LEN), 2); + eval_test(true, &g, &e, &format!("{} (len '(1 2 3))", *LEN), 3); +} +static MATCH: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 match (bvau de (x . cases) + !(let1 evaluate_case (rlambda evaluate_case (access c) + !(if (symbol? c) (list true (lambda (b) (list let1 c access b)))) + !(if (and (pair? c) (= 'unquote (car c))) (list (list = access (car (cdr c))) (lambda (b) b))) + !(if (and (pair? c) (= 'quote (car c))) (list (list = access c) (lambda (b) b))) + !(if (pair? c) + !(let1 tests (list and (list pair? access) (list = (len c) (list len access)))) + !(let1 (tests body_func) ((rlambda recurse (c tests access body_func) (if (pair? c) + !(let1 (inner_test inner_body_func) (evaluate_case (list car access) (car c))) + (recurse (cdr c) + (list and tests inner_test) + (list cdr access) + (lambda (b) (body_func (inner_body_func b)))) + ; else + (list tests body_func) + )) + c tests access (lambda (b) b))) + (list tests body_func)) + (list (list = access c) (lambda (b) b)) + )) + !(let1 helper (rlambda helper (x_sym cases) (if (= nil cases) (list assert false) + (let1 (test body_func) (evaluate_case x_sym (car cases)) + (concat (list if test (body_func (car (cdr cases)))) (list (helper x_sym (cdr (cdr cases))))))))) + + (eval (list let1 '___MATCH_SYM x (helper '___MATCH_SYM cases)) de) + ;!(let1 expanded (list let1 '___MATCH_SYM x (helper '___MATCH_SYM cases))) + ;(debug expanded (eval expanded de)) + )) + ", *LEN) +}); +#[test] +fn match_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(true, &g, &e, &format!("{} (match (+ 1 2) 1 2 2 3 3 4 _ 0)", *MATCH), 4); + eval_test(true, &g, &e, &format!("{} (match '(1 2) 1 2 2 3 3 4 _ 0)", *MATCH), 0); + eval_test(true, &g, &e, &format!("{} (match '(1 2) 1 2 2 3 (a b) (+ a (+ 2 b)) _ 0)", *MATCH), 5); + eval_test(true, &g, &e, &format!("{} (match '(1 2) 1 2 2 3 '(1 2) 7 _ 0)", *MATCH), 7); + eval_test(true, &g, &e, &format!("{} (let1 a 70 (match (+ 60 10) (unquote a) 100 2 3 _ 0))", *MATCH), 100); +} +static RBTREE: Lazy = Lazy::new(|| { + format!(" + {} + !(let1 empty (list 'B nil nil nil)) + !(let1 E empty) + !(let1 EE (list 'BB nil nil nil)) + + !(let1 generic-foldl (rlambda generic-foldl (f z t) (match t + (unquote E) z + + (c a x b) !(let1 new_left_result (generic-foldl f z a)) + !(let1 folded (f new_left_result x)) + (generic-foldl f folded b)))) + + !(let1 blacken (lambda (t) (match t + ('R a x b) (list 'B a x b) + t t))) + !(let1 balance (lambda (t) (match t + ; figures 1 and 2 + ('B ('R ('R a x b) y c) z d) (list 'R (list 'B a x b) y (list 'B c z d)) + ('B ('R a x ('R b y c)) z d) (list 'R (list 'B a x b) y (list 'B c z d)) + ('B a x ('R ('R b y c) z d)) (list 'R (list 'B a x b) y (list 'B c z d)) + ('B a x ('R b y ('R c z d))) (list 'R (list 'B a x b) y (list 'B c z d)) + ; figure 8, double black cases + ('BB ('R a x ('R b y c)) z d) (list 'B (list 'B a x b) y (list 'B c z d)) + ('BB a x ('R ('R b y c) z d)) (list 'B (list 'B a x b) y (list 'B c z d)) + ; already balenced + t t))) + + !(let1 map-insert !(let1 ins (rlambda ins (t k v) (match t + (unquote E) (list 'R t (list k v) t) + (c a x b) !(if (< k (car x)) (balance (list c (ins a k v) x b))) + !(if (= k (car x)) (list c a (list k v) b)) + (balance (list c a x (ins b k v)))))) + (lambda (t k v) (blacken (ins t k v)))) + + !(let1 map-empty empty) + + !(let1 make-test-tree (rlambda make-test-tree (n t) (if (<= n 0) t + (make-test-tree (- n 1) (map-insert t n (= 0 (% n 10))))))) + !(let1 reduce-test-tree (lambda (tree) (generic-foldl (lambda (a x) (if (car (cdr x)) (+ a 1) a)) 0 tree))) + ", *MATCH) +}); +#[test] +fn rbtree_eval_test() { let g = grammar::TermParser::new(); let e = root_env(); + eval_test(false, &g, &e, &format!("{} (reduce-test-tree (make-test-tree 10 map-empty))", *RBTREE), 1); + //eval_test(false, &g, &e, &format!("{} (reduce-test-tree (make-test-tree 20 map-empty))", *RBTREE), 2); +}