Experimenting with the LSP

This commit is contained in:
Mia
2026-03-08 14:34:12 +01:00
parent 2aababbbe1
commit 45fd421e19
16 changed files with 1682 additions and 228 deletions
Generated
+713 -9
View File
@@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.102"
@@ -20,12 +29,28 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "borrow-or-share"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c"
[[package]]
name = "boxcar"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36f64beae40a84da1b4b26ff2761a5b895c12adc41dc25aaee1c4f2bbfe97a6e"
[[package]]
name = "bstr"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.20.2"
@@ -38,6 +63,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cc"
version = "1.2.56"
@@ -63,12 +94,51 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crunchy"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "dashmap"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
dependencies = [
"cfg-if",
"crossbeam-utils",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "derive_more"
version = "2.1.1"
@@ -92,6 +162,26 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "either"
version = "1.15.0"
@@ -110,6 +200,93 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "fluent-uri"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc74ac4d8359ae70623506d512209619e5cf8f347124910440dbc221714b328e"
dependencies = [
"borrow-or-share",
"ref-cast",
"serde",
]
[[package]]
name = "futures"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-io"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
name = "futures-macro"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"slab",
]
[[package]]
name = "fxhash"
version = "0.2.1"
@@ -119,6 +296,30 @@ dependencies = [
"byteorder",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "globset"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "half"
version = "2.7.1"
@@ -130,12 +331,46 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "hermit-abi"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "ignore"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
dependencies = [
"crossbeam-deque",
"globset",
"log",
"memchr",
"regex-automata",
"same-file",
"walkdir",
"winapi-util",
]
[[package]]
name = "indexmap"
version = "2.13.0"
@@ -143,7 +378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.16.1",
]
[[package]]
@@ -156,7 +391,7 @@ dependencies = [
"libc",
"llvm-sys",
"once_cell",
"thiserror",
"thiserror 2.0.18",
]
[[package]]
@@ -179,6 +414,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "lazy_static"
version = "1.5.0"
@@ -233,6 +474,22 @@ dependencies = [
"leaf_parser",
]
[[package]]
name = "leaf_lsp"
version = "0.1.0"
dependencies = [
"boxcar",
"leaf_allocators",
"leaf_assembly",
"leaf_compiler",
"leaf_parser",
"rangemap",
"rust_search",
"scc",
"tokio",
"tower-lsp-server",
]
[[package]]
name = "leaf_parser"
version = "0.1.0"
@@ -249,6 +506,15 @@ version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "libredox"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
dependencies = [
"libc",
]
[[package]]
name = "llvm-sys"
version = "211.0.0"
@@ -263,12 +529,69 @@ dependencies = [
"semver",
]
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "ls-types"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b73932659f38b27a0145cbcba778739a7d76162f6534329b3ca8866125620996"
dependencies = [
"bitflags",
"fluent-uri",
"percent-encoding",
"serde",
"serde_json",
]
[[package]]
name = "memchr"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "num_cpus"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "peg"
version = "0.8.5"
@@ -296,6 +619,18 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "132dca9b868d927b35b5dd728167b2dee150eb1ad686008fc71ccb298b776fca"
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "proc-macro2"
version = "1.0.106"
@@ -314,12 +649,100 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rangemap"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
"thiserror 1.0.69",
]
[[package]]
name = "ref-cast"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "regex"
version = "1.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-lite"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30"
[[package]]
name = "regex-syntax"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "rust_search"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d27d7be20245d289c9dde663f06521de08663d73cbaefc45785aa65d02022378"
dependencies = [
"dirs",
"ignore",
"num_cpus",
"regex",
"strsim",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
@@ -336,20 +759,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16c7f49c9d5caa3bf4b3106900484b447b9253fe99670ceb81cb6cb5027855e1"
[[package]]
name = "scc"
version = "3.6.6"
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6012e652611b2fdcb557a7b4be8cee00d8be19397c70011906a68aa4dac2fe37"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scc"
version = "3.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bb5ce9efd4a6e7b0f86c2697fe4c1d78d1f4e6d988c54b752d577cafe22fe8"
dependencies = [
"saa",
"sdd",
]
[[package]]
name = "sdd"
version = "4.6.5"
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4becc2f27bd39aafb78a8a1b4e1d6877ed0a6b5bf096722ed538dc028367a9b5"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sdd"
version = "4.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b21a75f5913ab130e4b369fb8693be25f29b983e2ecad4279df9bfa5dd8aaf3e"
[[package]]
name = "semver"
@@ -357,12 +795,73 @@ version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.117"
@@ -374,13 +873,39 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl",
"thiserror-impl 2.0.18",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
@@ -394,6 +919,117 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio"
version = "1.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
dependencies = [
"pin-project-lite",
"tokio-macros",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-util"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tower"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-lsp-server"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0e711655c89181a6bc6a2cc348131fcd9680085f5b06b6af13427a393a6e72"
dependencies = [
"bytes",
"dashmap",
"futures",
"httparse",
"ls-types",
"memchr",
"serde",
"serde_json",
"tokio",
"tokio-util",
"tower",
"tracing",
]
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
@@ -412,6 +1048,68 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "zerocopy"
version = "0.8.40"
@@ -431,3 +1129,9 @@ dependencies = [
"quote",
"syn",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+1 -1
View File
@@ -1,3 +1,3 @@
[workspace]
resolver = "3"
members = ["allocators", "assembly", "compiler", "parser", "backends/llvm"]
members = ["allocators", "assembly", "compiler", "parser", "backends/llvm", "lsp"]
+6
View File
@@ -57,6 +57,12 @@ pub struct SyncArenaAllocator {
allocations: Vec<AllocationEntry>,
}
impl SyncArenaAllocator {
pub fn reset(&mut self) {
self.bump.lock().unwrap().reset();
}
}
impl Allocator for SyncArenaAllocator {
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
unsafe {
+2 -13
View File
@@ -1,7 +1,7 @@
use crate::{
assembly::Assembly,
types::Type,
values::{AnyConst, AnyValue, Value, ValueFlags},
values::{AnyConst, AnyValue, Value, ValueFlags, default_associated_values},
};
use derive_more::{Debug, Display};
use fxhash::FxBuildHasher;
@@ -51,21 +51,10 @@ impl<'l> Value<'l> for &'l StructT<'l> {
}
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
todo!()
default_associated_values(self, name)
}
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Struct(self)))
}
}
struct DebugFields<'l, 'r>(&'r OnceLock<FieldMap<'l>>);
impl std::fmt::Debug for DebugFields<'_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0.get() {
Some(v) => std::fmt::Debug::fmt(v, f),
None => f.write_str("{}"),
}
}
}
+2 -3
View File
@@ -88,7 +88,6 @@ impl<'l> Value<'l> for Float {
Float::F16(v) => v.ty(),
Float::F32(v) => v.ty(),
Float::F64(v) => v.ty(),
_ => unreachable!(),
}
}
@@ -199,13 +198,13 @@ impl<'l> Value<'l> for AnyConst<'l> {
Self::Str(s) => s.ty(),
Self::Struct(t, _) => Type::Struct(t),
Self::SizeOf(_) => Type::USIZE,
_ => todo!("{self:?}"),
Self::Function(f) => Type::Func(f.ty),
}
}
fn flags(&self) -> super::ValueFlags {
match self {
AnyConst::Function(f) => ValueFlags::Function,
AnyConst::Function(_) => ValueFlags::Function,
AnyConst::Type(_) => ValueFlags::Type,
_ => ValueFlags::Const,
}
@@ -2,10 +2,17 @@ use derive_more::Debug;
use leaf_parser::{LineCol, ParseError};
use std::ops::Range;
use crate::SourceFile;
use crate::{SourceFile, metadata::CodePosition};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Kind {
Info,
Warning,
Error,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Code {
Unknown = 0x0000,
Parsing = 0x0100,
@@ -36,30 +43,40 @@ pub enum Location {
file: SourceFile,
range: Range<usize>,
},
Position {
#[debug("{:?}", file.file)]
file: SourceFile,
position: LineCol,
},
}
#[derive(Debug)]
pub struct CompilationError {
impl Location {
pub fn file(&self) -> Option<&SourceFile> {
match self {
Location::None => None,
Location::Range { file, .. } => Some(file),
}
}
pub fn range(&self) -> Range<usize> {
match self {
Location::None => 0..0,
Location::Range { range, .. } => range.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct Diagnostic {
pub kind: Kind,
pub code: Code,
pub message: String,
pub location: Location,
pub cause: Option<Box<CompilationError>>,
pub position: CodePosition,
pub cause: Option<Box<Diagnostic>>,
}
impl CompilationError {
pub fn parsing(file: SourceFile, err: ParseError<LineCol>) -> Self {
impl Diagnostic {
pub fn parsing_err(file: SourceFile, err: ParseError<LineCol>) -> Self {
Self {
kind: Kind::Parsing,
kind: Kind::Error,
code: Code::Parsing,
message: err.to_string(),
location: Location::Position {
file,
position: err.location,
},
position: CodePosition::new(file, err.location.offset..err.location.offset + 1),
cause: None,
}
}
+15
View File
@@ -0,0 +1,15 @@
use crate::{diagnostics::Diagnostic, metadata::CodePosition};
use leaf_assembly::values::AnyValue;
#[derive(Debug, Clone)]
pub enum Event<'l> {
Symbol {
value: AnyValue<'l>,
position: CodePosition,
},
Definition {
value: AnyValue<'l>,
position: CodePosition,
},
Diagnostic(Diagnostic),
}
+50 -9
View File
@@ -1,4 +1,4 @@
use crate::{error::CompilationError, scope::Scope};
use crate::{diagnostics::Diagnostic, events::Event, metadata::Metadata, scope::Scope};
use arcstr::literal_substr;
use leaf_allocators::SyncAllocator;
use leaf_assembly::{
@@ -8,9 +8,16 @@ use leaf_assembly::{
values::{AnyConst, AnyValue},
};
use leaf_parser::{SourceCode, ast};
use std::{collections::VecDeque, ops::Deref, sync::Arc};
use std::{
any::TypeId,
collections::{HashMap, VecDeque},
ops::Deref,
sync::{Arc, Mutex},
};
mod error;
pub mod diagnostics;
pub mod events;
pub mod metadata;
mod scope;
pub type SourceFile = Arc<SourceCode>;
@@ -19,7 +26,9 @@ type FuncQueue<'l> = VecDeque<(&'l Function<'l>, Arc<ast::Block>, Scope<'l>)>;
pub struct CompilationContext<'l> {
ctx: &'l Context<'l>,
alloc: &'l dyn SyncAllocator,
_alloc: &'l dyn SyncAllocator,
event_callbacks: Vec<Box<dyn Fn(&Event<'_>) + Send + Sync + 'static>>,
metadata: Mutex<HashMap<(AnyValue<'l>, TypeId), Arc<dyn Metadata>>>,
}
impl<'l> Deref for CompilationContext<'l> {
@@ -33,8 +42,20 @@ impl<'l> Deref for CompilationContext<'l> {
impl<'l> CompilationContext<'l> {
pub fn new(alloc: &'l dyn SyncAllocator) -> Self {
Self {
alloc,
_alloc: alloc,
ctx: Context::new(alloc),
metadata: Default::default(),
event_callbacks: vec![],
}
}
pub fn add_event_callback(&mut self, callback: impl Fn(&Event<'_>) + Send + Sync + 'static) {
self.event_callbacks.push(Box::new(callback));
}
fn emit_event(&self, event: Event) {
for callback in &self.event_callbacks {
callback(&event);
}
}
@@ -42,32 +63,52 @@ impl<'l> CompilationContext<'l> {
self.ctx.get_assembly(ident)
}
#[allow(private_bounds)]
pub fn get_metadata<T: Metadata>(&self, v: AnyValue<'l>) -> Option<Arc<T>> {
let arc = {
let metadata = self.metadata.lock().unwrap();
metadata.get(&(v, TypeId::of::<T>()))?.clone()
};
let ptr = Arc::into_raw(arc);
let ptr = ptr as *const T;
unsafe { Some(Arc::from_raw(ptr)) }
}
#[allow(private_bounds)]
pub fn set_metadata<T: Metadata>(&self, v: AnyValue<'l>, meta: T) -> Arc<T> {
let meta = Arc::new(meta);
self.metadata
.lock()
.unwrap()
.insert((v, TypeId::of::<T>()), meta.clone());
meta
}
pub fn extend(
&'l self,
ident: AssemblyIdentifier,
sources: &[Arc<SourceCode>],
) -> Result<(), CompilationError> {
) -> Result<(), Diagnostic> {
let assembly = self.ctx.get_or_create_assembly(ident.clone());
let mut units = Vec::with_capacity(sources.len());
for src in sources {
match leaf_parser::parse(src) {
Ok(unit) => units.push(unit),
Err(err) => return Err(CompilationError::parsing(src.clone(), err)),
Err(err) => return Err(Diagnostic::parsing_err(src.clone(), err)),
}
}
let mut scopes: Vec<_> = sources
.iter()
.map(|src| {
let mut scope = Scope::new(assembly, src.clone());
let mut scope = Scope::new(self, assembly, src.clone());
macro_rules! insert_types {
($($id:literal : $ty:expr,)*) => {
$(
scope.insert(
literal_substr!($id),
AnyValue::Constant(AnyConst::Type($ty.into())),
false,
);
)*
};
+5
View File
@@ -13,9 +13,11 @@ use leaf_parser::SourceCode;
use std::{
path::{Path, PathBuf},
sync::Arc,
time::Instant,
};
fn main() {
let start = Instant::now();
let alloc = SyncArenaAllocator::default();
let context = CompilationContext::new(&alloc);
let ident = AssemblyIdentifier {
@@ -32,6 +34,7 @@ fn main() {
println!("{:#?}", err);
return;
}
let time = start.elapsed();
let assembly = context.get_assembly(&ident).unwrap();
println!("{:#?}\n", assembly);
@@ -60,4 +63,6 @@ fn main() {
target_machine
.write_to_file(&module, FileType::Assembly, Path::new("out.asm"))
.unwrap();
println!("Codegen time: {time:?}");
}
+66
View File
@@ -0,0 +1,66 @@
use leaf_parser::{LineCol, SourceCode};
use std::{
any::Any,
ops::Range,
sync::{Arc, OnceLock},
};
pub trait Metadata: Any + Send + Sync {}
impl<T: Any + Send + Sync> Metadata for T {}
#[derive(Debug, Clone)]
pub struct CodePosition {
pub file: Arc<SourceCode>,
pub range: Range<usize>,
line_col: OnceLock<Range<LineCol>>,
}
impl CodePosition {
pub fn new(file: Arc<SourceCode>, range: Range<usize>) -> Self {
Self {
file,
range,
line_col: OnceLock::new(),
}
}
pub fn line_col(&self) -> &Range<LineCol> {
self.line_col.get_or_init(|| {
let mut line_col_range = LineCol {
line: 0,
column: 0,
offset: self.range.start,
}..LineCol {
line: 0,
column: 0,
offset: self.range.end,
};
let mut line = 0;
let mut col = 0;
for (byte_idx, ch) in self.file.text.char_indices() {
if byte_idx == self.range.start {
line_col_range.start.line = line;
line_col_range.start.column = col;
}
if byte_idx == self.range.end {
line_col_range.end.line = line;
line_col_range.end.column = col;
}
if ch == '\n' {
line += 1;
col = 0;
} else {
col += 1;
}
}
if self.range.end == self.file.text.len() {
line_col_range.end.line = line;
line_col_range.end.column = col;
}
line_col_range
})
}
}
+143 -142
View File
@@ -1,4 +1,4 @@
use crate::{FuncQueue, error::*};
use crate::{CompilationContext, FuncQueue, diagnostics::*, events::Event, metadata::CodePosition};
use arcstr::{Substr, literal_substr};
use leaf_assembly::{
assembly::Assembly,
@@ -46,31 +46,35 @@ impl<'l, 'r, 'a> ExpressionContext<'l, 'r> {
#[derive(Clone)]
struct Variable<'l> {
value: Arc<OnceLock<AnyValue<'l>>>,
mutable: bool,
}
#[derive(Clone)]
pub struct Scope<'l> {
ctx: &'l CompilationContext<'l>,
assembly: &'l Assembly<'l>,
source: Arc<SourceCode>,
values: HashMap<Substr, Variable<'l>>,
}
impl<'l> Scope<'l> {
pub fn new(assembly: &'l Assembly<'l>, source: Arc<SourceCode>) -> Self {
pub fn new(
ctx: &'l CompilationContext<'l>,
assembly: &'l Assembly<'l>,
source: Arc<SourceCode>,
) -> Self {
Self {
ctx,
assembly,
source,
values: HashMap::default(),
}
}
pub fn insert(&mut self, name: Substr, value: AnyValue<'l>, mutable: bool) {
pub fn insert(&mut self, name: Substr, value: AnyValue<'l>) {
self.values.insert(
name,
Variable {
value: Arc::new(OnceLock::from(value)),
mutable,
},
);
}
@@ -82,7 +86,6 @@ impl<'l> Scope<'l> {
name.clone(),
Variable {
value: Arc::default(),
mutable: false,
},
);
}
@@ -93,7 +96,7 @@ impl<'l> Scope<'l> {
&mut self,
decl: &[ConstDecl],
fn_queue: &mut FuncQueue<'l>,
) -> Result<(), CompilationError> {
) -> Result<(), Diagnostic> {
for val in decl {
let expr = self.compile_expression(
&val.value,
@@ -105,13 +108,19 @@ impl<'l> Scope<'l> {
},
)?;
match &val.names {
NamePattern::Single(ident) => self
.values
NamePattern::Single(ident) => {
self.values
.get_mut(&ident.0)
.unwrap()
.value
.set(expr)
.unwrap(),
.unwrap();
self.ctx.emit_event(Event::Definition {
value: expr,
position: CodePosition::new(self.source.clone(), ident.range()),
});
}
NamePattern::Tuple(_) => todo!(),
NamePattern::List(_) => todo!(),
}
@@ -124,7 +133,7 @@ impl<'l> Scope<'l> {
func: &'l Function<'l>,
block: &Arc<ast::Block>,
fn_queue: &mut FuncQueue<'l>,
) -> Result<(), CompilationError> {
) -> Result<(), Diagnostic> {
let mut builder = func.create_body().unwrap();
let mut ret = self.compile_block(
block,
@@ -159,42 +168,42 @@ impl<'l> Scope<'l> {
&mut self,
expr: &Expr,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> {
) -> Result<AnyValue<'l>, Diagnostic> {
match expr {
Expr::Ident(Ident(name)) => match self.values.get(name) {
None => Err(CompilationError {
kind: Kind::SymbolNotFound,
None => Err(Diagnostic {
kind: Kind::Error,
code: Code::SymbolNotFound,
message: format!("Symbol `{name}` does not exist in the current scope."),
location: Location::Range {
file: self.source.clone(),
range: name.range(),
},
position: CodePosition::new(self.source.clone(), name.range()),
cause: None,
}),
Some(Variable { value, .. }) => match value.get() {
None => Err(CompilationError {
kind: Kind::UninitializedSymbol,
None => Err(Diagnostic {
kind: Kind::Error,
code: Code::UninitializedSymbol,
message: format!("Symbol `{name}` is not initialized at this time."),
location: Location::Range {
file: self.source.clone(),
range: name.range(),
},
position: CodePosition::new(self.source.clone(), name.range()),
cause: None,
}),
Some(value) => Ok(*value),
Some(value) => {
self.ctx.emit_event(Event::Symbol {
value: *value,
position: CodePosition::new(self.source.clone(), name.range()),
});
Ok(*value)
}
},
},
Expr::Func(func) => self
.make_function(func, ctx)
.map(|f| AnyValue::Constant(AnyConst::Function(f)))
.map_err(|err| CompilationError {
kind: Kind::FunctionCompilationFailed,
.map_err(|err| Diagnostic {
kind: Kind::Error,
code: Code::FunctionCompilationFailed,
message: "Could not compile function.".to_string(),
location: Location::Range {
file: self.source.clone(),
range: func.text.range(),
},
position: CodePosition::new(self.source.clone(), func.text.range()),
cause: Some(Box::new(err)),
}),
@@ -210,18 +219,16 @@ impl<'l> Scope<'l> {
_ => n.text.parse::<$ty>(),
}
.map(|v| AnyValue::Constant(AnyConst::Int(Int::$id(v))))
.map_err(|_| CompilationError {
kind: Kind::InvalidInteger,
.map_err(|_| Diagnostic {
kind: Kind::Error,
code: Code::InvalidInteger,
message: format!("`{}` is not a valid integer.", n.text),
location: Location::Range {
file: self.source.clone(),
range: n.text.range(),
},
position: CodePosition::new(self.source.clone(), n.text.range()),
cause: None,
})
};
}
match n.r#type.as_ref().map(|v| v.as_str()) {
let value = match n.r#type.as_ref().map(|v| v.as_str()) {
None if ctx.type_hint == Some(Type::I8) => parse_number!(i8, I8),
None if ctx.type_hint == Some(Type::I16) => parse_number!(i16, I16),
None if ctx.type_hint == Some(Type::I32) => parse_number!(i32, I32),
@@ -248,16 +255,19 @@ impl<'l> Scope<'l> {
Some("u64") => parse_number!(u64, U64),
Some("u128") => parse_number!(u128, U128),
Some("usize") => parse_number!(u64, USize),
Some(ty) => Err(CompilationError {
kind: Kind::InvalidIntegerType,
Some(ty) => Err(Diagnostic {
kind: Kind::Error,
code: Code::InvalidIntegerType,
message: format!("`{ty}` is not a valid integer type."),
location: Location::Range {
file: self.source.clone(),
range: n.text.range(),
},
position: CodePosition::new(self.source.clone(), n.text.range()),
cause: None,
}),
}
}?;
self.ctx.emit_event(Event::Symbol {
value: value,
position: CodePosition::new(self.source.clone(), n.text.range()),
});
Ok(value)
}
Expr::Access(expr) => {
@@ -269,17 +279,22 @@ impl<'l> Scope<'l> {
if let Some(value) = value.get_associated_value(&field.0) {
return Ok(value);
}
let value = 'value: {
match value.ty() {
Type::Struct(StructT { fields, .. }) => {
if let Some(fields) = fields.get() {
if let Some(field) = fields.get(field.0.as_str()) {
let builder = ctx.builder.as_mut().unwrap();
return Ok(builder
break 'value Some(
builder
.get_element_value(value, field.name.as_any_value())
.unwrap()
.as_any_value());
.as_any_value(),
);
}
}
None
}
Type::Ptr(PtrT {
base: Type::Struct(StructT { fields, .. }),
@@ -299,19 +314,28 @@ impl<'l> Scope<'l> {
}
}
return Ok(inst);
break 'value Some(inst);
}
}
None
}
_ => None,
}
_ => {}
};
return Err(CompilationError {
kind: Kind::FieldNotFound,
if let Some(value) = value {
self.ctx.emit_event(Event::Symbol {
value: value,
position: CodePosition::new(self.source.clone(), field.range()),
});
return Ok(value);
}
return Err(Diagnostic {
kind: Kind::Error,
code: Code::FieldNotFound,
message: format!("Value does not contain field `{}`.", field.0),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
position: CodePosition::new(self.source.clone(), field.range()),
cause: None,
});
}
@@ -453,28 +477,22 @@ impl<'l> Scope<'l> {
}
(Type::Ptr(PtrT { base, .. }), ty, BinaryOp::Assign(_)) => match *base == ty {
true => Ok(builder.store(lhs, rhs).unwrap()),
false => Err(CompilationError {
kind: Kind::InvalidType,
false => Err(Diagnostic {
kind: Kind::Error,
code: Code::InvalidType,
message: format!(
"Cannot assign a value of type `{ty}` to a value of type `{base}`."
),
location: Location::Range {
file: self.source.clone(),
range: rhs_expr.range(),
},
position: CodePosition::new(self.source.clone(), expr.range()),
cause: None,
}),
},
(src_ty, Type::Type, BinaryOp::Cast(_)) => {
let dst_ty =
self.assert_ty(rhs, rhs_expr)
.map_err(|err| CompilationError {
kind: Kind::InvalidCast,
let dst_ty = self.assert_ty(rhs, rhs_expr).map_err(|err| Diagnostic {
kind: Kind::Error,
code: Code::InvalidCast,
message: "Cannot perform cast.".to_string(),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
position: CodePosition::new(self.source.clone(), expr.range()),
cause: Some(Box::new(err)),
})?;
if src_ty == dst_ty {
@@ -533,13 +551,11 @@ impl<'l> Scope<'l> {
let func = match self.compile_expression(func, ctx)? {
AnyValue::Constant(AnyConst::Function(func)) => func,
_ => {
return Err(CompilationError {
kind: Kind::NotAFunction,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAFunction,
message: "Value is not a function".into(),
location: Location::Range {
file: self.source.clone(),
range: func.range(),
},
position: CodePosition::new(self.source.clone(), func.range()),
cause: None,
});
}
@@ -574,7 +590,7 @@ impl<'l> Scope<'l> {
};
let ctx = self.assembly.ctx();
scope.insert(literal_substr!("Self"), struct_ty.as_any_value(), false);
scope.insert(literal_substr!("Self"), struct_ty.as_any_value());
let mut field_map = FieldMap::default();
for ast::Field {
name,
@@ -612,14 +628,12 @@ impl<'l> Scope<'l> {
unreachable!()
};
if mutable.is_some() && !*is_mut {
return Err(CompilationError {
kind: Kind::NotAFunction,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAFunction,
message: "Cannot obtain a mutable pointer to an immutable value."
.into(),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
position: CodePosition::new(self.source.clone(), expr.range()),
cause: None,
});
}
@@ -677,13 +691,11 @@ impl<'l> Scope<'l> {
match value.is_lvalue() {
false => unsafe {
if !matches!(ty, Type::Ptr(_)) {
return Err(CompilationError {
kind: Kind::CannotDereference,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::CannotDereference,
message: format!("Cannot dereference a value of type `{ty}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
position: CodePosition::new(self.source.clone(), expr.range()),
cause: None,
});
}
@@ -703,13 +715,11 @@ impl<'l> Scope<'l> {
let Type::Ptr(PtrT { base, .. }) = ty else {
unreachable!()
};
return Err(CompilationError {
kind: Kind::CannotDereference,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::CannotDereference,
message: format!("Cannot dereference a value of type `{base}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
position: CodePosition::new(self.source.clone(), expr.range()),
cause: None,
});
}
@@ -735,13 +745,11 @@ impl<'l> Scope<'l> {
// TODO Add support for custom indexing operations
if index.ty() != Type::USIZE {
return Err(CompilationError {
kind: Kind::InvalidType,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::InvalidType,
message: "Value is not of type `usize`".into(),
location: Location::Range {
file: self.source.clone(),
range: expr.index.range(),
},
position: CodePosition::new(self.source.clone(), expr.index.range()),
cause: None,
});
}
@@ -775,13 +783,11 @@ impl<'l> Scope<'l> {
None => match ctx.type_hint {
Some(ty) => AnyValue::Constant(AnyConst::Type(ty)),
None => {
return Err(CompilationError {
kind: Kind::CannotInferType,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::CannotInferType,
message: "Type cannot be inferred.".into(),
location: Location::Range {
file: self.source.clone(),
range: ctor.range(),
},
position: CodePosition::new(self.source.clone(), ctor.range()),
cause: None,
});
}
@@ -791,16 +797,17 @@ impl<'l> Scope<'l> {
struct_ty @ StructT { fields, .. },
))) = ty
else {
return Err(CompilationError {
kind: Kind::NotAStruct,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAStruct,
message: format!("Expected struct type, got value of type `{}`.", ty.ty()),
location: Location::Range {
file: self.source.clone(),
range: match &ctor.r#type {
position: CodePosition::new(
self.source.clone(),
match &ctor.r#type {
None => ctor.range(),
Some(ty) => ty.range(),
},
},
),
cause: None,
});
};
@@ -813,13 +820,11 @@ impl<'l> Scope<'l> {
} in fields.values()
{
let Some(name_value_pair) = ctor.values.get(*fld_name) else {
return Err(CompilationError {
kind: Kind::UninitializedField,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::UninitializedField,
message: format!("Uninitialized field `{fld_name}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
position: CodePosition::new(self.source.clone(), expr.range()),
cause: None,
});
};
@@ -859,7 +864,7 @@ impl<'l> Scope<'l> {
&mut self,
ast: &Arc<ast::Function>,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<&'l Function<'l>, CompilationError> {
) -> Result<&'l Function<'l>, Diagnostic> {
let ret_ty = match ast.ret.as_ref() {
None => AnyValue::Constant(AnyConst::Type(Type::Void)),
Some(ty) => self.compile_expression(ty, ctx)?,
@@ -885,7 +890,7 @@ impl<'l> Scope<'l> {
let mut scope = self.clone();
for (i, arg) in ast.args.iter().enumerate() {
scope.insert(arg.name.0.clone(), AnyValue::Parameter(i, func), false);
scope.insert(arg.name.0.clone(), AnyValue::Parameter(i, func));
}
ctx.fn_queue.push_back((func, block.clone(), scope));
@@ -899,7 +904,7 @@ impl<'l> Scope<'l> {
value: &Expr,
mutable: bool,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> {
) -> Result<AnyValue<'l>, Diagnostic> {
let mut sub_ctx = ExpressionContext {
decl_names: Some(names),
builder: ctx.builder.as_deref_mut(),
@@ -922,9 +927,13 @@ impl<'l> Scope<'l> {
ident.0.clone(),
Variable {
value: Arc::new(OnceLock::from(value)),
mutable,
},
);
self.ctx.emit_event(Event::Definition {
value: value,
position: CodePosition::new(self.source.clone(), ident.range()),
});
}
NamePattern::Tuple(_) => todo!(),
NamePattern::List(_) => todo!(),
@@ -936,7 +945,7 @@ impl<'l> Scope<'l> {
&mut self,
block: &Block,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> {
) -> Result<AnyValue<'l>, Diagnostic> {
let mut scope = self.clone();
let builder = ctx.builder.as_mut().unwrap();
@@ -960,7 +969,7 @@ impl<'l> Scope<'l> {
&mut self,
expr: &If,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> {
) -> Result<AnyValue<'l>, Diagnostic> {
let If { cond, block, else_ } = expr;
let condition = self.compile_expression(cond, ctx)?;
self.assert_ty_eq(&condition, cond, &Type::Bool)?;
@@ -1018,20 +1027,14 @@ impl<'l> Scope<'l> {
.into())
}
fn assert_ty(
&self,
val: AnyValue<'l>,
value_expr: &Expr,
) -> Result<Type<'l>, CompilationError> {
fn assert_ty(&self, val: AnyValue<'l>, value_expr: &Expr) -> Result<Type<'l>, Diagnostic> {
match val {
AnyValue::Constant(AnyConst::Type(ty)) => Ok(ty),
_ => Err(CompilationError {
kind: Kind::NotAType,
_ => Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAType,
message: "Value is not a type.".to_string(),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
position: CodePosition::new(self.source.clone(), value_expr.range()),
cause: None,
}),
}
@@ -1042,18 +1045,16 @@ impl<'l> Scope<'l> {
value: &AnyValue<'l>,
value_expr: &Expr,
expected: &Type<'l>,
) -> Result<Type<'l>, CompilationError> {
) -> Result<Type<'l>, Diagnostic> {
let value_ty = value.ty();
match value_ty == *expected {
true => Ok(value_ty),
false => {
return Err(CompilationError {
kind: Kind::InvalidType,
return Err(Diagnostic {
kind: Kind::Error,
code: Code::InvalidType,
message: format!("Expected value of type `{expected}`, found `{value_ty}`."),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
position: CodePosition::new(self.source.clone(), value_expr.range()),
cause: None,
});
}
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "leaf_lsp"
version = "0.1.0"
edition = "2024"
[dependencies]
leaf_parser = { path = "../parser" }
leaf_compiler = { path = "../compiler" }
leaf_assembly = { path = "../assembly" }
leaf_allocators = { path = "../allocators" }
tower-lsp-server = "0.23.0"
tokio = { version = "1.50.0", features = ["io-std", "macros", "rt-multi-thread", "sync"] }
scc = "3.6.9"
rust_search = "2.1.0"
rangemap = "1.7.1"
boxcar = "0.2.14"
+153
View File
@@ -0,0 +1,153 @@
use crate::utils::UriUtils;
use crate::workspace::{Workspace, start_workspace_thread};
use std::sync::Arc;
use tokio::sync::RwLock;
use tower_lsp_server::jsonrpc::Result;
use tower_lsp_server::ls_types::request::{GotoDeclarationParams, GotoDeclarationResponse};
use tower_lsp_server::{Client, LspService, Server};
use tower_lsp_server::{LanguageServer, ls_types::*};
mod utils;
mod workspace;
struct Backend {
client: Client,
workspaces: RwLock<Vec<Arc<Workspace>>>,
}
impl LanguageServer for Backend {
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
let mut workspaces = self.workspaces.write().await;
for workspace in workspaces.drain(..) {
workspace.close().await;
}
for folder in params.workspace_folders.iter().flatten() {
workspaces
.push(start_workspace_thread(folder.uri.clone(), self.client.clone()).unwrap());
}
Ok(InitializeResult {
capabilities: ServerCapabilities {
hover_provider: Some(HoverProviderCapability::Simple(true)),
definition_provider: Some(OneOf::Left(true)),
declaration_provider: Some(DeclarationCapability::Simple(true)),
text_document_sync: Some(TextDocumentSyncCapability::Options(
TextDocumentSyncOptions {
save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions {
include_text: Some(false),
})),
..Default::default()
},
)),
semantic_tokens_provider: Some(
SemanticTokensServerCapabilities::SemanticTokensOptions(
SemanticTokensOptions {
legend: SemanticTokensLegend {
token_types: vec![
SemanticTokenType::TYPE,
SemanticTokenType::FUNCTION,
SemanticTokenType::NUMBER,
],
token_modifiers: vec![],
},
full: Some(SemanticTokensFullOptions::Bool(true)),
range: None,
..Default::default()
},
),
),
..Default::default()
},
..Default::default()
})
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "server initialized!")
.await;
}
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
if let Some(w) = self
.find_workspace(&params.text_document_position_params.text_document.uri)
.await
{
return Ok(w.hover(params).await);
}
Ok(None)
}
async fn goto_declaration(
&self,
params: GotoDeclarationParams,
) -> Result<Option<GotoDeclarationResponse>> {
if let Some(w) = self
.find_workspace(&params.text_document_position_params.text_document.uri)
.await
{
return Ok(w.go_to_declaration(params).await);
}
Ok(None)
}
async fn goto_definition(
&self,
params: GotoDeclarationParams,
) -> Result<Option<GotoDeclarationResponse>> {
if let Some(w) = self
.find_workspace(&params.text_document_position_params.text_document.uri)
.await
{
return Ok(w.go_to_declaration(params).await);
}
Ok(None)
}
async fn did_save(&self, params: DidSaveTextDocumentParams) {
if let Some(w) = self.find_workspace(&params.text_document.uri).await {
w.reload().await;
}
}
async fn semantic_tokens_full(
&self,
params: SemanticTokensParams,
) -> Result<Option<SemanticTokensResult>> {
if let Some(w) = self.find_workspace(&params.text_document.uri).await {
return Ok(w.semantic_tokens(params).await);
}
Ok(None)
}
async fn shutdown(&self) -> Result<()> {
let mut workspaces = self.workspaces.write().await;
for workspace in workspaces.drain(..) {
workspace.close().await;
}
Ok(())
}
}
impl Backend {
pub async fn find_workspace(&self, file: &Uri) -> Option<Arc<Workspace>> {
let workspaces = self.workspaces.read().await;
let path = file.strip_header();
workspaces
.iter()
.find(|w| path.starts_with(&w.base))
.cloned()
}
}
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(|client| Backend {
client,
workspaces: RwLock::default(),
});
Server::new(stdin, stdout, socket).serve(service).await;
}
+35
View File
@@ -0,0 +1,35 @@
use leaf_compiler::metadata::CodePosition;
use tower_lsp_server::ls_types::{Position, Range, Uri};
pub trait UriUtils {
fn strip_header(&self) -> &str;
}
impl UriUtils for Uri {
fn strip_header(&self) -> &str {
let Some(("", str)) = self.as_str().split_once("file://") else {
unimplemented!()
};
str
}
}
pub trait CodePositionUtils {
fn lsp_range(&self) -> Range;
}
impl CodePositionUtils for CodePosition {
fn lsp_range(&self) -> Range {
let range = self.line_col();
Range {
start: Position {
line: range.start.line as u32,
character: range.start.column as u32,
},
end: Position {
line: range.end.line as u32,
character: range.end.column as u32,
},
}
}
}
+407
View File
@@ -0,0 +1,407 @@
use leaf_allocators::SyncArenaAllocator;
use leaf_assembly::{
assembly::{AssemblyIdentifier, Version},
types::{Type, derivations::PtrT},
values::{AnyConst, AnyValue, Value},
};
use leaf_compiler::{CompilationContext, events::Event, metadata::CodePosition};
use leaf_parser::{ArcStr, SourceCode};
use rangemap::RangeMap;
use rust_search::SearchBuilder;
use std::{
borrow::Cow,
collections::HashMap,
fmt::Write,
ops::Range,
path::PathBuf,
sync::{Arc, OnceLock},
};
use tokio::sync::{
Mutex, Notify, RwLock,
mpsc::{Sender, channel},
};
use tower_lsp_server::{
Client,
ls_types::{
Diagnostic, DiagnosticSeverity, Hover, HoverContents, HoverParams, Location, MarkedString,
NumberOrString, Position, Range as LspRange, SemanticToken, SemanticTokenType,
SemanticTokens, SemanticTokensParams, SemanticTokensResult, TextDocumentPositionParams,
Uri,
request::{GotoDeclarationParams, GotoDeclarationResponse},
},
};
use crate::utils::{CodePositionUtils, UriUtils};
pub struct Workspace {
pub base: String,
sender: Sender<Request>,
}
impl Workspace {
pub async fn close(&self) -> bool {
let notify = Arc::new(Notify::new());
self.sender
.send(Request::Close(notify.clone()))
.await
.unwrap();
notify.notified().await;
true
}
pub async fn hover(&self, params: HoverParams) -> Option<Hover> {
let result = Arc::<(OnceLock<Hover>, Notify)>::default();
self.sender
.send(Request::Hover(params, result.clone()))
.await
.unwrap();
result.1.notified().await;
result.0.get().cloned()
}
pub async fn go_to_declaration(
&self,
params: GotoDeclarationParams,
) -> Option<GotoDeclarationResponse> {
let result = Arc::<(OnceLock<GotoDeclarationResponse>, Notify)>::default();
self.sender
.send(Request::GoToDeclaration(params, result.clone()))
.await
.unwrap();
result.1.notified().await;
result.0.get().cloned()
}
pub async fn semantic_tokens(
&self,
params: SemanticTokensParams,
) -> Option<SemanticTokensResult> {
let result = Arc::<(OnceLock<SemanticTokensResult>, Notify)>::default();
self.sender
.send(Request::SemanticTokens(params, result.clone()))
.await
.unwrap();
result.1.notified().await;
result.0.get().cloned()
}
pub async fn reload(&self) {
self.sender.send(Request::Reload).await.unwrap();
}
}
enum Request {
Reload,
Close(Arc<Notify>),
Hover(HoverParams, Arc<(OnceLock<Hover>, Notify)>),
GoToDeclaration(
GotoDeclarationParams,
Arc<(OnceLock<GotoDeclarationResponse>, Notify)>,
),
SemanticTokens(
SemanticTokensParams,
Arc<(OnceLock<SemanticTokensResult>, Notify)>,
),
}
struct State<'l> {
context: CompilationContext<'l>,
files: Arc<RwLock<HashMap<String, FileInfo>>>,
}
#[derive(Default)]
struct FileInfo {
line_ranges: HashMap<u32, Range<usize>>,
symbol_ranges: RangeMap<usize, [u8; size_of::<AnyValue<'_>>()]>,
symbol_positions: HashMap<[u8; size_of::<AnyValue<'_>>()], CodePosition>,
symbol_definitions: HashMap<[u8; size_of::<AnyValue<'_>>()], CodePosition>,
}
impl<'l> State<'l> {
pub fn new(alloc: &'l SyncArenaAllocator) -> Self {
State {
context: CompilationContext::new(alloc),
files: Default::default(),
}
}
}
pub fn start_workspace_thread(url: Uri, client: Client) -> Result<Arc<Workspace>, String> {
let base = url.strip_header().to_string();
let path = base.clone();
let (sender, mut receiver) = channel(1);
let _handle = tokio::task::spawn(async move {
let mut alloc = SyncArenaAllocator::default();
'global: loop {
alloc.reset();
let mut state = State::new(&alloc);
let mut diagnostics = HashMap::<PathBuf, Vec<Diagnostic>>::new();
let files: Vec<_> = tokio::task::block_in_place(|| {
SearchBuilder::default()
.location(&path)
.ext("leaf")
.build()
.map(|f| {
let mut info = state.files.blocking_write();
let info = info.entry(f.clone()).or_default();
let text: ArcStr = std::fs::read_to_string(&f).unwrap().into();
info.line_ranges = calc_line_ranges(text.as_str());
diagnostics.entry(PathBuf::from(&f)).or_default();
Arc::new(SourceCode {
text,
file: f.into(),
})
})
.collect()
});
let diagnostics = Arc::new(Mutex::new(diagnostics));
{
let info = state.files.clone();
let diagnostics = diagnostics.clone();
state.context.add_event_callback(move |e| unsafe {
tokio::task::block_in_place(|| match e {
Event::Symbol { value, position } => {
let mut info = info.blocking_write();
let info = info
.entry(position.file.file.to_string_lossy().to_string())
.or_default();
info.symbol_ranges
.insert(position.range.clone(), std::mem::transmute(*value));
info.symbol_positions
.insert(std::mem::transmute(*value), position.clone());
}
Event::Definition { value, position } => {
let mut info = info.blocking_write();
let info = info
.entry(position.file.file.to_string_lossy().to_string())
.or_default();
info.symbol_definitions
.insert(std::mem::transmute(*value), position.clone());
info.symbol_ranges
.insert(position.range.clone(), std::mem::transmute(*value));
info.symbol_positions
.insert(std::mem::transmute(*value), position.clone());
}
Event::Diagnostic(diagnostic) => {
let mut diagnostics = diagnostics.blocking_lock();
diagnostics
.entry(diagnostic.position.file.file.clone())
.or_default()
.extend(make_diagnostics(diagnostic));
}
});
});
}
if let Err(err) = state.context.extend(
AssemblyIdentifier {
version: Version::default(),
name: Cow::Borrowed("Leaf lsp tmp"),
},
&files,
) {
let mut diagnostics = diagnostics.lock().await;
diagnostics
.entry(err.position.file.file.clone())
.or_default()
.extend(make_diagnostics(&err));
}
{
let mut diagnostics = diagnostics.lock().await;
for (file, diagnostics) in diagnostics.drain() {
client
.publish_diagnostics(Uri::from_file_path(file).unwrap(), diagnostics, None)
.await;
}
}
while let Some(event) = receiver.recv().await {
match event {
Request::Reload => {
alloc = SyncArenaAllocator::default();
continue 'global;
}
Request::Hover(params, result) => {
let value = state
.with_file_and_range(
&params.text_document_position_params,
|info, range| unsafe {
let Some(symbol) = info.symbol_ranges.get(
&(range.start
+ params
.text_document_position_params
.position
.character as usize),
) else {
return None;
};
// This is blasphemy but what can I do? :3
Some(std::mem::transmute::<_, AnyValue>(*symbol))
},
)
.await;
if let Some(Some(value)) = value {
let mut message = String::new();
let _ = writeln!(
message,
"Type: {}",
match value.is_lvalue() {
false => value.ty(),
true => match value.ty() {
Type::Ptr(PtrT { base, .. }) => *base,
_ => unreachable!(),
},
}
);
result
.0
.set(Hover {
contents: HoverContents::Scalar(MarkedString::String(message)),
range: None,
})
.unwrap();
}
result.1.notify_one();
}
Request::GoToDeclaration(params, result) => {
let declaration = state
.with_file_and_range(
&params.text_document_position_params,
|info, range| {
let Some(symbol) = info.symbol_ranges.get(
&(range.start
+ params
.text_document_position_params
.position
.character as usize),
) else {
return None;
};
let Some(position) = info.symbol_definitions.get(symbol) else {
return None;
};
Some(position.clone())
},
)
.await;
if let Some(Some(decl)) = declaration {
result
.0
.set(GotoDeclarationResponse::Scalar(Location {
uri: Uri::from_file_path(&decl.file.file).unwrap(),
range: decl.lsp_range(),
}))
.unwrap();
}
result.1.notify_one();
}
Request::SemanticTokens(params, result) => {
let info = state.files.read().await;
let Some(file) = info.get(params.text_document.uri.strip_header()) else {
result.1.notify_one();
continue;
};
let mut tokens = SemanticTokens::default();
for (symbol, position) in file.symbol_positions.iter() {
let symbol: AnyValue = unsafe { std::mem::transmute(*symbol) };
let line_col = position.line_col();
tokens.data.push(SemanticToken {
delta_line: line_col.start.line as u32,
delta_start: line_col.start.column as u32,
length: position.range.len() as u32,
token_type: match symbol {
AnyValue::Constant(AnyConst::Type(_)) => 0,
AnyValue::Constant(AnyConst::Function(_)) => 1,
AnyValue::Constant(AnyConst::Int(_) | AnyConst::Float(_)) => 2,
_ => continue,
},
token_modifiers_bitset: 0,
});
}
let mut previous_line = 0;
let mut previous_start = 0;
tokens.data.sort_by_key(|v| (v.delta_line, v.delta_start));
for SemanticToken {
delta_line,
delta_start,
..
} in tokens.data.iter_mut()
{
let line = *delta_line;
let start = *delta_start;
*delta_start = match line == previous_line {
false => start,
true => start - previous_start,
};
*delta_line = line - previous_line;
previous_line = line;
previous_start = start;
}
result.0.set(SemanticTokensResult::Tokens(tokens)).unwrap();
result.1.notify_one();
}
Request::Close(notify) => {
notify.notify_waiters();
break 'global;
}
}
}
}
});
Ok(Arc::new(Workspace { base, sender }))
}
fn calc_line_ranges(text: &str) -> HashMap<u32, Range<usize>> {
let mut map = HashMap::new();
for line in text.split('\n') {
let start = line.as_ptr() as usize - text.as_ptr() as usize;
map.insert(map.len() as u32, start..start + line.len());
}
map
}
impl State<'_> {
async fn with_file_and_range<T>(
&self,
params: &TextDocumentPositionParams,
action: impl FnOnce(&FileInfo, Range<usize>) -> T,
) -> Option<T> {
let info = self.files.read().await;
let Some(info) = info.get(params.text_document.uri.strip_header()) else {
return None;
};
let Some(range) = info.line_ranges.get(&params.position.line) else {
return None;
};
Some(action(info, range.clone()))
}
}
fn make_diagnostics(diag: &leaf_compiler::diagnostics::Diagnostic) -> Vec<Diagnostic> {
vec![Diagnostic {
range: diag.position.lsp_range(),
severity: Some(match diag.kind {
leaf_compiler::diagnostics::Kind::Info => DiagnosticSeverity::INFORMATION,
leaf_compiler::diagnostics::Kind::Warning => DiagnosticSeverity::WARNING,
leaf_compiler::diagnostics::Kind::Error => DiagnosticSeverity::ERROR,
}),
code: Some(NumberOrString::Number(diag.code as i32)),
code_description: None,
source: Some("Leaf compiler".into()),
message: diag.message.clone(),
related_information: None,
tags: None,
data: None,
}]
}
+1 -1
View File
@@ -1,4 +1,4 @@
use arcstr::ArcStr;
pub use arcstr::ArcStr;
pub use parser::{compilation_unit as parse, *};
use std::{fmt::Debug, path::PathBuf};