commit e58020ffa4def9d891c056645663d7c792a3d8f8 Author: Michael Zhang Date: Thu Dec 7 10:35:12 2023 -0600 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cb6341b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1775 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +dependencies = [ + "backtrace", +] + +[[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 = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bidir" +version = "0.1.0" +dependencies = [ + "anyhow", + "contracts", + "dashmap", + "derivative", + "env_logger 0.10.1", + "im", + "lalrpop", + "lalrpop-util", + "lazy_static", + "leptos_reactive", + "proptest", + "proptest-derive", + "quickcheck", + "quickcheck_macros", + "rustyline", + "test-log", + "trace", + "tracing", + "tracing-subscriber", +] + +[[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 = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "contracts" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d1429e3bd78171c65aa010eabcdf8f863ba3254728dbfb0ad4b1545beac15c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[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.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fd-lock" +version = "3.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "proptest", + "quickcheck", + "rand_core", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "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 = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax 0.7.5", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leptos_reactive" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22207568e096ac153ba8da68635e3136c1ec614ea9012736fa861c05bfb2eeff" +dependencies = [ + "base64", + "cfg-if", + "futures", + "indexmap", + "paste", + "pin-project", + "rustc-hash", + "self_cell", + "serde", + "serde-wasm-bindgen", + "serde_json", + "slotmap", + "thiserror", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +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 = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[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.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "proptest-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf16337405ca084e9c78985114633b6827711d22b9e6ef6c6c0d665eb3f0b6e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger 0.8.4", + "log", + "rand", +] + +[[package]] +name = "quickcheck_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "rustyline" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "994eca4bca05c87e86e15d90fc7a91d1be64b4482b38cb2d27474568fe7c9db9" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "scopeguard", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "self_cell" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "serde", + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[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 = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[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 = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "test-log" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b" +dependencies = [ + "env_logger 0.10.1", + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "trace" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad0c048e114d19d1140662762bfdb10682f3bc806d8be18af846600214dd9af" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "time", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[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.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..91bb285 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "bidir" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = { version = "1.0.75", features = ["backtrace"] } +contracts = { version = "0.6.3" } +dashmap = "5.5.3" +derivative = "2.2.0" +env_logger = "0.10.0" +im = { version = "15.1.0", features = ["proptest", "quickcheck"] } +lalrpop-util = { version = "0.20.0", features = ["lexer", "regex", "unicode"] } +lazy_static = "1.4.0" +leptos_reactive = "0.5.2" +proptest = "1.4.0" +proptest-derive = "0.4.0" +quickcheck = "1.0.3" +quickcheck_macros = "1.0.0" +rustyline = "12.0.0" +trace = "0.1.7" +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.17", features = [ + "env-filter", + "json", + "regex", + "serde", + "time", + "tracing", +] } + +[build-dependencies] +lalrpop = "0.20.0" + +[dev-dependencies] +test-log = { version = "0.2.13", features = ["trace"] } + +[features] +trace_execution = [] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..699ada2 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + lalrpop::process_root().unwrap() +} diff --git a/src/abstract_data.rs b/src/abstract_data.rs new file mode 100644 index 0000000..cf73885 --- /dev/null +++ b/src/abstract_data.rs @@ -0,0 +1,9 @@ +pub trait Data { + /* Required methods */ + /* */ + + /* Provided methods */ + /* */ + + fn synthesize() {} +} diff --git a/src/bidir.rs b/src/bidir.rs new file mode 100644 index 0000000..b48dd15 --- /dev/null +++ b/src/bidir.rs @@ -0,0 +1,360 @@ +use anyhow::{bail, Result}; + +use crate::data::{Context, ContextEntry, FreeVar, Monotype, Term, Type}; +use crate::gensym::gensym_existential; + +// Figure 8. Applying a context, as a substitution, to a type + +#[cfg_attr(feature = "trace_execution", trace)] +pub fn app_ctx(ctx: &Context, ty: &Type) -> Result { + match ty { + Type::Unit => Ok(Type::Unit), + Type::Var(s) => Ok(Type::Var(s.clone())), + + Type::Existential(a) => match ctx.lookup_existential(a) { + Some((_, Some(m))) => Ok(m.into_poly()), + Some((_, None)) => Ok(Type::Existential(a.clone())), + None => bail!("existential variable {a} doesn't exist in context"), + }, + + Type::Polytype(a, t) => { + Ok(Type::Polytype(a.clone(), Box::new(app_ctx(ctx, t)?))) + } + + Type::Arrow(a, b) => Ok(Type::Arrow( + Box::new(app_ctx(ctx, a)?), + Box::new(app_ctx(ctx, b)?), + )), + } +} + +// Figure 9. Algorithmic subtyping + +/// Under input context Γ , type A is a subtype of B, with output context ∆ +#[cfg_attr(feature = "trace_execution", trace)] +pub fn subtype(ctx: &Context, left: &Type, right: &Type) -> Result { + match (left, right) { + // <:Unit rule + (Type::Unit, Type::Unit) => Ok(ctx.clone()), + + // <:Var rule + (Type::Var(x), Type::Var(y)) if x == y && ctx.lookup_type(x).is_some() => Ok(ctx.clone()), + + // <:Exvar rule + (Type::Existential(x), Type::Existential(y)) + if x == y && ctx.lookup_existential(x).is_some() => + { + Ok(ctx.clone()) + } + + // <:InstantiateL + (Type::Existential(a), ty_a) + if !ty_a + .free_vars() + .contains(&FreeVar::Existential(a.to_string())) + && ctx.lookup_existential(a).is_some() => + { + let ctx_delta = instantiate_left(ctx, a, ty_a)?; + Ok(ctx_delta) + } + + // <:InstantiateR + (ty_a, Type::Existential(a)) + if !ty_a + .free_vars() + .contains(&FreeVar::Existential(a.to_string())) + && ctx.lookup_existential(a).is_some() => + { + let ctx_delta = instantiate_right(ctx, ty_a, a)?; + Ok(ctx_delta) + } + + (Type::Existential(_), Type::Unit) => todo!(), + (Type::Existential(_), Type::Var(_)) => todo!(), + (Type::Existential(_), Type::Polytype(_, _)) => todo!(), + (Type::Existential(_), Type::Arrow(_, _)) => todo!(), + (Type::Polytype(_, _), Type::Unit) => todo!(), + (Type::Polytype(_, _), Type::Var(_)) => todo!(), + (Type::Polytype(_, _), Type::Existential(_)) => todo!(), + (Type::Polytype(_, _), Type::Polytype(_, _)) => todo!(), + (Type::Polytype(_, _), Type::Arrow(_, _)) => todo!(), + (Type::Arrow(_, _), Type::Unit) => todo!(), + (Type::Arrow(_, _), Type::Var(_)) => todo!(), + (Type::Arrow(_, _), Type::Existential(_)) => todo!(), + (Type::Arrow(_, _), Type::Polytype(_, _)) => todo!(), + (Type::Arrow(_, _), Type::Arrow(_, _)) => todo!(), + + _ => bail!("subtyping relation failed between {left:?} and {right:?} (ctx = {ctx:?})"), + } +} + +// Figure 10. Instantiation + +#[cfg_attr(feature = "trace_execution", trace)] +pub fn instantiate_left( + ctx: &Context, + a: &str, + ty_a: &Type, +) -> Result { + match ty_a { + // InstLReach rule + Type::Existential(b) + if ctx.has_existential(a) && ctx.has_existential(b) => + { + let mut new_ctx = ctx.clone(); + { + let b_entry = new_ctx + .0 + .iter_mut() + .find( + |entry| matches!(entry, ContextEntry::ExistentialVar(x) if x == b), + ) + .expect("should exist"); + + *b_entry = ContextEntry::ExistentialSolved( + b.to_owned(), + Monotype::Existential(a.to_owned()), + ); + } + + Ok(new_ctx) + } + + Type::Existential(_b) => todo!(), + + Type::Unit => todo!(), + Type::Var(_) => todo!(), + Type::Polytype(_, _) => todo!(), + Type::Arrow(_, _) => todo!(), + } +} + +#[cfg_attr(feature = "trace_execution", trace)] +pub fn instantiate_right( + ctx: &Context, + ty_a: &Type, + a: &str, +) -> Result { + match ty_a { + // InstRArr + Type::Arrow(ty_a1, ty_a2) if ctx.has_existential(a) => { + // TODO: In case it's already solved? + println!("original ctx: {ctx:?}"); + + let (ex_a1_s, ex_a2_s, ctx_gamma_aug) = + ctx.split_existential_function(a)?; + + let ctx_theta = instantiate_left(&ctx_gamma_aug, &ex_a1_s, &ty_a1)?; + + let ty_a2_aug = app_ctx(&ctx_theta, &ty_a2)?; + let ctx_delta = instantiate_right(&ctx_theta, &ty_a2_aug, &ex_a2_s)?; + + Ok(ctx_delta) + } + + // InstRAllL + Type::Polytype(beta, ty_b) if ctx.has_existential(a) => { + let ex_b = gensym_existential(); + let aug_ctx = ctx.add(vec![ + ContextEntry::Marker(ex_b.to_owned()), + ContextEntry::ExistentialVar(ex_b.to_owned()), + ]); + + let aug_b = ty_b.subst(beta, &Type::Existential(ex_b.to_owned())); + let out_ctx = instantiate_right(&aug_ctx, &aug_b, a)?; + + let (before, _after) = out_ctx + .split_by( + |entry| matches!(entry, ContextEntry::Marker(m) if *m == ex_b), + ) + .unwrap(); + + Ok(before) + } + + // InstRSolve + ty_a if ty_a.is_mono() && ctx.has_existential(a) => { + let (before, after) = ctx + .split_by(|entry| match entry { + ContextEntry::ExistentialVar(n) if n == a => true, + _ => false, + }) + .unwrap(); + + let ty_a_mono = ty_a.into_mono().unwrap(); + + Ok(Context::unsplit( + &before, + ContextEntry::ExistentialSolved(a.to_owned(), ty_a_mono), + &after, + )) + } + + Type::Unit => todo!(), + Type::Var(_) => todo!(), + Type::Existential(_) => todo!(), + + _ => todo!(), + } +} + +// Figure 11. Algorithmic typing + +#[cfg_attr(feature = "trace_execution", trace)] +pub fn typecheck(ctx: &Context, term: &Term, ty: &Type) -> Result { + match (term, ty) { + // 1I rule + (Term::Unit, Type::Unit) => Ok(ctx.clone()), + + // ∀I rule + (_e, Type::Polytype(_x, _tyA)) => todo!(), + + // →I rule + (Term::Lam(_x, _e), Type::Arrow(_ty_a, _ty_b)) => { + let _aug_ctx = ctx.clone(); + todo!() + } + + // Sub rule + (term, ty) => { + let (ty_a, ctx_theta) = synthesize(ctx, term)?; + let a = app_ctx(&ctx_theta, &ty_a)?; + let b = app_ctx(&ctx_theta, ty)?; + let ctx_delta = subtype(&ctx_theta, &a, &b)?; + Ok(ctx_delta) + } + } +} + +#[cfg_attr(feature = "trace_execution", trace)] +pub fn synthesize(ctx: &Context, term: &Term) -> Result<(Type, Context)> { + match term { + // Var rule + Term::Var(name) if ctx.has_type(name) => { + let (_, ty) = ctx.lookup_type(name).unwrap(); + Ok((ty, ctx.clone())) + } + Term::Var(name) => bail!("could not find name {name}"), + + // 1I⇒ rule + Term::Unit => Ok((Type::Unit, ctx.clone())), + + // Anno rule + Term::Annot(e, ty_a) => { + // Make sure the type is well formed + // TODO: Have an actual "well-formed" check + + let ctx_delta = typecheck(ctx, &e, ty_a)?; + Ok((ty_a.clone(), ctx_delta)) + } + + // →I⇒' rule + Term::Lam(x, e) => { + let ex_a_s = gensym_existential(); + let ex_b_s = gensym_existential(); + + let ex_gen = format!("{}*", ex_a_s); + + let ex_a = Type::Existential(ex_a_s.clone()); + let ex_b = Type::Existential(ex_b_s.clone()); + + let aug_ctx = ctx.add(vec![ + ContextEntry::Marker(ex_a_s.clone()), + ContextEntry::ExistentialVar(ex_a_s.clone()), + ContextEntry::ExistentialVar(ex_b_s.clone()), + ContextEntry::TermAnnot(x.clone(), ex_a.clone()), + ]); + + let wtf_ctx = typecheck(&aug_ctx, &e, &ex_b)?; + info!("WTF CTX {wtf_ctx:?}"); + + // Split back out at the marker + let (before_marker, after_marker) = wtf_ctx + .split_by(|entry| match entry { + ContextEntry::Marker(m) if *m == ex_a_s => true, + _ => false, + }) + .unwrap(); + info!("Unsolved: {:?}", after_marker.unsolved_existentials()); + + let mut tau = + app_ctx(&after_marker, &Type::Arrow(Box::new(ex_a), Box::new(ex_b)))?; + for name in after_marker.unsolved_existentials() { + warn!("substituting {tau:?} looking for {name}"); + tau = tau.subst(&name, &Type::Var(ex_gen.clone())); + } + + Ok((Type::Polytype(ex_gen, Box::new(tau)), before_marker)) + } + + // // →I⇒ rule + // // > Rule →I⇒ corresponds to Decl→I⇒, one of the guessing rules, so we + // // > create new existential variables ^α (for the function domain) and ^β (for + // // > the codomain) and check the function body against ^β. As in ∀App, we do + // // > not place a marker before ^α, because ^α and ^β appear in the output type + // // > (λx. e ⇒ ^α → ^β). + // Term::Lam(x, e) => { + // let ex_a_s = gensym_existential(); + // let ex_b_s = gensym_existential(); + // let ex_a = Type::Existential(ex_a_s.clone()); + // let ex_b = Type::Existential(ex_b_s.clone()); + // let aug_ctx = ctx.add(vec![ + // ContextEntry::ExistentialVar(ex_a_s.clone()), + // ContextEntry::ExistentialVar(ex_b_s.clone()), + // ContextEntry::TermAnnot(x.clone(), ex_a.clone()), + // ]); + + // let wtf_ctx = typecheck(&aug_ctx, &e, &ex_b)?; + // Ok((Type::Arrow(Box::new(ex_a), Box::new(ex_b)), ctx.clone())) + // } + + // →E rule + Term::App(e1, e2) => { + let (ty_a, ctx_theta) = synthesize(ctx, e1)?; + let app_a = app_ctx(&ctx_theta, &ty_a)?; + let (ty_c, ctx_delta) = app_synthesize(&ctx_theta, &app_a, &e2)?; + Ok((ty_c, ctx_delta)) + } + } +} + +#[cfg_attr(feature = "trace_execution", trace)] +pub fn app_synthesize( + ctx: &Context, + fun_ty: &Type, + term: &Term, +) -> Result<(Type, Context)> { + match (fun_ty, term) { + // →App rule + (Type::Arrow(ty_a, ty_c), e) => { + let out_ctx = typecheck(ctx, e, ty_a)?; + Ok((*ty_c.clone(), out_ctx)) + } + + // ∀App rule + (Type::Polytype(a, ty_a), e) => { + let ex_s = gensym_existential(); + let ex = ContextEntry::ExistentialVar(ex_s.clone()); + let aug_ctx = ctx.add(vec![ex.clone()]); + + let aug_ty = ty_a.subst(&a, &Type::Existential(ex_s)); + let (ty, ctx_delta) = app_synthesize(&aug_ctx, &aug_ty, e)?; + + Ok((ty, ctx_delta)) + } + + // âApp rule + (Type::Existential(a), e) if ctx.has_existential(a) => { + let (ex_a1_s, ex_a2_s, ctx_gamma_aug) = + ctx.split_existential_function(a)?; + + let ex_a1 = Type::Existential(ex_a1_s.clone()); + let ctx_delta = typecheck(&ctx_gamma_aug, e, &ex_a1)?; + + let ex_a2 = Type::Existential(ex_a2_s.clone()); + Ok((ex_a2, ctx_delta)) + } + + _ => bail!("trying to appSynthesize with a non-function type"), + } +} diff --git a/src/bidir_debruijn.rs b/src/bidir_debruijn.rs new file mode 100644 index 0000000..ecead61 --- /dev/null +++ b/src/bidir_debruijn.rs @@ -0,0 +1,365 @@ +use anyhow::{bail, ensure, Result}; + +use crate::data_debruijn::{ + Context, ContextEntry, ContextIndex, Monotype, Term, Type, Visitor, +}; +use crate::gensym::Symbol; +use crate::DEPTH; + +// Figure 8. Applying a context, as a substitution, to a type + +#[trace] +pub fn app_ctx(ctx: &Context, ty: &Type) -> Result { + match ty { + Type::Unit => Ok(Type::Unit), + Type::Var(s) => Ok(Type::Var(s.clone())), + + Type::Existential(a) => match ctx.get_existential(a) { + Some(Some(m)) => Ok(m.into_poly()), + Some(None) => Ok(Type::Existential(a.clone())), + None => bail!("existential variable {a:?} doesn't exist in context"), + }, + + // TODO: Is this right? + // Type::Polytype(t) => { + // let t = app_ctx(ctx, t)?; + // Ok(Type::Polytype(Box::new(t))) + // } + Type::Polytype(t) => { + // Weaken the context + let (aug_ctx, _) = + ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let t = app_ctx(&aug_ctx, t)?; + Ok(Type::Polytype(Box::new(t))) + } + + Type::Arrow(a, b) => Ok(Type::Arrow( + Box::new(app_ctx(ctx, a)?), + Box::new(app_ctx(ctx, b)?), + )), + } +} + +// Figure 9. Algorithmic subtyping + +/// Under input context Γ , type A is a subtype of B, with output context ∆ +pub fn subtype(ctx: &Context, left: &Type, right: &Type) -> Result { + match (left, right) { + // <:Unit rule + (Type::Unit, Type::Unit) => Ok(ctx.clone()), + + // <:Var rule + (Type::Var(x), Type::Var(y)) if x == y && ctx.get_type(x).is_some() => { + Ok(ctx.clone()) + } + + // <:Exvar rule + (Type::Existential(x), Type::Existential(y)) + if x == y && ctx.get_existential(x).is_some() => + { + Ok(ctx.clone()) + } + + // <:InstantiateL + (Type::Existential(a) , ty_a) if ctx.get_existential(a).is_some() => { + instantiate_left(ctx, a, ty_a) + } + + // <:InstantiateR + (ty_a, Type::Existential(a)) if ctx.get_existential(a).is_some() => { + instantiate_right (ctx, ty_a, a) + } + + (Type::Unit, Type::Var(_)) => todo!("wtf? {left:?} {right:?}"), + (Type::Unit, Type::Polytype(_)) => todo!(), + (Type::Unit, Type::Arrow(_, _)) => todo!(), + (Type::Var(_), Type::Unit) => todo!(), + (Type::Var(_), Type::Var(_)) => todo!(), + (Type::Var(_), Type::Existential(_)) => todo!(), + (Type::Var(_), Type::Polytype(_)) => todo!(), + (Type::Var(_), Type::Arrow(_, _)) => todo!(), + (Type::Existential(_), Type::Unit) => todo!(), + (Type::Existential(_), Type::Var(_)) => todo!(), + (Type::Existential(_), Type::Existential(_)) => todo!(), + (Type::Existential(_), Type::Polytype(_)) => todo!(), + (Type::Existential(_), Type::Arrow(_, _)) => todo!(), + (Type::Polytype(_), Type::Unit) => todo!(), + (Type::Polytype(_), Type::Var(_)) => todo!(), + (Type::Polytype(_), Type::Existential(_)) => todo!(), + (Type::Polytype(_), Type::Polytype(_)) => todo!(), + (Type::Polytype(_), Type::Arrow(_, _)) => todo!(), + (Type::Arrow(_, _), Type::Unit) => todo!(), + (Type::Arrow(_, _), Type::Var(_)) => todo!(), + (Type::Arrow(_, _), Type::Existential(_)) => todo!(), + (Type::Arrow(_, _), Type::Polytype(_)) => todo!(), + (Type::Arrow(_, _), Type::Arrow(_, _)) => todo!(), + + _ => bail!("subtyping relation failed between {left:?} and {right:?} (ctx = {ctx:?})"), + } +} + +// Figure 10. Instantiation + +#[trace] +pub fn instantiate_left( + ctx: &Context, + a: &ContextIndex, + ty_a: &Type, +) -> Result { + match ty_a { + // InstLReach rule + Type::Existential(b) + if ctx.get_existential(a).is_some() + && ctx.get_existential(b).is_some() => + { + let mut new_ctx = ctx.clone(); + { + let b_entry = new_ctx + .vector + .get_mut(b.debruijn_level) + .expect("should exist"); + + ensure!( + matches!(b_entry, ContextEntry::ExistentialVar(_)), + "not an existential variable" + ); + + *b_entry = + ContextEntry::ExistentialSolved(Monotype::Existential(a.to_owned())); + } + + Ok(new_ctx) + } + + Type::Existential(_b) => todo!(), + Type::Unit => todo!(), + Type::Var(_) => todo!(), + Type::Polytype(_) => todo!(), + + // InstLArr rule + Type::Arrow(ty_a1, ty_a2) => { + let (aug_ctx_a2, a2_idx) = + ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let (aug_ctx_a1, a1_idx) = + ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let (aug_ctx, a_idx) = + ctx.add(ContextEntry::ExistentialSolved(Monotype::Arrow( + Box::new(Monotype::Existential(a1_idx.clone())), + Box::new(Monotype::Existential(a2_idx.clone())), + )))?; + + let a1 = Type::Existential(a1_idx.clone()); + let a2 = Type::Existential(a2_idx.clone()); + + let ctx_theta = instantiate_right(&aug_ctx, &ty_a1, &a1_idx)?; + + let replaced_a2 = app_ctx(&ctx_theta, &ty_a2)?; + let ctx_delta = instantiate_left(&ctx_theta, &a2_idx, &replaced_a2)?; + + Ok(ctx_delta) + } + } +} + +#[trace] +pub fn instantiate_right( + ctx: &Context, + ty_a: &Type, + a: &ContextIndex, +) -> Result { + match ty_a { + // InstRSolve rule + ty if ty.is_mono() => { + let mut new_ctx = ctx.clone(); + { + let a_entry = new_ctx + .vector + .get_mut(a.debruijn_level) + .expect("should exist"); + + println!("ty: {ty:?}, a_entry: {a_entry:?}"); + ensure!( + matches!(a_entry, ContextEntry::ExistentialVar(_)), + "{a_entry:?} (@ {a:?}) is not an existential variable", + ); + + *a_entry = ContextEntry::ExistentialSolved(ty.try_into_mono().unwrap()); + } + Ok(new_ctx) + } + + Type::Unit => todo!("a={a:?}, ty_a={ty_a:?}, ctx={ctx:?}"), + Type::Var(_) => todo!(), + Type::Existential(_) => todo!(), + Type::Polytype(_) => todo!(), + Type::Arrow(_, _) => todo!(), + } +} + +// Figure 11. Algorithmic typing + +#[trace] +pub fn typecheck(ctx: &Context, term: &Term, ty: &Type) -> Result { + match (term, ty) { + // 1I rule + (Term::Unit, Type::Unit) => Ok(ctx.clone()), + + // ∀I rule + (_e, Type::Polytype(_t)) => todo!(), + + // →I rule + (Term::Lam(_e), Type::Arrow(_ty_a, _ty_b)) => { + todo!() + } + + // Sub rule + (term, ty) => { + let (ty_a, ctx_theta) = synthesize(ctx, term)?; + let a = app_ctx(&ctx_theta, &ty_a)?; + let b = app_ctx(&ctx_theta, ty)?; + let ctx_delta = subtype(&ctx_theta, &a, &b)?; + Ok(ctx_delta) + } + } +} + +#[trace] +pub fn synthesize(ctx: &Context, term: &Term) -> Result<(Type, Context)> { + match term { + // 1I⇒ rule + Term::Unit => Ok((Type::Unit, ctx.clone())), + + // Var rule + Term::Var(index) => { + let ty = match ctx.get_type(index) { + Some(v) => v, + None => bail!("no TermAnnot at index {index:?} of context: {ctx:?}"), + }; + Ok((ty, ctx.clone())) + } + + // →E rule + Term::App(e1, e2) => { + let (ty_a, ctx_theta) = synthesize(ctx, e1)?; + let app_a = app_ctx(&ctx_theta, &ty_a)?; + let (ty_c, ctx_delta) = app_synthesize(&ctx_theta, &app_a, &e2)?; + Ok((ty_c, ctx_delta)) + } + + // →I⇒' rule + Term::Lam(e) => { + let (aug_ctx, marker_idx) = ctx.add(ContextEntry::Marker)?; + let (aug_ctx_at_a, ex_a_idx) = + aug_ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let (aug_ctx_at_b, ex_b_idx) = + aug_ctx_at_a.add(ContextEntry::ExistentialVar(Symbol::default()))?; + + let ex_a = Type::Existential(ex_a_idx.clone()); + let ex_b = Type::Existential(ex_b_idx.clone()); + + let (aug_ctx, _annot_idx) = + aug_ctx_at_b.add(ContextEntry::TermAnnot(ex_a.clone()))?; + + struct V(usize, usize); + impl Visitor for V { + fn visit_index(&self, index: &mut ContextIndex) -> Result<()> { + index.debruijn_index += self.0; + index.debruijn_level = self.1 - 1 - index.debruijn_index; + Ok(()) + } + } + + let ex_a_2 = ex_b.transform_with_visitor(&V(2, aug_ctx.size()))?; + let ex_b_2 = ex_b.transform_with_visitor(&V(1, aug_ctx.size()))?; + let e_2 = e.transform_with_visitor(&V(0, aug_ctx.size()))?; + + let wtf_ctx = typecheck(&aug_ctx, &e_2, &ex_b_2)?; + + let (before_marker, after_marker) = wtf_ctx.split_at(&marker_idx); + + // Bump the levels down since we're splitting teh array + struct V2(usize, usize); + impl Visitor for V2 { + fn visit_index(&self, index: &mut ContextIndex) -> Result<()> { + index.debruijn_level -= self.0; + index.debruijn_index = self.1 - 1 - index.debruijn_level; + + Ok(()) + } + } + let after_marker = + after_marker.transform_with_visitor(&V2(1, after_marker.size()))?; + + // τ=[∆'](â→β) + let tau = Type::Arrow(Box::new(ex_a_2), Box::new(ex_b_2)); + let tau = tau.transform_with_visitor(&V2(1, after_marker.size()))?; + let tau = app_ctx(&after_marker, &tau)?; + + // let mut before_marker = before_marker; + // before_marker.vector.push_back(ContextEntry::ExistentialVar); + + Ok((Type::Polytype(Box::new(tau)), before_marker)) + } + + Term::Annot(_, _) => todo!(), + } +} + +pub fn app_synthesize( + ctx: &Context, + fun_ty: &Type, + term: &Term, +) -> Result<(Type, Context)> { + match (fun_ty, term) { + // →App rule + (Type::Arrow(ty_a, ty_c), e) => { + let out_ctx = typecheck(ctx, e, ty_a)?; + Ok((*ty_c.clone(), out_ctx)) + } + + // ∀App rule + (Type::Polytype(ty_a), e) => { + let (aug_ctx, a_idx) = + ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let aug_ty = ty_a.subst(&a_idx, Type::Existential(a_idx.clone())); + let (ty, ctx_delta) = app_synthesize(&aug_ctx, &aug_ty, e)?; + + Ok((ty, ctx_delta)) + } + + // âApp rule + (Type::Existential(a), e) if ctx.get_existential(a).is_some() => { + let (aug_ctx_a2, a2_idx) = + ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let (aug_ctx_a1, a1_idx) = + ctx.add(ContextEntry::ExistentialVar(Symbol::default()))?; + let (aug_ctx, a_idx) = + ctx.add(ContextEntry::ExistentialSolved(Monotype::Arrow( + Box::new(Monotype::Existential(a1_idx.clone())), + Box::new(Monotype::Existential(a2_idx.clone())), + )))?; + // let (ex_a1_s, ex_a2_s, ctx_gamma_aug) = + // ctx.split_existential_function(a)?; + // let ex_a1 = Type::Existential(ex_a1_s.clone()); + + let a1 = Type::Existential(a1_idx); + let a2 = Type::Existential(a2_idx); + let ctx_delta = typecheck(&aug_ctx, e, &a1)?; + + Ok((a2, ctx_delta)) + } + + (Type::Unit, Term::Unit) => todo!(), + (Type::Unit, Term::Var(_)) => todo!(), + (Type::Unit, Term::Lam(_)) => todo!(), + (Type::Unit, Term::App(_, _)) => todo!(), + (Type::Unit, Term::Annot(_, _)) => todo!(), + (Type::Var(_), Term::Unit) => todo!(), + (Type::Var(_), Term::Var(_)) => todo!(), + (Type::Var(_), Term::Lam(_)) => todo!(), + (Type::Var(_), Term::App(_, _)) => todo!(), + (Type::Var(_), Term::Annot(_, _)) => todo!(), + + _ => bail!("trying to appSynthesize with a non-function type"), + } +} diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..3d45e98 --- /dev/null +++ b/src/data.rs @@ -0,0 +1,322 @@ +use std::{fmt, hash::Hash}; + +use anyhow::{bail, Result}; +use im::{HashSet, Vector}; + +use crate::gensym::gensym_existential; + +#[derive(Clone)] +pub enum Term { + Unit, + Var(String), + Lam(String, Box), + App(Box, Box), + Annot(Box, Type), +} + +impl fmt::Debug for Term { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "unit"), + Self::Var(arg0) => write!(f, "{}", arg0), + Self::Lam(arg0, arg1) => write!(f, "(λ{}.{:?})", arg0, arg1), + Self::App(arg0, arg1) => write!(f, "({:?} · {:?})", arg0, arg1), + Self::Annot(arg0, arg1) => write!(f, "({:?} : {:?})", arg0, arg1), + } + } +} + +#[derive(Clone)] +pub enum Type { + Unit, + Var(String), + Existential(String), + Polytype(String, Box), + Arrow(Box, Box), +} + +impl fmt::Debug for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "𝟙"), + Self::Var(arg0) => write!(f, "{}", arg0), + Self::Existential(arg0) => write!(f, "{}", arg0), + Self::Polytype(arg0, arg1) => write!(f, "(∀ {} . {:?})", arg0, arg1), + Self::Arrow(arg0, arg1) => write!(f, "({:?} -> {:?})", arg0, arg1), + } + } +} + +impl Type { + pub fn into_mono(&self) -> Option { + match self { + Type::Unit => Some(Monotype::Unit), + Type::Var(x) => Some(Monotype::Var(x.clone())), + Type::Existential(x) => Some(Monotype::Existential(x.clone())), + Type::Polytype(_, _) => None, + Type::Arrow(a, b) => Some(Monotype::Arrow( + Box::new(a.into_mono()?), + Box::new(b.into_mono()?), + )), + } + } + + #[inline] + pub fn is_mono(&self) -> bool { + self.into_mono().is_some() + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum FreeVar { + Var(String), + Existential(String), +} + +impl Type { + pub fn free_vars(&self) -> HashSet { + fn free_vars_with_context(ctx: &Context, ty: &Type) -> HashSet { + match ty { + Type::Unit => HashSet::default(), + Type::Var(x) if ctx.lookup_type(x).is_some() => HashSet::default(), + Type::Var(x) => [FreeVar::Var(x.to_owned())].into_iter().collect(), + Type::Existential(x) if ctx.lookup_existential(x).is_some() => { + HashSet::default() + } + Type::Existential(x) => { + [FreeVar::Existential(x.to_owned())].into_iter().collect() + } + Type::Polytype(x, ty_a) => { + let new_ctx = + ctx.add(vec![ContextEntry::ExistentialVar(x.to_owned())]); + free_vars_with_context(&new_ctx, &ty_a) + } + Type::Arrow(ty_a, ty_b) => { + let a_vars = free_vars_with_context(&ctx, &ty_a); + let b_vars = free_vars_with_context(&ctx, &ty_b); + a_vars.union(b_vars) + } + } + } + + free_vars_with_context(&Context::default(), self) + } + + pub fn subst(&self, var: &str, replacement: &Type) -> Type { + match self { + Type::Unit => Type::Unit, + Type::Var(n) if n == var => replacement.clone(), + Type::Var(n) => Type::Var(n.clone()), + Type::Existential(s) if s == var => replacement.clone(), + Type::Existential(s) => Type::Existential(s.clone()), + Type::Polytype(a, t) => { + Type::Polytype(a.clone(), Box::new(t.subst(var, replacement))) + } + Type::Arrow(a, b) => Type::Arrow( + Box::new(a.subst(var, replacement)), + Box::new(b.subst(var, replacement)), + ), + } + } +} + +#[derive(Clone)] +pub enum Monotype { + Unit, + Var(String), + Existential(String), + Arrow(Box, Box), +} + +impl fmt::Debug for Monotype { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "𝟙"), + Self::Var(arg0) => write!(f, "{}", arg0), + Self::Existential(arg0) => write!(f, "{}", arg0), + Self::Arrow(arg0, arg1) => write!(f, "({arg0:?} -> {arg1:?})"), + } + } +} + +impl Monotype { + pub fn into_poly(&self) -> Type { + match self { + Monotype::Unit => Type::Unit, + Monotype::Var(x) => Type::Var(x.clone()), + Monotype::Existential(x) => Type::Existential(x.clone()), + Monotype::Arrow(a, b) => { + Type::Arrow(Box::new(a.into_poly()), Box::new(b.into_poly())) + } + } + } +} + +#[derive(Clone)] +pub enum ContextEntry { + TypeVar(String), + TermAnnot(String, Type), + ExistentialVar(String), + ExistentialSolved(String, Monotype), + Marker(String), +} + +impl fmt::Debug for ContextEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TypeVar(arg0) => write!(f, "{}", arg0), + Self::TermAnnot(arg0, arg1) => write!(f, "{} : {:?}", arg0, arg1), + Self::ExistentialVar(arg0) => write!(f, "{}", arg0), + Self::ExistentialSolved(arg0, arg1) => write!(f, "{} ≔ {:?}", arg0, arg1), + Self::Marker(arg0) => write!(f, "▶{}", arg0), + } + } +} + +#[derive(Debug, Clone)] +pub enum CompleteContextEntry { + TypeVar(String), + TermAnnot(String, Type), + ExistentialSolved(String, Monotype), + Marker(String), +} + +#[derive(Clone, Default)] +pub struct Context(pub(crate) Vector); + +impl fmt::Debug for Context { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Γ")?; + for rule in self.0.iter() { + f.write_str(", ")?; + rule.fmt(f)?; + } + Ok(()) + } +} + +impl Context { + pub fn add(&self, entries: Vec) -> Context { + let mut new_ctx = self.clone(); + for entry in entries { + new_ctx.0.push_back(entry); + } + new_ctx + } + + /// Looks up a polytype by name, also returning an index + pub fn lookup_type(&self, name: impl AsRef) -> Option<(usize, Type)> { + self + .0 + .iter() + .enumerate() + .find_map(|(i, entry)| match entry { + ContextEntry::TermAnnot(n, t) if n == name.as_ref() => { + Some((i, t.clone())) + } + _ => None, + }) + } + + #[inline] + pub fn has_type(&self, name: impl AsRef) -> bool { + self.lookup_type(name).is_some() + } + + /// Looks up an existential variable by name + /// - Returns Some(Some(t)) if solved + /// - Returns Some(None) if exists but unsolved + /// - Returns None if not found + pub fn lookup_existential( + &self, + name: impl AsRef, + ) -> Option<(usize, Option)> { + self + .0 + .iter() + .enumerate() + .find_map(|(i, entry)| match entry { + ContextEntry::ExistentialVar(n) if n == name.as_ref() => { + Some((i, None)) + } + ContextEntry::ExistentialSolved(n, t) if n == name.as_ref() => { + Some((i, Some(t.clone()))) + } + _ => None, + }) + } + + #[inline] + pub fn has_existential(&self, name: impl AsRef) -> bool { + self.lookup_existential(name).is_some() + } + + /// Returns a list of names of unsolved existentials + pub fn unsolved_existentials(&self) -> HashSet { + let mut unsolved = HashSet::new(); + + for entry in self.0.iter() { + match entry { + ContextEntry::ExistentialVar(n) => { + unsolved.insert(n.clone()); + } + _ => {} + } + } + + unsolved + } + + /// Returns (before, after) + pub fn split_by

(&self, p: P) -> Option<(Context, Context)> + where + P: Fn(&ContextEntry) -> bool, + { + let (before, after) = { + let idx = self.0.iter().position(p)?; + self.0.clone().split_at(idx) + }; + + Some((Context(before), Context(after))) + } + + pub fn unsplit( + left: &Context, + center: ContextEntry, + right: &Context, + ) -> Context { + let mut res = left.clone(); + res.0.push_back(center); + res.0.extend(right.0.clone().into_iter()); + res + } + + pub fn split_existential_function( + &self, + var: &str, + ) -> Result<(String, String, Context)> { + let mut ctx = self.clone(); + let idx = match ctx.lookup_existential(var) { + Some((idx, _)) => idx, + None => bail!("wtf?"), + }; + + let ex_a1_s = gensym_existential(); + let ex_a2_s = gensym_existential(); + ctx.0[idx] = ContextEntry::ExistentialSolved( + var.to_owned(), + Monotype::Arrow( + Box::new(Monotype::Existential(ex_a1_s.to_owned())), + Box::new(Monotype::Existential(ex_a2_s.to_owned())), + ), + ); + ctx + .0 + .insert(idx, ContextEntry::ExistentialVar(ex_a1_s.to_owned())); + ctx + .0 + .insert(idx, ContextEntry::ExistentialVar(ex_a2_s.to_owned())); + + Ok((ex_a1_s, ex_a2_s, ctx)) + } +} diff --git a/src/data_debruijn.rs b/src/data_debruijn.rs new file mode 100644 index 0000000..b270d20 --- /dev/null +++ b/src/data_debruijn.rs @@ -0,0 +1,591 @@ +use std::fmt::{self}; + +use anyhow::Result; +use im::Vector; + +use crate::{ + data, + gensym::{gensym_type, Symbol}, +}; + +/// A lambda calculus term. +#[derive(Clone)] +pub enum Term { + /// Unit type + Unit, + + /// Variable, with a reference into the context. + /// The entry pointed to by this index MUST be a TypeVar. + Var(ContextIndex), + + /// Lambda abstraction. + Lam(Box), + + /// Lambda application. + App(Box, Box), + + /// Type annotation + Annot(Box, Type), +} + +impl fmt::Debug for Term { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "unit"), + Self::Var(arg0) => write!(f, "{:?}", arg0), + Self::Lam(arg1) => write!(f, "(λ.{:?})", arg1), + Self::App(arg0, arg1) => write!(f, "({:?} · {:?})", arg0, arg1), + Self::Annot(arg0, arg1) => write!(f, "({:?} : {:?})", arg0, arg1), + } + } +} + +// impl Arbitrary for Term { +// fn arbitrary(g: &mut Gen) -> Self { +// // let var = Term::Var(ContextIndex::arbitrary(g)); +// match g.choose(&[0, 1, 2, 3, 4]).unwrap() { +// 0 => Term::Unit, +// 1 => Term::Var(ContextIndex::arbitrary(g)), +// 2 => Term::Lam(Box::new(Term::arbitrary(g))), +// 3 => { +// Term::App(Box::new(Term::arbitrary(g)), Box::new(Term::arbitrary(g))) +// } +// 4 => Term::Annot(Box::new(Term::arbitrary(g)), Type::Unit), +// _ => unreachable!(), +// } +// } +// } + +impl Term { + pub fn transform_with_visitor( + &self, + visitor: &V, + ) -> Result { + let mut expr = self.clone(); + visitor.visit_term_before(&mut expr)?; + let mut expr = match expr { + Term::Var(index) => { + let mut index = index.clone(); + visitor.visit_index(&mut index)?; + Term::Var(index) + } + Term::Lam(body) => { + // TODO: + body.transform_with_visitor(visitor)? + } + Term::App(a, b) => { + let a = a.transform_with_visitor(visitor)?; + let b = b.transform_with_visitor(visitor)?; + Term::App(Box::new(a), Box::new(b)) + } + Term::Annot(_, _) => todo!(), + _ => expr, + }; + visitor.visit_term_after(&mut expr)?; + Ok(expr) + } +} + +#[derive(Clone)] +pub enum Type { + Unit, + Var(ContextIndex), + Existential(ContextIndex), + Polytype(Box), + Arrow(Box, Box), +} + +impl fmt::Debug for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "𝟙"), + Self::Var(arg0) => write!(f, "{:?}", arg0), + Self::Existential(arg0) => write!(f, "ex{:?}", arg0), + Self::Polytype(arg1) => write!(f, "(∀.{:?})", arg1), + Self::Arrow(arg0, arg1) => write!(f, "({:?} -> {:?})", arg0, arg1), + } + } +} + +impl Type { + /// Attempt to turn this polytype into a monotype. + /// + /// This fails if any sub-expression of this type contains a polytype expression. + pub fn try_into_mono(&self) -> Option { + match self { + Type::Unit => Some(Monotype::Unit), + Type::Var(x) => Some(Monotype::Var(x.clone())), + Type::Existential(x) => Some(Monotype::Existential(x.clone())), + + // Polytypes cannot be converted to monotypes + Type::Polytype(_) => None, + + Type::Arrow(a, b) => Some(Monotype::Arrow( + Box::new(a.try_into_mono()?), + Box::new(b.try_into_mono()?), + )), + } + } + + #[inline] + pub fn is_mono(&self) -> bool { + self.try_into_mono().is_some() + } + + pub fn subst(&self, before: &ContextIndex, after: Type) -> Type { + match self { + Type::Unit => Type::Unit, + Type::Var(index) if index.debruijn_level == before.debruijn_level => { + after + } + Type::Var(index) => Type::Var(index.clone()), + Type::Existential(index) + if index.debruijn_level == before.debruijn_level => + { + after + } + Type::Existential(index) => Type::Existential(index.clone()), + Type::Polytype(_) => todo!(), + Type::Arrow(a, b) => Type::Arrow( + Box::new(a.subst(before, after.clone())), + Box::new(b.subst(before, after.clone())), + ), + } + } + + pub fn transform_with_visitor( + &self, + visitor: &V, + ) -> Result { + let mut ty = self.clone(); + visitor.visit_type_before(&mut ty)?; + let mut ty = match ty { + Type::Var(_) => todo!(), + Type::Existential(index) => { + let mut index = index.clone(); + visitor.visit_index(&mut index)?; + Type::Existential(index) + } + Type::Polytype(_) => todo!(), + Type::Arrow(a, b) => { + let a = a.transform_with_visitor(visitor)?; + let b = b.transform_with_visitor(visitor)?; + Type::Arrow(Box::new(a), Box::new(b)) + } + _ => ty, + }; + visitor.visit_type_after(&mut ty)?; + Ok(ty) + } +} + +#[derive(Clone)] +pub enum Monotype { + Unit, + Var(ContextIndex), + Existential(ContextIndex), + Arrow(Box, Box), +} + +impl fmt::Debug for Monotype { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unit => write!(f, "m𝟙"), + Self::Var(arg0) => write!(f, "m{:?}", arg0), + Self::Existential(arg0) => write!(f, "m'ex{:?}", arg0), + Self::Arrow(arg0, arg1) => write!(f, "m({:?} -> {:?})", arg0, arg1), + } + } +} + +impl Monotype { + pub fn into_poly(&self) -> Type { + match self { + Monotype::Unit => Type::Unit, + Monotype::Var(x) => Type::Var(x.clone()), + Monotype::Existential(x) => Type::Existential(x.clone()), + Monotype::Arrow(a, b) => { + Type::Arrow(Box::new(a.into_poly()), Box::new(b.into_poly())) + } + } + } + + pub fn transform_with_visitor( + &self, + visitor: &V, + ) -> Result { + let mut ty = self.clone(); + visitor.visit_monotype_before(&mut ty)?; + let mut ty = match ty { + Monotype::Var(_) => todo!(), + Monotype::Existential(index) => { + let mut index = index.clone(); + visitor.visit_index(&mut index)?; + Monotype::Existential(index) + } + Monotype::Arrow(a, b) => { + let a = a.transform_with_visitor(visitor)?; + let b = b.transform_with_visitor(visitor)?; + Monotype::Arrow(Box::new(a), Box::new(b)) + } + _ => ty, + }; + visitor.visit_monotype_after(&mut ty)?; + Ok(ty) + } +} + +#[derive(Clone)] +pub enum ContextEntry { + TypeVar(Symbol), + TermAnnot(Type), + ExistentialVar(Symbol), + ExistentialSolved(Monotype), + Marker, +} + +impl ContextEntry { + pub fn name(&self) -> String { + match self { + ContextEntry::TypeVar(name) | ContextEntry::ExistentialVar(name) => { + name.0.to_owned() + } + _ => String::new(), + } + } +} + +impl fmt::Debug for ContextEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TypeVar(name) => write!(f, "Ty({name})"), + Self::TermAnnot(arg0) => f.debug_tuple("Annot").field(arg0).finish(), + Self::ExistentialVar(name) => write!(f, "ExVar({name})"), + Self::ExistentialSolved(arg0) => { + f.debug_tuple("ExSolv").field(arg0).finish() + } + Self::Marker => write!(f, "▶"), + } + } +} + +#[derive(Debug, Clone)] +pub enum CompleteContextEntry { + TypeVar(String), + TermAnnot(String, Type), + ExistentialSolved(String, Monotype), + Marker(String), +} + +#[derive(Clone)] +pub struct Context { + // TODO: Make this not pub(crate) + pub(crate) vector: Vector, +} + +impl fmt::Debug for Context { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Γ{:?}", self.vector) + } +} + +impl Default for Context { + fn default() -> Self { + let vector = Vector::default(); + + Context { vector } + } +} + +impl Context { + #[inline] + pub fn size(&self) -> usize { + self.vector.len() + } + + pub fn add(&self, item: ContextEntry) -> Result<(Context, ContextIndex)> { + let idx = self.vector.len(); + struct V; + impl Visitor for V { + fn visit_index(&self, index: &mut ContextIndex) -> Result<()> { + index.debruijn_index += 1; + Ok(()) + } + } + let mut new_ctx = self.transform_with_visitor(&V)?; + let name = item.name(); + new_ctx.vector.push_back(item); + + let idx = ContextIndex { + debruijn_index: 0, + debruijn_level: idx, + label: name, + }; + Ok((new_ctx, idx)) + } + + pub fn get<'a>(&'a self, index: &ContextIndex) -> Option<&ContextEntry> { + let item = self.vector.get(index.debruijn_level)?; + Some(item) + } + + pub fn get_existential( + &self, + index: &ContextIndex, + ) -> Option> { + let item = self.get(index)?; + + match item { + ContextEntry::ExistentialSolved(t) => Some(Some(t.clone())), + ContextEntry::ExistentialVar(_) => Some(None), + _ => None, + } + } + + pub fn get_type(&self, index: &ContextIndex) -> Option { + let item = self.get(index)?; + + match item { + ContextEntry::TermAnnot(t) => Some(t.clone()), + _ => None, + } + } + + pub fn unsolved_existentials(&self) -> Vec { + let mut unsolved = Vec::new(); + for (idx, item) in self.vector.iter().enumerate() { + match item { + ContextEntry::ExistentialVar(_) => { + let index = ContextIndex { + debruijn_level: idx, + debruijn_index: self.vector.len() - idx, + label: item.name(), + }; + unsolved.push(index) + } + _ => {} + } + } + unsolved + } + + /// Splits the context + pub fn split_at(&self, index: &ContextIndex) -> (Context, Context) { + let (before, mut after) = + self.vector.clone().split_at(index.debruijn_level); + after.pop_front(); + + (Context { vector: before }, Context { vector: after }) + } + + pub fn is_valid(&self) -> bool { + for item in self.vector.iter() { + match item { + ContextEntry::TermAnnot(_) => todo!(), + ContextEntry::ExistentialSolved(_) => todo!(), + _ => {} + } + } + true + } + + pub fn ensure_validity(&self) -> bool { + fn ensure_item_validity(ctx: &Context, item: &ContextEntry) -> bool { + match item { + ContextEntry::TermAnnot(ty) => ensure_type_validity(ctx, ty), + ContextEntry::ExistentialSolved(ty) => { + ensure_monotype_validity(ctx, ty) + } + _ => true, + } + } + + fn ensure_type_validity(ctx: &Context, ty: &Type) -> bool { + match ty { + Type::Var(idx) => ensure_index_validity(ctx, idx), + Type::Existential(idx) => ensure_index_validity(ctx, idx), + Type::Polytype(ty) => ensure_type_validity(ctx, ty), + Type::Arrow(ty1, ty2) => { + ensure_type_validity(ctx, ty1) && ensure_type_validity(ctx, ty2) + } + _ => true, + } + } + + fn ensure_monotype_validity(ctx: &Context, ty: &Monotype) -> bool { + match ty { + Monotype::Var(idx) => ensure_index_validity(ctx, idx), + Monotype::Existential(idx) => ensure_index_validity(ctx, idx), + Monotype::Arrow(ty1, ty2) => { + ensure_monotype_validity(ctx, ty1) + && ensure_monotype_validity(ctx, ty2) + } + _ => true, + } + } + + fn ensure_index_validity(ctx: &Context, idx: &ContextIndex) -> bool { + idx.debruijn_index + idx.debruijn_level == ctx.vector.len() + } + + self + .vector + .iter() + .all(|item| ensure_item_validity(self, item)) + } + + pub fn transform_with_visitor( + &self, + visitor: &V, + ) -> Result { + Ok(Context { + vector: self + .vector + .iter() + .map(|entry| { + let mut entry = entry.clone(); + visitor.visit_context_entry_before(&mut entry)?; + let mut entry = match entry { + ContextEntry::TermAnnot(ty) => { + ContextEntry::TermAnnot(ty.transform_with_visitor(visitor)?) + } + ContextEntry::ExistentialSolved(ty) => { + ContextEntry::ExistentialSolved( + ty.transform_with_visitor(visitor)?, + ) + } + _ => entry, + }; + visitor.visit_context_entry_after(&mut entry)?; + Ok(entry) + }) + .collect::>()?, + }) + } +} + +/// An index into the context. +#[derive(Clone, PartialEq, Eq)] +pub struct ContextIndex { + pub(crate) debruijn_index: usize, + pub(crate) debruijn_level: usize, + pub(crate) label: String, +} + +impl fmt::Debug for ContextIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}#{}/{}", + self.label, self.debruijn_level, self.debruijn_index + ) + } +} + +// impl Arbitrary for ContextIndex { +// fn arbitrary(g: &mut Gen) -> Self { +// ContextIndex { +// debruijn_index: usize::arbitrary(g), +// debruijn_level: usize::arbitrary(g), +// } +// } +// } + +/* Convert */ + +pub fn convert_term(term: &data::Term) -> Term { + fn convert_term_with_context( + ctx: &data::Context, + ctx2: &Context, + term: &data::Term, + ) -> Term { + match term { + data::Term::Unit => Term::Unit, + + data::Term::Var(name) => { + println!("Looking up name {name}"); + let (idx, _) = ctx.lookup_type(name).unwrap(); + + let index = ContextIndex { + debruijn_index: 0, + debruijn_level: idx, + label: name.to_owned(), + }; + Term::Var(index) + } + + data::Term::Lam(arg, body) => { + let ty = gensym_type(); + let aug_ctx = ctx.add(vec![data::ContextEntry::TermAnnot( + arg.to_owned(), + data::Type::Var(ty.clone()), + )]); + let body = convert_term_with_context(&aug_ctx, ctx2, body); + Term::Lam(Box::new(body)) + } + + data::Term::App(func, arg) => { + let func = convert_term_with_context(ctx, ctx2, &func); + let arg = convert_term_with_context(ctx, ctx2, &arg); + Term::App(Box::new(func), Box::new(arg)) + } + + data::Term::Annot(term, ty) => { + let term = convert_term_with_context(ctx, ctx2, &term); + let ty = convert_ty_with_context(ctx, ctx2, &ty); + Term::Annot(Box::new(term), ty) + } + } + } + + fn convert_ty_with_context( + _ctx: &data::Context, + _ctx2: &Context, + ty: &data::Type, + ) -> Type { + match ty { + data::Type::Unit => Type::Unit, + + data::Type::Var(_) => todo!(), + data::Type::Existential(_) => todo!(), + data::Type::Polytype(_, _) => todo!(), + data::Type::Arrow(_, _) => todo!(), + } + } + + convert_term_with_context( + &data::Context::default(), + &Context::default(), + term, + ) +} + +pub trait Visitor { + fn visit_context_entry_before(&self, expr: &mut ContextEntry) -> Result<()> { + Ok(()) + } + fn visit_context_entry_after(&self, expr: &mut ContextEntry) -> Result<()> { + Ok(()) + } + fn visit_type_before(&self, expr: &mut Type) -> Result<()> { + Ok(()) + } + fn visit_type_after(&self, expr: &mut Type) -> Result<()> { + Ok(()) + } + fn visit_monotype_before(&self, expr: &mut Monotype) -> Result<()> { + Ok(()) + } + fn visit_monotype_after(&self, expr: &mut Monotype) -> Result<()> { + Ok(()) + } + fn visit_term_before(&self, expr: &mut Term) -> Result<()> { + Ok(()) + } + fn visit_term_after(&self, expr: &mut Term) -> Result<()> { + Ok(()) + } + fn visit_index(&self, index: &mut ContextIndex) -> Result<()> { + Ok(()) + } +} diff --git a/src/gensym.rs b/src/gensym.rs new file mode 100644 index 0000000..9ea9900 --- /dev/null +++ b/src/gensym.rs @@ -0,0 +1,58 @@ +use core::fmt; +use std::fmt::Formatter; + +use dashmap::DashMap; + +thread_local! { + static CTRMAP: DashMap<&'static str, usize> = DashMap::new(); +} + +const EXISTENTIALS: [&'static str; 24] = [ + "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", + "π", "ρ", "σ", "τ", "υ", "φ", "χ", "ψ", "ω", +]; + +const TYPEVARS: [&'static str; 26] = [ + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", +]; + +#[derive(Debug, Clone)] +pub struct Symbol(pub(crate) String); + +impl Default for Symbol { + fn default() -> Self { + let i = idx("wtf"); + Self(format!("var{}", i)) + } +} + +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +pub fn gensym() -> String { + let i = idx("wtf"); + format!("var{}", i) +} + +pub fn gensym_existential() -> String { + let result = idx("existential"); + format!("{}\u{0302}", EXISTENTIALS[result]) +} + +pub fn gensym_type() -> String { + let result = idx("existential"); + format!("{}\u{0302}", TYPEVARS[result]) +} + +fn idx(ty: &'static str) -> usize { + CTRMAP.with(|ctrmap| { + let mut g = ctrmap.entry(ty).or_insert(0); + let ctr = *g; + *g += 1; + ctr + }) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..80daff8 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,32 @@ +#[macro_use] +extern crate quickcheck; +#[macro_use] +extern crate quickcheck_macros; +#[macro_use] +extern crate contracts; +#[macro_use] +extern crate derivative; +#[macro_use] +extern crate tracing; +#[macro_use] +extern crate trace; + +use lalrpop_util::lalrpop_mod; + +// #[macro_export] +// pub mod fmt; + +pub mod abstract_data; +pub mod bidir; +pub mod data; + +pub mod bidir_debruijn; +pub mod data_debruijn; + +mod gensym; +#[cfg(test)] +mod tests; + +lalrpop_mod!(pub parser); + +trace::init_depth_var!(); diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8a0141c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,60 @@ +use anyhow::Result; +use bidir::{ + bidir_debruijn::{app_ctx, synthesize}, + data_debruijn::convert_term, + data_debruijn::Context, + parser::TermParser, +}; +use rustyline::{Config, DefaultEditor}; + +fn main() -> Result<()> { + let term_parser = TermParser::new(); + + let rl_config = Config::builder().auto_add_history(true).build(); + let mut rl = DefaultEditor::with_config(rl_config)?; + + loop { + let line = match rl.readline(">> ") { + Ok(line) => line, + Err(_) => break, + }; + + // let line = r"\x.\y.x"; + + let parsed_term = match term_parser.parse(&line) { + Ok(term) => term, + Err(err) => { + eprintln!("parser error: {err}"); + continue; + } + }; + println!("parsed: {:?}", parsed_term); + + let converted_term = convert_term(&parsed_term); + println!("converted: {converted_term:?}"); + + let ctx = Context::default(); + let (ty, out_ctx) = match synthesize(&ctx, &converted_term) { + Ok(v) => v, + Err(err) => { + eprintln!("typecheck error: {err}"); + eprintln!("{}", err.backtrace()); + continue; + } + }; + + let ty = match app_ctx(&out_ctx, &ty) { + Ok(v) => v, + Err(err) => { + eprintln!("substitution error: {err}"); + eprintln!("{}", err.backtrace()); + continue; + } + }; + + println!("synthesized: {:?}", ty); + // break; + } + + Ok(()) +} diff --git a/src/parser.lalrpop b/src/parser.lalrpop new file mode 100644 index 0000000..4849bae --- /dev/null +++ b/src/parser.lalrpop @@ -0,0 +1,49 @@ +grammar; + +use crate::data::*; + +pub Term: Term = { + #[precedence(level = "1")] + "()" => Term::Unit, + "(" ")" => term, + Ident => Term::Var(<>), + + #[precedence(level = "2")] + "λ" "." => Term::Lam(name, Box::new(term)), + "\\" "." => Term::Lam(name, Box::new(term)), + + #[precedence(level = "4")] + ":" => Term::Annot(Box::new(term), ty), + + #[precedence(level = "5")] + #[assoc(side = "left")] + => Term::App(Box::new(func), Box::new(arg)), +} + +// https://github.com/lalrpop/lalrpop/issues/596 +TermReset: Term = ; + +pub Type: Type = { + #[precedence(level = "0")] + "()" => Type::Unit, + "(" ")" => ty, + + Ident => Type::Var(<>), + ExistIdent => Type::Existential(<>), + "forall" "." => Type::Polytype(name, Box::new(ty)), + + #[precedence(level = "5")] + #[assoc(side = "right")] + "->" => Type::Arrow(Box::new(a), Box::new(b)), +}; + +// https://github.com/lalrpop/lalrpop/issues/596 +TypeReset: Type = ; + +ExistIdent: String = { + r"\^[A-Za-z_]+" => <>.to_string(), +} + +pub Ident: String = { + r"[A-Za-z_]+" => <>.to_string(), +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..d726241 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,60 @@ +use anyhow::{bail, Result}; + +use crate::{ + bidir_debruijn::{app_ctx, synthesize}, + data_debruijn::Context, + data_debruijn::{convert_term, Term}, + parser::TermParser, +}; + +fn term_of(str: &'static str) -> Result { + let term_parser = TermParser::new(); + let term = term_parser.parse(str)?; + let converted = convert_term(&term); + Ok(converted) +} + +#[test] +fn test_id_only() -> Result<()> { + let id = term_of(r"\x.x")?; + let ctx = Context::default(); + let (ty, out_ctx) = synthesize(&ctx, &id)?; + bail!("[test] Synthesized: {:?} (context = {:?})", ty, out_ctx); + Ok(()) +} + +#[test] +fn test_id_of_unit() -> Result<()> { + let id_of_unit = term_of(r"(\x.x) ()")?; + let ctx = Context::default(); + + let (ty, out_ctx) = synthesize(&ctx, &id_of_unit)?; + // let wtf = app_ctx(&out_ctx, &ty); + // println!("WTF: {wtf:?}"); + bail!("[test] Synthesized: {:?} (context = {:?})", ty, out_ctx); + Ok(()) +} + +#[test] +fn test_add() -> Result<()> { + let add = term_of(r"\m.\n.\f.\x. (m f (n f x))")?; + let ctx = Context::default(); + + let (ty, out_ctx) = match synthesize(&ctx, &add) { + Ok(v) => v, + Err(err) => { + error!("WTF? {err}"); + error!("{}", err.backtrace()); + return Err(err); + } + }; + bail!("[test] Synthesized: {:?} (context = {:?})", ty, out_ctx); + Ok(()) +} + +// #[quickcheck] +// fn quickly_check(term: Term) -> Result<()> { +// let ctx = Context::default(); +// synthesize(&ctx, &term)?; +// Ok(()) +// }