diff --git a/Cargo.lock b/Cargo.lock index f9fb2da..217f8a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,11 +26,69 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "async-trait" @@ -40,7 +98,7 @@ checksum = "86ea188f25f0255d8f92797797c97ebf5631fa88178beb1a46fdf5622c9a00e4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.18", ] [[package]] @@ -116,6 +174,7 @@ dependencies = [ "salsa", "syntax", "test-utils", + "tracing", ] [[package]] @@ -131,16 +190,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" [[package]] -name = "bitflags" -version = "1.3.2" +name = "bimap" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] name = "bitflags" -version = "2.0.2" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitmaps" @@ -181,40 +240,45 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.1.11" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" +checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28" dependencies = [ - "bitflags 2.0.2", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.9" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" +checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b" dependencies = [ "heck 0.4.1", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] name = "clap_lex" -version = "0.3.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "cli" @@ -256,6 +320,12 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "console" version = "0.15.5" @@ -332,13 +402,13 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -359,7 +429,7 @@ checksum = "311a6d2f1f9d60bff73d2c78a0af97ed27f79672f15c238192a5bbb64db56d00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.18", ] [[package]] @@ -488,7 +558,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "fnv", "log", @@ -557,6 +627,26 @@ dependencies = [ "util", ] +[[package]] +name = "hir-new" +version = "0.1.0" +dependencies = [ + "base-db", + "bimap", + "duplicate", + "im", + "impl-tools", + "insta", + "la-arena", + "paste", + "rustc-hash", + "smol_str", + "syntax", + "test-utils", + "tracing", + "util", +] + [[package]] name = "httparse" version = "1.8.0" @@ -567,6 +657,7 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" name = "ide" version = "0.1.0" dependencies = [ + "extend", "hir", "ide-db", "itertools", @@ -610,6 +701,30 @@ dependencies = [ "version_check", ] +[[package]] +name = "impl-tools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bde75c0fa563af28932bd7317eaa58186d4d29043858f5f3a8c199076c06da7" +dependencies = [ + "autocfg", + "impl-tools-lib", + "proc-macro-error", + "syn 1.0.109", +] + +[[package]] +name = "impl-tools-lib" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffdf3b0bdfaa18798f4df71bc965704f63fba521b24d425cd61fb2bc771a77b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "indenter" version = "0.3.3" @@ -628,9 +743,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.28.0" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea5b3894afe466b4bcf0388630fc15e11938a6074af0cd637c825ba2ec8a099" +checksum = "9a28d25139df397cbca21408bb742cf6837e04cdbebf1b07b760caf971d6a972" dependencies = [ "console", "globset", @@ -652,25 +767,25 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd6da19f25979c7270e70fa95ab371ec3b701cd0eefc47667a09785b3c59155" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "is-terminal" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -702,9 +817,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linked-hash-map" @@ -714,9 +829,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" [[package]] name = "lock_api" @@ -739,25 +854,34 @@ dependencies = [ [[package]] name = "logos" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" +checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" dependencies = [ "logos-derive", ] [[package]] -name = "logos-derive" -version = "0.12.1" +name = "logos-codegen" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" +checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", "proc-macro2", "quote", - "regex-syntax", - "syn 1.0.109", + "regex-syntax 0.6.29", + "syn 2.0.18", +] + +[[package]] +name = "logos-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +dependencies = [ + "logos-codegen", ] [[package]] @@ -766,7 +890,7 @@ version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" dependencies = [ - "bitflags 1.3.2", + "bitflags", "serde", "serde_json", "serde_repr", @@ -790,9 +914,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.6.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] @@ -847,12 +971,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - [[package]] name = "overload" version = "0.1.1" @@ -981,12 +1099,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "prettyplease" -version = "0.1.25" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "3b69d39aab54d069e7f2fe8cb970493e7834601ca2d8c65fd7bbd183578080d1" dependencies = [ "proc-macro2", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] @@ -1015,18 +1133,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -1052,18 +1170,18 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.1", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1072,14 +1190,20 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "ron" @@ -1088,15 +1212,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" dependencies = [ "base64", - "bitflags 1.3.2", + "bitflags", "serde", ] [[package]] name = "rowan" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332" +checksum = "64449cfef9483a475ed56ae30e2da5ee96448789fb2aa240a04beb6a055078bf" dependencies = [ "countme", "hashbrown", @@ -1119,16 +1243,16 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.36.10" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe885c3a125aa45213b68cc1472a49880cb5923dc23f522ad2791b882228778" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1183,29 +1307,29 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.157" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.157" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -1220,7 +1344,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.18", ] [[package]] @@ -1265,9 +1389,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smol_str" -version = "0.1.24" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" dependencies = [ "serde", ] @@ -1277,7 +1401,7 @@ name = "sourcegen" version = "0.1.0" dependencies = [ "prettyplease", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] @@ -1305,9 +1429,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.2" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -1327,15 +1451,6 @@ dependencies = [ "util", ] -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "test-utils" version = "0.1.0" @@ -1381,26 +1496,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "num_cpus", "pin-project-lite", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] @@ -1491,20 +1606,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -1533,9 +1648,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -1551,9 +1666,9 @@ dependencies = [ [[package]] name = "tracing-tree" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758e983ab7c54fee18403994507e7f212b9005e957ce7984996fac8d11facedb" +checksum = "4f9742d8df709837409dbb22aa25dd7769c260406f20ff48a2320b80a4a6aed0" dependencies = [ "atty", "nu-ansi-term", @@ -1582,9 +1697,9 @@ checksum = "7d502c968c6a838ead8e69b2ee18ec708802f99db92a0d156705ec9ef801993b" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -1613,6 +1728,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "util" version = "0.1.0" @@ -1676,13 +1797,13 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -1691,7 +1812,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] @@ -1700,13 +1830,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -1715,42 +1860,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "xshell" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index 3955245..f5c1345 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["crates/*", "xtask"] +resolver = "2" [profile.dev.package.insta] opt-level = 3 @@ -14,7 +15,7 @@ util = { path = "crates/util" } hir = { path = "crates/hir" } paths = { git = "https://github.com/rust-lang/rust-analyzer", rev = "d712e529405b0ef5719c81ae620c88a97db78d93" } test-utils = { path = "crates/test-utils" } -insta = { version = "1.28.0", features = ["glob"] } +insta = { version = "1.29.0", features = ["glob"] } drop_bomb = "0.1.5" la-arena = "0.3" @@ -24,6 +25,6 @@ tracing = "0.1.37" itertools = "0.10.5" dashmap = "5.4.0" -tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -tracing-tree = "0.2.2" +tracing-tree = "0.2.3" diff --git a/crates/athena-language-server/Cargo.toml b/crates/athena-language-server/Cargo.toml index d46fff9..ee92e24 100644 --- a/crates/athena-language-server/Cargo.toml +++ b/crates/athena-language-server/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] dashmap.workspace = true syntax.workspace = true -tokio = { version = "1.26.0", features = [ +tokio = { version = "1.28.2", features = [ "macros", "io-std", "rt", @@ -21,8 +21,8 @@ paths.workspace = true parking_lot = "0.12.1" extend = "1.2.0" tracing-subscriber.workspace = true -anyhow = "1.0.70" +anyhow = "1.0.71" tracing.workspace = true tracing-tree.workspace = true -serde = { version = "1.0.157", features = ["derive"] } -serde_json = "1.0.94" +serde = { version = "1.0.163", features = ["derive"] } +serde_json = "1.0.96" diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index 96ec946..7a4f270 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -10,3 +10,4 @@ salsa = "0.17.0-pre.2" paths.workspace = true syntax.workspace = true test-utils.workspace = true +tracing.workspace = true diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 1464905..73be89f 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -5,7 +5,7 @@ use test_utils::{ extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, }; -use crate::{FileId, FilePosition, FileRange, SourceDatabase, VirtualFilePath}; +use crate::{FileId, FilePosition, FileRange, SourceDatabase, VfsPath, VirtualFilePathBuf}; pub trait WithFixture: Default + SourceDatabase + 'static { fn with_single_file(ath_fixture: &str) -> (Self, FileId) { @@ -59,7 +59,7 @@ impl WithFixture for DB {} pub struct ChangeFixture { pub file_position: Option<(FileId, RangeOrOffset)>, - file_paths: Vec, + file_paths: Vec, file_contents: Vec, pub files: Vec, } @@ -67,6 +67,12 @@ pub struct ChangeFixture { impl ChangeFixture { pub fn apply(&mut self, db: &mut dyn SourceDatabase) { assert_eq!(self.file_paths.len(), self.file_contents.len()); + db.set_roots( + vec![VfsPath::Virtual(VirtualFilePathBuf::assert( + "virtual:/".into(), + ))] + .into(), + ); for (idx, (path, text)) in self .file_paths .iter() @@ -75,7 +81,7 @@ impl ChangeFixture { { let id = db.intern_path(path.clone().into()); assert_eq!(id.0.as_usize(), idx); - db.set_virtual_file_contents(path.clone(), Arc::new(text.clone())); + db.add_virtual_file(path.clone(), Arc::new(text.clone())); self.files.push(id); } } @@ -85,7 +91,7 @@ impl ChangeFixture { let mut file_paths = Vec::new(); let mut file_contents = Vec::new(); - let source_root_prefix = "/".to_string(); + let source_root_prefix = VirtualFilePathBuf::PREFIX.to_string(); let mut file_id = FileId(salsa::InternId::from(0u32)); let mut file_position = None; @@ -104,10 +110,16 @@ impl ChangeFixture { entry.text.clone() }; - let meta = FileMeta::from(entry); + let mut meta = FileMeta::from(entry); + if !meta.path.starts_with(source_root_prefix.as_str()) { + assert!(meta.path.starts_with('/')); + let path = [source_root_prefix.as_str(), meta.path.as_str()].join(""); + + meta.path = path; + } assert!(meta.path.starts_with(&source_root_prefix)); - file_paths.push(meta.path.into()); + file_paths.push(meta.path.try_into().unwrap()); file_contents.push(text); file_id = FileId(salsa::InternId::from(file_id.0.as_u32() + 1)); } diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index e91ee84..ea5f955 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -1,9 +1,12 @@ pub mod fixture; +mod resolve_path; +mod virtual_path; pub use paths::{AbsPath, AbsPathBuf}; pub use salsa::{self, Cancelled}; use std::sync::Arc; use syntax::{ast, Parse, TextRange, TextSize}; +pub use virtual_path::VirtualFilePathBuf; #[macro_export] macro_rules! impl_intern_key { @@ -45,7 +48,7 @@ impl_intern_key!(FileId); #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum VfsPath { Real(AbsPathBuf), - Virtual(VirtualFilePath), + Virtual(VirtualFilePathBuf), } impl VfsPath { @@ -70,41 +73,45 @@ impl From for VfsPath { } } -impl From for VfsPath { - fn from(value: VirtualFilePath) -> Self { +impl From for VfsPath { + fn from(value: VirtualFilePathBuf) -> Self { Self::Virtual(value) } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct VirtualFilePath(String); - -impl From for VirtualFilePath { - fn from(value: String) -> Self { - Self(value) - } -} - pub trait FileWatcher { fn did_change_file(&mut self, file_id: FileId); fn in_mem_contents(&self, path: &AbsPath) -> Option>; fn set_in_mem_contents(&mut self, path: AbsPathBuf, contents: Arc); + + fn add_virtual_file(&mut self, path: VirtualFilePathBuf, contents: Arc); + + fn get_virtual_file(&self, path: VirtualFilePathBuf) -> Option>; } #[salsa::query_group(SourceDatabaseStorage)] -pub trait SourceDatabase: std::fmt::Debug + FileWatcher { +pub trait SourceDatabase: std::fmt::Debug + FileWatcher + VirtualFileDatabase { #[salsa::invoke(parse_query)] fn parse(&self, file_id: FileId) -> Parse; #[salsa::interned] fn intern_path(&self, path: VfsPath) -> FileId; + fn file_contents(&self, file: FileId) -> Arc; + + #[salsa::invoke(resolve_path::resolve_file_path_query)] + fn resolve_file_path(&self, from: FileId, path: String) -> Option; + #[salsa::input] - fn virtual_file_contents(&self, file: VirtualFilePath) -> Arc; + fn roots(&self) -> Arc<[VfsPath]>; +} - fn file_contents(&self, file: FileId) -> Arc; +#[salsa::query_group(VirtualFileDatabaseStorage)] +pub trait VirtualFileDatabase { + #[salsa::input] + fn virtual_file_contents(&self, file: VirtualFilePathBuf) -> Arc; } fn file_contents(db: &dyn SourceDatabase, file: FileId) -> Arc { diff --git a/crates/base-db/src/resolve_path.rs b/crates/base-db/src/resolve_path.rs new file mode 100644 index 0000000..e4ff3ca --- /dev/null +++ b/crates/base-db/src/resolve_path.rs @@ -0,0 +1,275 @@ +use std::{path::Path, str::FromStr}; + +use paths::{AbsPath, AbsPathBuf}; + +use crate::{virtual_path::VirtualFilePath, FileId, SourceDatabase, VfsPath, VirtualFilePathBuf}; + +trait FileExists { + fn file_exists(&self, db: &dyn SourceDatabase) -> bool; +} + +impl FileExists for &AbsPath { + fn file_exists(&self, db: &dyn SourceDatabase) -> bool { + db.in_mem_contents(self).is_some() || std::fs::metadata(self).is_ok() + } +} + +impl FileExists for &VirtualFilePath { + fn file_exists(&self, db: &dyn SourceDatabase) -> bool { + db.get_virtual_file((*self).to_owned()).is_some() + } +} + +impl FileExists for VfsPath { + fn file_exists(&self, db: &dyn SourceDatabase) -> bool { + match self { + VfsPath::Real(path) => path.as_path().file_exists(db), + VfsPath::Virtual(path) => path.as_path().file_exists(db), + } + } +} + +trait PathLike: Sized { + type JoinPath<'a>: ?Sized; + type Owned; + + fn parent(&self) -> Option; + + fn join(&self, other: &Self::JoinPath<'_>) -> Self::Owned; +} + +impl<'p> PathLike for &'p AbsPath { + type JoinPath<'a> = Path; + type Owned = AbsPathBuf; + + fn parent(&self) -> Option { + AbsPath::parent(self) + } + + fn join(&self, other: &Self::JoinPath<'static>) -> AbsPathBuf { + AbsPath::join(self, other) + } +} + +impl<'p> PathLike for &'p VirtualFilePath { + type JoinPath<'a> = VirtualFilePath; + type Owned = VirtualFilePathBuf; + + fn parent(&self) -> Option { + ::parent(self) + } + + fn join(&self, other: &VirtualFilePath) -> VirtualFilePathBuf { + (**self).join(other) + } +} + +impl PathLike for VfsPath { + type JoinPath<'a> = VfsPathComponent<'a>; + type Owned = VfsPath; + + fn parent(&self) -> Option { + match self { + VfsPath::Real(path) => path.parent().map(|it| it.to_owned().into()), + VfsPath::Virtual(path) => path.parent().map(|it| it.to_owned().into()), + } + } + + fn join(&self, other: &Self::JoinPath<'_>) -> Self { + match (self, other) { + (VfsPath::Real(a), VfsPathComponent::Real(b)) => a.join(b).into(), + (VfsPath::Real(_), VfsPathComponent::Virtual(_)) + | (VfsPath::Virtual(_), VfsPathComponent::Real(_)) => { + panic!("Cannot join real and virtual paths") + } + (VfsPath::Virtual(a), VfsPathComponent::Virtual(b)) => a.join(b).into(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum VfsPathComponent<'a> { + Real(&'a Path), + Virtual(&'a VirtualFilePath), +} + +impl<'a> VfsPathComponent<'a> { + fn matches(&self, path: &VfsPath) -> bool { + matches!( + (self, path), + (VfsPathComponent::Real(_), VfsPath::Real(_)) + | (VfsPathComponent::Virtual(_), VfsPath::Virtual(_)) + ) + } +} + +impl<'a> From<&'a VirtualFilePath> for VfsPathComponent<'a> { + fn from(v: &'a VirtualFilePath) -> Self { + Self::Virtual(v) + } +} + +impl<'a> From<&'a Path> for VfsPathComponent<'a> { + fn from(v: &'a Path) -> Self { + Self::Real(v) + } +} + +#[must_use] +fn find_file(db: &dyn SourceDatabase, from: FileId, path: VfsPathComponent<'_>) -> Option { + eprintln!("find_file({:?}, {:?})", from, path); + let current_file = db.lookup_intern_path(from); + let dir = current_file.parent()?; + let candidate = dir.join(&path); + if candidate.file_exists(db) { + eprintln!("yuh"); + let file_id = db.intern_path(candidate); + return Some(file_id); + } + let roots = db.roots(); + for root in roots.iter() { + let comp: VfsPathComponent<'_> = path.clone(); + if !comp.matches(root) { + continue; + } + let path = root.join(&comp); + if path.file_exists(db) { + let file_id = db.intern_path(path); + return Some(file_id); + } + } + None +} + +pub(super) fn resolve_file_path_query( + db: &dyn SourceDatabase, + from: FileId, + path: String, +) -> Option { + eprintln!("resolve_file_path_query({:?}, {:?})", from, path); + if let Ok(virt) = VirtualFilePathBuf::try_from(&*path) { + if virt.is_absolute() { + eprintln!("absolute"); + if virt.as_path().file_exists(db) { + return Some(db.intern_path(virt.into())); + } + } + return find_file(db, from, virt.as_path().into()); + } + + let path = std::path::PathBuf::from_str(path.as_str()).ok()?; + + if path.is_absolute() { + let path = AbsPathBuf::assert(path); + if std::fs::metadata(path.as_path()).is_ok() { + let file_id = db.intern_path(path.into()); + return Some(file_id); + } + None + } else { + let from = db.lookup_intern_path(from); + let from = match from { + VfsPath::Real(path) => path, + VfsPath::Virtual(_) => return None, + }; + + let path = from.parent().unwrap().join(&path); + if std::fs::metadata(path.as_path()).is_ok() { + let file_id = db.intern_path(path.into()); + return Some(file_id); + } + None + } +} + +#[cfg(test)] +mod test { + use core::fmt; + use std::sync::Arc; + + use test_utils::FxHashSet; + + use crate::{FileWatcher, VirtualFileDatabase}; + + use super::*; + + #[derive(Default)] + #[salsa::database(crate::SourceDatabaseStorage, crate::VirtualFileDatabaseStorage)] + struct TestDb { + virtual_files: FxHashSet, + storage: salsa::Storage, + } + + impl TestDb { + fn add_file(&mut self, path: &str, s: &str) -> FileId { + let path = virt(path); + let contents = contents(s); + let file_id = self.intern_path(path.clone().into()); + self.add_virtual_file(path, contents); + file_id + } + + fn change_roots<'a>(&mut self, roots: impl IntoIterator) { + let roots = roots.into_iter().map(|it| virt(it).into()).collect(); + + self.set_roots(roots); + } + } + + impl crate::FileWatcher for TestDb { + fn did_change_file(&mut self, _file_id: FileId) { + unimplemented!() + } + + fn in_mem_contents(&self, _path: &AbsPath) -> Option> { + unimplemented!() + } + + fn set_in_mem_contents(&mut self, _path: AbsPathBuf, _contents: std::sync::Arc) { + unimplemented!() + } + + fn add_virtual_file(&mut self, path: VirtualFilePathBuf, contents: std::sync::Arc) { + self.virtual_files.insert(path.clone()); + self.set_virtual_file_contents(path, contents); + } + + fn get_virtual_file(&self, path: VirtualFilePathBuf) -> Option> { + eprintln!("get_virtual_file({path:?}) : {:?}", self.virtual_files); + if self.virtual_files.contains(&path) { + eprintln!("contains!"); + Some(self.virtual_file_contents(path)) + } else { + None + } + } + } + + impl fmt::Debug for TestDb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TestDb") + .field("virtual_files", &self.virtual_files) + .finish() + } + } + + impl salsa::Database for TestDb {} + + fn virt(path: &str) -> VirtualFilePathBuf { + VirtualFilePathBuf::assert(path.into()) + } + + fn contents(s: &str) -> Arc { + Arc::new(s.into()) + } + + #[test] + fn test_resolve_file_path() { + let mut db = TestDb::default(); + db.change_roots(["virtual:/home"]); + let a = db.add_file("virtual:/foo/baz", "domain A"); + let b = db.add_file("virtual:/foo/bar", "domain B"); + + assert_eq!(db.resolve_file_path(a, "virtual:bar".into()), Some(b)); + } +} diff --git a/crates/base-db/src/virtual_path.rs b/crates/base-db/src/virtual_path.rs new file mode 100644 index 0000000..746d406 --- /dev/null +++ b/crates/base-db/src/virtual_path.rs @@ -0,0 +1,112 @@ +use std::{ + borrow::Borrow, + path::{Path, PathBuf}, +}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct VirtualFilePathBuf(PathBuf); + +#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(transparent)] +pub struct VirtualFilePath(Path); + +impl VirtualFilePath { + pub fn join(&self, other: &VirtualFilePath) -> VirtualFilePathBuf { + VirtualFilePathBuf(self.0.join(&other.0)) + } + + pub fn as_str(&self) -> &str { + self.0.to_str().unwrap() + } + + pub fn parent(&self) -> Option<&VirtualFilePath> { + self.0.parent().map(VirtualFilePath::from_path) + } + + fn from_path(path: &Path) -> &VirtualFilePath { + // SAFETY: VirtualFilePath is a repr(transparent) wrapper around Path + unsafe { &*(path as *const Path as *const VirtualFilePath) } + } + + pub fn is_absolute(&self) -> bool { + self.0.is_absolute() + } +} + +impl std::ops::Deref for VirtualFilePathBuf { + type Target = VirtualFilePath; + + fn deref(&self) -> &Self::Target { + self.as_path() + } +} + +impl VirtualFilePathBuf { + pub const PREFIX: &'static str = "virtual:"; + + pub fn assert(pth: String) -> VirtualFilePathBuf { + VirtualFilePathBuf::try_from(pth).unwrap() + } + + pub fn as_path(&self) -> &VirtualFilePath { + VirtualFilePath::from_path(self.0.as_path()) + } + + pub fn components(&self) -> impl Iterator { + self.0.components() + } +} + +impl TryFrom for VirtualFilePathBuf { + type Error = (); + + fn try_from(value: String) -> Result { + VirtualFilePathBuf::try_from(value.as_str()) + } +} + +impl TryFrom<&str> for VirtualFilePathBuf { + type Error = (); + + fn try_from(value: &str) -> Result { + if value.starts_with(VirtualFilePathBuf::PREFIX) { + Ok(VirtualFilePathBuf(PathBuf::from( + value.strip_prefix(VirtualFilePathBuf::PREFIX).unwrap(), + ))) + } else { + Err(()) + } + } +} + +impl ToOwned for VirtualFilePath { + type Owned = VirtualFilePathBuf; + + fn to_owned(&self) -> Self::Owned { + VirtualFilePathBuf(self.0.to_owned()) + } +} + +impl Borrow for VirtualFilePathBuf { + fn borrow(&self) -> &VirtualFilePath { + self.as_path() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parent() { + let path = VirtualFilePathBuf::try_from("virtual:/foo/bar").unwrap(); + assert_eq!(path.parent().unwrap().as_str(), "/foo"); + } + + #[test] + fn test_join() { + let path = VirtualFilePathBuf::assert("virtual:/foo/bar".into()); + let child = VirtualFilePathBuf::assert("virtual:baz".into()); + assert_eq!(path.join(&child).as_str(), "/foo/bar/baz"); + } +} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 0608864..108522c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -6,10 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "4.1.11", features = ["derive"] } +clap = { version = "4.3.1", features = ["derive"] } color-eyre = "0.6.2" glob = "0.3.1" -serde = { version = "1.0.157", features = ["derive"] } -serde_json = "1.0.94" +serde = { version = "1.0.163", features = ["derive"] } +serde_json = "1.0.96" syntax.workspace = true xshell = "0.2.3" diff --git a/crates/hir-new/Cargo.toml b/crates/hir-new/Cargo.toml new file mode 100644 index 0000000..f0f7ed0 --- /dev/null +++ b/crates/hir-new/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "hir-new" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +la-arena.workspace = true + +syntax.workspace = true +base-db.workspace = true +rustc-hash.workspace = true +smol_str = "0.2.0" +paste = "1.0.12" +util.workspace = true +tracing.workspace = true +duplicate = "1.0.0" +im = "15.1.0" +impl-tools = "0.8.0" +bimap = "0.6.3" + +[dev-dependencies] +insta.workspace = true +test-utils.workspace = true diff --git a/crates/hir-new/src/ast_map.rs b/crates/hir-new/src/ast_map.rs new file mode 100644 index 0000000..bf8ed2d --- /dev/null +++ b/crates/hir-new/src/ast_map.rs @@ -0,0 +1,145 @@ +use core::fmt; +use std::sync::Arc; + +use base_db::{salsa, FileId, SourceDatabase}; +use la_arena::{Arena, Idx}; +use rustc_hash::FxHashMap; +use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; + +use crate::InFile; + +#[salsa::query_group(AstDatabaseStorage)] +pub trait AstDatabase: SourceDatabase { + fn ast_id_map(&self, file_id: FileId) -> Arc; +} + +pub struct FileAstId { + #[allow(dead_code)] + raw: ErasedAstId, + _type: std::marker::PhantomData N>, +} + +impl Clone for FileAstId { + fn clone(&self) -> FileAstId { + *self + } +} +impl Copy for FileAstId {} + +impl PartialEq for FileAstId { + fn eq(&self, other: &Self) -> bool { + self.raw == other.raw + } +} +impl Eq for FileAstId {} +impl std::hash::Hash for FileAstId { + fn hash(&self, hasher: &mut H) { + self.raw.hash(hasher); + } +} + +impl fmt::Debug for FileAstId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "FileAstId::<{}>({})", + std::any::type_name::(), + self.raw.into_raw() + ) + } +} + +type ErasedAstId = Idx; + +#[allow(dead_code)] +pub type AstId = InFile>; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct AstIdMap { + arena: Arena, + ptr_to_id: FxHashMap, +} + +impl AstIdMap { + pub(crate) fn from_source(node: &SyntaxNode) -> Self { + let mut arena = Arena::default(); + + bdfs(node, |node| { + let kind = node.kind(); + if ast::Dir::can_cast(kind) + || ast::Stmt::can_cast(kind) + || ast::Sort::can_cast(kind) + || ast::Phrase::can_cast(kind) + || ast::Pat::can_cast(kind) + { + arena.alloc(SyntaxNodePtr::new(&node)); + true + } else { + false + } + }); + + let ptr_to_id = arena + .iter() + .map(|(erased, ptr)| (ptr.clone(), erased)) + .collect(); + + AstIdMap { arena, ptr_to_id } + } + + pub fn ast_id(&self, node: &N) -> FileAstId { + let raw = self.erased_ast_id(node.syntax()); + FileAstId { + raw, + _type: std::marker::PhantomData, + } + } + + pub fn ast_id_ptr(&self, node: &AstPtr) -> FileAstId { + let ptr = node.syntax_node_ptr(); + let raw = self.ptr_to_id.get(&ptr).copied().unwrap(); + FileAstId { + raw, + _type: std::marker::PhantomData, + } + } + + pub fn get(&self, id: FileAstId) -> AstPtr { + AstPtr::try_from_raw(self.arena[id.raw].clone()).unwrap() + } + + fn erased_ast_id(&self, node: &SyntaxNode) -> ErasedAstId { + let ptr = SyntaxNodePtr::new(node); + self.ptr_to_id.get(&ptr).copied().unwrap() + } +} + +fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) { + let mut current = vec![node.clone()]; + let mut next = Vec::new(); + + while !current.is_empty() { + for node in current.drain(..) { + let mut preorder = node.preorder(); + + while let Some(event) = preorder.next() { + match event { + syntax::WalkEvent::Enter(node) => { + if f(node.clone()) { + next.extend(node.children()); + preorder.skip_subtree(); + } + } + syntax::WalkEvent::Leave(_) => {} + } + } + } + current.append(&mut next); + } +} + +fn ast_id_map(db: &dyn AstDatabase, file_id: FileId) -> Arc { + // let _p = profile::span("ast_id_map"); + let source_file = db.parse(file_id); + Arc::new(AstIdMap::from_source(source_file.tree().syntax())) +} diff --git a/crates/hir-new/src/db.rs b/crates/hir-new/src/db.rs new file mode 100644 index 0000000..bb39a34 --- /dev/null +++ b/crates/hir-new/src/db.rs @@ -0,0 +1,29 @@ +use std::sync::Arc; + +use base_db::{FileId, Upcast}; + +use crate::{ + ast_map::AstDatabase, + hir::{FileHir, SourceMap}, +}; +use base_db::salsa; + +#[salsa::query_group(HirNewDatabaseStorage)] +pub trait HirNewDatabase: AstDatabase + Upcast { + #[salsa::invoke(FileHir::file_hir_with_source_map_query)] + fn file_hir_with_source_map(&self, file_id: FileId) -> (Arc, Arc); + + fn file_hir(&self, file_id: FileId) -> Arc; + + fn source_map(&self, file_id: FileId) -> Arc; + #[salsa::invoke(FileHir::debug_dump_query)] + fn debug_dump(&self, file_id: FileId) -> String; +} + +fn file_hir(db: &dyn HirNewDatabase, file_id: FileId) -> Arc { + db.file_hir_with_source_map(file_id).0 +} + +fn source_map(db: &dyn HirNewDatabase, file_id: FileId) -> Arc { + db.file_hir_with_source_map(file_id).1 +} diff --git a/crates/hir-new/src/fixture.rs b/crates/hir-new/src/fixture.rs new file mode 100644 index 0000000..7ae28b0 --- /dev/null +++ b/crates/hir-new/src/fixture.rs @@ -0,0 +1,15 @@ +//! Utilities for creating `Analysis` instances for tests. + +#![allow(dead_code)] + +use base_db::{fixture::ChangeFixture, FileId}; + +use crate::test_db::TestDB; + +/// Creates analysis for a single file. +pub(crate) fn file(ra_fixture: &str) -> (TestDB, FileId) { + let mut db = TestDB::default(); + let mut change_fixture = ChangeFixture::parse(ra_fixture); + change_fixture.apply(&mut db); + (db, change_fixture.files[0]) +} diff --git a/crates/hir-new/src/hir.rs b/crates/hir-new/src/hir.rs new file mode 100644 index 0000000..7ba530d --- /dev/null +++ b/crates/hir-new/src/hir.rs @@ -0,0 +1,390 @@ +mod debug_dump; +mod ded; +mod dir; +mod expr; +mod lower; +mod name; +mod pat; +mod phrase; +mod sort_ref; +mod stmt; + +#[cfg(test)] +mod tests; + +use core::fmt; +use std::{hash::BuildHasherDefault, sync::Arc}; + +use base_db::FileId; +use la_arena::{Arena, Idx}; +use rustc_hash::FxHasher; +use syntax::{ast, AstNode, AstPtr}; + +use crate::{ast_map::FileAstId, db::HirNewDatabase, InFile}; + +use self::stmt::{Datatypes, Structures}; +pub use self::{ + debug_dump::{DebugDump, DebugDumper}, + ded::Ded, + dir::Dir, + expr::Expr, + name::{AsName, Name, NameOrWildcard}, + pat::Pat, + phrase::{Phrase, PhraseId}, + sort_ref::SortRef, + stmt::{ + Assertion, ClosedAssertion, DefKind, Definition, DomainDeclaration, FileImport, + FunctionSymbol, Module, ModuleExtension, ModuleImport, Overload, Overloads, Param, + SortAlias, + }, +}; + +pub type FxBiMap = bimap::BiHashMap>; + +#[derive(Debug, Eq, PartialEq)] +pub struct FileHir { + file_id: FileId, + top_level: Vec, + data: HirData, // generated by hir_maps! below +} + +impl FileHir { + fn empty(file_id: FileId) -> Self { + Self { + file_id, + top_level: Vec::new(), + data: HirData::default(), + } + } + + pub(crate) fn file_hir_with_source_map_query( + db: &dyn HirNewDatabase, + file_id: FileId, + ) -> (Arc, Arc) { + let file = db.parse(file_id).tree(); + let ctx = lower::Ctx::new(db, file_id); + let (hir, map) = ctx.lower_file(file); + (Arc::new(hir), Arc::new(map)) + } + + pub(crate) fn debug_dump_query(db: &dyn HirNewDatabase, file_id: FileId) -> String { + let (hir, source_map) = db.file_hir_with_source_map(file_id); + let mut buf = String::new(); + + let mut dd = DebugDumper::new(&hir, &source_map, &mut buf, db); + hir.debug_dump(&mut dd).unwrap(); + buf + } +} + +impl DebugDump for FileHir { + fn debug_dump(&self, dd: &mut DebugDumper) -> fmt::Result { + for stmt in &self.top_level { + stmt.debug_dump(dd)?; + } + Ok(()) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct SourceMap { + file_id: FileId, + ast_id_map: Arc, + hir_map: HirAstMap, // generated by hir_maps! below +} + +impl SourceMap { + fn empty(file_id: FileId, ast_id_map: Arc) -> Self { + Self { + file_id, + ast_id_map, + hir_map: HirAstMap::default(), + } + } +} + +pub trait HasHir { + type Hir: HirNode; + + fn hir(&self, source_map: &SourceMap) -> Option>; + + fn file_id(&self) -> FileId; +} + +pub type Source = InFile>; + +pub trait HirNode: Sized { + type Ast: AstNode; + + fn source(id: Idx, source_map: &SourceMap) -> Option>; + + fn node(id: Idx, hir: &FileHir) -> &Self; + + fn alloc(self, hir: &mut FileHir) -> Idx; + + fn record_source(id: Idx, file_ast_id: FileAstId, source_map: &mut SourceMap); +} + +pub trait Get { + type Output<'a>; + + fn get(self, hir: &FileHir) -> Self::Output<'_>; +} + +impl Get for &T +where + T: Get + Copy, +{ + type Output<'a> = ::Output<'a>; + + fn get(self, hir: &FileHir) -> Self::Output<'_> { + (*self).get(hir) + } +} + +impl FileHir { + pub fn get(&self, id: G) -> ::Output<'_> { + id.get(self) + } +} + +macro_rules! hir_maps { + (@inner $({ ast: $ast: ty, hir: $hir: ty, arena: $arena: ident}),*) => { + #[derive(Default, Debug, Eq, PartialEq)] + struct HirAstMap { + $( + $arena: FxBiMap, Idx<$hir>>, + )* + } + + #[derive(Default, Debug, Eq, PartialEq)] + struct HirData { + $( + $arena: Arena<$hir>, + )* + } + + $( + impl HasHir for Source<$ast> { + type Hir = $hir; + + fn hir(&self, source_map: &SourceMap) -> Option> { + source_map + .hir_map + .$arena + .get_by_left(&source_map.ast_id_map.ast_id_ptr(&self.value)) + .copied() + } + + fn file_id(&self) -> FileId { + self.file_id + } + } + + impl HirNode for $hir { + type Ast = $ast; + + fn source(id: Idx, source_map: &SourceMap) -> Option> { + let ast_id = source_map.hir_map.$arena.get_by_right(&id)?; + Some(InFile::new( + source_map.file_id, + source_map.ast_id_map.get(*ast_id), + )) + } + + fn node(id: Idx, hir: &FileHir) -> &Self { + &hir.data.$arena[id] + } + + fn alloc(self, hir: &mut FileHir) -> Idx { + hir.data.$arena.alloc(self) + } + + fn record_source(id: Idx, file_ast_id: FileAstId<$ast>, source_map: &mut SourceMap) { + source_map.hir_map.$arena.insert( + file_ast_id, + id, + ); + } + } + + + paste::paste! { + pub type [<$hir Id>] = ::la_arena::Idx<$hir>; + } + + impl ::std::ops::Index<::la_arena::Idx<$hir>> for FileHir { + type Output = $hir; + + fn index(&self, index: ::la_arena::Idx<$hir>) -> &Self::Output { + &self.data.$arena[index] + } + } + + impl Get for ::la_arena::Idx<$hir> { + type Output<'a> = &'a $hir; + + fn get(self, hir: &FileHir) -> Self::Output<'_> { + &hir.data.$arena[self] + } + } + + )* + }; + ($( + $ast:ty => $hir: ty | $arena: ident + ),* $(,)?) => { + hir_maps!(@inner $({ ast: $ast, hir: $hir, arena: $arena }),*); + }; +} + +hir_maps! { + ast::ModuleDir => Module | modules, + ast::ExtendModuleDir => ModuleExtension | module_exts, + ast::TermSymbol => FunctionSymbol | func_symbols, + ast::DefineSortDir => SortAlias | sort_aliases, + ast::LoadDir => FileImport | file_imports, + ast::OpenDir => ModuleImport | module_imports, + ast::Domain => DomainDeclaration | domains, + ast::AssertDir => Assertion | assertions, + ast::AssertClosedDir => ClosedAssertion | closed_assertions, + ast::Dir => Dir | dirs, + ast::Pat => Pat | pats, + ast::SortLike => SortRef | sort_refs, + ast::DefineDir => Definition | definitions, + ast::Expr => Expr | exprs, + ast::Ded => Ded | deds, + ast::OverloadDir => Overloads | overloads, + ast::DatatypeOrDatatypes => Datatypes | datatypes, + ast::StructureOrStructures => Structures | structures, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum ModuleStmt { + Module(Idx), + ModuleExtension(Idx), + FunctionSymbol(Idx), + SortAlias(Idx), + FileImport(Idx), + ModuleImport(Idx), + DomainDeclaration(Idx), + Assertion(Idx), + ClosedAssertion(Idx), + Dir(Idx), + Definition(Idx), + Phrase(PhraseId), + Overloads(Idx), + Datatypes(Idx), + Structures(Idx), +} + +macro_rules! impl_from_idx { + ($($v: ident),+ for $t: ty) => { + $( + impl From> for $t { + fn from(idx: Idx<$v>) -> Self { + Self::$v(idx) + } + } + )+ + }; +} + +macro_rules! impl_debug_dump { + (delegate $($e: ident),* for $t: ty) => { + impl $crate::hir::DebugDump for $t { + fn debug_dump( + &self, + dd: &mut $crate::hir::debug_dump::DebugDumper<'_>, + ) -> ::core::fmt::Result { + match self { + $( + Self::$e(v) => { + v.debug_dump(dd)?; + } + )+ + } + Ok(()) + } + } + }; + ($($e: ident),* for $t: ty) => { + impl $crate::hir::DebugDump for $t { + fn debug_dump( + &self, + dd: &mut $crate::hir::debug_dump::DebugDumper<'_>, + ) -> ::core::fmt::Result { + match self { + $( + Self::$e(idx) => { + dd.get(*idx).debug_dump(dd)?; + } + )+ + } + Ok(()) + } + } + }; + (delegate ids $($e: ident),* for $t: ty) => { + impl $crate::hir::DebugDump for $t { + fn debug_dump( + &self, + hir: &$crate::hir::FileHir, + source_map: &$crate::hir::SourceMap, + f: &mut dyn ::core::fmt::Write, + ) -> ::core::fmt::Result { + match self { + $( + Self::$e(idx) => { + hir[*idx].debug_dump(hir, source_map, f)?; + } + )+ + } + Ok(()) + } + } + }; +} + +pub(crate) use impl_debug_dump; + +impl_from_idx! { + Module, + ModuleExtension, + FunctionSymbol, + SortAlias, + FileImport, + ModuleImport, + DomainDeclaration, + Assertion, + ClosedAssertion, + Dir, + Overloads, + Datatypes, + Structures, + Definition for ModuleStmt +} + +impl_debug_dump! { + Module, + ModuleExtension, + FunctionSymbol, + SortAlias, + FileImport, + ModuleImport, + DomainDeclaration, + Assertion, + ClosedAssertion, + Dir, + Definition, + Overloads, + Datatypes, + Structures, + Phrase for ModuleStmt +} + +impl From for ModuleStmt { + fn from(id: PhraseId) -> Self { + Self::Phrase(id) + } +} diff --git a/crates/hir-new/src/hir/debug_dump.rs b/crates/hir-new/src/hir/debug_dump.rs new file mode 100644 index 0000000..7530d7f --- /dev/null +++ b/crates/hir-new/src/hir/debug_dump.rs @@ -0,0 +1,136 @@ +use base_db::FileId; + +use super::Get; +use std::fmt::{self, Write}; + +type WriteTarget<'a> = &'a mut (dyn fmt::Write + 'a); + +pub(crate) fn tab(f: WriteTarget<'_>, n: usize) -> fmt::Result { + let s = " "; + for _ in 0..n { + write!(f, "{s}")?; + } + + Ok(()) +} + +pub struct DebugDumper<'a> { + pub hir: &'a super::FileHir, + #[allow(unused)] + source_map: &'a super::SourceMap, + f: &'a mut dyn fmt::Write, + indent: usize, + + last: u8, + db: &'a dyn super::HirNewDatabase, +} + +impl<'a> DebugDumper<'a> { + pub(crate) fn get(&self, g: G) -> ::Output<'a> { + g.get(self.hir) + } + + pub(crate) fn debug_dump(&mut self, d: D) -> fmt::Result { + d.debug_dump(self) + } + + pub(crate) fn dump(&mut self, g: G) -> fmt::Result + where + ::Output<'a>: DebugDump, + { + self.debug_dump(self.get(g)) + } + + pub(crate) fn tab(&mut self) -> fmt::Result { + if self.indent == 0 { + return Ok(()); + } + tab(self.f, self.indent) + } + + pub(crate) fn indent(&mut self) { + self.indent += 1; + } + + pub(crate) fn dedent(&mut self) { + self.indent -= 1; + } + + pub(crate) fn indented(&mut self, func: impl FnOnce(&mut Self) -> R) -> R { + self.indent(); + let r = func(self); + self.dedent(); + r + } + + pub(crate) fn comma_separated( + &mut self, + values: impl IntoIterator, + mut func: impl FnMut(&mut Self, T) -> fmt::Result, + ) -> fmt::Result { + for (i, value) in values.into_iter().enumerate() { + if i != 0 { + write!(self, ", ")?; + } + func(self, value)?; + } + + Ok(()) + } + + pub(crate) fn dump_file(&mut self, file_id: FileId) -> fmt::Result { + let s = self.db.debug_dump(file_id); + self.write_str(&s) + } +} + +impl<'a> DebugDumper<'a> { + pub(crate) fn new( + hir: &'a super::FileHir, + source_map: &'a super::SourceMap, + f: &'a mut dyn fmt::Write, + db: &'a dyn super::HirNewDatabase, + ) -> Self { + Self { + hir, + source_map, + f, + indent: 0, + last: b'\0', + db, + } + } +} + +impl fmt::Write for DebugDumper<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let mut lines = s.split_inclusive('\n'); + if let Some(first) = lines.next() { + if self.last == b'\n' { + self.tab()?; + } + self.f.write_str(first)?; + } + for l in lines { + self.tab()?; + self.f.write_str(l)?; + } + if !s.is_empty() { + self.last = s.as_bytes().last().copied().unwrap(); + } + Ok(()) + } +} + +pub trait DebugDump { + fn debug_dump(&self, dd: &mut DebugDumper) -> fmt::Result; +} + +impl DebugDump for &T +where + T: DebugDump, +{ + fn debug_dump(&self, dd: &mut DebugDumper) -> fmt::Result { + (*self).debug_dump(dd) + } +} diff --git a/crates/hir-new/src/hir/ded.rs b/crates/hir-new/src/hir/ded.rs new file mode 100644 index 0000000..f691542 --- /dev/null +++ b/crates/hir-new/src/hir/ded.rs @@ -0,0 +1,21 @@ +use super::{debug_dump::DebugDumper, DebugDump, ExprId, PhraseId}; +use core::fmt::Write; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Ded { + MethodCall(ExprId, PhraseId), +} + +impl DebugDump for Ded { + fn debug_dump(&self, dd: &mut DebugDumper<'_>) -> core::fmt::Result { + match self { + Ded::MethodCall(expr, phrase) => { + write!(dd, "Ded::MethodCall(")?; + dd.dump(expr)?; + write!(dd, ", ")?; + dd.dump(phrase)?; + write!(dd, ")") + } + } + } +} diff --git a/crates/hir-new/src/hir/dir.rs b/crates/hir-new/src/hir/dir.rs new file mode 100644 index 0000000..8e0f2b4 --- /dev/null +++ b/crates/hir-new/src/hir/dir.rs @@ -0,0 +1,35 @@ +use crate::hir::{ExprId, Name}; + +use super::{DebugDump, DebugDumper}; +use core::fmt::Write; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Associativity { + Left, + Right, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DirKind { + SetPrecedence(Vec, ExprId), + SetAssociativity(Name, Associativity), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Dir { + pub kind: DirKind, +} + +impl DebugDump for Dir { + fn debug_dump(&self, dd: &mut DebugDumper) -> core::fmt::Result { + match &self.kind { + DirKind::SetPrecedence(names, val) => { + writeln!(dd, "set-precedence {:?}", names)?; + dd.dump(val) + } + DirKind::SetAssociativity(name, assoc) => { + writeln!(dd, "set-assoc {} {:?}", name, assoc) + } + } + } +} diff --git a/crates/hir-new/src/hir/expr.rs b/crates/hir-new/src/hir/expr.rs new file mode 100644 index 0000000..96fe947 --- /dev/null +++ b/crates/hir-new/src/hir/expr.rs @@ -0,0 +1,61 @@ +use core::fmt::{self, Write}; + +use crate::hir::Name; + +use super::{DebugDump, ExprId, PhraseId, SortRefId}; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Literal { + String(String), + Char(char), + Symbol(Name), +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Expr { + Ident(Name), + Literal(Literal), + TermVar(Name, Option), + Unit, + Check(Vec), +} + +pub type ExprCheckArm = CheckArm; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct CheckArm { + pub condition: PhraseId, + pub result: R, +} + +impl DebugDump for Expr { + fn debug_dump(&self, dd: &mut super::DebugDumper) -> fmt::Result { + match self { + Expr::Ident(name) => write!(dd, "{}", name), + Expr::Literal(lit) => write!(dd, "{:?}", lit), + Expr::TermVar(name, sort) => { + if let Some(sort) = sort { + write!(dd, "({}: ", name,)?; + dd.debug_dump(dd.get(sort))?; + write!(dd, ")") + } else { + write!(dd, "{}", name) + } + } + Expr::Unit => write!(dd, "()"), + Expr::Check(arms) => { + writeln!(dd, "check {{")?; + dd.indented(|dd| { + for arm in arms { + dd.debug_dump(dd.get(arm.condition))?; + writeln!(dd, " => ")?; + dd.debug_dump(dd.get(arm.result))?; + } + Ok(()) + })?; + writeln!(dd, "}}")?; + Ok(()) + } + } + } +} diff --git a/crates/hir-new/src/hir/lower.rs b/crates/hir-new/src/hir/lower.rs new file mode 100644 index 0000000..9917b78 --- /dev/null +++ b/crates/hir-new/src/hir/lower.rs @@ -0,0 +1,747 @@ +use std::sync::Arc; + +use base_db::FileId; +use hir::pat::PatKind; +use la_arena::Idx; +use syntax::{ + ast::{self, HasDefineBody, HasDefineName, HasName, HasNameRef}, + AstToken, +}; + +use crate::{ + ast_map::AstIdMap, + db::HirNewDatabase, + hir::{ + self, expr::Literal, AsName, DedId, DefKind, Definition, ExprId, FileImport, + ModuleExtension, NameOrWildcard, Param, PatId, PhraseId, SortRef, SortRefId, + }, +}; + +use super::{ + dir::Associativity, + stmt::{ + Constructor, ConstructorParam, Datatype, Datatypes, SortDeclaration, Structure, + StructureDef, Structures, + }, + Expr, FileHir, FileImportId, FunctionSymbol, HirNode, Module, ModuleStmt, Pat, SortAlias, + SourceMap, +}; + +pub(super) struct Ctx<'db> { + db: &'db dyn HirNewDatabase, + hir: FileHir, + ast_id_map: Arc, + source_map: SourceMap, +} + +fn into(val: T) -> S +where + T: Into, +{ + val.into() +} + +pub type Id = Idx; + +fn lower_name_ref(id: &impl HasNameRef) -> Option { + let name = id.name_ref()?; + Some(name.as_name()) +} + +fn lower_name(id: &impl HasName) -> Option { + let name = id.name()?; + Some(name.as_name()) +} + +fn lower_assoc(assoc: &ast::AssociativityDir) -> Option { + if let Some(_) = assoc.left_assoc_token() { + Some(Associativity::Left) + } else if let Some(_) = assoc.right_assoc_token() { + Some(Associativity::Right) + } else { + None + } +} + +fn sort_like(sort: impl Into) -> ast::SortLike { + sort.into() +} + +fn lower_some_thing(thing: &ast::SomeThing) -> Option { + macro_rules! map_some_thing { + (match $ast: ident { $($name: ident => $thing: ident),* $(,)? }) => { + $( + paste::paste! { + if let Some(_) = $ast.[]() { + return Some(hir::pat::Thing::$thing); + } + } + )* + }; + } + + map_some_thing!(match thing { + var => Var, + sent_con => SentCon, + quant => Quant, + term => Term, + atom => Atom, + sentence => Sentence, + list => List, + cell => Cell, + vector => Vector, + proc => Proc, + method => Method, + symbol => Symbol, + table => Table, + map => Map, + sub => Sub, + char => Char, + }); + + None +} + +impl<'db> Ctx<'db> { + pub(super) fn new(db: &'db dyn HirNewDatabase, file_id: FileId) -> Self { + let ast_id_map = db.ast_id_map(file_id); + Self { + db, + hir: FileHir::empty(file_id), + source_map: SourceMap::empty(file_id, ast_id_map.clone()), + ast_id_map, + } + } + + fn alloc(&mut self, ast: &::Ast, node: H) -> Id { + let id = node.alloc(&mut self.hir); + let ast_id = self.ast_id_map.ast_id(ast); + H::record_source(id, ast_id, &mut self.source_map); + id + } + + pub(super) fn lower_file(mut self, file: ast::SourceFile) -> (FileHir, SourceMap) { + self.hir.top_level = file + .stmts() + .filter_map(|stmt| self.lower_module_stmt(&stmt)) + .collect(); + + (self.hir, self.source_map) + } + + fn lower_module_stmt(&mut self, stmt: &ast::Stmt) -> Option { + match stmt { + ast::Stmt::Dir(ast::Dir::ModuleDir(module)) => self.lower_module_dir(module).map(into), + ast::Stmt::Dir(ast::Dir::ExtendModuleDir(module_ext)) => { + self.lower_extend_module_dir(module_ext).map(into) + } + ast::Stmt::Dir(ast::Dir::DeclareDir(func_declare)) => { + let sym = func_declare.clone().into(); + self.lower_term_symbol(&sym).map(into) + } + ast::Stmt::Dir(ast::Dir::ConstantDeclareDir(constant_declare)) => { + let sym = constant_declare.clone().into(); + self.lower_term_symbol(&sym).map(into) + } + ast::Stmt::Dir(ast::Dir::DefineDir(define)) => self.lower_define_dir(define).map(into), + ast::Stmt::Dir(ast::Dir::DefineSortDir(alias_def)) => { + let name = lower_name(alias_def)?; + let sort = self.lower_sort_ref(&alias_def.sort()?)?; + Some(self.alloc(alias_def, SortAlias { name, sort }).into()) + } + ast::Stmt::Dir(ast::Dir::LoadDir(load)) => self.lower_load_dir(load).map(into), + ast::Stmt::Dir(ast::Dir::DomainDir(domain)) => { + let sort_decl = self.lower_sort_decl(&domain.sort_decl()?)?; + let domain = ast::Domain::from(domain.clone()); + Some( + self.alloc( + &domain, + hir::DomainDeclaration { + domains: vec![sort_decl], + }, + ) + .into(), + ) + } + ast::Stmt::Dir(ast::Dir::DomainsDir(domains)) => { + let domain_ast = ast::Domain::from(domains.clone()); + let domains = domains + .sort_decls() + .filter_map(|domain| self.lower_sort_decl(&domain)) + .collect(); + Some( + self.alloc(&domain_ast, hir::DomainDeclaration { domains }) + .into(), + ) + } + ast::Stmt::Dir(dir @ ast::Dir::AssociativityDir(associativity)) => { + let name = lower_name_ref(associativity)?; + let assoc = lower_assoc(associativity)?; + Some( + self.alloc( + dir, + hir::Dir { + kind: hir::dir::DirKind::SetAssociativity(name, assoc), + }, + ) + .into(), + ) + } + ast::Stmt::Dir(dir @ ast::Dir::SetPrecedenceDir(set_prec)) => { + let names = set_prec + .name_refs() + .filter_map(|n| lower_name_ref(&n)) + .collect(); + let prec = self.lower_expr(&set_prec.expr()?)?; + Some( + self.alloc( + dir, + hir::Dir { + kind: hir::dir::DirKind::SetPrecedence(names, prec), + }, + ) + .into(), + ) + } + ast::Stmt::Dir(ast::Dir::AssertDir(assert)) => { + let name = assert.name().as_ref().map(lower_name).flatten(); + let facts = match assert { + ast::AssertDir::InfixAssertDir(infix) => { + infix.exprs().filter_map(|e| self.lower_expr(&e)).collect() + } + ast::AssertDir::PrefixAssertDir(prefix) => { + prefix.exprs().filter_map(|e| self.lower_expr(&e)).collect() + } + }; + Some(self.alloc(assert, hir::Assertion { name, facts }).into()) + } + ast::Stmt::Dir(ast::Dir::AssertClosedDir(assert)) => { + let name = assert.name().as_ref().map(lower_name).flatten(); + let fact = self.lower_expr(&assert.expr()?)?; + Some( + self.alloc(assert, hir::ClosedAssertion { name, fact }) + .into(), + ) + } + ast::Stmt::Dir(ast::Dir::OpenDir(open)) => { + let names = open + .name_refs() + .filter_map(|n| lower_name_ref(&n)) + .collect(); + Some(self.alloc(open, hir::ModuleImport { names }).into()) + } + ast::Stmt::Dir(ast::Dir::OverloadDir(overload)) => { + let overloads = match overload { + ast::OverloadDir::OverloadSingle(overload) => { + let target = self.lower_phrase(&overload.first_phrase()?)?; + let overload = self.lower_phrase(&overload.second_phrase()?)?; + vec![hir::Overload { target, overload }] + } + ast::OverloadDir::OverloadMulti(overloads) => overloads + .phrase_pairs() + .filter_map(|pair| { + let target = self.lower_phrase(&pair.first_phrase()?)?; + let overload = self.lower_phrase(&pair.second_phrase()?)?; + Some(hir::Overload { target, overload }) + }) + .collect(), + }; + + Some(self.alloc(overload, hir::Overloads { overloads }).into()) + } + ast::Stmt::Dir(ast::Dir::RuleDir(_rule)) => todo!(), + ast::Stmt::PhraseStmt(p) => self.lower_phrase(&p.phrase()).map(into), + ast::Stmt::DatatypeStmt(datatype) => { + let def = self.lower_structure_def(&datatype.structure_def()?)?; + Some( + self.alloc( + &ast::DatatypeOrDatatypes::from(datatype.clone()), + Datatypes { + datatypes: vec![Datatype::from(def)], + }, + ) + .into(), + ) + } + ast::Stmt::DatatypesStmt(datatypes_stmt) => { + let datatypes = datatypes_stmt + .structure_defs() + .filter_map(|def| self.lower_structure_def(&def)) + .map(Datatype::from) + .collect(); + Some( + self.alloc( + &ast::DatatypeOrDatatypes::from(datatypes_stmt.clone()), + Datatypes { datatypes }, + ) + .into(), + ) + } + ast::Stmt::StructureStmt(s) => { + let def = self.lower_structure_def(&s.structure_def()?)?; + Some( + self.alloc( + &ast::StructureOrStructures::from(s.clone()), + Structures { + structures: vec![Structure::from(def)], + }, + ) + .into(), + ) + } + ast::Stmt::StructuresStmt(s) => { + let structures = s + .structure_defs() + .filter_map(|def| self.lower_structure_def(&def)) + .map(Structure::from) + .collect(); + Some( + self.alloc( + &ast::StructureOrStructures::from(s.clone()), + Structures { structures }, + ) + .into(), + ) + } + } + } + + fn lower_structure_def(&mut self, def: &ast::StructureDef) -> Option { + let name_def = def.structure_name_def()?; + + let SortDeclaration { name, sort_args } = self.lower_sort_decl(&name_def.sort_decl()?)?; + let constructors = def + .structure_constructors() + .filter_map(|c| self.lower_constructor(&c)) + .collect(); + Some(StructureDef { + name, + sort_args, + constructors, + }) + } + + fn lower_constructor( + &mut self, + constructor: &ast::StructureConstructor, + ) -> Option { + let name = lower_name(&constructor.name()?)?; + + let params = match constructor { + ast::StructureConstructor::ConstantConstructor(_) => { + vec![] + } + ast::StructureConstructor::CompoundConstructor(c) => c + .maybe_tagged_field_sorts() + .filter_map(|s| self.lower_constructor_param(&s)) + .collect(), + }; + + Some(Constructor { name, params }) + } + + fn lower_constructor_param( + &mut self, + param: &ast::MaybeTaggedFieldSort, + ) -> Option { + let tag = param.tag().map(|n| lower_name(&n)).flatten(); + let sort = self.lower_limited_sort(¶m.limited_sort()?)?; + + Some(ConstructorParam { tag, sort }) + } + + fn lower_limited_sort(&mut self, sort_ref: &ast::LimitedSort) -> Option { + match sort_ref { + ast::LimitedSort::IdentSort(ident_sort) => Some(self.alloc( + &sort_like(sort_ref.clone()), + SortRef::Ident(lower_name_ref(ident_sort)?), + )), + ast::LimitedSort::LimitedCompoundSort(compound) => { + let name = compound.ident_sort()?; + let ident_sort = ast::Sort::IdentSort(name); + let ident_sort = self.lower_sort_ref(&ident_sort)?; + let rest = compound + .limited_sorts() + .filter_map(|s| self.lower_limited_sort(&s)) + .collect(); + Some(self.alloc( + &sort_like(sort_ref.clone()), + SortRef::Apply(ident_sort, rest), + )) + } + } + } + + fn lower_sort_decl(&mut self, sort_decl: &ast::SortDecl) -> Option { + match sort_decl { + ast::SortDecl::IdentSortDecl(ident) => Some(SortDeclaration { + name: ident.name()?.as_name(), + sort_args: vec![], + }), + ast::SortDecl::CompoundSortDecl(compound) => { + let mut parts = compound.ident_sort_decls(); + + let name = parts.next()?.name()?.as_name(); + let sort_args = parts.filter_map(|part| lower_name(&part)).collect(); + + Some(SortDeclaration { name, sort_args }) + } + } + } + + fn lower_load_dir(&mut self, load: &ast::LoadDir) -> Option { + let path = load.file_path()?.string_token()?; + let path = path.text().trim_matches('"').to_owned(); + let Some(resolved) = self.db.resolve_file_path(self.hir.file_id, path.clone()) else { + tracing::error!("failed to resolve file path: {}", path); + return None; + }; + let import = FileImport { file: resolved }; + Some(self.alloc(load, import)) + } + + fn lower_phrase(&mut self, phrase: &ast::Phrase) -> Option { + match phrase { + ast::Phrase::Expr(expr) => self.lower_expr(expr).map(into), + ast::Phrase::Ded(ded) => self.lower_ded(ded).map(into), + } + } + + fn lower_sort_ref(&mut self, sort_ref: &ast::Sort) -> Option { + let sort_like = sort_like(sort_ref.clone()); + Some(match sort_ref { + ast::Sort::VarSort(v) => { + let name = ast::Ident::cast(v.ident_token()?)?.as_name(); + self.alloc(&sort_like, SortRef::Var(name)) + } + ast::Sort::IdentSort(name) => { + self.alloc(&sort_like, SortRef::Ident(name.name_ref()?.as_name())) + } + ast::Sort::CompoundSort(compound) => { + let mut sorts = compound.sorts(); + let first_ast = sorts.next()?; + let first = self.lower_sort_ref(&first_ast)?; + + let rest = sorts + .filter_map(|s| self.lower_sort_ref(&s)) + .collect::>(); + + self.alloc(&sort_like, SortRef::Apply(first, rest)) + } + }) + } + + fn lower_param(&mut self, param: &ast::MaybeWildcardTypedParam) -> Option { + let (name, sort, op_arity) = match param { + ast::MaybeWildcardTypedParam::MaybeTypedParam(maybe_typed) => match maybe_typed { + ast::MaybeTypedParam::Name(name) => { + (NameOrWildcard::Name(lower_name(name)?), None, None) + } + ast::MaybeTypedParam::TypedParam(typed) => { + let name = lower_name(&typed.name()?)?; + let sort = self.lower_sort_ref(&typed.sort()?)?; + (NameOrWildcard::Name(name), Some(sort), None) + } + ast::MaybeTypedParam::OpAnnotatedParam(op) => ( + NameOrWildcard::Name(lower_name(&op.name()?)?), + None, + lower_name_ref(&op.name_ref()?), + ), + }, + ast::MaybeWildcardTypedParam::Wildcard(_) => (NameOrWildcard::Wildcard, None, None), + }; + Some(Param { + name, + sort, + op_arity, + }) + } + + fn lower_define_dir(&mut self, define: &ast::DefineDir) -> Option> { + let name = define.define_name()?; + let kind = match name { + ast::DefineName::Name(name) => DefKind::Value(name.as_name()), + ast::DefineName::DefineNamedPattern(_) => todo!(), + ast::DefineName::DefineProc(proc) => { + let name = proc.name()?.as_name(); + let args = proc.args(); + let params = args + .filter_map(|arg| self.lower_param(&arg)) + .collect::>(); + DefKind::Procedure(name, params) + } + ast::DefineName::ListPat(pat) => { + let pat: ast::Pat = pat.into(); + let pat = self.lower_pat(&pat)?; + DefKind::PatternValue(pat) + } + }; + let body = define.define_body()?; + let body = self.lower_phrase(&body)?; + + Some(self.alloc(define, Definition { kind, body })) + } + + fn lower_pat(&mut self, pat: &ast::Pat) -> Option { + let kind = match pat { + ast::Pat::IdentPat(id) => { + let p = id.maybe_wildcard_typed_param()?; + match p { + ast::MaybeWildcardTypedParam::MaybeTypedParam(maybe_typed) => match maybe_typed + { + ast::MaybeTypedParam::Name(name) => { + let name = lower_name(&name)?; + PatKind::Ident { + name, + sort: None, + op_arity: None, + } + } + ast::MaybeTypedParam::TypedParam(typed) => { + let name = lower_name(&typed)?; + let sort = self.lower_sort_ref(&typed.sort()?)?; + PatKind::Ident { + name, + sort: Some(sort), + op_arity: None, + } + } + ast::MaybeTypedParam::OpAnnotatedParam(op) => { + let name = lower_name(&op.name()?)?; + PatKind::Ident { + name, + sort: None, + op_arity: lower_name_ref(&op.name_ref()?), + } + } + }, + ast::MaybeWildcardTypedParam::Wildcard(_) => PatKind::Wildcard, + } + } + ast::Pat::VarPat(var) => { + let name = hir::Name::new_trustme(var.ident_token()?.text()); + let sort = var.sort().and_then(|s| self.lower_sort_ref(&s)); + PatKind::Var { name, sort } + } + ast::Pat::MetaIdentPat(meta) => { + let name = hir::Name::new_trustme(meta.meta_ident()?.ident_token()?.text()); + PatKind::Symbol(name) + } + ast::Pat::LiteralPat(lit) => { + let literal = lit.literal()?; + let literal = self.lower_literal(&literal)?; + PatKind::Literal(literal) + } + ast::Pat::UnitPat(_) => PatKind::Unit, + ast::Pat::NamedPat(named) => { + let name = lower_name(named)?; + let pat = self.lower_pat(&named.pat()?)?; + PatKind::Named { name, pat } + } + ast::Pat::ValOfPat(v) => PatKind::ValOf(lower_name_ref(v)?), + ast::Pat::ListOfPat(l) => { + let first = self.lower_pat(&l.first()?)?; + let second = self.lower_pat(&l.second()?)?; + PatKind::ListOf(first, second) + } + ast::Pat::SplitPat(split) => { + let first = self.lower_pat(&split.first()?)?; + let second = self.lower_pat(&split.second()?)?; + let rest = split.rest().filter_map(|r| self.lower_pat(&r)); + PatKind::Split([first, second].into_iter().chain(rest).collect()) + } + ast::Pat::ListPat(list) => { + let pats = list.pats().filter_map(|p| self.lower_pat(&p)).collect(); + PatKind::List(pats) + } + ast::Pat::CompoundPat(compound) => { + let pats = compound.pats().filter_map(|p| self.lower_pat(&p)).collect(); + PatKind::Compound(pats) + } + ast::Pat::WherePat(where_) => { + let pat = self.lower_pat(&where_.pat()?)?; + let cond = self.lower_expr(&where_.expr()?)?; + PatKind::Where(pat, cond) + } + ast::Pat::SomeThingPat(some) => { + let thing = lower_some_thing(&some.some_thing()?)?; + let ident = some.ident_pat()?; + let name = match ident.maybe_wildcard_typed_param()? { + ast::MaybeWildcardTypedParam::MaybeTypedParam(mtp) => match mtp { + ast::MaybeTypedParam::Name(n) => lower_name(&n)?.into(), + ast::MaybeTypedParam::TypedParam(tp) => lower_name(&tp)?.into(), + ast::MaybeTypedParam::OpAnnotatedParam(op) => lower_name(&op)?.into(), + }, + ast::MaybeWildcardTypedParam::Wildcard(_) => NameOrWildcard::Wildcard, + }; + PatKind::Some(thing, name) + } + }; + + Some(self.alloc(pat, Pat { kind })) + } + + fn lower_literal(&mut self, lit: &ast::Literal) -> Option { + if let Some(string) = lit.string_token() { + Some(Literal::String(String::from( + // remove the quotes + &string.text()[1..string.text().len() - 1], + ))) + } else if let Some(char) = lit.char_token() { + let mut chars = char.text().chars(); + assert_eq!('`', chars.next()?); + Some(Literal::Char(chars.next()?)) + } else { + None + } + } + + fn lower_expr(&mut self, expr: &ast::Expr) -> Option { + match expr { + ast::Expr::IdentExpr(ident) => { + Some(self.alloc(expr, Expr::Ident(lower_name_ref(ident)?))) + } + ast::Expr::UnitExpr(_) => Some(self.alloc(expr, Expr::Unit)), + ast::Expr::LiteralExpr(lit) => { + let lit = self.lower_literal(&lit.literal()?)?; + Some(self.alloc(expr, Expr::Literal(lit))) + } + ast::Expr::TermVarExpr(var) => { + let sort = var.sort().map(|s| self.lower_sort_ref(&s)).flatten(); + Some(self.alloc( + expr, + Expr::TermVar(hir::Name::new_trustme(var.ident_token()?.text()), sort), + )) + } + ast::Expr::MetaIdent(meta) => Some(self.alloc( + expr, + Expr::Literal(Literal::Symbol(hir::Name::new_trustme( + meta.ident_token()?.text(), + ))), + )), + ast::Expr::CheckExpr(_) => todo!(), + ast::Expr::LambdaExpr(_) => todo!(), + ast::Expr::ApplicationExpr(_) => todo!(), + ast::Expr::ListExpr(_) => todo!(), + ast::Expr::MethodExpr(_) => todo!(), + ast::Expr::LetExpr(_) => todo!(), + ast::Expr::LetRecExpr(_) => todo!(), + ast::Expr::MatchExpr(_) => todo!(), + ast::Expr::TryExpr(_) => todo!(), + ast::Expr::CellExpr(_) => todo!(), + ast::Expr::SetExpr(_) => todo!(), + ast::Expr::RefExpr(_) => todo!(), + ast::Expr::WhileExpr(_) => todo!(), + ast::Expr::MakeVectorExpr(_) => todo!(), + ast::Expr::VectorSubExpr(_) => todo!(), + ast::Expr::VectorSetExpr(_) => todo!(), + ast::Expr::SeqExpr(_) => todo!(), + ast::Expr::AndExpr(_) => todo!(), + ast::Expr::OrExpr(_) => todo!(), + ast::Expr::MapExpr(_) => todo!(), + ast::Expr::WildcardExpr(_) => todo!(), + ast::Expr::PrefixCheckExpr(_) => todo!(), + } + } + + fn lower_ded(&mut self, _ded: &ast::Ded) -> Option { + match _ded { + ast::Ded::MethodCallDed(_) => todo!(), + ast::Ded::BangMethodCallDed(_) => todo!(), + ast::Ded::AssumeDed(_) => todo!(), + ast::Ded::NamedAssumeDed(_) => todo!(), + ast::Ded::ProofByContraDed(_) => todo!(), + ast::Ded::GeneralizeOverDed(_) => todo!(), + ast::Ded::PickAnyDed(_) => todo!(), + ast::Ded::WithWitnessDed(_) => todo!(), + ast::Ded::PickWitnessDed(_) => todo!(), + ast::Ded::PickWitnessesDed(_) => todo!(), + ast::Ded::InductDed(_) => todo!(), + ast::Ded::CasesDed(_) => todo!(), + ast::Ded::CheckDed(_) => todo!(), + ast::Ded::MatchDed(_) => todo!(), + ast::Ded::LetDed(_) => todo!(), + ast::Ded::LetRecDed(_) => todo!(), + ast::Ded::TryDed(_) => todo!(), + ast::Ded::ConcludeDed(_) => todo!(), + ast::Ded::InferBlockDed(_) => todo!(), + ast::Ded::PrefixAssumeDed(_) => todo!(), + ast::Ded::SeqDed(_) => todo!(), + } + } + + fn lower_extend_module_dir( + &mut self, + extend_module: &ast::ExtendModuleDir, + ) -> Option> { + let name = extend_module.name()?.as_name(); + let stmts = extend_module + .stmts() + .filter_map(|stmt| self.lower_module_stmt(&stmt)) + .collect(); + let extension = self.alloc(extend_module, ModuleExtension { name, stmts }); + Some(extension) + } + + fn lower_module_dir(&mut self, module: &ast::ModuleDir) -> Option> { + let name = module.name()?.as_name(); + let stmts = module + .stmts() + .filter_map(|stmt| self.lower_module_stmt(&stmt)) + .collect(); + let module = self.alloc(module, Module { name, stmts }); + Some(module) + } + + fn lower_term_symbol(&mut self, term_symbol: &ast::TermSymbol) -> Option> { + match term_symbol { + ast::TermSymbol::Function(func) => match func { + ast::DeclareDir::PrefixDeclareDir(_) => todo!(), + ast::DeclareDir::InfixDeclareDir(declare) => { + let names = declare.names().map(|name| name.as_name()).collect(); + let sort_vars = declare + .sort_vars_decl() + .map(|decl| { + decl.ident_sort_decls() + .filter_map(|i| i.name().map(|n| n.as_name())) + .collect() + }) + .unwrap_or_default(); + let arg_sorts = declare + .func_sorts()? + .sorts() + .filter_map(|s| self.lower_sort_ref(&s)) + .collect(); + let ret_sort = self.lower_sort_ref(&declare.return_sort()?)?; + let func = self.alloc( + term_symbol, + FunctionSymbol { + names, + arg_sorts, + ret_sort, + sort_vars, + }, + ); + Some(func) + } + }, + ast::TermSymbol::Constant(constant) => match constant { + ast::ConstantDeclareDir::PrefixConstantDeclare(_) => todo!(), + ast::ConstantDeclareDir::InfixConstantDeclare(declare) => { + let names = declare.names().map(|name| name.as_name()).collect(); + let ret_sort = self.lower_sort_ref(&declare.sort()?)?; + let func = self.alloc( + term_symbol, + FunctionSymbol { + names, + sort_vars: Vec::new(), + arg_sorts: Vec::new(), + ret_sort, + }, + ); + Some(func) + } + }, + } + } +} diff --git a/crates/hir-new/src/hir/name.rs b/crates/hir-new/src/hir/name.rs new file mode 100644 index 0000000..cc81308 --- /dev/null +++ b/crates/hir-new/src/hir/name.rs @@ -0,0 +1,50 @@ +use core::fmt; + +use smol_str::SmolStr; +use syntax::{ast, AstToken}; +use util::impl_from; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Name(SmolStr); + +impl Name { + pub fn new_trustme(text: impl Into) -> Name { + Name(text.into()) + } +} + +pub trait AsName { + fn as_name(&self) -> Name; +} + +impl AsName for ast::Ident { + fn as_name(&self) -> Name { + Name(self.text().into()) + } +} + +impl AsName for ast::Name { + fn as_name(&self) -> Name { + Name(self.text()) + } +} + +impl AsName for ast::NameRef { + fn as_name(&self) -> Name { + Name(self.text()) + } +} + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum NameOrWildcard { + Name(Name), + Wildcard, +} + +impl_from!(Name for NameOrWildcard); diff --git a/crates/hir-new/src/hir/pat.rs b/crates/hir-new/src/hir/pat.rs new file mode 100644 index 0000000..57a44ca --- /dev/null +++ b/crates/hir-new/src/hir/pat.rs @@ -0,0 +1,104 @@ +use la_arena::Idx; + +use crate::hir::Name; + +use super::{expr::Literal, ExprId, NameOrWildcard, PatId, SortRefId}; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum PatKind { + Wildcard, + Ident { + name: Name, + sort: Option, + op_arity: Option, + }, + Var { + name: Name, + sort: Option, + }, + Symbol(Name), + List(Vec), + Literal(Literal), + Unit, + Named { + name: Name, + pat: PatId, + }, + ValOf(Name), + ListOf(PatId, PatId), + Split(Vec), + Compound(Vec), + Where(PatId, ExprId), + Some(Thing, NameOrWildcard), +} + +#[derive(Debug, Clone, Eq, PartialEq, Copy)] +pub enum Thing { + Var, + SentCon, + Quant, + Term, + Atom, + Sentence, + List, + Cell, + Vector, + Proc, + Method, + Symbol, + Table, + Map, + Sub, + Char, +} + +impl Pat { + pub fn walk_child_pats(&self, mut f: impl FnMut(Idx)) { + match &self.kind { + PatKind::Ident { .. } => {} + PatKind::Var { .. } => {} + PatKind::Symbol(_) => {} + PatKind::Literal(_) => {} + PatKind::List(pats) => { + for pat in pats { + f(*pat); + } + } + PatKind::Unit => {} + PatKind::Named { pat, .. } => { + f(*pat); + } + PatKind::ValOf(_) => {} + PatKind::ListOf(pat1, pat2) => { + f(*pat1); + f(*pat2); + } + PatKind::Split(pats) => { + for pat in pats { + f(*pat); + } + } + PatKind::Compound(pats) => { + for pat in pats { + f(*pat); + } + } + PatKind::Wildcard => {} + PatKind::Where(pat, _) => { + f(*pat); + } + PatKind::Some(_, _) => {} + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Pat { + pub kind: PatKind, +} + +impl super::DebugDump for Pat { + fn debug_dump(&self, _dd: &mut super::DebugDumper) -> core::fmt::Result { + todo!() + } +} diff --git a/crates/hir-new/src/hir/phrase.rs b/crates/hir-new/src/hir/phrase.rs new file mode 100644 index 0000000..f2121dd --- /dev/null +++ b/crates/hir-new/src/hir/phrase.rs @@ -0,0 +1,61 @@ +use util::impl_from; + +use crate::hir::{Ded, DedId, Expr, ExprId}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum PhraseId { + Expr(ExprId), + Ded(DedId), +} + +impl_from!(Expr(ExprId), Ded(DedId) for PhraseId); + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Phrase { + Expr(Expr), + Ded(Ded), +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PhraseRef<'a> { + Expr(&'a Expr), + Ded(&'a Ded), +} + +impl<'a> From<&'a Expr> for PhraseRef<'a> { + fn from(expr: &'a Expr) -> Self { + Self::Expr(expr) + } +} + +impl<'a> From<&'a Ded> for PhraseRef<'a> { + fn from(ded: &'a Ded) -> Self { + Self::Ded(ded) + } +} + +impl_from!(Expr, Ded for Phrase); + +use super::{impl_debug_dump, DebugDump, DebugDumper}; + +impl_debug_dump!(delegate Expr, Ded for Phrase); + +impl super::Get for PhraseId { + type Output<'a> = PhraseRef<'a>; + + fn get(self, hir: &super::FileHir) -> Self::Output<'_> { + match self { + Self::Expr(expr) => PhraseRef::Expr(&hir[expr]), + Self::Ded(ded) => PhraseRef::Ded(&hir[ded]), + } + } +} + +impl<'a> DebugDump for PhraseRef<'a> { + fn debug_dump(&self, dd: &mut DebugDumper) -> core::fmt::Result { + match self { + Self::Expr(expr) => expr.debug_dump(dd), + Self::Ded(ded) => ded.debug_dump(dd), + } + } +} diff --git a/crates/hir-new/src/hir/snapshots/hir_new__hir__tests__load_lowers.snap.new b/crates/hir-new/src/hir/snapshots/hir_new__hir__tests__load_lowers.snap.new new file mode 100644 index 0000000..4e7191e --- /dev/null +++ b/crates/hir-new/src/hir/snapshots/hir_new__hir__tests__load_lowers.snap.new @@ -0,0 +1,14 @@ +--- +source: crates/hir-new/src/hir/tests.rs +assertion_line: 26 +description: "\n //- /foo.ath\n module my-module {\n declare Foo: [int] -> int\n\n load \"virtual:/bar.ath\"\n }\n //- /bar.ath\n module barry {\n declare Bar: (A, B) [int (List A) (List B)] -> int\n }\n " +--- +module my-module { + declare Foo: () [] -> + load { + module barry { + declare Bar: (A, B) [, <>, <>] -> + } + } +} + diff --git a/crates/hir-new/src/hir/sort_ref.rs b/crates/hir-new/src/hir/sort_ref.rs new file mode 100644 index 0000000..a0c541d --- /dev/null +++ b/crates/hir-new/src/hir/sort_ref.rs @@ -0,0 +1,32 @@ +use crate::hir::Name; +use core::fmt::Write; + +use super::{DebugDump, SortRefId}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SortRef { + Var(Name), + Ident(Name), + Apply(SortRefId, Vec), +} + +impl DebugDump for SortRef { + fn debug_dump(&self, dd: &mut super::DebugDumper) -> core::fmt::Result { + match self { + SortRef::Var(name) => write!(dd, "<{}>", name), + SortRef::Ident(name) => write!(dd, "<{}>", name), + SortRef::Apply(sort, args) => { + dd.dump(sort)?; + write!(dd, "<")?; + for (i, arg) in args.iter().enumerate() { + if i != 0 { + write!(dd, ", ")?; + } + dd.dump(arg)?; + } + write!(dd, ">")?; + Ok(()) + } + } + } +} diff --git a/crates/hir-new/src/hir/stmt.rs b/crates/hir-new/src/hir/stmt.rs new file mode 100644 index 0000000..72a8bcc --- /dev/null +++ b/crates/hir-new/src/hir/stmt.rs @@ -0,0 +1,297 @@ +use base_db::FileId; + +use crate::hir::{ExprId, Name, NameOrWildcard, PatId, PhraseId, SortRefId}; + +use super::DebugDump; +use super::DebugDumper; +use core::fmt::Write; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Module { + pub name: Name, + pub stmts: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleExtension { + pub name: Name, + pub stmts: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FunctionSymbol { + pub names: Vec, + pub sort_vars: Vec, + pub arg_sorts: Vec, + pub ret_sort: SortRefId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SortAlias { + pub name: Name, + pub sort: SortRefId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FileImport { + pub file: FileId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleImport { + pub names: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SortDeclaration { + pub name: Name, + pub sort_args: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DomainDeclaration { + pub domains: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Assertion { + pub name: Option, + pub facts: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ClosedAssertion { + pub name: Option, + pub fact: ExprId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Overload { + pub target: PhraseId, + pub overload: PhraseId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Overloads { + pub overloads: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Definition { + pub kind: DefKind, + pub body: PhraseId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DefKind { + Procedure(Name, Vec), + + Value(Name), + + PatternValue(PatId), + + NamedPatternValue(Name, PatId), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Param { + pub name: NameOrWildcard, + pub sort: Option, + pub op_arity: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PrimitiveMethod {} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PhraseStmt { + pub phrase: PhraseId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstructorParam { + pub tag: Option, + pub sort: SortRefId, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Constructor { + pub name: Name, + pub params: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Datatype { + pub name: Name, + pub sort_args: Vec, + pub constructors: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Datatypes { + pub datatypes: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Structure { + pub name: Name, + pub sort_args: Vec, + pub constructors: Vec, +} + +pub(crate) struct StructureDef { + pub name: Name, + pub sort_args: Vec, + pub constructors: Vec, +} + +impl From for Structure { + fn from(def: StructureDef) -> Self { + Self { + name: def.name, + sort_args: def.sort_args, + constructors: def.constructors, + } + } +} + +impl From for Datatype { + fn from(def: StructureDef) -> Self { + Self { + name: def.name, + sort_args: def.sort_args, + constructors: def.constructors, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Structures { + pub structures: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PrecedenceDeclaration { + pub names: Vec, + pub value: ExprId, +} + +impl DebugDump for Module { + fn debug_dump(&self, dd: &mut DebugDumper) -> core::fmt::Result { + writeln!(dd, "module {} {{", self.name)?; + dd.indented(|dd| { + for stmt in &self.stmts { + stmt.debug_dump(dd)?; + } + Ok(()) + })?; + writeln!(dd, "}}") + } +} + +impl DebugDump for ModuleExtension { + fn debug_dump(&self, dd: &mut DebugDumper) -> core::fmt::Result { + writeln!(dd, "extend-module {} {{", self.name)?; + for stmt in &self.stmts { + stmt.debug_dump(dd)?; + } + writeln!(dd, "}}") + } +} + +impl DebugDump for FunctionSymbol { + fn debug_dump(&self, dd: &mut DebugDumper) -> core::fmt::Result { + write!(dd, "declare ")?; + dd.comma_separated(&self.names, |dd, name| write!(dd, "{name}"))?; + write!(dd, ": (")?; + dd.comma_separated(&self.sort_vars, |dd, sort| write!(dd, "{sort}"))?; + write!(dd, ") [")?; + dd.comma_separated(&self.arg_sorts, |dd, arg| dd.hir[*arg].debug_dump(dd))?; + write!(dd, "] -> ")?; + dd.hir[self.ret_sort].debug_dump(dd)?; + writeln!(dd) + } +} + +impl DebugDump for SortAlias { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for FileImport { + fn debug_dump(&self, dd: &mut DebugDumper) -> core::fmt::Result { + writeln!(dd, "load {{")?; + dd.indented(|dd| { + dd.dump_file(self.file)?; + Ok(()) + })?; + writeln!(dd, "}}") + } +} + +impl DebugDump for ModuleImport { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for SortDeclaration { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for DomainDeclaration { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for Assertion { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for ClosedAssertion { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for Overloads { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for Definition { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for PhraseStmt { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for Datatypes { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for Structures { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} + +impl DebugDump for PrecedenceDeclaration { + fn debug_dump(&self, _dd: &mut DebugDumper) -> core::fmt::Result { + todo!() + } +} diff --git a/crates/hir-new/src/hir/tests.rs b/crates/hir-new/src/hir/tests.rs new file mode 100644 index 0000000..d9e8ff0 --- /dev/null +++ b/crates/hir-new/src/hir/tests.rs @@ -0,0 +1,63 @@ +use insta::assert_snapshot; + +use crate::{db::HirNewDatabase, fixture}; + +macro_rules! function { + () => {{ + // man this is ugly: https://stackoverflow.com/questions/38088067/equivalent-of-func-or-function-in-rust + fn f() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + let name = type_name_of(f); + + // Find and cut the rest of the path + match &name[..name.len() - 3].rfind(':') { + Some(pos) => &name[pos + 1..name.len() - 3], + None => &name[..name.len() - 3], + } + }}; +} + +#[track_caller] +fn check(name: &str, ra_fixture: &str) { + let (db, file_id) = fixture::file(ra_fixture); + let dump = db.debug_dump(file_id); + insta::with_settings!({description => ra_fixture, omit_expression => true }, { assert_snapshot!(name, dump) }); +} + +macro_rules! test { + ($input: literal) => { + check(function!(), $input) + }; +} + +#[test] +fn load_lowers() { + test!( + r#" + //- /foo.ath + module my-module { + declare Foo: [int] -> int + + load "virtual:/bar.ath" + } + //- /bar.ath + module barry { + declare Bar: (A, B) [int (List A) (List B)] -> int + } + "# + ); +} + +#[test] +fn define_lowers() { + test!( + r#" + //- /foo.ath + module my-module { + define Foo := 1; + } + "# + ); +} diff --git a/crates/hir-new/src/lib.rs b/crates/hir-new/src/lib.rs new file mode 100644 index 0000000..1364aea --- /dev/null +++ b/crates/hir-new/src/lib.rs @@ -0,0 +1,21 @@ +mod ast_map; +pub mod db; +#[cfg(test)] +mod fixture; +pub mod hir; +#[cfg(test)] +mod test_db; + +use base_db::FileId; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InFile { + pub file_id: FileId, + pub value: T, +} + +impl InFile { + pub fn new(file_id: FileId, value: T) -> Self { + Self { file_id, value } + } +} diff --git a/crates/hir-new/src/test_db.rs b/crates/hir-new/src/test_db.rs new file mode 100644 index 0000000..ab21874 --- /dev/null +++ b/crates/hir-new/src/test_db.rs @@ -0,0 +1,66 @@ +use core::fmt; + +use crate::{ast_map::AstDatabase, db::HirNewDatabase}; +use base_db::{salsa, FileWatcher, Upcast, VirtualFileDatabase, VirtualFilePathBuf}; +use rustc_hash::FxHashSet; + +#[derive(Default)] +#[salsa::database( + base_db::SourceDatabaseStorage, + crate::db::HirNewDatabaseStorage, + base_db::VirtualFileDatabaseStorage, + crate::ast_map::AstDatabaseStorage +)] +pub(crate) struct TestDB { + storage: salsa::Storage, + + virtual_files: FxHashSet, +} + +impl salsa::Database for TestDB {} + +impl FileWatcher for TestDB { + fn did_change_file(&mut self, _file_id: base_db::FileId) {} + + fn in_mem_contents(&self, _path: &base_db::AbsPath) -> Option> { + None + } + + fn set_in_mem_contents( + &mut self, + _path: base_db::AbsPathBuf, + _contents: std::sync::Arc, + ) { + } + + fn add_virtual_file(&mut self, path: VirtualFilePathBuf, contents: std::sync::Arc) { + self.virtual_files.insert(dbg!(path.clone())); + self.set_virtual_file_contents(path, contents); + } + + fn get_virtual_file(&self, path: VirtualFilePathBuf) -> Option> { + if self.virtual_files.contains(dbg!(&path)) { + Some(self.virtual_file_contents(path)) + } else { + None + } + } +} + +impl Upcast for TestDB { + fn upcast(&self) -> &(dyn HirNewDatabase + 'static) { + self + } +} + +impl Upcast for TestDB { + fn upcast(&self) -> &(dyn AstDatabase + 'static) { + self + } +} + +impl fmt::Debug for TestDB { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TestDB").finish() + } +} diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 502e9fe..9eb1bad 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -11,7 +11,7 @@ la-arena.workspace = true syntax.workspace = true base-db.workspace = true rustc-hash.workspace = true -smol_str = "0.1.24" +smol_str = "0.2.0" paste = "1.0.12" util.workspace = true tracing.workspace = true diff --git a/crates/hir/src/file_hir/lower.rs b/crates/hir/src/file_hir/lower.rs index 64fdbc1..b4aef53 100644 --- a/crates/hir/src/file_hir/lower.rs +++ b/crates/hir/src/file_hir/lower.rs @@ -148,27 +148,6 @@ macro_rules! or_continue { }; } -macro_rules! or_return { - ($exp: expr) => { - match $exp { - Some(it) => it, - None => return, - } - }; - ($exp: expr, default) => { - match $exp { - Some(it) => it, - None => return Default::default(), - } - }; - ($exp: expr, $ret: expr) => { - match $exp { - Some(it) => it, - None => return $ret, - } - }; -} - struct HirBuilder { file_id: FileId, ast: N, @@ -303,7 +282,11 @@ impl Ctx { fn lower_stmt(&mut self, stmt: ast::Stmt) -> Vec { match stmt { ast::Stmt::Dir(dir) => self.lower_dir(dir).into_iter().flatten().collect(), - ast::Stmt::Phrase(p) => self.lower_phrase(p).into_iter().map(Into::into).collect(), + ast::Stmt::PhraseStmt(p) => self + .lower_phrase(p.phrase()) + .into_iter() + .map(Into::into) + .collect(), ast::Stmt::DatatypeStmt(_) => { // todo!(); TODO: implement Vec::new() @@ -638,6 +621,10 @@ impl Ctx { // todo!(); TODO: implement None } + ast::Dir::DefineSortDir(_) => { + // todo!(); TODO: implement + None + } } } diff --git a/crates/hir/src/test_db.rs b/crates/hir/src/test_db.rs index 4b058ae..195b6bf 100644 --- a/crates/hir/src/test_db.rs +++ b/crates/hir/src/test_db.rs @@ -1,12 +1,19 @@ use core::fmt; use crate::db::HirDatabase; -use base_db::{salsa, FileWatcher, Upcast}; +use base_db::{salsa, FileWatcher, Upcast, VirtualFileDatabase, VirtualFilePathBuf}; +use rustc_hash::FxHashSet; #[derive(Default)] -#[salsa::database(base_db::SourceDatabaseStorage, crate::db::HirDatabaseStorage)] +#[salsa::database( + base_db::SourceDatabaseStorage, + crate::db::HirDatabaseStorage, + base_db::VirtualFileDatabaseStorage +)] pub(crate) struct TestDB { storage: salsa::Storage, + + virtual_files: FxHashSet, } impl salsa::Database for TestDB {} @@ -24,6 +31,19 @@ impl FileWatcher for TestDB { _contents: std::sync::Arc, ) { } + + fn add_virtual_file(&mut self, path: VirtualFilePathBuf, contents: std::sync::Arc) { + self.virtual_files.insert(path.clone()); + self.set_virtual_file_contents(path, contents); + } + + fn get_virtual_file(&self, path: VirtualFilePathBuf) -> Option> { + if self.virtual_files.contains(&path) { + Some(self.virtual_file_contents(path)) + } else { + None + } + } } impl Upcast for TestDB { diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index cb3b8f6..f8eed6a 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -7,18 +7,20 @@ use std::sync::Arc; pub use base_db; -use base_db::{salsa, FileContentsQuery, FileId, FileWatcher}; +use base_db::{salsa, FileContentsQuery, FileId, FileWatcher, VirtualFileDatabase}; use line_index::LineIndex; use rustc_hash::FxHashMap; #[salsa::database( base_db::SourceDatabaseStorage, + base_db::VirtualFileDatabaseStorage, LineIndexDatabaseStorage, hir::HirDatabaseStorage )] pub struct RootDatabase { storage: salsa::Storage, in_mem_files: Arc>>, + virtual_files: Arc>>, } impl salsa::Database for RootDatabase {} @@ -34,6 +36,7 @@ impl salsa::ParallelDatabase for RootDatabase { salsa::Snapshot::new(RootDatabase { storage: self.storage.snapshot(), in_mem_files: self.in_mem_files.clone(), + virtual_files: self.virtual_files.clone(), }) } } @@ -43,6 +46,7 @@ impl RootDatabase { RootDatabase { storage: salsa::Storage::default(), in_mem_files: Default::default(), + virtual_files: Default::default(), } } } @@ -67,6 +71,15 @@ impl FileWatcher for RootDatabase { fn set_in_mem_contents(&mut self, path: base_db::AbsPathBuf, contents: Arc) { Arc::make_mut(&mut self.in_mem_files).insert(path, contents); } + + fn add_virtual_file(&mut self, path: base_db::VirtualFilePathBuf, contents: Arc) { + Arc::make_mut(&mut self.virtual_files).insert(path.clone(), contents.clone()); + self.set_virtual_file_contents(path, contents); + } + + fn get_virtual_file(&self, path: base_db::VirtualFilePathBuf) -> Option> { + self.virtual_files.get(&path).cloned() + } } #[salsa::query_group(LineIndexDatabaseStorage)] diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 370763d..d971629 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -10,6 +10,7 @@ ide-db.workspace = true syntax.workspace = true hir.workspace = true tracing.workspace = true +extend = "1.2.0" [dev-dependencies] test-utils.workspace = true diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 4da9bf9..6e262f4 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -13,7 +13,7 @@ use ide_db::{ }; use core::fmt; -use std::{panic::UnwindSafe, sync::Arc}; +use std::{panic::UnwindSafe, path::PathBuf, sync::Arc}; pub use crate::syntax_highlighting::{ tags::{Highlight, HlPunct, HlTag}, @@ -36,11 +36,21 @@ pub struct AnalysisHost { db: RootDatabase, } +fn init_roots(db: &mut RootDatabase) { + if let Ok(home) = std::env::var("ATHENA_HOME") { + let home = PathBuf::from(home); + let Ok(home) = home.canonicalize() else { return }; + db.set_roots(vec![ide_db::base_db::VfsPath::from(AbsPathBuf::assert(home))].into()); + } else { + db.set_roots(Arc::new([])) + } +} + impl AnalysisHost { pub fn new() -> AnalysisHost { - AnalysisHost { - db: RootDatabase::new(), - } + let mut db = RootDatabase::new(); + init_roots(&mut db); + AnalysisHost { db } } pub fn analysis(&self) -> Analysis { diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 553f44a..381248f 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] drop_bomb.workspace = true -logos = "0.12.1" +logos = "0.13.0" static_assertions = "1.1.0" [features] diff --git a/crates/parser/src/grammar/directives.rs b/crates/parser/src/grammar/directives.rs index d0debd4..e6397c1 100644 --- a/crates/parser/src/grammar/directives.rs +++ b/crates/parser/src/grammar/directives.rs @@ -356,7 +356,10 @@ fn func_sorts(p: &mut Parser) { while !p.at(T![']']) && !p.at_end() { if !super::sorts::sort(p) { - p.error("expected a sort declaration"); + p.err_recover( + "expected a sort declaration", + SORT_DECL_START.union(TokenSet::single(T![']'])), + ); } } @@ -620,7 +623,9 @@ fn load_dir(p: &mut Parser, kind: ParseKind) { p.bump_any(); } } else { + let m = p.start(); p.bump(SyntaxKind::STRING); + m.complete(p, SyntaxKind::FILE_PATH); } if kind.is_prefix() { diff --git a/crates/parser/src/grammar/statements.rs b/crates/parser/src/grammar/statements.rs index c1d3b4f..b564e54 100644 --- a/crates/parser/src/grammar/statements.rs +++ b/crates/parser/src/grammar/statements.rs @@ -13,7 +13,12 @@ use super::{directives::DIR_START_SET, phrases::PHRASE_START_SET, sorts::sort_de fn phrase_stmt(p: &mut Parser) { // test_err(stmt) phrase_stmt_err // (! ) - super::phrases::phrase(p); + let m = p.start(); + if super::phrases::phrase(p) { + m.complete(p, SyntaxKind::PHRASE_STMT); + } else { + m.abandon(p); + } } // test(stmt) dir_stmt @@ -168,6 +173,9 @@ fn structure_def(p: &mut Parser) { // test(stmt) datatype_stmt // datatype Foo := bar | (baz num:Int) + +// test(stmt) polymorphic_datatype +// datatype (List S) := nil | (:: S (List S)) fn datatype_stmt(p: &mut Parser) { assert!(p.at(T![datatype])); diff --git a/crates/parser/src/lexer.rs b/crates/parser/src/lexer.rs index 73150a7..03d6f8e 100644 --- a/crates/parser/src/lexer.rs +++ b/crates/parser/src/lexer.rs @@ -27,7 +27,9 @@ impl<'i> LexedInput<'i> { let mut pos = 0; for (i, token) in lexer.enumerate() { - let syntax_kind = token.to_syntax_kind(); + let syntax_kind = token + .map(|t| t.to_syntax_kind()) + .unwrap_or(SyntaxKind::ERROR); if syntax_kind == SyntaxKind::ERROR { error.push(LexerError { // FIXME: this is a terrible error message @@ -35,7 +37,7 @@ impl<'i> LexedInput<'i> { token: i as u32, }); } - let len = token.len(); + let len = token.map(|t| t.len()).unwrap_or(0); kind.push(syntax_kind); start.push(pos as u32); pos += len; diff --git a/crates/parser/src/lexer/generated.rs b/crates/parser/src/lexer/generated.rs index fb70df4..8b46e64 100644 --- a/crates/parser/src/lexer/generated.rs +++ b/crates/parser/src/lexer/generated.rs @@ -232,8 +232,6 @@ pub(crate) enum LexerToken { SomeSub(usize), #[token("some-char", |lex|lex.slice().len())] SomeChar(usize), - #[error] - Error, } impl LexerToken { pub(crate) fn to_syntax_kind(self) -> SyntaxKind { @@ -347,7 +345,6 @@ impl LexerToken { Self::Char(..) => SyntaxKind::CHAR, Self::Whitespace(..) => SyntaxKind::WHITESPACE, Self::Comment(..) => SyntaxKind::COMMENT, - Self::Error => SyntaxKind::ERROR, } } pub(crate) fn len(self) -> usize { @@ -461,7 +458,6 @@ impl LexerToken { Self::Char(len) => len, Self::Whitespace(len) => len, Self::Comment(len) => len, - Self::Error => 0, } } } diff --git a/crates/parser/src/snapshots/parser__tests__parse_inline_err.snap b/crates/parser/src/snapshots/parser__tests__parse_inline_err.snap index df56012..5b74d0c 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_inline_err.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_inline_err.snap @@ -23,9 +23,10 @@ SOURCE_FILE R_BRACK "]" ERROR R_BRACK "]" - LIST_EXPR - L_BRACK "[" - R_BRACK "]" + PHRASE_STMT + LIST_EXPR + L_BRACK "[" + R_BRACK "]" WHITESPACE "\n " INFIX_DECLARE_DIR DECLARE_KW "declare" diff --git a/crates/parser/src/snapshots/parser__tests__parse_inline_err@0088_phrase_stmt_err.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_inline_err@0088_phrase_stmt_err.ath.snap index 2144a7c..e909f60 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_inline_err@0088_phrase_stmt_err.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_inline_err@0088_phrase_stmt_err.ath.snap @@ -3,11 +3,12 @@ source: crates/parser/src/tests.rs description: "(! )\n" input_file: crates/parser/test_data/parser/inline/err/stmt/0088_phrase_stmt_err.ath --- -BANG_METHOD_CALL_DED - L_PAREN "(" - BANG "!" - WHITESPACE " " - R_PAREN ")" +PHRASE_STMT + BANG_METHOD_CALL_DED + L_PAREN "(" + BANG "!" + WHITESPACE " " + R_PAREN ")" WHITESPACE "\n" error 2: expected method expression to apply diff --git a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0084_phrase_stmt.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0084_phrase_stmt.ath.snap index c87bd2a..00f62a9 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0084_phrase_stmt.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0084_phrase_stmt.ath.snap @@ -3,16 +3,17 @@ source: crates/parser/src/tests.rs description: "(!claim A)\n" input_file: crates/parser/test_data/parser/inline/ok/stmt/0084_phrase_stmt.ath --- -BANG_METHOD_CALL_DED - L_PAREN "(" - BANG "!" - IDENT_EXPR - NAME_REF - IDENT "claim" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "A" - R_PAREN ")" +PHRASE_STMT + BANG_METHOD_CALL_DED + L_PAREN "(" + BANG "!" + IDENT_EXPR + NAME_REF + IDENT "claim" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "A" + R_PAREN ")" WHITESPACE "\n" diff --git a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0090_load_dir.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0090_load_dir.ath.snap index b4a4173..0fd2c00 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0090_load_dir.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0090_load_dir.ath.snap @@ -6,6 +6,7 @@ input_file: crates/parser/test_data/parser/inline/ok/dir/0090_load_dir.ath LOAD_DIR LOAD_KW "load" WHITESPACE " " - STRING "\"list.ath\"" + FILE_PATH + STRING "\"list.ath\"" WHITESPACE "\n" diff --git a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0166_load_prefix.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0166_load_prefix.ath.snap index 87fc827..27a7248 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0166_load_prefix.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0166_load_prefix.ath.snap @@ -7,7 +7,8 @@ LOAD_DIR L_PAREN "(" LOAD_KW "load" WHITESPACE " " - STRING "\"list.ath\"" + FILE_PATH + STRING "\"list.ath\"" R_PAREN ")" WHITESPACE "\n" diff --git a/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0190_polymorphic_datatype.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0190_polymorphic_datatype.ath.snap new file mode 100644 index 0000000..1ec1ed2 --- /dev/null +++ b/crates/parser/src/snapshots/parser__tests__parse_inline_ok@0190_polymorphic_datatype.ath.snap @@ -0,0 +1,53 @@ +--- +source: crates/parser/src/tests.rs +description: "datatype (List S) := nil | (:: S (List S))\n" +input_file: crates/parser/test_data/parser/inline/ok/stmt/0190_polymorphic_datatype.ath +--- +DATATYPE_STMT + DATATYPE_KW "datatype" + WHITESPACE " " + STRUCTURE_DEF + STRUCTURE_NAME_DEF + COMPOUND_SORT + L_PAREN "(" + IDENT_SORT_DECL + NAME + IDENT "List" + WHITESPACE " " + IDENT_SORT_DECL + NAME + IDENT "S" + R_PAREN ")" + WHITESPACE " " + COLON_EQ ":=" + WHITESPACE " " + CONSTANT_CONSTRUCTOR + NAME + IDENT "nil" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + COMPOUND_CONSTRUCTOR + L_PAREN "(" + NAME + IDENT "::" + WHITESPACE " " + MAYBE_TAGGED_FIELD_SORT + IDENT_SORT + NAME_REF + IDENT "S" + WHITESPACE " " + MAYBE_TAGGED_FIELD_SORT + LIMITED_COMPOUND_SORT + L_PAREN "(" + IDENT_SORT + NAME_REF + IDENT "List" + WHITESPACE " " + IDENT_SORT + NAME_REF + IDENT "S" + R_PAREN ")" + R_PAREN ")" + WHITESPACE "\n" + diff --git a/crates/parser/src/snapshots/parser__tests__parse_ok@baddefine.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_ok@baddefine.ath.snap index af6dc3b..8d96ecf 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_ok@baddefine.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_ok@baddefine.ath.snap @@ -4,34 +4,20 @@ description: "match p {\n\t(|| (some-atom _) (~ (some-atom _))) => true\n| _ => input_file: crates/parser/test_data/parser/ok/file/baddefine.ath --- SOURCE_FILE - INFIX_MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "p" - WHITESPACE " " - L_CURLY "{" - WHITESPACE "\n\t" - MATCH_ARM - OR_PAT - L_PAREN "(" - PIPE2 "||" - WHITESPACE " " - SOME_THING_PAT - L_PAREN "(" - SOME_ATOM_KW "some-atom" - WHITESPACE " " - IDENT_PAT - WILDCARD - UNDERSCORE "_" - R_PAREN ")" - WHITESPACE " " - COMPOUND_PAT + PHRASE_STMT + INFIX_MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "p" + WHITESPACE " " + L_CURLY "{" + WHITESPACE "\n\t" + MATCH_ARM + OR_PAT L_PAREN "(" - IDENT_PAT - NAME - IDENT "~" + PIPE2 "||" WHITESPACE " " SOME_THING_PAT L_PAREN "(" @@ -41,26 +27,41 @@ SOURCE_FILE WILDCARD UNDERSCORE "_" R_PAREN ")" + WHITESPACE " " + COMPOUND_PAT + L_PAREN "(" + IDENT_PAT + NAME + IDENT "~" + WHITESPACE " " + SOME_THING_PAT + L_PAREN "(" + SOME_ATOM_KW "some-atom" + WHITESPACE " " + IDENT_PAT + WILDCARD + UNDERSCORE "_" + R_PAREN ")" + R_PAREN ")" R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "true" - WHITESPACE "\n" - MATCH_ARM - PIPE "|" - WHITESPACE " " - IDENT_PAT - UNDERSCORE "_" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "false" - WHITESPACE "\n" - R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "true" + WHITESPACE "\n" + MATCH_ARM + PIPE "|" + WHITESPACE " " + IDENT_PAT + UNDERSCORE "_" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "false" + WHITESPACE "\n" + R_CURLY "}" diff --git a/crates/parser/src/snapshots/parser__tests__parse_ok@by-ded.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_ok@by-ded.ath.snap index b62a3e3..8e57bed 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_ok@by-ded.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_ok@by-ded.ath.snap @@ -4,37 +4,38 @@ description: "(!absurd (q by (!mp premise p)))\n" input_file: crates/parser/test_data/parser/ok/file/by-ded.ath --- SOURCE_FILE - BANG_METHOD_CALL_DED - L_PAREN "(" - BANG "!" - IDENT_EXPR - NAME_REF - IDENT "absurd" - WHITESPACE " " - BY_DED + PHRASE_STMT + BANG_METHOD_CALL_DED L_PAREN "(" + BANG "!" IDENT_EXPR NAME_REF - IDENT "q" + IDENT "absurd" WHITESPACE " " - BY_KW "by" - WHITESPACE " " - BANG_METHOD_CALL_DED + BY_DED L_PAREN "(" - BANG "!" IDENT_EXPR NAME_REF - IDENT "mp" + IDENT "q" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "premise" + BY_KW "by" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "p" + BANG_METHOD_CALL_DED + L_PAREN "(" + BANG "!" + IDENT_EXPR + NAME_REF + IDENT "mp" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "premise" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "p" + R_PAREN ")" R_PAREN ")" R_PAREN ")" - R_PAREN ")" WHITESPACE "\n" diff --git a/crates/parser/src/snapshots/parser__tests__parse_ok@hardmatch.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_ok@hardmatch.ath.snap index 9e58b41..4e539d6 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_ok@hardmatch.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_ok@hardmatch.ath.snap @@ -4,38 +4,39 @@ description: "(match foo { _ => lambda (_) 1} 0)" input_file: crates/parser/test_data/parser/ok/file/hardmatch.ath --- SOURCE_FILE - APPLICATION_EXPR - L_PAREN "(" - INFIX_MATCH_EXPR - MATCH_KW "match" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "foo" - WHITESPACE " " - L_CURLY "{" - WHITESPACE " " - MATCH_ARM - IDENT_PAT - UNDERSCORE "_" + PHRASE_STMT + APPLICATION_EXPR + L_PAREN "(" + INFIX_MATCH_EXPR + MATCH_KW "match" WHITESPACE " " - FAT_ARROW "=>" + IDENT_EXPR + NAME_REF + IDENT "foo" WHITESPACE " " - LAMBDA_EXPR - LAMBDA_KW "lambda" - WHITESPACE " " - L_PAREN "(" - WILDCARD + L_CURLY "{" + WHITESPACE " " + MATCH_ARM + IDENT_PAT UNDERSCORE "_" - R_PAREN ")" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "1" - R_CURLY "}" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "0" - R_PAREN ")" + FAT_ARROW "=>" + WHITESPACE " " + LAMBDA_EXPR + LAMBDA_KW "lambda" + WHITESPACE " " + L_PAREN "(" + WILDCARD + UNDERSCORE "_" + R_PAREN ")" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "1" + R_CURLY "}" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "0" + R_PAREN ")" diff --git a/crates/parser/src/snapshots/parser__tests__parse_ok@loopy.ath.snap b/crates/parser/src/snapshots/parser__tests__parse_ok@loopy.ath.snap index 4ed8b12..e3c058e 100644 --- a/crates/parser/src/snapshots/parser__tests__parse_ok@loopy.ath.snap +++ b/crates/parser/src/snapshots/parser__tests__parse_ok@loopy.ath.snap @@ -7,12 +7,14 @@ SOURCE_FILE LOAD_DIR LOAD_KW "load" WHITESPACE " " - STRING "\"nat-minus\"" + FILE_PATH + STRING "\"nat-minus\"" WHITESPACE "\n" LOAD_DIR LOAD_KW "load" WHITESPACE " " - STRING "\"nat-minus\"" + FILE_PATH + STRING "\"nat-minus\"" WHITESPACE "\n\n" MODULE_DIR MODULE_KW "module" @@ -54,23 +56,24 @@ SOURCE_FILE R_BRACK "]" R_BRACK "]" WHITESPACE "\n " - APPLICATION_EXPR - L_PAREN "(" - IDENT_EXPR - NAME_REF - IDENT "transform-output" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "eval" - WHITESPACE " " - LIST_EXPR - L_BRACK "[" + PHRASE_STMT + APPLICATION_EXPR + L_PAREN "(" IDENT_EXPR NAME_REF - IDENT "nat->int" - R_BRACK "]" - R_PAREN ")" + IDENT "transform-output" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "eval" + WHITESPACE " " + LIST_EXPR + L_BRACK "[" + IDENT_EXPR + NAME_REF + IDENT "nat->int" + R_BRACK "]" + R_PAREN ")" WHITESPACE "\n \n " INFIX_ASSERT_DIR ASSERT_KW "assert" @@ -272,41 +275,43 @@ SOURCE_FILE IDENT "one" R_PAREN ")" WHITESPACE "\n\n " - APPLICATION_EXPR - L_PAREN "(" - IDENT_EXPR - NAME_REF - IDENT "eval" - WHITESPACE " " + PHRASE_STMT APPLICATION_EXPR L_PAREN "(" IDENT_EXPR NAME_REF - IDENT "factorial" + IDENT "eval" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "4" + APPLICATION_EXPR + L_PAREN "(" + IDENT_EXPR + NAME_REF + IDENT "factorial" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "4" + R_PAREN ")" R_PAREN ")" - R_PAREN ")" WHITESPACE "\n " - APPLICATION_EXPR - L_PAREN "(" - IDENT_EXPR - NAME_REF - IDENT "eval" - WHITESPACE " " + PHRASE_STMT APPLICATION_EXPR L_PAREN "(" IDENT_EXPR NAME_REF - IDENT "factorial" + IDENT "eval" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "5" + APPLICATION_EXPR + L_PAREN "(" + IDENT_EXPR + NAME_REF + IDENT "factorial" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "5" + R_PAREN ")" R_PAREN ")" - R_PAREN ")" WHITESPACE "\n\n " INFIX_DEFINE_DIR DEFINE_KW "define" @@ -488,161 +493,162 @@ SOURCE_FILE NAME_REF IDENT "bar" WHITESPACE "\n " - INDUCT_DED - BY_INDUCTION_KW "by-induction" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "f_x_less_than" - WHITESPACE " " - L_CURLY "{" - WHITESPACE "\n " - RESTRICTED_MATCH_DED - IDENT_PAT - NAME - IDENT "zero" + PHRASE_STMT + INDUCT_DED + BY_INDUCTION_KW "by-induction" WHITESPACE " " - FAT_ARROW "=>" + IDENT_EXPR + NAME_REF + IDENT "f_x_less_than" WHITESPACE " " - CONCLUDE_DED - CONCLUDE_KW "conclude" - WHITESPACE " " - NAME - IDENT "base_case" + L_CURLY "{" + WHITESPACE "\n " + RESTRICTED_MATCH_DED + IDENT_PAT + NAME + IDENT "zero" WHITESPACE " " - COLON_EQ ":=" + FAT_ARROW "=>" WHITESPACE " " - APPLICATION_EXPR - L_PAREN "(" - IDENT_EXPR - NAME_REF - IDENT "factorial" + CONCLUDE_DED + CONCLUDE_KW "conclude" + WHITESPACE " " + NAME + IDENT "base_case" + WHITESPACE " " + COLON_EQ ":=" WHITESPACE " " APPLICATION_EXPR L_PAREN "(" IDENT_EXPR NAME_REF - IDENT "zero" + IDENT "factorial" + WHITESPACE " " + APPLICATION_EXPR + L_PAREN "(" + IDENT_EXPR + NAME_REF + IDENT "zero" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "-" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "one" + R_PAREN ")" WHITESPACE " " IDENT_EXPR NAME_REF - IDENT "-" + IDENT "<=" WHITESPACE " " IDENT_EXPR NAME_REF - IDENT "one" + IDENT "factorial" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "zero" R_PAREN ")" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "<=" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "factorial" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "zero" - R_PAREN ")" - WHITESPACE "\n " - BANG_METHOD_CALL_DED - L_PAREN "(" - BANG "!" - IDENT_EXPR - NAME_REF - IDENT "force" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "base_case" - R_PAREN ")" - WHITESPACE "\n \n \n " - RESTRICTED_MATCH_DED - PIPE "|" - WHITESPACE " " - NAMED_PAT - L_PAREN "(" - NAME - IDENT "m" - WHITESPACE " " - AS_KW "as" + WHITESPACE "\n " + BANG_METHOD_CALL_DED + L_PAREN "(" + BANG "!" + IDENT_EXPR + NAME_REF + IDENT "force" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "base_case" + R_PAREN ")" + WHITESPACE "\n \n \n " + RESTRICTED_MATCH_DED + PIPE "|" WHITESPACE " " - COMPOUND_PAT + NAMED_PAT L_PAREN "(" - IDENT_PAT - NAME - IDENT "S" + NAME + IDENT "m" + WHITESPACE " " + AS_KW "as" WHITESPACE " " - IDENT_PAT - NAME - IDENT "n" + COMPOUND_PAT + L_PAREN "(" + IDENT_PAT + NAME + IDENT "S" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "n" + R_PAREN ")" R_PAREN ")" - R_PAREN ")" - WHITESPACE " " - FAT_ARROW "=>" - WHITESPACE " " - CONCLUDE_DED - CONCLUDE_KW "conclude" - WHITESPACE " " - NAME - IDENT "inductive_step" WHITESPACE " " - COLON_EQ ":=" + FAT_ARROW "=>" WHITESPACE " " - APPLICATION_EXPR - L_PAREN "(" + CONCLUDE_DED + CONCLUDE_KW "conclude" + WHITESPACE " " + NAME + IDENT "inductive_step" + WHITESPACE " " + COLON_EQ ":=" + WHITESPACE " " APPLICATION_EXPR L_PAREN "(" - IDENT_EXPR - NAME_REF - IDENT "factorial" - WHITESPACE " " APPLICATION_EXPR L_PAREN "(" IDENT_EXPR NAME_REF - IDENT "m" + IDENT "factorial" WHITESPACE " " + APPLICATION_EXPR + L_PAREN "(" + IDENT_EXPR + NAME_REF + IDENT "m" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "-" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "one" + R_PAREN ")" + R_PAREN ")" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "<=" + WHITESPACE " " + APPLICATION_EXPR + L_PAREN "(" IDENT_EXPR NAME_REF - IDENT "-" + IDENT "factorial" WHITESPACE " " IDENT_EXPR NAME_REF - IDENT "one" + IDENT "m" R_PAREN ")" R_PAREN ")" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "<=" - WHITESPACE " " - APPLICATION_EXPR + WHITESPACE "\n " + BANG_METHOD_CALL_DED L_PAREN "(" + BANG "!" IDENT_EXPR NAME_REF - IDENT "factorial" + IDENT "force" WHITESPACE " " IDENT_EXPR NAME_REF - IDENT "m" + IDENT "inductive_step" R_PAREN ")" - R_PAREN ")" - WHITESPACE "\n " - BANG_METHOD_CALL_DED - L_PAREN "(" - BANG "!" - IDENT_EXPR - NAME_REF - IDENT "force" - WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "inductive_step" - R_PAREN ")" - WHITESPACE "\n " - R_CURLY "}" + WHITESPACE "\n " + R_CURLY "}" WHITESPACE "\n\n" R_CURLY "}" diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 8f6f8a9..68fbd5d 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -244,6 +244,7 @@ pub enum SyntaxKind { DOMAINS_DIR, MODULE_DIR, LOAD_DIR, + FILE_PATH, INFIX_ASSERT_DIR, ASSERT_CLOSED_DIR, OPEN_DIR, @@ -280,6 +281,7 @@ pub enum SyntaxKind { DATATYPES_STMT, STRUCTURE_STMT, STRUCTURES_STMT, + PHRASE_STMT, #[doc(hidden)] __LAST, } @@ -530,6 +532,7 @@ impl SyntaxKind { | DOMAINS_DIR | MODULE_DIR | LOAD_DIR + | FILE_PATH | INFIX_ASSERT_DIR | ASSERT_CLOSED_DIR | OPEN_DIR @@ -566,6 +569,7 @@ impl SyntaxKind { | DATATYPES_STMT | STRUCTURE_STMT | STRUCTURES_STMT + | PHRASE_STMT ) } pub fn from_keyword(ident: &str) -> Option { @@ -1014,5 +1018,11 @@ macro_rules! T { [shebang] => { $crate ::SyntaxKind::SHEBANG }; + [string] => { + $crate ::SyntaxKind::STRING + }; + [char] => { + $crate ::SyntaxKind::CHAR + }; } pub use T; diff --git a/crates/parser/test_data/parser/inline/ok/stmt/0190_polymorphic_datatype.ath b/crates/parser/test_data/parser/inline/ok/stmt/0190_polymorphic_datatype.ath new file mode 100644 index 0000000..e80dc50 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/stmt/0190_polymorphic_datatype.ath @@ -0,0 +1 @@ +datatype (List S) := nil | (:: S (List S)) diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml index e63e1ae..34ab595 100644 --- a/crates/sourcegen/Cargo.toml +++ b/crates/sourcegen/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -prettyplease = "0.1.25" -syn = "1.0.109" +prettyplease = "0.2.6" +syn = "2.0.18" diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 06abb1a..613ece3 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] either = "1.8.1" -rowan = "0.15.10" -smol_str = "0.1.24" +rowan = "0.15.11" +smol_str = "0.2.0" parser = { path = "../parser" } util = { version = "0.1.0", path = "../util" } diff --git a/crates/syntax/ast.ron b/crates/syntax/ast.ron index 7f5d73f..70587a4 100644 --- a/crates/syntax/ast.ron +++ b/crates/syntax/ast.ron @@ -240,6 +240,7 @@ KindsSrc( "DOMAINS_DIR", "MODULE_DIR", "LOAD_DIR", + "FILE_PATH", "INFIX_ASSERT_DIR", "ASSERT_CLOSED_DIR", "OPEN_DIR", @@ -277,5 +278,6 @@ KindsSrc( "DATATYPES_STMT", "STRUCTURE_STMT", "STRUCTURES_STMT", + "PHRASE_STMT", ], ) \ No newline at end of file diff --git a/crates/syntax/athena.ungram b/crates/syntax/athena.ungram index f9b8a40..d2351a8 100644 --- a/crates/syntax/athena.ungram +++ b/crates/syntax/athena.ungram @@ -16,6 +16,9 @@ // A? -- zero or one repetition // (A) -- same as A // label:A -- suggested name for field of AST node +// +// Special cases: +// required__{label} indicates that the node _must_ be present in the syntax tree // // The `Tokens` non-terminal definition is special. It should consist of alternating terminals @@ -107,12 +110,15 @@ SourceFile = Stmt = Dir // ✅ - | Phrase // ✅ + | PhraseStmt // ✅ | DatatypeStmt | StructureStmt | DatatypesStmt | StructuresStmt +PhraseStmt = + required__phrase : Phrase + StructureNameDef = SortDecl @@ -131,7 +137,7 @@ LimitedCompoundSort = '(' IdentSort LimitedSort* ')' CompoundConstructor = - '(' Name MaybeTaggedFieldSort ')' + '(' Name MaybeTaggedFieldSort* ')' MaybeTaggedFieldSort = (tag:Name ':')? LimitedSort @@ -205,6 +211,7 @@ Dir = | SetPrecedenceDir | OverloadDir | RuleDir + | DefineSortDir ModuleDir = 'module' Name '{' Stmt* '}' @@ -273,7 +280,7 @@ DeclareAttrs = '[' DeclareAttr* InputTransformDecl? ']' FuncSorts = - '[' Sort* ']' + '['? Sort* ']'? SortVarsDecl = '(' (IdentSortDecl (',' IdentSortDecl)*) ')' @@ -310,8 +317,11 @@ DefineNamedPattern = DefineProc = '(' Name args:MaybeWildcardTypedParam* ')' +FilePath = + 'string' + LoadDir = - '('? 'load' 'string' ')'? // can be surrounded by parens + '('? 'load' FilePath ')'? // can be surrounded by parens AssertDir = InfixAssertDir @@ -355,14 +365,14 @@ SetPrecedenceDir = // if multiple idents, must be surrounded by parens '('? 'set-precedence' '('? NameRef* ')'? Expr ')'? // can be surrounded by parens PhrasePair = - '(' Phrase Phrase ')' + '(' first_phrase:Phrase second_phrase:Phrase ')' OverloadDir = OverloadSingle | OverloadMulti OverloadSingle = - '('? 'overload' Phrase Phrase ')'? + '('? 'overload' first_phrase:Phrase second_phrase:Phrase ')'? OverloadMulti = '('? 'overload' PhrasePair* ')'? @@ -750,7 +760,7 @@ ValOfPat = '(' 'val-of' NameRef ')' ListOfPat = - '(' 'list-of' Pat Pat ')' + '(' 'list-of' first:Pat second:Pat ')' SplitPat = '(' 'split' first:Pat second:Pat rest:Pat* ')' diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 657011a..bd48f44 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs @@ -12,7 +12,7 @@ mod traits; pub use self::{ generated::{nodes::*, tokens::*}, - node_ext::{NameOrNameRef, SortLike}, + node_ext::{DatatypeOrDatatypes, NameOrNameRef, SortLike, StructureOrStructures, TermSymbol}, }; pub use traits::{HasDefineBody, HasDefineName, HasName, HasNameRef}; /// The main trait to go from untyped `SyntaxNode` to a typed ast. The @@ -131,14 +131,6 @@ mod support { } mod ext { - use super::PrefixDefine; - - impl From for super::Definition { - fn from(value: PrefixDefine) -> Self { - super::Definition::PrefixDefineDir(value.into()) - } - } - impl super::Sort { pub fn as_ident_sort(&self) -> Option<&super::IdentSort> { match self { @@ -147,4 +139,28 @@ mod ext { } } } + + impl From for super::Stmt { + fn from(value: super::Domain) -> Self { + match value { + super::Domain::DomainDir(d) => d.into(), + super::Domain::DomainsDir(d) => d.into(), + } + } + } + + impl From for super::Dir { + fn from(value: super::TermSymbol) -> Self { + match value { + super::TermSymbol::Function(f) => f.into(), + super::TermSymbol::Constant(c) => c.into(), + } + } + } + + impl From for super::Stmt { + fn from(value: super::TermSymbol) -> Self { + super::Dir::from(value).into() + } + } } diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 7623dca..383509d 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -37,7 +37,14 @@ impl NameRef { pub struct Literal { pub(crate) syntax: SyntaxNode, } -impl Literal {} +impl Literal { + pub fn string_token(&self) -> Option { + support::token(&self.syntax, T![string]) + } + pub fn char_token(&self) -> Option { + support::token(&self.syntax, T![char]) + } +} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MetaIdent { @@ -175,6 +182,16 @@ impl SourceFile { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PhraseStmt { + pub(crate) syntax: SyntaxNode, +} +impl PhraseStmt { + pub fn phrase(&self) -> Phrase { + support::child(&self.syntax).expect("node is required: this indicates a bug in the parser") + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct DatatypeStmt { pub(crate) syntax: SyntaxNode, @@ -253,8 +270,8 @@ impl CompoundConstructor { pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn maybe_tagged_field_sort(&self) -> Option { - support::child(&self.syntax) + pub fn maybe_tagged_field_sorts(&self) -> AstChildren { + support::children(&self.syntax) } pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) @@ -424,6 +441,9 @@ impl LoadDir { pub fn load_token(&self) -> Option { support::token(&self.syntax, T![load]) } + pub fn file_path(&self) -> Option { + support::child(&self.syntax) + } pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } @@ -478,6 +498,23 @@ impl SetPrecedenceDir { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DefineSortDir { + pub(crate) syntax: SyntaxNode, +} +impl ast::HasName for DefineSortDir {} +impl DefineSortDir { + pub fn define_sort_token(&self) -> Option { + support::token(&self.syntax, T![define - sort]) + } + pub fn colon_eq_token(&self) -> Option { + support::token(&self.syntax, T![:=]) + } + pub fn sort(&self) -> Option { + support::child(&self.syntax) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IdentSortDecl { pub(crate) syntax: SyntaxNode, @@ -853,6 +890,16 @@ impl ListPat { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct FilePath { + pub(crate) syntax: SyntaxNode, +} +impl FilePath { + pub fn string_token(&self) -> Option { + support::token(&self.syntax, T![string]) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct InfixAssertDir { pub(crate) syntax: SyntaxNode, @@ -958,23 +1005,6 @@ impl ExpandInputDir { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct DefineSortDir { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasName for DefineSortDir {} -impl DefineSortDir { - pub fn define_sort_token(&self) -> Option { - support::token(&self.syntax, T![define - sort]) - } - pub fn colon_eq_token(&self) -> Option { - support::token(&self.syntax, T![:=]) - } - pub fn sort(&self) -> Option { - support::child(&self.syntax) - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PhrasePair { pub(crate) syntax: SyntaxNode, @@ -983,7 +1013,10 @@ impl PhrasePair { pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn phrase(&self) -> Option { + pub fn first_phrase(&self) -> Option { + support::child(&self.syntax) + } + pub fn second_phrase(&self) -> Option { support::child(&self.syntax) } pub fn r_paren_token(&self) -> Option { @@ -1002,7 +1035,10 @@ impl OverloadSingle { pub fn overload_token(&self) -> Option { support::token(&self.syntax, T![overload]) } - pub fn phrase(&self) -> Option { + pub fn first_phrase(&self) -> Option { + support::child(&self.syntax) + } + pub fn second_phrase(&self) -> Option { support::child(&self.syntax) } pub fn r_paren_token(&self) -> Option { @@ -2624,7 +2660,10 @@ impl ListOfPat { pub fn list_of_token(&self) -> Option { support::token(&self.syntax, T![list - of]) } - pub fn pat(&self) -> Option { + pub fn first(&self) -> Option { + support::child(&self.syntax) + } + pub fn second(&self) -> Option { support::child(&self.syntax) } pub fn r_paren_token(&self) -> Option { @@ -2834,7 +2873,7 @@ pub enum Phrase { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Stmt { Dir(Dir), - Phrase(Phrase), + PhraseStmt(PhraseStmt), DatatypeStmt(DatatypeStmt), StructureStmt(StructureStmt), DatatypesStmt(DatatypesStmt), @@ -2858,6 +2897,7 @@ pub enum Dir { SetPrecedenceDir(SetPrecedenceDir), OverloadDir(OverloadDir), RuleDir(RuleDir), + DefineSortDir(DefineSortDir), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -3323,6 +3363,21 @@ impl AstNode for SourceFile { &self.syntax } } +impl AstNode for PhraseStmt { + fn can_cast(kind: SyntaxKind) -> bool { + kind == PHRASE_STMT + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for DatatypeStmt { fn can_cast(kind: SyntaxKind) -> bool { kind == DATATYPE_STMT @@ -3623,6 +3678,21 @@ impl AstNode for SetPrecedenceDir { &self.syntax } } +impl AstNode for DefineSortDir { + fn can_cast(kind: SyntaxKind) -> bool { + kind == DEFINE_SORT_DIR + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for IdentSortDecl { fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_SORT_DECL @@ -3938,9 +4008,9 @@ impl AstNode for ListPat { &self.syntax } } -impl AstNode for InfixAssertDir { +impl AstNode for FilePath { fn can_cast(kind: SyntaxKind) -> bool { - kind == INFIX_ASSERT_DIR + kind == FILE_PATH } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -3953,9 +4023,9 @@ impl AstNode for InfixAssertDir { &self.syntax } } -impl AstNode for PrefixAssertDir { +impl AstNode for InfixAssertDir { fn can_cast(kind: SyntaxKind) -> bool { - kind == PREFIX_ASSERT_DIR + kind == INFIX_ASSERT_DIR } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -3968,9 +4038,9 @@ impl AstNode for PrefixAssertDir { &self.syntax } } -impl AstNode for InfixRuleDir { +impl AstNode for PrefixAssertDir { fn can_cast(kind: SyntaxKind) -> bool { - kind == INFIX_RULE_DIR + kind == PREFIX_ASSERT_DIR } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -3983,9 +4053,9 @@ impl AstNode for InfixRuleDir { &self.syntax } } -impl AstNode for PrefixRuleDir { +impl AstNode for InfixRuleDir { fn can_cast(kind: SyntaxKind) -> bool { - kind == PREFIX_RULE_DIR + kind == INFIX_RULE_DIR } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -3998,9 +4068,9 @@ impl AstNode for PrefixRuleDir { &self.syntax } } -impl AstNode for ExpandInputDir { +impl AstNode for PrefixRuleDir { fn can_cast(kind: SyntaxKind) -> bool { - kind == EXPAND_INPUT_DIR + kind == PREFIX_RULE_DIR } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -4013,9 +4083,9 @@ impl AstNode for ExpandInputDir { &self.syntax } } -impl AstNode for DefineSortDir { +impl AstNode for ExpandInputDir { fn can_cast(kind: SyntaxKind) -> bool { - kind == DEFINE_SORT_DIR + kind == EXPAND_INPUT_DIR } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -5552,6 +5622,21 @@ impl From for MaybeWildcardTypedParam { MaybeWildcardTypedParam::Wildcard(node) } } +impl From for MaybeWildcardTypedParam { + fn from(node: Name) -> MaybeWildcardTypedParam { + MaybeWildcardTypedParam::MaybeTypedParam(node.into()) + } +} +impl From for MaybeWildcardTypedParam { + fn from(node: TypedParam) -> MaybeWildcardTypedParam { + MaybeWildcardTypedParam::MaybeTypedParam(node.into()) + } +} +impl From for MaybeWildcardTypedParam { + fn from(node: OpAnnotatedParam) -> MaybeWildcardTypedParam { + MaybeWildcardTypedParam::MaybeTypedParam(node.into()) + } +} impl AstNode for MaybeWildcardTypedParam { fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, WILDCARD) || MaybeTypedParam::can_cast(kind) @@ -5711,6 +5796,246 @@ impl From for Phrase { Phrase::Ded(node) } } +impl From for Phrase { + fn from(node: IdentExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: LiteralExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: UnitExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: TermVarExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: MetaIdent) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: CheckExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: LambdaExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: ApplicationExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: ListExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: MethodExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: LetExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: LetRecExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: MatchExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: TryExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: CellExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: SetExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: RefExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: WhileExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: MakeVectorExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: VectorSubExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: VectorSetExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: SeqExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: AndExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: OrExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: MapExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: WildcardExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: PrefixCheckExpr) -> Phrase { + Phrase::Expr(node.into()) + } +} +impl From for Phrase { + fn from(node: MethodCallDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: BangMethodCallDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: AssumeDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: NamedAssumeDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: ProofByContraDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: GeneralizeOverDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: PickAnyDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: WithWitnessDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: PickWitnessDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: PickWitnessesDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: InductDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: CasesDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: CheckDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: MatchDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: LetDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: LetRecDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: TryDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: ConcludeDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: InferBlockDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: PrefixAssumeDed) -> Phrase { + Phrase::Ded(node.into()) + } +} +impl From for Phrase { + fn from(node: SeqDed) -> Phrase { + Phrase::Ded(node.into()) + } +} impl AstNode for Phrase { fn can_cast(kind: SyntaxKind) -> bool { Expr::can_cast(kind) || Ded::can_cast(kind) @@ -5743,9 +6068,9 @@ impl From for Stmt { Stmt::Dir(node) } } -impl From for Stmt { - fn from(node: Phrase) -> Stmt { - Stmt::Phrase(node) +impl From for Stmt { + fn from(node: PhraseStmt) -> Stmt { + Stmt::PhraseStmt(node) } } impl From for Stmt { @@ -5768,16 +6093,96 @@ impl From for Stmt { Stmt::StructuresStmt(node) } } +impl From for Stmt { + fn from(node: ModuleDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: DomainDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: DomainsDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: DefineDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: LoadDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: AssertDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: AssertClosedDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: DeclareDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: ConstantDeclareDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: ExtendModuleDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: OpenDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: AssociativityDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: SetPrecedenceDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: OverloadDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: RuleDir) -> Stmt { + Stmt::Dir(node.into()) + } +} +impl From for Stmt { + fn from(node: DefineSortDir) -> Stmt { + Stmt::Dir(node.into()) + } +} impl AstNode for Stmt { fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - DATATYPE_STMT | STRUCTURE_STMT | DATATYPES_STMT | STRUCTURES_STMT + PHRASE_STMT | DATATYPE_STMT | STRUCTURE_STMT | DATATYPES_STMT | STRUCTURES_STMT ) || Dir::can_cast(kind) - || Phrase::can_cast(kind) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { + PHRASE_STMT => Self::PhraseStmt(PhraseStmt { syntax }), DATATYPE_STMT => Self::DatatypeStmt(DatatypeStmt { syntax }), STRUCTURE_STMT => Self::StructureStmt(StructureStmt { syntax }), DATATYPES_STMT => Self::DatatypesStmt(DatatypesStmt { syntax }), @@ -5787,8 +6192,6 @@ impl AstNode for Stmt { return None; } else if Dir::can_cast(other) { return Dir::cast(syntax).map(Self::Dir); - } else if Phrase::can_cast(other) { - return Phrase::cast(syntax).map(Self::Phrase); } else { return None; } @@ -5800,7 +6203,7 @@ impl AstNode for Stmt { fn syntax(&self) -> &SyntaxNode { match self { Stmt::Dir(it) => it.syntax(), - Stmt::Phrase(it) => it.syntax(), + Stmt::PhraseStmt(it) => it.syntax(), Stmt::DatatypeStmt(it) => it.syntax(), Stmt::StructureStmt(it) => it.syntax(), Stmt::DatatypesStmt(it) => it.syntax(), @@ -5883,6 +6286,71 @@ impl From for Dir { Dir::RuleDir(node) } } +impl From for Dir { + fn from(node: DefineSortDir) -> Dir { + Dir::DefineSortDir(node) + } +} +impl From for Dir { + fn from(node: InfixDefineDir) -> Dir { + Dir::DefineDir(node.into()) + } +} +impl From for Dir { + fn from(node: PrefixDefineDir) -> Dir { + Dir::DefineDir(node.into()) + } +} +impl From for Dir { + fn from(node: InfixAssertDir) -> Dir { + Dir::AssertDir(node.into()) + } +} +impl From for Dir { + fn from(node: PrefixAssertDir) -> Dir { + Dir::AssertDir(node.into()) + } +} +impl From for Dir { + fn from(node: PrefixDeclareDir) -> Dir { + Dir::DeclareDir(node.into()) + } +} +impl From for Dir { + fn from(node: InfixDeclareDir) -> Dir { + Dir::DeclareDir(node.into()) + } +} +impl From for Dir { + fn from(node: InfixConstantDeclare) -> Dir { + Dir::ConstantDeclareDir(node.into()) + } +} +impl From for Dir { + fn from(node: PrefixConstantDeclare) -> Dir { + Dir::ConstantDeclareDir(node.into()) + } +} +impl From for Dir { + fn from(node: OverloadSingle) -> Dir { + Dir::OverloadDir(node.into()) + } +} +impl From for Dir { + fn from(node: OverloadMulti) -> Dir { + Dir::OverloadDir(node.into()) + } +} +impl From for Dir { + fn from(node: InfixRuleDir) -> Dir { + Dir::RuleDir(node.into()) + } +} +impl From for Dir { + fn from(node: PrefixRuleDir) -> Dir { + Dir::RuleDir(node.into()) + } +} impl AstNode for Dir { fn can_cast(kind: SyntaxKind) -> bool { matches!( @@ -5896,6 +6364,7 @@ impl AstNode for Dir { | OPEN_DIR | ASSOCIATIVITY_DIR | SET_PRECEDENCE_DIR + | DEFINE_SORT_DIR ) || DefineDir::can_cast(kind) || AssertDir::can_cast(kind) || DeclareDir::can_cast(kind) @@ -5914,6 +6383,7 @@ impl AstNode for Dir { OPEN_DIR => Self::OpenDir(OpenDir { syntax }), ASSOCIATIVITY_DIR => Self::AssociativityDir(AssociativityDir { syntax }), SET_PRECEDENCE_DIR => Self::SetPrecedenceDir(SetPrecedenceDir { syntax }), + DEFINE_SORT_DIR => Self::DefineSortDir(DefineSortDir { syntax }), other => { if false { return None; @@ -5954,6 +6424,7 @@ impl AstNode for Dir { Dir::SetPrecedenceDir(it) => it.syntax(), Dir::OverloadDir(it) => it.syntax(), Dir::RuleDir(it) => it.syntax(), + Dir::DefineSortDir(it) => it.syntax(), } } } @@ -6067,6 +6538,46 @@ impl From for MetaDefinition { MetaDefinition::Assertion(node) } } +impl From for MetaDefinition { + fn from(node: InfixDefineDir) -> MetaDefinition { + MetaDefinition::Definition(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: PrefixDefineDir) -> MetaDefinition { + MetaDefinition::Definition(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: DomainDir) -> MetaDefinition { + MetaDefinition::Domain(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: DomainsDir) -> MetaDefinition { + MetaDefinition::Domain(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: DeclareDir) -> MetaDefinition { + MetaDefinition::FunctionSymbol(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: ConstantDeclareDir) -> MetaDefinition { + MetaDefinition::FunctionSymbol(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: AssertDir) -> MetaDefinition { + MetaDefinition::Assertion(node.into()) + } +} +impl From for MetaDefinition { + fn from(node: AssertClosedDir) -> MetaDefinition { + MetaDefinition::Assertion(node.into()) + } +} impl AstNode for MetaDefinition { fn can_cast(kind: SyntaxKind) -> bool { Definition::can_cast(kind) @@ -6113,6 +6624,16 @@ impl From for Definition { Definition::PrefixDefineDir(node) } } +impl From for Definition { + fn from(node: PrefixDefine) -> Definition { + Definition::PrefixDefineDir(node.into()) + } +} +impl From for Definition { + fn from(node: PrefixDefineBlocks) -> Definition { + Definition::PrefixDefineDir(node.into()) + } +} impl AstNode for Definition { fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, INFIX_DEFINE_DIR) || PrefixDefineDir::can_cast(kind) @@ -6180,6 +6701,26 @@ impl From for FunctionSymbol { FunctionSymbol::ConstantDeclareDir(node) } } +impl From for FunctionSymbol { + fn from(node: PrefixDeclareDir) -> FunctionSymbol { + FunctionSymbol::DeclareDir(node.into()) + } +} +impl From for FunctionSymbol { + fn from(node: InfixDeclareDir) -> FunctionSymbol { + FunctionSymbol::DeclareDir(node.into()) + } +} +impl From for FunctionSymbol { + fn from(node: InfixConstantDeclare) -> FunctionSymbol { + FunctionSymbol::ConstantDeclareDir(node.into()) + } +} +impl From for FunctionSymbol { + fn from(node: PrefixConstantDeclare) -> FunctionSymbol { + FunctionSymbol::ConstantDeclareDir(node.into()) + } +} impl AstNode for FunctionSymbol { fn can_cast(kind: SyntaxKind) -> bool { DeclareDir::can_cast(kind) || ConstantDeclareDir::can_cast(kind) @@ -6217,6 +6758,16 @@ impl From for Assertion { Assertion::AssertClosedDir(node) } } +impl From for Assertion { + fn from(node: InfixAssertDir) -> Assertion { + Assertion::AssertDir(node.into()) + } +} +impl From for Assertion { + fn from(node: PrefixAssertDir) -> Assertion { + Assertion::AssertDir(node.into()) + } +} impl AstNode for Assertion { fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ASSERT_CLOSED_DIR) || AssertDir::can_cast(kind) @@ -6466,6 +7017,16 @@ impl From for DefineDir { DefineDir::PrefixDefineDir(node) } } +impl From for DefineDir { + fn from(node: PrefixDefine) -> DefineDir { + DefineDir::PrefixDefineDir(node.into()) + } +} +impl From for DefineDir { + fn from(node: PrefixDefineBlocks) -> DefineDir { + DefineDir::PrefixDefineDir(node.into()) + } +} impl AstNode for DefineDir { fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, INFIX_DEFINE_DIR) || PrefixDefineDir::can_cast(kind) @@ -6718,6 +7279,16 @@ impl From for Expr { Expr::PrefixCheckExpr(node) } } +impl From for Expr { + fn from(node: InfixMatchExpr) -> Expr { + Expr::MatchExpr(node.into()) + } +} +impl From for Expr { + fn from(node: PrefixMatchExpr) -> Expr { + Expr::MatchExpr(node.into()) + } +} impl AstNode for Expr { fn can_cast(kind: SyntaxKind) -> bool { matches!( @@ -6972,6 +7543,71 @@ impl From for Ded { Ded::SeqDed(node) } } +impl From for Ded { + fn from(node: InfixCheckDed) -> Ded { + Ded::CheckDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixCheckDed) -> Ded { + Ded::CheckDed(node.into()) + } +} +impl From for Ded { + fn from(node: InfixMatchDed) -> Ded { + Ded::MatchDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixMatchDed) -> Ded { + Ded::MatchDed(node.into()) + } +} +impl From for Ded { + fn from(node: InfixLetDed) -> Ded { + Ded::LetDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixLetDed) -> Ded { + Ded::LetDed(node.into()) + } +} +impl From for Ded { + fn from(node: InfixLetRecDed) -> Ded { + Ded::LetRecDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixLetRecDed) -> Ded { + Ded::LetRecDed(node.into()) + } +} +impl From for Ded { + fn from(node: InfixTryDed) -> Ded { + Ded::TryDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixTryDed) -> Ded { + Ded::TryDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixNamedAssumeDed) -> Ded { + Ded::PrefixAssumeDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixSingleAssumeDed) -> Ded { + Ded::PrefixAssumeDed(node.into()) + } +} +impl From for Ded { + fn from(node: PrefixAssumeLetDed) -> Ded { + Ded::PrefixAssumeDed(node.into()) + } +} impl AstNode for Ded { fn can_cast(kind: SyntaxKind) -> bool { matches!( @@ -7296,6 +7932,156 @@ impl From for InferOrExpr { InferOrExpr::Expr(node) } } +impl From for InferOrExpr { + fn from(node: InferFrom) -> InferOrExpr { + InferOrExpr::Inference(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: InferBy) -> InferOrExpr { + InferOrExpr::Inference(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: Ded) -> InferOrExpr { + InferOrExpr::Inference(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: IdentExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: LiteralExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: UnitExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: TermVarExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: MetaIdent) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: CheckExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: LambdaExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: ApplicationExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: ListExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: MethodExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: LetExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: LetRecExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: MatchExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: TryExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: CellExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: SetExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: RefExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: WhileExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: MakeVectorExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: VectorSubExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: VectorSetExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: SeqExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: AndExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: OrExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: MapExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: WildcardExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} +impl From for InferOrExpr { + fn from(node: PrefixCheckExpr) -> InferOrExpr { + InferOrExpr::Expr(node.into()) + } +} impl AstNode for InferOrExpr { fn can_cast(kind: SyntaxKind) -> bool { Inference::can_cast(kind) || Expr::can_cast(kind) @@ -7338,6 +8124,111 @@ impl From for Inference { Inference::Ded(node) } } +impl From for Inference { + fn from(node: MethodCallDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: BangMethodCallDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: AssumeDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: NamedAssumeDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: ProofByContraDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: GeneralizeOverDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: PickAnyDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: WithWitnessDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: PickWitnessDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: PickWitnessesDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: InductDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: CasesDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: CheckDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: MatchDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: LetDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: LetRecDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: TryDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: ConcludeDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: InferBlockDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: PrefixAssumeDed) -> Inference { + Inference::Ded(node.into()) + } +} +impl From for Inference { + fn from(node: SeqDed) -> Inference { + Inference::Ded(node.into()) + } +} impl AstNode for Inference { fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, INFER_FROM | INFER_BY) || Ded::can_cast(kind) @@ -7424,6 +8315,7 @@ impl AstNode for AnyHasName { | MODULE_DIR | EXTEND_MODULE_DIR | ASSERT_CLOSED_DIR + | DEFINE_SORT_DIR | IDENT_SORT_DECL | PREFIX_SINGLE_SYMBOL | DECLARE_ATTR @@ -7433,7 +8325,6 @@ impl AstNode for AnyHasName { | PREFIX_ASSERT_DIR | INFIX_RULE_DIR | PREFIX_RULE_DIR - | DEFINE_SORT_DIR | LET_REC_PART | PICK_WITNESS_DED | PICK_WITNESSES_DED @@ -7728,6 +8619,11 @@ impl std::fmt::Display for SourceFile { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for PhraseStmt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for DatatypeStmt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -7828,6 +8724,11 @@ impl std::fmt::Display for SetPrecedenceDir { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for DefineSortDir { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for IdentSortDecl { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -7933,6 +8834,11 @@ impl std::fmt::Display for ListPat { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for FilePath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for InfixAssertDir { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -7958,11 +8864,6 @@ impl std::fmt::Display for ExpandInputDir { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for DefineSortDir { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.syntax(), f) - } -} impl std::fmt::Display for PhrasePair { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 127487d..642c29f 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -1,4 +1,4 @@ -use crate::{ast, AstNode, SyntaxKind, SyntaxNode}; +use crate::{ast, AstNode, SyntaxNode}; use smol_str::SmolStr; impl ast::Name { @@ -23,86 +23,104 @@ fn text_of_first_token(node: &SyntaxNode) -> SmolStr { .into() } -#[derive(Debug, Clone)] -pub enum NameOrNameRef { - Name(ast::Name), - NameRef(ast::NameRef), -} - -impl ast::AstNode for NameOrNameRef { - fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF) - } - - fn cast(syntax: SyntaxNode) -> Option { - let res = match syntax.kind() { - SyntaxKind::NAME => NameOrNameRef::Name(ast::Name { syntax }), - SyntaxKind::NAME_REF => NameOrNameRef::NameRef(ast::NameRef { syntax }), - _ => return None, - }; - - Some(res) - } - - fn syntax(&self) -> &SyntaxNode { - match self { - NameOrNameRef::Name(it) => it.syntax(), - NameOrNameRef::NameRef(it) => it.syntax(), +macro_rules! wrapper_enum { + (@inner { @derive = { #[derive($($derive: tt)*)] }, @vis = $v:vis, @name = $enm:ident, @variants = [$(($variant:ident, $typ: ty)),*] }) => { + #[derive($($derive)*)] + $v enum $enm { $($variant($typ)),* } + + $( + impl From<$typ> for $enm { + fn from(t: $typ) -> Self { + $enm::$variant(t) + } + } + )* + + impl $crate::ast::AstNode for $enm { + fn can_cast(kind: $crate::SyntaxKind) -> bool { + $( + <$typ as $crate::ast::AstNode>::can_cast(kind) + )||* + } + + fn cast(syntax: $crate::SyntaxNode) -> Option { + $( + if let Some(it) = <$typ as $crate::ast::AstNode>::cast(syntax.clone()).map($enm::$variant) { + return Some(it); + } + )* + + None + } + + fn syntax(&self) -> &$crate::SyntaxNode { + match self { + $( + $enm::$variant(it) => it.syntax(), + )* + } + } } - } -} - -#[derive(Debug, Clone)] -pub enum SortLike { - Sort(ast::Sort), - SortDecl(ast::SortDecl), - LimitedSort(ast::LimitedSort), + }; + (#[derive($($derive:tt)*)] $v: vis enum $enm: ident { $($variant:ident ($typ:ty)),* $(,)?}) => { + wrapper_enum! { + @inner { + @derive = { #[derive($($derive)*)] }, + @vis = $v, + @name = $enm, + @variants = [$(($variant, $typ)),*] + } + } + }; + ($v: vis enum $enm: ident { $($variant:ident ($typ:ty)),* $(,)?}) => { + wrapper_enum! { + @inner { + @derive = { #[derive(Debug, Clone)] }, + @vis = $v, + @name = $enm, + @variants = [$(($variant, $typ)),*] + } + } + }; } -impl From for SortLike { - fn from(sort: ast::Sort) -> Self { - SortLike::Sort(sort) +wrapper_enum! { + #[derive(Debug, Clone)] + pub enum NameOrNameRef { + Name(ast::Name), + NameRef(ast::NameRef), } } -impl From for SortLike { - fn from(decl: ast::SortDecl) -> Self { - SortLike::SortDecl(decl) +wrapper_enum! { + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum SortLike { + Sort(ast::Sort), + SortDecl(ast::SortDecl), + LimitedSort(ast::LimitedSort), } } -impl From for SortLike { - fn from(limited: ast::LimitedSort) -> Self { - SortLike::LimitedSort(limited) +wrapper_enum! { + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum DatatypeOrDatatypes { + Datatype(ast::DatatypeStmt), + Datatypes(ast::DatatypesStmt), } } -impl ast::AstNode for SortLike { - fn can_cast(kind: SyntaxKind) -> bool { - ast::Sort::can_cast(kind) - || ast::SortDecl::can_cast(kind) - || ast::LimitedSort::can_cast(kind) - } - - fn cast(syntax: SyntaxNode) -> Option { - if let Some(sort) = ast::Sort::cast(syntax.clone()) { - return Some(SortLike::Sort(sort)); - } - if let Some(decl) = ast::SortDecl::cast(syntax.clone()) { - return Some(SortLike::SortDecl(decl)); - } - if let Some(limited) = ast::LimitedSort::cast(syntax) { - return Some(SortLike::LimitedSort(limited)); - } - - None +wrapper_enum! { + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum StructureOrStructures { + Structure(ast::StructureStmt), + Structures(ast::StructuresStmt), } +} - fn syntax(&self) -> &SyntaxNode { - match self { - SortLike::Sort(it) => it.syntax(), - SortLike::SortDecl(it) => it.syntax(), - SortLike::LimitedSort(it) => it.syntax(), - } +wrapper_enum! { + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum TermSymbol { + Function(ast::DeclareDir), + Constant(ast::ConstantDeclareDir), } } diff --git a/crates/syntax/src/ast/traits.rs b/crates/syntax/src/ast/traits.rs index bcc5312..df3bdb8 100644 --- a/crates/syntax/src/ast/traits.rs +++ b/crates/syntax/src/ast/traits.rs @@ -23,3 +23,15 @@ pub trait HasDefineBody: AstNode { support::child(self.syntax()) } } + +impl HasNameRef for ast::NameRef { + fn name_ref(&self) -> Option { + Some(self.clone()) + } +} + +impl HasName for ast::Name { + fn name(&self) -> Option { + Some(self.clone()) + } +} diff --git a/crates/syntax/src/snapshots/syntax__tests__syntax_validation.snap b/crates/syntax/src/snapshots/syntax__tests__syntax_validation.snap index 07797d8..82052a6 100644 --- a/crates/syntax/src/snapshots/syntax__tests__syntax_validation.snap +++ b/crates/syntax/src/snapshots/syntax__tests__syntax_validation.snap @@ -4,33 +4,34 @@ description: ((!claim A) by (!claim B)) input_file: crates/syntax/test_data/validation/by-ded-expr-start.ath --- SOURCE_FILE - BY_DED - L_PAREN "(" - BANG_METHOD_CALL_DED + PHRASE_STMT + BY_DED L_PAREN "(" - BANG "!" - IDENT_EXPR - NAME_REF - IDENT "claim" + BANG_METHOD_CALL_DED + L_PAREN "(" + BANG "!" + IDENT_EXPR + NAME_REF + IDENT "claim" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "A" + R_PAREN ")" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "A" - R_PAREN ")" - WHITESPACE " " - BY_KW "by" - WHITESPACE " " - BANG_METHOD_CALL_DED - L_PAREN "(" - BANG "!" - IDENT_EXPR - NAME_REF - IDENT "claim" + BY_KW "by" WHITESPACE " " - IDENT_EXPR - NAME_REF - IDENT "B" + BANG_METHOD_CALL_DED + L_PAREN "(" + BANG "!" + IDENT_EXPR + NAME_REF + IDENT "claim" + WHITESPACE " " + IDENT_EXPR + NAME_REF + IDENT "B" + R_PAREN ")" R_PAREN ")" - R_PAREN ")" error Node(BANG_METHOD_CALL_DED@1..11): By deduction must start with an expression diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs index 2186d16..e190dcd 100644 --- a/crates/test-utils/src/lib.rs +++ b/crates/test-utils/src/lib.rs @@ -6,7 +6,7 @@ mod fixture; use std::collections::BTreeMap; pub use dissimilar::diff as __diff; -pub use rustc_hash::FxHashMap; +pub use rustc_hash::{FxHashMap, FxHashSet}; use text_size::{TextRange, TextSize}; use tracing_subscriber::EnvFilter; diff --git a/crates/util/src/macros.rs b/crates/util/src/macros.rs index 8b73a82..417ada8 100644 --- a/crates/util/src/macros.rs +++ b/crates/util/src/macros.rs @@ -24,29 +24,22 @@ macro_rules! format_to { /// ``` #[macro_export] macro_rules! impl_from { - ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => { + ($($variant:ident$(<$V:ident>)?),* for $enum:ident) => { $( - impl From<$variant> for $enum { - fn from(it: $variant) -> $enum { + impl$(<$V>)? From<$variant$(<$V>)?> for $enum$(<$V>)? { + fn from(it: $variant$(<$V>)?) -> $enum$(<$V>)? { $enum::$variant(it) } } - $($( - impl From<$sub_variant> for $enum { - fn from(it: $sub_variant) -> $enum { - $enum::$variant($variant::$sub_variant(it)) - } - } - )*)? )* }; - ($($variant:ident$(<$V:ident>)?),* for $enum:ident) => { + ($($variant:ident($t:ty)),* for $enum:ident) => { $( - impl$(<$V>)? From<$variant$(<$V>)?> for $enum$(<$V>)? { - fn from(it: $variant$(<$V>)?) -> $enum$(<$V>)? { + impl From<$t> for $enum { + fn from(it: $t) -> $enum { $enum::$variant(it) } } )* - } + }; } diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 46c24b5..7b965e9 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -9,10 +9,10 @@ edition = "2021" fs-err = "2.9.0" itertools.workspace = true pico-args = "0.5.0" -proc-macro2 = "1.0.52" -quote = "1.0.26" +proc-macro2 = "1.0.59" +quote = "1.0.28" ron = "0.8.0" -serde = { version = "1.0.157", features = ["derive"] } +serde = { version = "1.0.163", features = ["derive"] } sourcegen = { path = "../crates/sourcegen" } ungrammar = "1.16.1" xshell = "0.2.3" diff --git a/xtask/src/codegen/ast.rs b/xtask/src/codegen/ast.rs index d093979..d9de368 100644 --- a/xtask/src/codegen/ast.rs +++ b/xtask/src/codegen/ast.rs @@ -128,6 +128,19 @@ impl AstEnumSrc { .collect() } + fn transitive_variants(&self, grammar: &AstSrc) -> Vec<(Ident, Ident)> { + let mut new_variants = Vec::new(); + for variant in self.variants() { + if let Some(enm) = grammar.get_enum_node(&variant.to_string()) { + new_variants.extend( + std::iter::repeat_with(|| variant.clone()).zip(enm.variants().into_iter()), + ); + } + } + + new_variants + } + fn partitioned_variants(&self, grammar: &AstSrc) -> (Vec, Vec) { let mut enums = Vec::new(); let mut non_enums = Vec::new(); @@ -187,9 +200,17 @@ fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> String { } } } else { + let (ret, unwrap) = if field.is_optional() { + (quote!(Option<#ty>), quote!()) + } else { + ( + quote!(#ty), + quote!(.expect("node is required: this indicates a bug in the parser")), + ) + }; quote! { - pub fn #method_name(&self) -> Option<#ty> { - support::child(&self.syntax) + pub fn #method_name(&self) -> #ret { + support::child(&self.syntax) #unwrap } } } @@ -318,6 +339,8 @@ fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> String { } }; + let (transitive_parents, transitive_variants): (Vec<_>, Vec<_>) = en.transitive_variants(grammar).into_iter().unzip(); + ( quote! { @@ -336,6 +359,13 @@ fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> String { } } )* + #( + impl From<#transitive_variants> for #name { + fn from(node: #transitive_variants) -> #name { + #name::#transitive_parents(node.into()) + } + } + )* #ast_node }, ) @@ -616,6 +646,8 @@ fn generate_syntax_kinds(grammar: &KindsSrc) -> String { [lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT }; [ident] => { $crate::SyntaxKind::IDENT }; [shebang] => { $crate::SyntaxKind::SHEBANG }; + [string] => { $crate::SyntaxKind::STRING }; + [char] => { $crate::SyntaxKind::CHAR }; } pub use T; }; @@ -678,7 +710,6 @@ fn generate_lexer(grammar: &AstSrc) -> String { match self { #(Self::#variant_names(..) => #syntax_kind,)* #(Self::#complex_variant_names(..) => #complex_syntax_kind,)* - Self::Error => SyntaxKind::ERROR, } } }; @@ -691,8 +722,6 @@ fn generate_lexer(grammar: &AstSrc) -> String { #[derive(Logos, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum LexerToken { #( #logos_rule )* - #[error] - Error, } impl LexerToken { @@ -702,7 +731,6 @@ fn generate_lexer(grammar: &AstSrc) -> String { match self { #(Self::#variant_names(len) => len,)* #(Self::#complex_variant_names(len) => len,)* - Self::Error => 0, } } } @@ -837,6 +865,15 @@ impl Field { } ) } + fn is_optional(&self) -> bool { + matches!( + self, + Field::Node { + cardinality: Cardinality::Optional, + .. + } + ) + } fn token_kind(&self) -> Option { match self { Field::Token(token) => Some(token_kind_raw(token)), @@ -1015,6 +1052,27 @@ fn print_rule(rule: &Rule, grammar: &Grammar) { } } +struct LabelInfo { + name: String, + is_optional: bool, +} + +fn parse_label(label: impl AsRef) -> LabelInfo { + let label = label.as_ref(); + if label.starts_with("required__") { + let name = label.trim_start_matches("required__").to_string(); + LabelInfo { + name, + is_optional: false, + } + } else { + LabelInfo { + name: label.to_string(), + is_optional: true, + } + } +} + fn lower_rule(acc: &mut Vec, grammar: &Grammar, label: Option<&String>, rule: &Rule) { if lower_comma_list(acc, grammar, label, rule) { return; @@ -1023,30 +1081,40 @@ fn lower_rule(acc: &mut Vec, grammar: &Grammar, label: Option<&String>, r match rule { Rule::Node(node) => { let ty = grammar[*node].name.clone(); - let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty)); + let label_info = label.map(parse_label); + let name = label_info + .as_ref() + .map(|l| l.name.clone()) + .unwrap_or_else(|| to_lower_snake_case(&ty)); + + let is_optional = label_info.map(|l| l.is_optional).unwrap_or(true); let field = Field::Node { name, ty, - cardinality: Cardinality::Optional, + cardinality: if is_optional { + Cardinality::Optional + } else { + Cardinality::One + }, }; acc.push(field); } Rule::Token(token) => { assert!(label.is_none()); let mut name = grammar[*token].name.clone(); - if name != "int_number" && name != "string" && name != "char" { - if "[]{}()".contains(&name) { - name = format!("'{name}'"); - } - let field = Field::Token(name); - acc.push(field); + if "[]{}()".contains(&name) { + name = format!("'{name}'"); } + let field = Field::Token(name); + acc.push(field); } Rule::Rep(inner) => { if let Rule::Node(node) = &**inner { let ty = grammar[*node].name.clone(); - let name = label - .cloned() + let label_info = label.map(parse_label); + let name = label_info + .as_ref() + .map(|l| l.name.clone()) .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty))); let field = Field::Node { name, diff --git a/xtask/src/codegen/ast/ast_src.rs b/xtask/src/codegen/ast/ast_src.rs index 8f0c85f..4245542 100644 --- a/xtask/src/codegen/ast/ast_src.rs +++ b/xtask/src/codegen/ast/ast_src.rs @@ -40,6 +40,7 @@ pub(crate) enum Field { #[derive(Debug, Eq, PartialEq)] pub(crate) enum Cardinality { Optional, + One, Many, }