something idk
This commit is contained in:
parent
f1ea01ef0c
commit
4c15f61cb7
680
Cargo.lock
generated
680
Cargo.lock
generated
|
@ -3,12 +3,30 @@
|
|||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -18,54 +36,92 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
name = "async-trait"
|
||||
version = "0.1.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
name = "axum"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.1"
|
||||
name = "axum-core"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.4"
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
|
@ -76,39 +132,99 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.2"
|
||||
name = "bytes"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.2"
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "depell"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
"axum",
|
||||
"rusqlite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.5"
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
|
@ -116,6 +232,15 @@ version = "0.15.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hbbytecode"
|
||||
version = "0.1.0"
|
||||
|
@ -128,7 +253,6 @@ version = "0.1.0"
|
|||
name = "hblang"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"hashbrown 0.15.0",
|
||||
"hbbytecode",
|
||||
"hbvm",
|
||||
|
@ -152,16 +276,101 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
name = "html-macro"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
|
@ -169,12 +378,28 @@ version = "0.2.158"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
|
@ -190,6 +415,99 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.10.2"
|
||||
|
@ -204,33 +522,24 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
name = "rusqlite"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
@ -238,6 +547,72 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
|
@ -245,10 +620,135 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
name = "socket2"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||
|
||||
[[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.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
@ -326,3 +826,23 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit"]
|
||||
members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit", "depell", "depell/html-macro"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
8
depell/Cargo.toml
Normal file
8
depell/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "depell"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.7.7"
|
||||
rusqlite = "0.32.1"
|
7
depell/html-macro/Cargo.toml
Normal file
7
depell/html-macro/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "html-macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
530
depell/html-macro/src/lib.rs
Normal file
530
depell/html-macro/src/lib.rs
Normal file
|
@ -0,0 +1,530 @@
|
|||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_def_site)]
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
macro_rules! diag {
|
||||
($level:ident: $($tt:tt)*) => {diag!($level(proc_macro::Span::call_site()): $($tt)*)};
|
||||
($level:ident[$span:expr]: $($tt:tt)*) => {diag!($level($span.span()): $($tt)*)};
|
||||
($level:ident($span:expr): $($tt:tt)*) => {{
|
||||
proc_macro::Diagnostic::spanned($span, proc_macro::Level::$level, format!($($tt)*)).emit();
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! fatal_diag {
|
||||
($($tt:tt)*) => {{
|
||||
diag!($($tt)*);
|
||||
return None;
|
||||
}};
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn html(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut trees = input.into_iter().peekable();
|
||||
let mut st = State {
|
||||
final_code: "Html({ let mut ___out = String::new(); ".to_string(),
|
||||
write_target: "___out".to_string(),
|
||||
error_handler: ".unwrap()",
|
||||
..State::default()
|
||||
};
|
||||
|
||||
if st.output_fmt(&mut trees).is_none() {
|
||||
return proc_macro::TokenStream::default();
|
||||
};
|
||||
|
||||
st.final_code.push_str("___out })");
|
||||
|
||||
if !st.tag_stack.is_empty() {
|
||||
diag!(Error(proc_macro::Span::def_site()): "unclosed tags: {}", st.tag_stack);
|
||||
}
|
||||
|
||||
proc_macro::TokenStream::from_str(&st.final_code).unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn write_html(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut trees = input.into_iter().peekable();
|
||||
let mut st = State {
|
||||
write_target: trees.next().expect("expected first token").to_string(),
|
||||
error_handler: ".unwrap()",
|
||||
..State::default()
|
||||
};
|
||||
|
||||
if st.output_fmt(&mut trees).is_none() {
|
||||
return proc_macro::TokenStream::default();
|
||||
};
|
||||
|
||||
if !st.tag_stack.is_empty() {
|
||||
diag!(Error(proc_macro::Span::def_site()): "unclosed tags: {}", st.tag_stack);
|
||||
}
|
||||
|
||||
proc_macro::TokenStream::from_str(&st.final_code).unwrap()
|
||||
}
|
||||
|
||||
type Trees = std::iter::Peekable<proc_macro::token_stream::IntoIter>;
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
final_code: String,
|
||||
template: String,
|
||||
tstr: String,
|
||||
tag_stack: String,
|
||||
write_target: String,
|
||||
no_escaping: bool,
|
||||
error_handler: &'static str,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn flush_template(&mut self) {
|
||||
if self.template.is_empty() {
|
||||
return;
|
||||
}
|
||||
write!(
|
||||
self.final_code,
|
||||
"write!({}, {:?}){};",
|
||||
self.write_target, self.template, self.error_handler
|
||||
)
|
||||
.unwrap();
|
||||
self.template.clear();
|
||||
}
|
||||
|
||||
fn display_expr(&mut self, expr: impl std::fmt::Display) {
|
||||
self.flush_template();
|
||||
if std::mem::take(&mut self.no_escaping) {
|
||||
write!(
|
||||
self.final_code,
|
||||
"write!({}, \"{{}}\", {expr}){};",
|
||||
self.write_target, self.error_handler
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
write!(
|
||||
self.final_code,
|
||||
"write!({}, \"{{}}\", &HtmlEscaped(&{expr})){};",
|
||||
self.write_target, self.error_handler,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_group(
|
||||
&mut self,
|
||||
trees: &mut Trees,
|
||||
delim: proc_macro::Delimiter,
|
||||
) -> Option<proc_macro::TokenStream> {
|
||||
match trees.next() {
|
||||
Some(proc_macro::TokenTree::Group(g)) if g.delimiter() == delim => Some(g.stream()),
|
||||
Some(c) => fatal_diag!(Error[c]: "expected {delim:?} group"),
|
||||
None => fatal_diag!(Error: "expected {delim:?} group, got eof"),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_punct(&mut self, trees: &mut Trees, c: char) -> Option<()> {
|
||||
match trees.next() {
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == c => Some(()),
|
||||
Some(c) => fatal_diag!(Error[c]: "expected {c}"),
|
||||
None => fatal_diag!(Error: "expected {c}, got eof"),
|
||||
}
|
||||
}
|
||||
|
||||
fn tag(&mut self, p: proc_macro::Punct, trees: &mut Trees) -> Option<()> {
|
||||
let temp = match trees.next() {
|
||||
Some(proc_macro::TokenTree::Ident(id)) => {
|
||||
let temp = temp_str(&id, &mut self.tstr);
|
||||
if !is_html_tag(temp) {
|
||||
diag!(Error[p]: "expected html5 tag name");
|
||||
}
|
||||
temp
|
||||
}
|
||||
Some(proc_macro::TokenTree::Literal(lit)) => {
|
||||
let temp = temp_str(&lit, &mut self.tstr).trim_matches('"');
|
||||
if is_html_tag(temp) {
|
||||
if !temp.contains('!') {
|
||||
diag!(Warning[p]: "unnescessary string escaping");
|
||||
}
|
||||
} else if !is_valid_webcomponent(temp) {
|
||||
diag!(Error[p]: "invalid web component identifier");
|
||||
}
|
||||
temp
|
||||
}
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '/' => {
|
||||
let Some((_, top)) = self.tag_stack.rsplit_once(',') else {
|
||||
fatal_diag!(Error[p]: "no tag to close");
|
||||
};
|
||||
|
||||
let new_tag_stack_len = self.tag_stack.len() - top.len() - 1;
|
||||
|
||||
let (temp, span) = match trees.next() {
|
||||
Some(proc_macro::TokenTree::Ident(id)) => {
|
||||
(temp_str(&id, &mut self.tstr), id.span())
|
||||
}
|
||||
Some(proc_macro::TokenTree::Literal(lit)) => {
|
||||
(temp_str(&lit, &mut self.tstr).trim_matches('"'), lit.span())
|
||||
}
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '>' => {
|
||||
// easter egg
|
||||
write!(&mut self.template, "</{top}>").unwrap();
|
||||
self.tag_stack.truncate(new_tag_stack_len);
|
||||
return Some(());
|
||||
}
|
||||
Some(c) => fatal_diag!(Error[c]: "unexpected token in closing tag"),
|
||||
None => {
|
||||
fatal_diag!(Error[p]: "expected tag ident or string or '>'")
|
||||
}
|
||||
};
|
||||
|
||||
if temp != top {
|
||||
diag!(Error(span): "expected closing '{top}' tag");
|
||||
}
|
||||
|
||||
write!(&mut self.template, "</{top}>").unwrap();
|
||||
self.expect_punct(trees, '>')?;
|
||||
self.tag_stack.truncate(new_tag_stack_len);
|
||||
return Some(());
|
||||
}
|
||||
_ => fatal_diag!(Error[p]: "expected tag ident or string literal"),
|
||||
};
|
||||
|
||||
write!(&mut self.template, "<{temp}").unwrap();
|
||||
if !is_self_closing(temp) {
|
||||
write!(self.tag_stack, ",{temp}").unwrap();
|
||||
}
|
||||
|
||||
let mut has_attr = false;
|
||||
while let Some(c) = trees.next() {
|
||||
let mut has_attr_tmp = false;
|
||||
match c {
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '=' && has_attr => loop {
|
||||
match trees.next() {
|
||||
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '!' => {
|
||||
self.no_escaping = true;
|
||||
continue;
|
||||
}
|
||||
Some(proc_macro::TokenTree::Literal(lit)) => {
|
||||
write!(&mut self.template, "={lit}").unwrap();
|
||||
}
|
||||
Some(proc_macro::TokenTree::Ident(id)) => {
|
||||
write!(&mut self.template, "=\"").unwrap();
|
||||
self.display_expr(id);
|
||||
write!(&mut self.template, "\"").unwrap();
|
||||
}
|
||||
Some(proc_macro::TokenTree::Group(g))
|
||||
if g.delimiter() == proc_macro::Delimiter::Brace =>
|
||||
{
|
||||
write!(&mut self.template, "=\"").unwrap();
|
||||
self.display_expr(g.stream());
|
||||
write!(&mut self.template, "\"").unwrap();
|
||||
}
|
||||
Some(c) => {
|
||||
diag!(Error[c]: "unexpected token in attr value")
|
||||
}
|
||||
None => diag!(Error[p]: "expected attribute value"),
|
||||
}
|
||||
break;
|
||||
},
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '>' => {
|
||||
write!(&mut self.template, ">").unwrap();
|
||||
break;
|
||||
}
|
||||
proc_macro::TokenTree::Ident(id) => {
|
||||
write!(&mut self.template, " {id}").unwrap();
|
||||
has_attr_tmp = true;
|
||||
}
|
||||
proc_macro::TokenTree::Literal(lit) => {
|
||||
let temp = temp_str(&lit, &mut self.tstr).trim_matches('"');
|
||||
if !is_valid_html_attt_name(temp) {
|
||||
diag!(Error[p]: "invalid attribute name");
|
||||
}
|
||||
write!(&mut self.template, " {temp}").unwrap();
|
||||
has_attr_tmp = true;
|
||||
}
|
||||
c => diag!(Error[c]: "unexpected token in attribute list"),
|
||||
}
|
||||
has_attr = has_attr_tmp;
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn matches_char(t: &proc_macro::TokenTree, ch: char, spacing: proc_macro::Spacing) -> bool {
|
||||
matches!(t, proc_macro::TokenTree::Punct(p) if p.as_char() == ch && p.spacing() == spacing)
|
||||
}
|
||||
|
||||
fn match_expr(&mut self, trees: &mut Trees) -> Option<()> {
|
||||
let expr = self.expect_group(trees, proc_macro::Delimiter::Parenthesis)?;
|
||||
let mut body = self
|
||||
.expect_group(trees, proc_macro::Delimiter::Brace)?
|
||||
.into_iter()
|
||||
.peekable();
|
||||
self.flush_template();
|
||||
|
||||
write!(&mut self.final_code, "match {expr} {{").unwrap();
|
||||
|
||||
loop {
|
||||
let mut pattern = proc_macro::TokenStream::new();
|
||||
let mut looped = false;
|
||||
|
||||
while let Some(c) = body.next() {
|
||||
if !Self::matches_char(&c, '=', proc_macro::Spacing::Joint) {
|
||||
pattern.extend([c]);
|
||||
looped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
let nc = body.next().expect("haaaaa");
|
||||
if Self::matches_char(&nc, '>', proc_macro::Spacing::Alone) {
|
||||
break;
|
||||
}
|
||||
pattern.extend([c, nc]);
|
||||
looped = true;
|
||||
}
|
||||
|
||||
if !looped {
|
||||
break;
|
||||
}
|
||||
|
||||
let body = self.expect_group(&mut body, proc_macro::Delimiter::Brace)?;
|
||||
|
||||
write!(&mut self.final_code, "{pattern} => {{").unwrap();
|
||||
self.output_fmt(&mut body.into_iter().peekable())?;
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
}
|
||||
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn for_expr(&mut self, trees: &mut Trees) -> Option<()> {
|
||||
let mut ink = proc_macro::Span::call_site();
|
||||
let loop_var = trees
|
||||
.by_ref()
|
||||
.take_while(|t| {
|
||||
ink = t.span();
|
||||
!matches!(t, proc_macro::TokenTree::Ident(id) if temp_str(id, &mut self.tstr) == "in")
|
||||
})
|
||||
.collect::<proc_macro::TokenStream>();
|
||||
|
||||
let iter = self.expect_group(trees, proc_macro::Delimiter::Parenthesis)?;
|
||||
let body = self.expect_group(trees, proc_macro::Delimiter::Brace)?;
|
||||
let else_body = match trees.peek() {
|
||||
Some(proc_macro::TokenTree::Ident(id)) if temp_str(id, &mut self.tstr) == "else" => {
|
||||
trees.next();
|
||||
self.expect_group(trees, proc_macro::Delimiter::Brace)?
|
||||
}
|
||||
_ => proc_macro::TokenStream::new(),
|
||||
};
|
||||
|
||||
self.tstr.clear();
|
||||
|
||||
self.flush_template();
|
||||
|
||||
if else_body.is_empty() {
|
||||
write!(&mut self.final_code, "for {loop_var} in {iter} {{").unwrap();
|
||||
} else {
|
||||
write!(
|
||||
&mut self.final_code,
|
||||
"let mut looped = false;\
|
||||
for {loop_var} in {iter} {{\
|
||||
looped = true;"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
self.output_fmt(&mut body.into_iter().peekable())?;
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
if !else_body.is_empty() {
|
||||
write!(&mut self.final_code, "if !looped {{").unwrap();
|
||||
self.output_fmt(&mut else_body.into_iter().peekable())?;
|
||||
write!(&mut self.final_code, "}}").unwrap();
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn output_fmt(&mut self, trees: &mut Trees) -> Option<()> {
|
||||
while let Some(c) = trees.next() {
|
||||
match c {
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '!' => self.no_escaping = true,
|
||||
proc_macro::TokenTree::Punct(p) if p.as_char() == '<' => self.tag(p, trees)?,
|
||||
proc_macro::TokenTree::Literal(lit) => self
|
||||
.template
|
||||
.push_str(temp_str(&lit, &mut self.tstr).trim_matches('"')),
|
||||
proc_macro::TokenTree::Ident(id) => match temp_str(&id, &mut self.tstr) {
|
||||
"match" => self.match_expr(trees)?,
|
||||
"for" => self.for_expr(trees)?,
|
||||
_ => self.display_expr(id),
|
||||
},
|
||||
proc_macro::TokenTree::Group(g)
|
||||
if g.delimiter() == proc_macro::Delimiter::Brace =>
|
||||
{
|
||||
self.display_expr(g.stream());
|
||||
}
|
||||
c => fatal_diag!(Error[c]: "unexpected token"),
|
||||
}
|
||||
}
|
||||
self.flush_template();
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
fn temp_str(i: impl std::fmt::Display, buf: &mut String) -> &str {
|
||||
buf.clear();
|
||||
write!(buf, "{i}").unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
fn is_valid_html_attt_name(tag: &str) -> bool {
|
||||
tag.bytes()
|
||||
.all(|c| matches!(c, b'a'..=b'z' | b'_' | b'-' | b'A'..=b'Z' | 128..=u8::MAX))
|
||||
}
|
||||
|
||||
fn is_valid_webcomponent(tag: &str) -> bool {
|
||||
let mut seen_dash = false;
|
||||
tag.bytes()
|
||||
.inspect(|c| seen_dash |= *c == b'-')
|
||||
.all(|c| matches!(c, b'a'..=b'z' | b'_' | b'-' | b'.' | 128..=u8::MAX))
|
||||
&& seen_dash
|
||||
}
|
||||
|
||||
fn is_html_tag(tag: &str) -> bool {
|
||||
matches!(
|
||||
tag,
|
||||
"!DOCTYPE"
|
||||
| "a"
|
||||
| "abbr"
|
||||
| "acronym"
|
||||
| "address"
|
||||
| "area"
|
||||
| "article"
|
||||
| "aside"
|
||||
| "audio"
|
||||
| "b"
|
||||
| "base"
|
||||
| "basefont"
|
||||
| "bdi"
|
||||
| "bdo"
|
||||
| "big"
|
||||
| "blockquote"
|
||||
| "body"
|
||||
| "br"
|
||||
| "button"
|
||||
| "canvas"
|
||||
| "caption"
|
||||
| "center"
|
||||
| "cite"
|
||||
| "code"
|
||||
| "col"
|
||||
| "colgroup"
|
||||
| "data"
|
||||
| "datalist"
|
||||
| "dd"
|
||||
| "del"
|
||||
| "details"
|
||||
| "dfn"
|
||||
| "dialog"
|
||||
| "div"
|
||||
| "dl"
|
||||
| "dt"
|
||||
| "em"
|
||||
| "embed"
|
||||
| "fieldset"
|
||||
| "figcaption"
|
||||
| "figure"
|
||||
| "footer"
|
||||
| "form"
|
||||
| "h1"
|
||||
| "h2"
|
||||
| "h3"
|
||||
| "h4"
|
||||
| "h5"
|
||||
| "h6"
|
||||
| "head"
|
||||
| "header"
|
||||
| "hr"
|
||||
| "html"
|
||||
| "i"
|
||||
| "iframe"
|
||||
| "img"
|
||||
| "input"
|
||||
| "ins"
|
||||
| "kbd"
|
||||
| "label"
|
||||
| "legend"
|
||||
| "li"
|
||||
| "link"
|
||||
| "main"
|
||||
| "map"
|
||||
| "mark"
|
||||
| "meta"
|
||||
| "meter"
|
||||
| "nav"
|
||||
| "noscript"
|
||||
| "object"
|
||||
| "ol"
|
||||
| "optgroup"
|
||||
| "option"
|
||||
| "output"
|
||||
| "p"
|
||||
| "param"
|
||||
| "picture"
|
||||
| "pre"
|
||||
| "progress"
|
||||
| "q"
|
||||
| "rp"
|
||||
| "rt"
|
||||
| "ruby"
|
||||
| "s"
|
||||
| "samp"
|
||||
| "script"
|
||||
| "section"
|
||||
| "select"
|
||||
| "small"
|
||||
| "source"
|
||||
| "span"
|
||||
| "strong"
|
||||
| "style"
|
||||
| "sub"
|
||||
| "summary"
|
||||
| "sup"
|
||||
| "svg"
|
||||
| "table"
|
||||
| "tbody"
|
||||
| "td"
|
||||
| "template"
|
||||
| "textarea"
|
||||
| "tfoot"
|
||||
| "th"
|
||||
| "thead"
|
||||
| "time"
|
||||
| "title"
|
||||
| "tr"
|
||||
| "track"
|
||||
| "u"
|
||||
| "ul"
|
||||
| "var"
|
||||
| "video"
|
||||
| "wbr"
|
||||
)
|
||||
}
|
||||
|
||||
fn is_self_closing(tag: &str) -> bool {
|
||||
matches!(
|
||||
tag,
|
||||
"!DOCTYPE"
|
||||
| "area"
|
||||
| "base"
|
||||
| "br"
|
||||
| "col"
|
||||
| "embed"
|
||||
| "hr"
|
||||
| "img"
|
||||
| "input"
|
||||
| "link"
|
||||
| "meta"
|
||||
| "param"
|
||||
| "source"
|
||||
| "track"
|
||||
| "wbr"
|
||||
)
|
||||
}
|
3
depell/src/main.rs
Normal file
3
depell/src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
sb0[]-[]:
|
||||
0: iCall { func: 1 }:[Def: v3i fixed(p1i)]
|
||||
1: iCInt { value: 0 }:[Def: v6i reg]
|
||||
2: iCInt { value: 30 }:[Def: v5i reg]
|
||||
3: iCInt { value: 100 }:[Def: v4i reg]
|
||||
4: iLoop:[]
|
||||
eb0[VReg(vreg = 6, class = Int), VReg(vreg = 6, class = Int), VReg(vreg = 6, class = Int)]-[Block(1)]:
|
||||
sb1[VReg(vreg = 18, class = Int), VReg(vreg = 8, class = Int), VReg(vreg = 15, class = Int)]-[Block(0), Block(11)]:
|
||||
5: iIf:[Use: v8i reg, Use: v5i reg]
|
||||
eb1[]-[Block(2), Block(10)]:
|
||||
sb2[]-[Block(1)]:
|
||||
6: iBinOp { op: Add }:[Def: v19i reg, Use: v18i reg]
|
||||
7: iCall { func: 2 }:[Def: v20i fixed(p1i), Use: v6i fixed(p2i), Use: v19i fixed(p3i), Use: v5i fixed(p4i)]
|
||||
8: iIf:[Use: v20i reg, Use: v15i reg]
|
||||
eb2[]-[Block(3), Block(4)]:
|
||||
sb3[]-[Block(2)]:
|
||||
9: iReturn:[Use: v6i fixed(p1i)]
|
||||
eb3[]-[]:
|
||||
sb4[]-[Block(2)]:
|
||||
10: iIf:[Use: v19i reg, Use: v4i reg]
|
||||
eb4[]-[Block(5), Block(9)]:
|
||||
sb5[]-[Block(4)]:
|
||||
11: iLoop:[]
|
||||
eb5[VReg(vreg = 19, class = Int)]-[Block(6)]:
|
||||
sb6[VReg(vreg = 36, class = Int)]-[Block(5), Block(7)]:
|
||||
12: iIf:[Use: v4i reg, Use: v36i reg]
|
||||
eb6[]-[Block(7), Block(8)]:
|
||||
sb7[]-[Block(6)]:
|
||||
13: iBinOp { op: Add }:[Def: v41i reg, Use: v36i reg]
|
||||
14: iLoop:[]
|
||||
eb7[VReg(vreg = 41, class = Int)]-[Block(6)]:
|
||||
sb8[]-[Block(6)]:
|
||||
15: iReturn:[Use: v15i fixed(p1i)]
|
||||
eb8[]-[]:
|
||||
sb9[]-[Block(4)]:
|
||||
16: iRegion:[]
|
||||
eb9[VReg(vreg = 6, class = Int), VReg(vreg = 19, class = Int), VReg(vreg = 15, class = Int)]-[Block(11)]:
|
||||
sb10[]-[Block(1)]:
|
||||
17: iBinOp { op: Add }:[Def: v16i reg, Use: v15i reg]
|
||||
18: iBinOp { op: Add }:[Def: v14i reg, Use: v8i reg]
|
||||
19: iRegion:[]
|
||||
eb10[VReg(vreg = 14, class = Int), VReg(vreg = 18, class = Int), VReg(vreg = 16, class = Int)]-[Block(11)]:
|
||||
sb11[VReg(vreg = 32, class = Int), VReg(vreg = 33, class = Int), VReg(vreg = 34, class = Int)]-[Block(10), Block(9)]:
|
||||
20: iLoop:[]
|
||||
eb11[VReg(vreg = 33, class = Int), VReg(vreg = 32, class = Int), VReg(vreg = 34, class = Int)]-[Block(1)]:
|
||||
|
||||
|
48
fooll.txt
48
fooll.txt
|
@ -1,48 +0,0 @@
|
|||
sb0[]-[]:
|
||||
0: iCall { func: 1 }:[Def: v3i fixed(p1i)]
|
||||
1: iCInt { value: 0 }:[Def: v6i reg]
|
||||
2: iCInt { value: 30 }:[Def: v5i reg]
|
||||
3: iCInt { value: 100 }:[Def: v4i reg]
|
||||
4: iLoop:[]
|
||||
eb0[VReg(vreg = 4, class = Int), VReg(vreg = 6, class = Int), VReg(vreg = 6, class = Int), VReg(vreg = 6, class = Int)]-[Block(1)]:
|
||||
sb1[VReg(vreg = 26, class = Int), VReg(vreg = 8, class = Int), VReg(vreg = 15, class = Int), VReg(vreg = 18, class = Int)]-[Block(0), Block(11)]:
|
||||
5: iIf:[Use: v8i reg, Use: v5i reg]
|
||||
eb1[]-[Block(2), Block(10)]:
|
||||
sb2[]-[Block(1)]:
|
||||
6: iBinOp { op: Add }:[Def: v19i reg, Use: v18i reg]
|
||||
7: iCall { func: 2 }:[Def: v20i fixed(p1i), Use: v6i fixed(p2i), Use: v19i fixed(p3i), Use: v5i fixed(p4i)]
|
||||
8: iIf:[Use: v20i reg, Use: v15i reg]
|
||||
eb2[]-[Block(3), Block(4)]:
|
||||
sb3[]-[Block(2)]:
|
||||
9: iReturn:[Use: v6i fixed(p1i)]
|
||||
eb3[]-[]:
|
||||
sb4[]-[Block(2)]:
|
||||
10: iIf:[Use: v19i reg, Use: v4i reg]
|
||||
eb4[]-[Block(5), Block(9)]:
|
||||
sb5[]-[Block(4)]:
|
||||
11: iBinOp { op: Add }:[Def: v35i reg, Use: v26i reg]
|
||||
12: iLoop:[]
|
||||
eb5[VReg(vreg = 19, class = Int)]-[Block(6)]:
|
||||
sb6[VReg(vreg = 38, class = Int)]-[Block(5), Block(7)]:
|
||||
13: iIf:[Use: v35i reg, Use: v38i reg]
|
||||
eb6[]-[Block(7), Block(8)]:
|
||||
sb7[]-[Block(6)]:
|
||||
14: iBinOp { op: Add }:[Def: v43i reg, Use: v38i reg]
|
||||
15: iLoop:[]
|
||||
eb7[VReg(vreg = 43, class = Int)]-[Block(6)]:
|
||||
sb8[]-[Block(6)]:
|
||||
16: iReturn:[Use: v15i fixed(p1i)]
|
||||
eb8[]-[]:
|
||||
sb9[]-[Block(4)]:
|
||||
17: iRegion:[]
|
||||
eb9[VReg(vreg = 6, class = Int), VReg(vreg = 19, class = Int), VReg(vreg = 15, class = Int)]-[Block(11)]:
|
||||
sb10[]-[Block(1)]:
|
||||
18: iBinOp { op: Add }:[Def: v16i reg, Use: v15i reg]
|
||||
19: iBinOp { op: Add }:[Def: v14i reg, Use: v8i reg]
|
||||
20: iRegion:[]
|
||||
eb10[VReg(vreg = 14, class = Int), VReg(vreg = 18, class = Int), VReg(vreg = 16, class = Int)]-[Block(11)]:
|
||||
sb11[VReg(vreg = 32, class = Int), VReg(vreg = 33, class = Int), VReg(vreg = 34, class = Int)]-[Block(10), Block(9)]:
|
||||
21: iLoop:[]
|
||||
eb11[VReg(vreg = 0, class = Int), VReg(vreg = 32, class = Int), VReg(vreg = 34, class = Int), VReg(vreg = 33, class = Int)]-[Block(1)]:
|
||||
|
||||
|
|
@ -14,9 +14,6 @@ hbvm = { path = "../hbvm", features = ["nightly"] }
|
|||
log = { version = "0.4.22", features = ["release_max_level_error"] }
|
||||
regalloc2 = { git = "https://github.com/jakubDoka/regalloc2", branch = "reuse-allocations", features = [] }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.11.5"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
|
|
@ -178,8 +178,7 @@ main := fn(): int {
|
|||
}
|
||||
|
||||
pass := fn(t: ^Ty): int {
|
||||
.{a, b} := *t
|
||||
return a - b
|
||||
return t.a - t.b
|
||||
}
|
||||
|
||||
odher_pass := fn(t: Ty2): Ty2 {
|
||||
|
|
|
@ -2150,7 +2150,7 @@ impl Codegen {
|
|||
self.ci.emit(jala(ZERO, RET_ADDR, 0));
|
||||
self.ci.regs.free(core::mem::take(&mut self.ci.ret_reg));
|
||||
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
||||
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
||||
self.tys.ins.funcs[id as usize].relocs = self.ci.relocs.drain(..).collect();
|
||||
self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci));
|
||||
self.ct.vm.write_reg(reg::STACK_PTR, ct_stack_base);
|
||||
}
|
||||
|
|
442
hblang/src/fmt.rs
Normal file
442
hblang/src/fmt.rs
Normal file
|
@ -0,0 +1,442 @@
|
|||
use {
|
||||
crate::{
|
||||
lexer::{self, TokenKind},
|
||||
parser::{self, CommentOr, CtorField, Expr, Poser, Radix, StructField},
|
||||
},
|
||||
alloc::string::String,
|
||||
core::fmt,
|
||||
};
|
||||
|
||||
pub fn minify(source: &mut str) -> Option<&str> {
|
||||
fn needs_space(c: u8) -> bool {
|
||||
matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | 127..)
|
||||
}
|
||||
|
||||
let mut writer = source.as_mut_ptr();
|
||||
let mut reader = &source[..];
|
||||
let mut prev_needs_whitecpace = false;
|
||||
loop {
|
||||
let mut token = lexer::Lexer::new(reader).next();
|
||||
match token.kind {
|
||||
TokenKind::Eof => break,
|
||||
TokenKind::CtIdent | TokenKind::Directive => token.start -= 1,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut suffix = 0;
|
||||
if token.kind == TokenKind::Comment && reader.as_bytes()[token.end as usize - 1] != b'/' {
|
||||
token.end = token.start + reader[token.range()].trim_end().len() as u32;
|
||||
suffix = b'\n';
|
||||
}
|
||||
|
||||
let mut prefix = 0;
|
||||
if prev_needs_whitecpace && needs_space(reader.as_bytes()[token.start as usize]) {
|
||||
prefix = b' ';
|
||||
}
|
||||
|
||||
prev_needs_whitecpace = needs_space(reader.as_bytes()[token.end as usize - 1]);
|
||||
let sstr = reader[token.start as usize..].as_ptr();
|
||||
reader = &reader[token.end as usize..];
|
||||
unsafe {
|
||||
if prefix != 0 {
|
||||
writer.write(prefix);
|
||||
writer = writer.add(1);
|
||||
}
|
||||
writer.copy_from(sstr, token.range().len());
|
||||
writer = writer.add(token.range().len());
|
||||
if suffix != 0 {
|
||||
writer.write(suffix);
|
||||
writer = writer.add(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub struct Formatter<'a> {
|
||||
source: &'a str,
|
||||
depth: usize,
|
||||
disp_buff: String,
|
||||
}
|
||||
|
||||
impl<'a> Formatter<'a> {
|
||||
pub fn new(source: &'a str) -> Self {
|
||||
Self { source, depth: 0, disp_buff: Default::default() }
|
||||
}
|
||||
|
||||
fn fmt_list<T: Poser, F: core::fmt::Write>(
|
||||
&mut self,
|
||||
f: &mut F,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
sep: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&mut Self, &T, &mut F) -> fmt::Result,
|
||||
) -> fmt::Result {
|
||||
self.fmt_list_low(f, trailing, end, sep, list, |s, v, f| {
|
||||
fmt(s, v, f)?;
|
||||
Ok(true)
|
||||
})
|
||||
}
|
||||
|
||||
fn fmt_list_low<T: Poser, F: core::fmt::Write>(
|
||||
&mut self,
|
||||
f: &mut F,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
sep: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&mut Self, &T, &mut F) -> Result<bool, fmt::Error>,
|
||||
) -> fmt::Result {
|
||||
if !trailing {
|
||||
let mut first = true;
|
||||
for expr in list {
|
||||
if !core::mem::take(&mut first) {
|
||||
write!(f, "{sep} ")?;
|
||||
}
|
||||
first = !fmt(self, expr, f)?;
|
||||
}
|
||||
return write!(f, "{end}");
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
self.depth += 1;
|
||||
let res = (|| {
|
||||
for (i, stmt) in list.iter().enumerate() {
|
||||
for _ in 0..self.depth {
|
||||
write!(f, "\t")?;
|
||||
}
|
||||
let add_sep = fmt(self, stmt, f)?;
|
||||
if add_sep {
|
||||
write!(f, "{sep}")?;
|
||||
}
|
||||
if let Some(expr) = list.get(i + 1)
|
||||
&& let Some(rest) = self.source.get(expr.posi() as usize..)
|
||||
{
|
||||
if insert_needed_semicolon(rest) {
|
||||
write!(f, ";")?;
|
||||
}
|
||||
if preserve_newlines(&self.source[..expr.posi() as usize]) > 1 {
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
if add_sep {
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
self.depth -= 1;
|
||||
|
||||
for _ in 0..self.depth {
|
||||
write!(f, "\t")?;
|
||||
}
|
||||
write!(f, "{end}")?;
|
||||
res
|
||||
}
|
||||
|
||||
fn fmt_paren<F: core::fmt::Write>(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
f: &mut F,
|
||||
cond: impl FnOnce(&Expr) -> bool,
|
||||
) -> fmt::Result {
|
||||
if cond(expr) {
|
||||
write!(f, "(")?;
|
||||
self.fmt(expr, f)?;
|
||||
write!(f, ")")
|
||||
} else {
|
||||
self.fmt(expr, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt<F: core::fmt::Write>(&mut self, expr: &Expr, f: &mut F) -> fmt::Result {
|
||||
macro_rules! impl_parenter {
|
||||
($($name:ident => $pat:pat,)*) => {
|
||||
$(
|
||||
let $name = |e: &Expr| matches!(e, $pat);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_parenter! {
|
||||
unary => Expr::BinOp { .. },
|
||||
postfix => Expr::UnOp { .. } | Expr::BinOp { .. },
|
||||
consecutive => Expr::UnOp { .. },
|
||||
}
|
||||
|
||||
match *expr {
|
||||
Expr::Ct { value, .. } => {
|
||||
write!(f, "$: ")?;
|
||||
self.fmt(value, f)
|
||||
}
|
||||
Expr::String { literal, .. } => write!(f, "{literal}"),
|
||||
Expr::Comment { literal, .. } => write!(f, "{}", literal.trim_end()),
|
||||
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
|
||||
Expr::Field { target, name: field, .. } => {
|
||||
self.fmt_paren(target, f, postfix)?;
|
||||
write!(f, ".{field}")
|
||||
}
|
||||
Expr::Directive { name, args, .. } => {
|
||||
write!(f, "@{name}(")?;
|
||||
self.fmt_list(f, false, ")", ",", args, Self::fmt)
|
||||
}
|
||||
Expr::Struct { fields, trailing_comma, packed, .. } => {
|
||||
if packed {
|
||||
write!(f, "packed ")?;
|
||||
}
|
||||
|
||||
write!(f, "struct {{")?;
|
||||
self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| {
|
||||
match field {
|
||||
CommentOr::Or(StructField { name, ty, .. }) => {
|
||||
write!(f, "{name}: ")?;
|
||||
s.fmt(ty, f)?
|
||||
}
|
||||
CommentOr::Comment { literal, .. } => write!(f, "{literal}")?,
|
||||
}
|
||||
Ok(field.or().is_some())
|
||||
})
|
||||
}
|
||||
Expr::Ctor { ty, fields, trailing_comma, .. } => {
|
||||
if let Some(ty) = ty {
|
||||
self.fmt_paren(ty, f, unary)?;
|
||||
}
|
||||
write!(f, ".{{")?;
|
||||
self.fmt_list(
|
||||
f,
|
||||
trailing_comma,
|
||||
"}",
|
||||
",",
|
||||
fields,
|
||||
|s: &mut Self, CtorField { name, value, .. }: &_, f| {
|
||||
if matches!(value, Expr::Ident { name: n, .. } if name == n) {
|
||||
write!(f, "{name}")
|
||||
} else {
|
||||
write!(f, "{name}: ")?;
|
||||
s.fmt(value, f)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
Expr::Tupl { ty, fields, trailing_comma, .. } => {
|
||||
if let Some(ty) = ty {
|
||||
self.fmt_paren(ty, f, unary)?;
|
||||
}
|
||||
write!(f, ".(")?;
|
||||
self.fmt_list(f, trailing_comma, ")", ",", fields, Self::fmt)
|
||||
}
|
||||
Expr::Slice { item, size, .. } => {
|
||||
write!(f, "[")?;
|
||||
self.fmt(item, f)?;
|
||||
if let Some(size) = size {
|
||||
write!(f, "; ")?;
|
||||
self.fmt(size, f)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
Expr::Index { base, index } => {
|
||||
self.fmt(base, f)?;
|
||||
write!(f, "[")?;
|
||||
self.fmt(index, f)?;
|
||||
write!(f, "]")
|
||||
}
|
||||
Expr::UnOp { op, val, .. } => {
|
||||
write!(f, "{op}")?;
|
||||
self.fmt_paren(val, f, unary)
|
||||
}
|
||||
Expr::Break { .. } => write!(f, "break"),
|
||||
Expr::Continue { .. } => write!(f, "continue"),
|
||||
Expr::If { cond, then, else_, .. } => {
|
||||
write!(f, "if ")?;
|
||||
self.fmt(cond, f)?;
|
||||
write!(f, " ")?;
|
||||
self.fmt_paren(then, f, consecutive)?;
|
||||
if let Some(e) = else_ {
|
||||
write!(f, " else ")?;
|
||||
self.fmt(e, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Expr::Loop { body, .. } => {
|
||||
write!(f, "loop ")?;
|
||||
self.fmt(body, f)
|
||||
}
|
||||
Expr::Closure { ret, body, args, .. } => {
|
||||
write!(f, "fn(")?;
|
||||
self.fmt_list(f, false, "", ",", args, |s, arg, f| {
|
||||
if arg.is_ct {
|
||||
write!(f, "$")?;
|
||||
}
|
||||
write!(f, "{}: ", arg.name)?;
|
||||
s.fmt(&arg.ty, f)
|
||||
})?;
|
||||
write!(f, "): ")?;
|
||||
self.fmt(ret, f)?;
|
||||
write!(f, " ")?;
|
||||
self.fmt_paren(body, f, consecutive)?;
|
||||
Ok(())
|
||||
}
|
||||
Expr::Call { func, args, trailing_comma } => {
|
||||
self.fmt_paren(func, f, postfix)?;
|
||||
write!(f, "(")?;
|
||||
self.fmt_list(f, trailing_comma, ")", ",", args, Self::fmt)
|
||||
}
|
||||
Expr::Return { val: Some(val), .. } => {
|
||||
write!(f, "return ")?;
|
||||
self.fmt(val, f)
|
||||
}
|
||||
Expr::Return { val: None, .. } => write!(f, "return"),
|
||||
Expr::Ident { name, is_ct: true, .. } => write!(f, "${name}"),
|
||||
Expr::Ident { name, is_ct: false, .. } => write!(f, "{name}"),
|
||||
Expr::Block { stmts, .. } => {
|
||||
write!(f, "{{")?;
|
||||
self.fmt_list(f, true, "}", "", stmts, Self::fmt)
|
||||
}
|
||||
Expr::Number { value, radix, .. } => match radix {
|
||||
Radix::Decimal => write!(f, "{value}"),
|
||||
Radix::Hex => write!(f, "{value:#X}"),
|
||||
Radix::Octal => write!(f, "{value:#o}"),
|
||||
Radix::Binary => write!(f, "{value:#b}"),
|
||||
},
|
||||
Expr::Bool { value, .. } => write!(f, "{value}"),
|
||||
Expr::Idk { .. } => write!(f, "idk"),
|
||||
Expr::BinOp {
|
||||
left,
|
||||
op: TokenKind::Assign,
|
||||
right: Expr::BinOp { left: lleft, op, right },
|
||||
} if {
|
||||
let mut b = core::mem::take(&mut self.disp_buff);
|
||||
self.fmt(lleft, &mut b)?;
|
||||
let len = b.len();
|
||||
self.fmt(left, &mut b)?;
|
||||
let (lleft, left) = b.split_at(len);
|
||||
let res = lleft == left;
|
||||
b.clear();
|
||||
self.disp_buff = b;
|
||||
res
|
||||
} =>
|
||||
{
|
||||
self.fmt(left, f)?;
|
||||
write!(f, " {op}= ")?;
|
||||
self.fmt(right, f)
|
||||
}
|
||||
Expr::BinOp { right, op, left } => {
|
||||
let pec_miss = |e: &Expr| {
|
||||
matches!(
|
||||
e, Expr::BinOp { op: lop, .. } if op.precedence() > lop.precedence()
|
||||
)
|
||||
};
|
||||
|
||||
self.fmt_paren(left, f, pec_miss)?;
|
||||
if let Some(mut prev) = self.source.get(..right.pos() as usize) {
|
||||
prev = prev.trim_end();
|
||||
let estimate_bound =
|
||||
prev.rfind(|c: char| c.is_ascii_whitespace()).map_or(prev.len(), |i| i + 1);
|
||||
let exact_bound = lexer::Lexer::new(&prev[estimate_bound..]).last().start;
|
||||
prev = &prev[..exact_bound as usize + estimate_bound];
|
||||
if preserve_newlines(prev) > 0 {
|
||||
writeln!(f)?;
|
||||
for _ in 0..self.depth + 1 {
|
||||
write!(f, "\t")?;
|
||||
}
|
||||
write!(f, "{op} ")?;
|
||||
} else {
|
||||
write!(f, " {op} ")?;
|
||||
}
|
||||
} else {
|
||||
write!(f, " {op} ")?;
|
||||
}
|
||||
self.fmt_paren(right, f, pec_miss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preserve_newlines(source: &str) -> usize {
|
||||
source[source.trim_end().len()..].chars().filter(|&c| c == '\n').count()
|
||||
}
|
||||
|
||||
pub fn insert_needed_semicolon(source: &str) -> bool {
|
||||
let kind = lexer::Lexer::new(source).next().kind;
|
||||
kind.precedence().is_some() || matches!(kind, TokenKind::Ctor | TokenKind::Tupl)
|
||||
}
|
||||
|
||||
impl core::fmt::Display for parser::Ast {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for (i, expr) in self.exprs().iter().enumerate() {
|
||||
Formatter::new(&self.file).fmt(expr, f)?;
|
||||
if let Some(expr) = self.exprs().get(i + 1)
|
||||
&& let Some(rest) = self.file.get(expr.pos() as usize..)
|
||||
{
|
||||
if insert_needed_semicolon(rest) {
|
||||
write!(f, ";")?;
|
||||
}
|
||||
|
||||
if preserve_newlines(&self.file[..expr.pos() as usize]) > 1 {
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
|
||||
if i + 1 != self.exprs().len() {
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use {
|
||||
crate::parser::{self, StackAlloc},
|
||||
alloc::borrow::ToOwned,
|
||||
std::{fmt::Write, string::String},
|
||||
};
|
||||
|
||||
pub fn format(ident: &str, input: &str) {
|
||||
let ast =
|
||||
parser::Ast::new(ident, input.to_owned(), &mut StackAlloc::default(), &|_, _| Ok(0));
|
||||
let mut output = String::new();
|
||||
write!(output, "{ast}").unwrap();
|
||||
|
||||
let input_path = format!("formatter_{ident}.expected");
|
||||
let output_path = format!("formatter_{ident}.actual");
|
||||
std::fs::write(&input_path, input).unwrap();
|
||||
std::fs::write(&output_path, output).unwrap();
|
||||
|
||||
let success = std::process::Command::new("diff")
|
||||
.arg("-u")
|
||||
.arg("--color")
|
||||
.arg(&input_path)
|
||||
.arg(&output_path)
|
||||
.status()
|
||||
.unwrap()
|
||||
.success();
|
||||
std::fs::remove_file(&input_path).unwrap();
|
||||
std::fs::remove_file(&output_path).unwrap();
|
||||
assert!(success, "test failed");
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($($name:ident => $input:expr;)*) => {$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
format(stringify!($name), $input);
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
test! {
|
||||
comments => "// comment\n// comment\n\n// comment\n\n\
|
||||
/* comment */\n/* comment */\n\n/* comment */";
|
||||
some_ordinary_code => "loft := fn(): int return loft(1, 2, 3)";
|
||||
some_arg_per_line_code => "loft := fn(): int return loft(\
|
||||
\n\t1,\n\t2,\n\t3,\n)";
|
||||
some_ordinary_struct => "loft := fn(): int return loft.{a: 1, b: 2}";
|
||||
some_ordinary_fild_per_lin_struct => "loft := fn(): int return loft.{\
|
||||
\n\ta: 1,\n\tb: 2,\n}";
|
||||
code_block => "loft := fn(): int {\n\tloft()\n\treturn 1\n}";
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ use {
|
|||
collections::VecDeque,
|
||||
eprintln,
|
||||
ffi::OsStr,
|
||||
io,
|
||||
io::{self, Write as _},
|
||||
path::{Path, PathBuf},
|
||||
string::ToString,
|
||||
sync::Mutex,
|
||||
|
@ -68,35 +68,12 @@ impl Options {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn format_to(ast: &parser::Ast, source: &str, out: &mut String) -> core::fmt::Result {
|
||||
for (i, expr) in ast.exprs().iter().enumerate() {
|
||||
parser::Formatter::new(&ast.file).fmt(expr, out)?;
|
||||
if let Some(expr) = ast.exprs().get(i + 1)
|
||||
&& let Some(rest) = source.get(expr.pos() as usize..)
|
||||
{
|
||||
if parser::insert_needed_semicolon(rest) {
|
||||
write!(out, ";")?;
|
||||
}
|
||||
if parser::preserve_newlines(&source[..expr.pos() as usize]) > 1 {
|
||||
writeln!(out)?;
|
||||
}
|
||||
}
|
||||
|
||||
if i + 1 != ast.exprs().len() {
|
||||
writeln!(out)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
let parsed = parse_from_fs(options.extra_threads, root_file)?;
|
||||
|
||||
fn format_ast(ast: parser::Ast) -> std::io::Result<()> {
|
||||
let mut output = String::new();
|
||||
let source = std::fs::read_to_string(&*ast.path)?;
|
||||
format_to(&ast, &source, &mut output).unwrap();
|
||||
write!(output, "{ast}").unwrap();
|
||||
std::fs::write(&*ast.path, output)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -107,9 +84,7 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
|
|||
}
|
||||
} else if options.fmt_stdout {
|
||||
let ast = parsed.into_iter().next().unwrap();
|
||||
let source = std::fs::read_to_string(&*ast.path)?;
|
||||
format_to(&ast, &source, unsafe { std::mem::transmute::<&mut Vec<u8>, &mut String>(out) })
|
||||
.unwrap();
|
||||
write!(out, "{ast}").unwrap();
|
||||
} else {
|
||||
let mut codegen = codegen::Codegen::default();
|
||||
codegen.files = parsed;
|
||||
|
|
|
@ -61,6 +61,7 @@ macro_rules! run_tests {
|
|||
}
|
||||
|
||||
pub mod codegen;
|
||||
pub mod fmt;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub mod fs;
|
||||
pub mod parser;
|
||||
|
@ -1316,13 +1317,13 @@ fn test_parse_files(ident: &'static str, input: &'static str) -> Vec<parser::Ast
|
|||
let mut last_start = 0;
|
||||
let mut last_module_name = "test";
|
||||
for (i, m) in input.match_indices("// in module: ") {
|
||||
parser::test::format(ident, input[last_start..i].trim());
|
||||
fmt::test::format(ident, input[last_start..i].trim());
|
||||
module_map.push((last_module_name, &input[last_start..i]));
|
||||
let (module_name, _) = input[i + m.len()..].split_once('\n').unwrap();
|
||||
last_module_name = module_name;
|
||||
last_start = i + m.len() + module_name.len() + 1;
|
||||
}
|
||||
parser::test::format(ident, input[last_start..].trim());
|
||||
fmt::test::format(ident, input[last_start..].trim());
|
||||
module_map.push((last_module_name, input[last_start..].trim()));
|
||||
|
||||
let loader = |path: &str, _: &str| {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
fmt::Formatter,
|
||||
ident::{self, Ident},
|
||||
lexer::{self, Lexer, Token, TokenKind},
|
||||
},
|
||||
|
@ -901,7 +902,7 @@ impl Poser for CtorField<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
trait Poser {
|
||||
pub trait Poser {
|
||||
fn posi(&self) -> Pos;
|
||||
}
|
||||
|
||||
|
@ -945,6 +946,7 @@ pub struct Display<'a> {
|
|||
source: &'a str,
|
||||
expr: &'a Expr<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Display<'a> {
|
||||
pub fn new(source: &'a str, expr: &'a Expr<'a>) -> Self {
|
||||
Self { source, expr }
|
||||
|
@ -957,315 +959,6 @@ impl core::fmt::Display for Display<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Formatter<'a> {
|
||||
source: &'a str,
|
||||
depth: usize,
|
||||
disp_buff: String,
|
||||
}
|
||||
|
||||
impl<'a> Formatter<'a> {
|
||||
pub fn new(source: &'a str) -> Self {
|
||||
Self { source, depth: 0, disp_buff: Default::default() }
|
||||
}
|
||||
|
||||
fn fmt_list<T: Poser, F: core::fmt::Write>(
|
||||
&mut self,
|
||||
f: &mut F,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
sep: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&mut Self, &T, &mut F) -> fmt::Result,
|
||||
) -> fmt::Result {
|
||||
self.fmt_list_low(f, trailing, end, sep, list, |s, v, f| {
|
||||
fmt(s, v, f)?;
|
||||
Ok(true)
|
||||
})
|
||||
}
|
||||
|
||||
fn fmt_list_low<T: Poser, F: core::fmt::Write>(
|
||||
&mut self,
|
||||
f: &mut F,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
sep: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&mut Self, &T, &mut F) -> Result<bool, fmt::Error>,
|
||||
) -> fmt::Result {
|
||||
if !trailing {
|
||||
let mut first = true;
|
||||
for expr in list {
|
||||
if !core::mem::take(&mut first) {
|
||||
write!(f, "{sep} ")?;
|
||||
}
|
||||
first = !fmt(self, expr, f)?;
|
||||
}
|
||||
return write!(f, "{end}");
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
self.depth += 1;
|
||||
let res = (|| {
|
||||
for (i, stmt) in list.iter().enumerate() {
|
||||
for _ in 0..self.depth {
|
||||
write!(f, "\t")?;
|
||||
}
|
||||
let add_sep = fmt(self, stmt, f)?;
|
||||
if add_sep {
|
||||
write!(f, "{sep}")?;
|
||||
}
|
||||
if let Some(expr) = list.get(i + 1)
|
||||
&& let Some(rest) = self.source.get(expr.posi() as usize..)
|
||||
{
|
||||
if insert_needed_semicolon(rest) {
|
||||
write!(f, ";")?;
|
||||
}
|
||||
if preserve_newlines(&self.source[..expr.posi() as usize]) > 1 {
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
if add_sep {
|
||||
writeln!(f)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
self.depth -= 1;
|
||||
|
||||
for _ in 0..self.depth {
|
||||
write!(f, "\t")?;
|
||||
}
|
||||
write!(f, "{end}")?;
|
||||
res
|
||||
}
|
||||
|
||||
fn fmt_paren<F: core::fmt::Write>(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
f: &mut F,
|
||||
cond: impl FnOnce(&Expr) -> bool,
|
||||
) -> fmt::Result {
|
||||
if cond(expr) {
|
||||
write!(f, "(")?;
|
||||
self.fmt(expr, f)?;
|
||||
write!(f, ")")
|
||||
} else {
|
||||
self.fmt(expr, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt<F: core::fmt::Write>(&mut self, expr: &Expr, f: &mut F) -> fmt::Result {
|
||||
macro_rules! impl_parenter {
|
||||
($($name:ident => $pat:pat,)*) => {
|
||||
$(
|
||||
let $name = |e: &Expr| matches!(e, $pat);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_parenter! {
|
||||
unary => Expr::BinOp { .. },
|
||||
postfix => Expr::UnOp { .. } | Expr::BinOp { .. },
|
||||
consecutive => Expr::UnOp { .. },
|
||||
}
|
||||
|
||||
match *expr {
|
||||
Expr::Ct { value, .. } => {
|
||||
write!(f, "$: ")?;
|
||||
self.fmt(value, f)
|
||||
}
|
||||
Expr::String { literal, .. } => write!(f, "{literal}"),
|
||||
Expr::Comment { literal, .. } => write!(f, "{}", literal.trim_end()),
|
||||
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
|
||||
Expr::Field { target, name: field, .. } => {
|
||||
self.fmt_paren(target, f, postfix)?;
|
||||
write!(f, ".{field}")
|
||||
}
|
||||
Expr::Directive { name, args, .. } => {
|
||||
write!(f, "@{name}(")?;
|
||||
self.fmt_list(f, false, ")", ",", args, Self::fmt)
|
||||
}
|
||||
Expr::Struct { fields, trailing_comma, packed, .. } => {
|
||||
if packed {
|
||||
write!(f, "packed ")?;
|
||||
}
|
||||
|
||||
write!(f, "struct {{")?;
|
||||
self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| {
|
||||
match field {
|
||||
CommentOr::Or(StructField { name, ty, .. }) => {
|
||||
write!(f, "{name}: ")?;
|
||||
s.fmt(ty, f)?
|
||||
}
|
||||
CommentOr::Comment { literal, .. } => write!(f, "{literal}")?,
|
||||
}
|
||||
Ok(field.or().is_some())
|
||||
})
|
||||
}
|
||||
Expr::Ctor { ty, fields, trailing_comma, .. } => {
|
||||
if let Some(ty) = ty {
|
||||
self.fmt_paren(ty, f, unary)?;
|
||||
}
|
||||
write!(f, ".{{")?;
|
||||
self.fmt_list(
|
||||
f,
|
||||
trailing_comma,
|
||||
"}",
|
||||
",",
|
||||
fields,
|
||||
|s: &mut Self, CtorField { name, value, .. }: &_, f| {
|
||||
if matches!(value, Expr::Ident { name: n, .. } if name == n) {
|
||||
write!(f, "{name}")
|
||||
} else {
|
||||
write!(f, "{name}: ")?;
|
||||
s.fmt(value, f)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
Expr::Tupl { ty, fields, trailing_comma, .. } => {
|
||||
if let Some(ty) = ty {
|
||||
self.fmt_paren(ty, f, unary)?;
|
||||
}
|
||||
write!(f, ".(")?;
|
||||
self.fmt_list(f, trailing_comma, ")", ",", fields, Self::fmt)
|
||||
}
|
||||
Expr::Slice { item, size, .. } => {
|
||||
write!(f, "[")?;
|
||||
self.fmt(item, f)?;
|
||||
if let Some(size) = size {
|
||||
write!(f, "; ")?;
|
||||
self.fmt(size, f)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
Expr::Index { base, index } => {
|
||||
self.fmt(base, f)?;
|
||||
write!(f, "[")?;
|
||||
self.fmt(index, f)?;
|
||||
write!(f, "]")
|
||||
}
|
||||
Expr::UnOp { op, val, .. } => {
|
||||
write!(f, "{op}")?;
|
||||
self.fmt_paren(val, f, unary)
|
||||
}
|
||||
Expr::Break { .. } => write!(f, "break"),
|
||||
Expr::Continue { .. } => write!(f, "continue"),
|
||||
Expr::If { cond, then, else_, .. } => {
|
||||
write!(f, "if ")?;
|
||||
self.fmt(cond, f)?;
|
||||
write!(f, " ")?;
|
||||
self.fmt_paren(then, f, consecutive)?;
|
||||
if let Some(e) = else_ {
|
||||
write!(f, " else ")?;
|
||||
self.fmt(e, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Expr::Loop { body, .. } => {
|
||||
write!(f, "loop ")?;
|
||||
self.fmt(body, f)
|
||||
}
|
||||
Expr::Closure { ret, body, args, .. } => {
|
||||
write!(f, "fn(")?;
|
||||
self.fmt_list(f, false, "", ",", args, |s, arg, f| {
|
||||
if arg.is_ct {
|
||||
write!(f, "$")?;
|
||||
}
|
||||
write!(f, "{}: ", arg.name)?;
|
||||
s.fmt(&arg.ty, f)
|
||||
})?;
|
||||
write!(f, "): ")?;
|
||||
self.fmt(ret, f)?;
|
||||
write!(f, " ")?;
|
||||
self.fmt_paren(body, f, consecutive)?;
|
||||
Ok(())
|
||||
}
|
||||
Expr::Call { func, args, trailing_comma } => {
|
||||
self.fmt_paren(func, f, postfix)?;
|
||||
write!(f, "(")?;
|
||||
self.fmt_list(f, trailing_comma, ")", ",", args, Self::fmt)
|
||||
}
|
||||
Expr::Return { val: Some(val), .. } => {
|
||||
write!(f, "return ")?;
|
||||
self.fmt(val, f)
|
||||
}
|
||||
Expr::Return { val: None, .. } => write!(f, "return"),
|
||||
Expr::Ident { name, is_ct: true, .. } => write!(f, "${name}"),
|
||||
Expr::Ident { name, is_ct: false, .. } => write!(f, "{name}"),
|
||||
Expr::Block { stmts, .. } => {
|
||||
write!(f, "{{")?;
|
||||
self.fmt_list(f, true, "}", "", stmts, Self::fmt)
|
||||
}
|
||||
Expr::Number { value, radix, .. } => match radix {
|
||||
Radix::Decimal => write!(f, "{value}"),
|
||||
Radix::Hex => write!(f, "{value:#X}"),
|
||||
Radix::Octal => write!(f, "{value:#o}"),
|
||||
Radix::Binary => write!(f, "{value:#b}"),
|
||||
},
|
||||
Expr::Bool { value, .. } => write!(f, "{value}"),
|
||||
Expr::Idk { .. } => write!(f, "idk"),
|
||||
Expr::BinOp {
|
||||
left,
|
||||
op: TokenKind::Assign,
|
||||
right: Expr::BinOp { left: lleft, op, right },
|
||||
} if {
|
||||
let mut b = core::mem::take(&mut self.disp_buff);
|
||||
self.fmt(lleft, &mut b)?;
|
||||
let len = b.len();
|
||||
self.fmt(left, &mut b)?;
|
||||
let (lleft, left) = b.split_at(len);
|
||||
let res = lleft == left;
|
||||
b.clear();
|
||||
self.disp_buff = b;
|
||||
res
|
||||
} =>
|
||||
{
|
||||
self.fmt(left, f)?;
|
||||
write!(f, " {op}= ")?;
|
||||
self.fmt(right, f)
|
||||
}
|
||||
Expr::BinOp { right, op, left } => {
|
||||
let pec_miss = |e: &Expr| {
|
||||
matches!(
|
||||
e, Expr::BinOp { op: lop, .. } if op.precedence() > lop.precedence()
|
||||
)
|
||||
};
|
||||
|
||||
self.fmt_paren(left, f, pec_miss)?;
|
||||
if let Some(mut prev) = self.source.get(..right.pos() as usize) {
|
||||
prev = prev.trim_end();
|
||||
let estimate_bound =
|
||||
prev.rfind(|c: char| c.is_ascii_whitespace()).map_or(prev.len(), |i| i + 1);
|
||||
let exact_bound = lexer::Lexer::new(&prev[estimate_bound..]).last().start;
|
||||
prev = &prev[..exact_bound as usize + estimate_bound];
|
||||
if preserve_newlines(prev) > 0 {
|
||||
writeln!(f)?;
|
||||
for _ in 0..self.depth + 1 {
|
||||
write!(f, "\t")?;
|
||||
}
|
||||
write!(f, "{op} ")?;
|
||||
} else {
|
||||
write!(f, " {op} ")?;
|
||||
}
|
||||
} else {
|
||||
write!(f, " {op} ")?;
|
||||
}
|
||||
self.fmt_paren(right, f, pec_miss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preserve_newlines(source: &str) -> usize {
|
||||
source[source.trim_end().len()..].chars().filter(|&c| c == '\n').count()
|
||||
}
|
||||
|
||||
pub fn insert_needed_semicolon(source: &str) -> bool {
|
||||
let kind = lexer::Lexer::new(source).next().kind;
|
||||
kind.precedence().is_some() || matches!(kind, TokenKind::Ctor | TokenKind::Tupl)
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AstInner<T: ?Sized> {
|
||||
ref_count: AtomicUsize,
|
||||
|
@ -1627,53 +1320,3 @@ impl Drop for ArenaChunk {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use {crate::parser::StackAlloc, alloc::borrow::ToOwned, std::string::String};
|
||||
|
||||
pub fn format(ident: &str, input: &str) {
|
||||
let ast =
|
||||
super::Ast::new(ident, input.to_owned(), &mut StackAlloc::default(), &|_, _| Ok(0));
|
||||
let mut output = String::new();
|
||||
crate::fs::format_to(&ast, input, &mut output).unwrap();
|
||||
|
||||
let input_path = format!("formatter_{ident}.expected");
|
||||
let output_path = format!("formatter_{ident}.actual");
|
||||
std::fs::write(&input_path, input).unwrap();
|
||||
std::fs::write(&output_path, output).unwrap();
|
||||
|
||||
let success = std::process::Command::new("diff")
|
||||
.arg("-u")
|
||||
.arg("--color")
|
||||
.arg(&input_path)
|
||||
.arg(&output_path)
|
||||
.status()
|
||||
.unwrap()
|
||||
.success();
|
||||
std::fs::remove_file(&input_path).unwrap();
|
||||
std::fs::remove_file(&output_path).unwrap();
|
||||
assert!(success, "test failed");
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($($name:ident => $input:expr;)*) => {$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
format(stringify!($name), $input);
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
test! {
|
||||
comments => "// comment\n// comment\n\n// comment\n\n\
|
||||
/* comment */\n/* comment */\n\n/* comment */";
|
||||
some_ordinary_code => "loft := fn(): int return loft(1, 2, 3)";
|
||||
some_arg_per_line_code => "loft := fn(): int return loft(\
|
||||
\n\t1,\n\t2,\n\t3,\n)";
|
||||
some_ordinary_struct => "loft := fn(): int return loft.{a: 1, b: 2}";
|
||||
some_ordinary_fild_per_lin_struct => "loft := fn(): int return loft.{\
|
||||
\n\ta: 1,\n\tb: 2,\n}";
|
||||
code_block => "loft := fn(): int {\n\tloft()\n\treturn 1\n}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use {
|
|||
task,
|
||||
ty::{self},
|
||||
vc::{BitSet, Vc},
|
||||
Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
|
||||
Func, HashMap, Offset, OffsetIter, Reloc, Sig, Size, SymKey, TypedReloc, Types,
|
||||
},
|
||||
alloc::{borrow::ToOwned, string::String, vec::Vec},
|
||||
core::{
|
||||
|
@ -20,7 +20,8 @@ use {
|
|||
cell::RefCell,
|
||||
convert::identity,
|
||||
fmt::{self, Debug, Display, Write},
|
||||
format_args as fa, mem, ops,
|
||||
format_args as fa, mem,
|
||||
ops::{self, Range},
|
||||
},
|
||||
hashbrown::hash_map,
|
||||
regalloc2::VReg,
|
||||
|
@ -303,10 +304,17 @@ impl Nodes {
|
|||
}
|
||||
K::Stre { offset } => {
|
||||
let parent = self[target].inputs[2];
|
||||
let value = self[target].inputs[1];
|
||||
|
||||
if self[parent].kind == (K::Stre { offset }) && self[parent].outputs.len() == 1 {
|
||||
return Some(self.modify_input(parent, 1, self[target].inputs[1]));
|
||||
}
|
||||
|
||||
if self[value].kind == K::Stck {
|
||||
for str in self[value].outputs.clone() {
|
||||
assert!(self[str].outputs.is_empty(), "TODO: this is lost cause");
|
||||
}
|
||||
}
|
||||
}
|
||||
K::Load { offset } => {
|
||||
let parent = self[target].inputs[1];
|
||||
|
@ -381,26 +389,6 @@ impl Nodes {
|
|||
self.values.iter().enumerate().filter_map(|(i, s)| Some((i as _, s.as_ref().ok()?)))
|
||||
}
|
||||
|
||||
fn graphviz_low(&self, out: &mut String) -> core::fmt::Result {
|
||||
use core::fmt::Write;
|
||||
|
||||
for (i, node) in self.iter() {
|
||||
let color = if self.is_cfg(i) { "yellow" } else { "white" };
|
||||
writeln!(out, "node{i}[label=\"{}\" color={color}]", node.kind)?;
|
||||
for (j, &o) in node.outputs.iter().enumerate() {
|
||||
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" };
|
||||
let index = self[o].inputs.iter().position(|&inp| i == inp).unwrap();
|
||||
let style = if index == 0 && !self.is_cfg(o) { "style=dotted" } else { "" };
|
||||
writeln!(
|
||||
out,
|
||||
"node{o} -> node{i}[color={color} taillabel={index} headlabel={j} {style}]",
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::format_in_format_args)]
|
||||
fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> core::fmt::Result {
|
||||
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
||||
|
@ -539,13 +527,6 @@ impl Nodes {
|
|||
log::info!("{out}");
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn graphviz(&self) {
|
||||
let out = &mut String::new();
|
||||
_ = self.graphviz_low(out);
|
||||
log::info!("{out}");
|
||||
}
|
||||
|
||||
fn is_cfg(&self, o: Nid) -> bool {
|
||||
self[o].kind.is_cfg()
|
||||
}
|
||||
|
@ -882,6 +863,7 @@ struct ItemCtx {
|
|||
loops: Vec<Loop>,
|
||||
vars: Vec<Variable>,
|
||||
memories: Vec<MemKey>,
|
||||
clobbered: Vec<Nid>,
|
||||
ret_relocs: Vec<Reloc>,
|
||||
relocs: Vec<TypedReloc>,
|
||||
jump_relocs: Vec<(Nid, Reloc)>,
|
||||
|
@ -960,53 +942,90 @@ pub struct Codegen {
|
|||
}
|
||||
|
||||
impl Codegen {
|
||||
fn mem_op(
|
||||
&mut self,
|
||||
mut region: Nid,
|
||||
offset: Offset,
|
||||
kind: Kind,
|
||||
mut ty: ty::Id,
|
||||
mut inps: Vc,
|
||||
) -> Nid {
|
||||
region = self.ci.nodes.trace_mem(region);
|
||||
fn graphviz_low(&self, out: &mut String) -> core::fmt::Result {
|
||||
use core::fmt::Write;
|
||||
|
||||
let size = self.tys.size_of(ty);
|
||||
let insert_start = self
|
||||
for (i, node) in self.ci.nodes.iter() {
|
||||
let color = if self.ci.nodes.is_cfg(i) { "yellow" } else { "white" };
|
||||
writeln!(
|
||||
out,
|
||||
"node{i}[label=\"{} {}\" color={color}]",
|
||||
node.kind,
|
||||
self.ty_display(node.ty)
|
||||
)?;
|
||||
for (j, &o) in node.outputs.iter().enumerate() {
|
||||
let color = if self.ci.nodes.is_cfg(i) && self.ci.nodes.is_cfg(o) {
|
||||
"red"
|
||||
} else {
|
||||
"lightgray"
|
||||
};
|
||||
let index = self.ci.nodes[o].inputs.iter().position(|&inp| i == inp).unwrap();
|
||||
let style =
|
||||
if index == 0 && !self.ci.nodes.is_cfg(o) { "style=dotted" } else { "" };
|
||||
writeln!(
|
||||
out,
|
||||
"node{o} -> node{i}[color={color} taillabel={index} headlabel={j} {style}]",
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn graphviz(&self) {
|
||||
let out = &mut String::new();
|
||||
_ = self.graphviz_low(out);
|
||||
log::info!("{out}");
|
||||
}
|
||||
|
||||
fn region_range(&self, region: Nid, offset: Offset, size: Size) -> Range<usize> {
|
||||
let start = self
|
||||
.ci
|
||||
.memories
|
||||
.binary_search_by_key(&(region, offset), |k| (k.region, k.offset))
|
||||
.unwrap_or_else(identity);
|
||||
let insert_end = self
|
||||
let end = self
|
||||
.ci
|
||||
.memories
|
||||
.binary_search_by(|k| (k.region, k.offset).cmp(&(region, offset + size)))
|
||||
.unwrap_or_else(identity);
|
||||
|
||||
for mk in &self.ci.memories[insert_start..insert_end] {
|
||||
start..end
|
||||
}
|
||||
|
||||
fn mem_op(
|
||||
&mut self,
|
||||
mut region: Nid,
|
||||
offset: Offset,
|
||||
kind: Kind,
|
||||
ty: ty::Id,
|
||||
mut inps: Vc,
|
||||
) -> Nid {
|
||||
region = self.ci.nodes.trace_mem(region);
|
||||
let size = self.tys.size_of(ty);
|
||||
let range = self.region_range(region, offset, size);
|
||||
|
||||
for mk in &self.ci.memories[range.clone()] {
|
||||
debug_assert_eq!(mk.region, region);
|
||||
debug_assert!(mk.offset >= offset);
|
||||
debug_assert!(mk.offset < offset + size);
|
||||
inps.push(mk.node);
|
||||
}
|
||||
|
||||
if insert_start == insert_end {
|
||||
if range.is_empty() {
|
||||
inps.push(region);
|
||||
}
|
||||
|
||||
if matches!(kind, Kind::Ptr { .. }) {
|
||||
ty = self.tys.make_ptr(ty);
|
||||
}
|
||||
|
||||
let (new_op, peeped) = self.ci.nodes.new_node_low(ty, kind, inps);
|
||||
if !peeped && !matches!(kind, Kind::Ptr { .. }) {
|
||||
for mk in &self.ci.memories[insert_start..insert_end] {
|
||||
if !peeped {
|
||||
for mk in &self.ci.memories[range.clone()] {
|
||||
self.ci.nodes.unlock(mk.node);
|
||||
}
|
||||
|
||||
self.ci.memories.splice(
|
||||
insert_start..insert_end,
|
||||
core::iter::once(MemKey { node: new_op, region, offset }),
|
||||
);
|
||||
self.ci
|
||||
.memories
|
||||
.splice(range, core::iter::once(MemKey { node: new_op, region, offset }));
|
||||
self.ci.nodes.lock(new_op);
|
||||
}
|
||||
new_op
|
||||
|
@ -1020,8 +1039,20 @@ impl Codegen {
|
|||
self.mem_op(region, offset, Kind::Load { offset }, ty, [VOID].into())
|
||||
}
|
||||
|
||||
fn ptr_mem(&mut self, region: Nid, offset: Offset, ty: ty::Id) -> Nid {
|
||||
self.mem_op(region, offset, Kind::Ptr { offset }, ty, [VOID].into())
|
||||
fn ptr_mem(&mut self, on: Nid, offset: Offset, ty: ty::Id, derefed: bool) -> Nid {
|
||||
let offset = match self.ci.nodes[on].kind {
|
||||
Kind::Ptr { offset } => offset,
|
||||
_ => 0,
|
||||
} + offset;
|
||||
let region = self.ci.nodes.trace_mem(on);
|
||||
if region != on {
|
||||
self.ci.nodes.remove(on);
|
||||
}
|
||||
let n = self.ci.nodes.new_node_nop(ty, Kind::Ptr { offset }, [VOID, region]);
|
||||
if derefed {
|
||||
self.ci.nodes[n].offset = u32::MAX;
|
||||
}
|
||||
n
|
||||
}
|
||||
|
||||
pub fn generate(&mut self) {
|
||||
|
@ -1038,11 +1069,11 @@ impl Codegen {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr(&mut self, expr: &Expr) -> Option<Nid> {
|
||||
self.expr_ctx(expr, Ctx::default())
|
||||
fn raw_expr(&mut self, expr: &Expr) -> Option<Nid> {
|
||||
self.raw_expr_ctx(expr, Ctx::default())
|
||||
}
|
||||
|
||||
fn expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Nid> {
|
||||
fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Nid> {
|
||||
let msg = "i know nothing about this name, gal, which is vired \
|
||||
because we parsed succesfully";
|
||||
// ordered by complexity of the expression
|
||||
|
@ -1092,7 +1123,7 @@ impl Codegen {
|
|||
None
|
||||
}
|
||||
Expr::Field { target, name, pos } => {
|
||||
let vtarget = self.expr(target)?;
|
||||
let vtarget = self.raw_expr(target)?;
|
||||
let tty = self.tof(vtarget);
|
||||
|
||||
let ty::Kind::Struct(s) = self.tys.base_of(tty).unwrap_or(tty).expand() else {
|
||||
|
@ -1107,7 +1138,7 @@ impl Codegen {
|
|||
return Some(NEVER);
|
||||
};
|
||||
|
||||
let Some((ty, offset)) = OffsetIter::offset_of(&self.tys, s, name) else {
|
||||
let Some((offset, ty)) = OffsetIter::offset_of(&self.tys, s, name) else {
|
||||
let field_list = self
|
||||
.tys
|
||||
.struct_fields(s)
|
||||
|
@ -1126,24 +1157,25 @@ impl Codegen {
|
|||
return Some(NEVER);
|
||||
};
|
||||
|
||||
Some(self.load_mem(vtarget, ty, offset))
|
||||
Some(self.ptr_mem(vtarget, offset, ty, true))
|
||||
}
|
||||
Expr::UnOp { op: TokenKind::Band, val, .. } => {
|
||||
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
|
||||
|
||||
let mut val = self.expr_ctx(val, ctx)?;
|
||||
let mut val = self.raw_expr_ctx(val, ctx)?;
|
||||
let ty = self.tof(val);
|
||||
if !matches!(self.ci.nodes[val].kind, Kind::Stck) {
|
||||
if !matches!(self.ci.nodes[self.ci.nodes.trace_mem(val)].kind, Kind::Stck) {
|
||||
let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]);
|
||||
self.store_mem(stck, 0, val);
|
||||
val = stck;
|
||||
}
|
||||
|
||||
Some(self.ptr_mem(val, 0, ty))
|
||||
let ptr = self.tys.make_ptr(ty);
|
||||
Some(self.ptr_mem(val, 0, ptr, false))
|
||||
}
|
||||
Expr::UnOp { op: TokenKind::Mul, val, pos } => {
|
||||
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
||||
let val = self.expr_ctx(val, ctx)?;
|
||||
let val = self.raw_expr_ctx(val, ctx)?;
|
||||
let Some(base) = self.get_load_type(val) else {
|
||||
self.report(
|
||||
pos,
|
||||
|
@ -1151,7 +1183,7 @@ impl Codegen {
|
|||
);
|
||||
return Some(NEVER);
|
||||
};
|
||||
Some(self.load_mem(val, 0, base))
|
||||
Some(self.ptr_mem(val, 0, base, true))
|
||||
}
|
||||
Expr::UnOp { pos, op: op @ TokenKind::Sub, val } => {
|
||||
let val = self.expr_ctx(val, ctx)?;
|
||||
|
@ -1261,7 +1293,7 @@ impl Codegen {
|
|||
if self.tys.size_of(ty) == 0 {
|
||||
continue;
|
||||
}
|
||||
let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||
let value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||
_ = self.assert_ty(
|
||||
arg.pos(),
|
||||
self.tof(value),
|
||||
|
@ -1269,19 +1301,24 @@ impl Codegen {
|
|||
true,
|
||||
fa!("argument {}", carg.name),
|
||||
);
|
||||
if ty.is_pointer() {
|
||||
value = self.ci.nodes.trace_mem(value);
|
||||
value = self
|
||||
.ci
|
||||
.memories
|
||||
.binary_search_by_key(&(value, 0), |k| (k.region, k.offset))
|
||||
.map_or(value, |i| self.ci.memories[i].node);
|
||||
// mark the read as clobbed since function can store
|
||||
self.ci.nodes[value].offset = u32::MAX;
|
||||
if let Some(base) = self.tys.base_of(ty) {
|
||||
let Kind::Ptr { offset } = self.ci.nodes[value].kind else {
|
||||
unreachable!()
|
||||
};
|
||||
let reg = self.ci.nodes.trace_mem(value);
|
||||
let size = self.tys.size_of(base);
|
||||
for mk in &self.ci.memories[self.region_range(reg, offset, size)] {
|
||||
self.ci.nodes[mk.node].offset = u32::MAX;
|
||||
self.ci.clobbered.push(mk.node);
|
||||
}
|
||||
}
|
||||
inps.push(value);
|
||||
}
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func }, inps);
|
||||
for c in self.ci.clobbered.drain(..) {
|
||||
self.ci.nodes[self.ci.ctrl].inputs.push(c);
|
||||
self.ci.nodes[c].outputs.push(self.ci.ctrl);
|
||||
}
|
||||
|
||||
Some(self.ci.ctrl)
|
||||
}
|
||||
|
@ -1559,6 +1596,22 @@ impl Codegen {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Nid> {
|
||||
let n = self.raw_expr_ctx(expr, ctx)?;
|
||||
if let Kind::Ptr { offset } = self.ci.nodes[n].kind
|
||||
&& self.ci.nodes[n].offset == u32::MAX
|
||||
{
|
||||
let r = Some(self.load_mem(n, offset, self.tof(n)));
|
||||
self.ci.nodes.remove(n);
|
||||
return r;
|
||||
}
|
||||
Some(n)
|
||||
}
|
||||
|
||||
fn expr(&mut self, expr: &Expr) -> Option<Nid> {
|
||||
self.expr_ctx(expr, Default::default())
|
||||
}
|
||||
|
||||
fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Nid> {
|
||||
let Some(mut loob) = self.ci.loops.last_mut() else {
|
||||
self.report(pos, "break outside a loop");
|
||||
|
@ -1713,7 +1766,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
if self.errors.borrow().is_empty() {
|
||||
self.ci.nodes.graphviz();
|
||||
self.graphviz();
|
||||
self.gcm();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -1727,7 +1780,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
//self.ci.nodes.basic_blocks();
|
||||
self.ci.nodes.graphviz();
|
||||
self.graphviz();
|
||||
|
||||
let mut stack_size = 0;
|
||||
'_compute_stack: {
|
||||
|
@ -1941,10 +1994,12 @@ impl Codegen {
|
|||
debug_assert_eq!(size, 8, "TODO");
|
||||
let (base, offset) = match func.nodes[region].kind {
|
||||
Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset + offset),
|
||||
Kind::Arg { .. } => {
|
||||
(atr(allocs[1]), func.nodes[region].offset + offset)
|
||||
}
|
||||
k => unreachable!("{k:?}"),
|
||||
};
|
||||
let &[dst] = allocs else { unreachable!() };
|
||||
self.ci.emit(instrs::ld(atr(dst), base, offset as _, size as _));
|
||||
self.ci.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _));
|
||||
}
|
||||
Kind::Stre { offset } => {
|
||||
let region = func.nodes.trace_mem(node.inputs[2]);
|
||||
|
@ -2484,15 +2539,12 @@ impl<'a> Function<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Kind::Phi | Kind::Arg { .. } | Kind::Mem => {}
|
||||
Kind::Stck => {
|
||||
let ops = vec![self.drg(nid)];
|
||||
self.add_instr(nid, ops);
|
||||
}
|
||||
Kind::Stck | Kind::Phi | Kind::Arg { .. } | Kind::Mem => {}
|
||||
Kind::Ptr { .. } => {
|
||||
let region = self.nodes.trace_mem(node.inputs[1]);
|
||||
let ops = match self.nodes[region].kind {
|
||||
Kind::Stck => vec![self.drg(nid)],
|
||||
Kind::Arg { .. } => vec![self.drg(nid), self.urg(region)],
|
||||
k => unreachable!("{k:?}"),
|
||||
};
|
||||
self.add_instr(nid, ops);
|
||||
|
@ -2501,6 +2553,7 @@ impl<'a> Function<'a> {
|
|||
let region = self.nodes.trace_mem(node.inputs[1]);
|
||||
let ops = match self.nodes[region].kind {
|
||||
Kind::Stck => vec![self.drg(nid)],
|
||||
Kind::Arg { .. } => vec![self.drg(nid), self.urg(region)],
|
||||
k => unreachable!("{k:?}"),
|
||||
};
|
||||
self.add_instr(nid, ops);
|
||||
|
@ -2833,7 +2886,8 @@ mod tests {
|
|||
};
|
||||
|
||||
fn generate(ident: &'static str, input: &'static str, output: &mut String) {
|
||||
_ = env_logger::builder().is_test(true).try_init();
|
||||
_ = log::set_logger(&crate::fs::Logger);
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
|
||||
let mut codegen =
|
||||
super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() };
|
||||
|
|
51
pointers.hb
Normal file
51
pointers.hb
Normal file
|
@ -0,0 +1,51 @@
|
|||
Point := struct {
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
||||
|
||||
Rect := struct {
|
||||
min: Point,
|
||||
max: Point,
|
||||
}
|
||||
|
||||
main := fn(): void {
|
||||
rect := Rect.(.(0, 0), .(0, 0))
|
||||
// eliminates initila 0
|
||||
rect.min.x = 1
|
||||
// here as well
|
||||
rect.min.y = 2
|
||||
// eliminates previous 2 lines, intermidiate stack slot is created, and stores are
|
||||
// delegated to the rect
|
||||
rect.min = .(3, 4)
|
||||
|
||||
// encompasses the previous two loads
|
||||
ptr := &rect.min
|
||||
// pointer escapes to a function -> rect.min now has unknown values
|
||||
clobber(ptr)
|
||||
|
||||
// this can not be folded but load can be reused
|
||||
rect.max.x = rect.min.x * rect.min.x
|
||||
|
||||
// this should invalidate the previous loads
|
||||
clobber(ptr)
|
||||
// now all stores are clobbered
|
||||
clobber(&rect.max)
|
||||
|
||||
// conslusion: pointers fundamentally dont do anything and are not registered anywhere,
|
||||
// thay are just bound to the base memory and when you interact with them (store, load)
|
||||
// they modity the memory state, they are literally a view trought which we look at the
|
||||
// memory and remotely modify it, so in summary, pointers are not bound to a specific load
|
||||
// or store, but they can invalidate them.
|
||||
//
|
||||
// The fact pointers are bound to the base memory also makes it easy to tell how aliasing works
|
||||
// for the pointer, we prohibit pointer arithmetic on these pointers, instead this is delegated
|
||||
// to special pointer type that can only be created when compiler can prove ist safe or explicitly
|
||||
// with a directive
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
clobber := fn(p: ^Point): void {
|
||||
*p = .(5, 6)
|
||||
return
|
||||
}
|
Loading…
Reference in a new issue