diff --git a/Cargo.lock b/Cargo.lock index 7698ffc..0d6e0db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,35 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "const-random", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "argh" version = "0.1.12" @@ -50,7 +21,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.63", + "syn", ] [[package]] @@ -62,134 +33,6 @@ dependencies = [ "serde", ] -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "cc" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "color-eyre" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "hbasm" -version = "0.1.0" -dependencies = [ - "paste", - "rhai", - "with_builtin_macros", -] - [[package]] name = "hbbytecode" version = "0.1.0" @@ -220,39 +63,12 @@ dependencies = [ "memmap2", ] -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - [[package]] name = "memmap2" version = "0.9.4" @@ -262,57 +78,12 @@ dependencies = [ "libc", ] -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - [[package]] name = "proc-macro2" version = "1.0.82" @@ -331,40 +102,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rhai" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7d88770120601ba1e548bb6bc2a05019e54ff01b51479e38e64ec3b59d4759" -dependencies = [ - "ahash", - "bitflags", - "instant", - "num-traits", - "once_cell", - "rhai_codegen", - "smallvec", - "smartstring", - "thin-vec", -] - -[[package]] -name = "rhai_codegen" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59aecf17969c04b9c0c5d21f6bc9da9fec9dd4980e64d1871443a476589d8c86" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.63", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "serde" version = "1.0.202" @@ -382,50 +119,7 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "syn", ] [[package]] @@ -439,141 +133,16 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "thin-vec" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "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", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "with_builtin_macros" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a59d55032495429b87f9d69954c6c8602e4d3f3e0a747a12dea6b0b23de685da" -dependencies = [ - "with_builtin_macros-proc_macros", -] - -[[package]] -name = "with_builtin_macros-proc_macros" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bd7679c15e22924f53aee34d4e448c45b674feb6129689af88593e129f8f42" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "xtask" version = "0.1.0" dependencies = [ "argh", - "color-eyre", "once_cell", ] - -[[package]] -name = "zerocopy" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.63", -] diff --git a/Cargo.toml b/Cargo.toml index 539119e..04c812b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] resolver = "2" -members = ["hbasm", "hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit"] +members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit"] diff --git a/hbasm/Cargo.toml b/hbasm/Cargo.toml deleted file mode 100644 index 3cac566..0000000 --- a/hbasm/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "hbasm" -version = "0.1.0" -edition = "2021" - -[dependencies] -paste = "1.0" -rhai = "1.16" -with_builtin_macros = "0.0.3" diff --git a/hbasm/examples/ableos/main.rhai b/hbasm/examples/ableos/main.rhai deleted file mode 100644 index 0302a2c..0000000 --- a/hbasm/examples/ableos/main.rhai +++ /dev/null @@ -1,13 +0,0 @@ -import "hbasm/examples/ableos/std" as std; - -fn main(){ - std::Error(":+)"); - std::Warn("Your mom fell in a well!"); - std::Info("Hello, world!"); - std::Debug("ABC"); - std::Trace("Trace Deez"); - - tx(); -} - -main(); \ No newline at end of file diff --git a/hbasm/examples/ableos/std.rhai b/hbasm/examples/ableos/std.rhai deleted file mode 100644 index 5ff9dee..0000000 --- a/hbasm/examples/ableos/std.rhai +++ /dev/null @@ -1,24 +0,0 @@ -fn ipc_send(buffer_id, mem_addr, length){ - // set the ecall - li8(r1, 3); - // Set the buffer ID to be the BufferID - li64(r2, buffer_id); - lra(r3, r0, mem_addr); - // set the length - li64(r4, length); - // ecall - eca(); -} - -private fn log(log_level, string){ - let str = data::str(string); - ipc_send(1, str, str.len); -} - -fn Error(string) {log(0, string);} -fn Warn(string) {log(1, string);} -fn Info(string) {log(2, string);} -// Due to rhai limitations this cannot be debug -// because of this all of the log levels are upper case -fn Debug(string) {log(3, string);} -fn Trace(string) {log(4, string);} diff --git a/hbasm/examples/hello-linux.rhai b/hbasm/examples/hello-linux.rhai deleted file mode 100644 index 326a80a..0000000 --- a/hbasm/examples/hello-linux.rhai +++ /dev/null @@ -1,9 +0,0 @@ -let hello = data::str("Hello, world!"); - -li8 (r1, 1); // Write syscall -li8 (r2, 1); // Stdout FD -lra16 (r3, r0, hello); // String buffer -li8 (r4, hello.len); // String length -eca (); // System call - -tx (); // End program \ No newline at end of file diff --git a/hbasm/examples/macros.rhai b/hbasm/examples/macros.rhai deleted file mode 100644 index afd7bd2..0000000 --- a/hbasm/examples/macros.rhai +++ /dev/null @@ -1,33 +0,0 @@ -li8(r1, 69); -li8(r2, 0); - -if_eq(r1, r2, - || puts("Equals!"), - || puts("Not equals!"), -); - - -tx(); // END OF MAIN - -/// Inline function – write text to stdout -fn puts(string) { - let d = data::str(string); - li8 (r1, 1); // Write syscall - li8 (r2, 1); // Stdout handle - lra16 (r3, r0, d); - li64 (r4, d.len); - eca (); -} - -fn if_eq(a, b, thenblk, elseblk) { - let elselbl = declabel(); - let endlbl = declabel(); - - jne(a, b, elselbl); - thenblk.call(); - jmp16(endlbl); - - elselbl.here(); - elseblk.call(); - endlbl.here(); -} \ No newline at end of file diff --git a/hbasm/src/data.rs b/hbasm/src/data.rs deleted file mode 100644 index 16e00f4..0000000 --- a/hbasm/src/data.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Data section inserts - -use { - crate::{object::SymbolRef, SharedObject}, - rhai::{CustomType, Engine, FuncRegistration, ImmutableString, Module}, -}; - -/// Generate insertions for data types -/// -/// `gen_data_instructions!($module, $obj, [$type, …]);` -/// - `$module`: Rhai module -/// - `$obj`: Code object -/// - `$type`: Type of single array item -macro_rules! gen_data_insertions { - ($module:expr, $obj:expr, [$($ty:ident),* $(,)?] $(,)?) => {{ - let (module, obj) = ($module, $obj); - $({ - // Clone object to each function - let obj = ::std::rc::Rc::clone(obj); - - FuncRegistration::new(stringify!($ty)) - .with_namespace(rhai::FnNamespace::Global) - .set_into_module::<_, 1, false, _, true, _>(module, move |arr: ::rhai::Array| { - let obj = &mut *obj.borrow_mut(); - let symbol = obj.symbol($crate::object::Section::Data); - - // Reserve space for object so we don't resize it - // all the time - obj.sections - .data - .reserve(arr.len() * ::std::mem::size_of::<$ty>()); - - // For every item… - for item in arr { - // … try do conversions from i32 to desired type - // and insert it. - obj.sections.data.extend( - match item.as_int() { - Ok(num) => $ty::try_from(num).map_err(|_| "i64".to_owned()), - Err(ty) => Err(ty.to_owned()), - } - .map_err(|err| { - - ::rhai::EvalAltResult::ErrorMismatchDataType( - stringify!($ty).to_owned(), - err, - ::rhai::Position::NONE, - ) - })? - .to_le_bytes(), - ); - } - - Ok(DataRef { - symbol, - len: obj.sections.data.len() - symbol.0, - }) - }); - })* - }}; -} - -/// Reference to entry in data section -#[derive(Clone, Copy, Debug)] -pub struct DataRef { - pub symbol: SymbolRef, - pub len: usize, -} - -impl CustomType for DataRef { - fn build(mut builder: rhai::TypeBuilder) { - builder - .with_name("DataRef") - .with_get("symbol", |this: &mut Self| this.symbol) - .with_get("len", |this: &mut Self| this.len as u64 as i64); - } -} - -pub fn module(engine: &mut Engine, obj: SharedObject) -> Module { - let mut module = Module::new(); - - gen_data_insertions!(&mut module, &obj, [i8, i16, i32, i64]); - - // Specialisation for strings, they should be - // inserted as plain UTF-8 arrays - FuncRegistration::new("str") - .with_namespace(rhai::FnNamespace::Global) - .set_into_module::<_, 1, false, _, true, _>(&mut module, move |s: ImmutableString| { - let obj = &mut *obj.borrow_mut(); - let symbol = obj.symbol(crate::object::Section::Data); - - obj.sections.data.extend(s.as_bytes()); - Ok(DataRef { - symbol, - len: s.len(), - }) - }); - - engine.build_type::(); - module -} diff --git a/hbasm/src/ins.rs b/hbasm/src/ins.rs deleted file mode 100644 index 4b4a240..0000000 --- a/hbasm/src/ins.rs +++ /dev/null @@ -1,321 +0,0 @@ -//! Functions for inserting instructions -//! -//! Most of the code you see is just metaprogramming stuff. -//! This ensures that adding new instructions won't need any -//! specific changes and consistent behaviour. -//! -//! > I tried to comment stuff here, but I meanwhile forgor how it works. -//! -//! — Erin - -use { - crate::object::Object, - rhai::{FuncRegistration, Module}, - std::{cell::RefCell, rc::Rc}, -}; - -/// Operand types and their insertions -pub mod optypes { - use { - crate::{ - label::UnboundLabel, - object::{Object, RelocKey, RelocType, SymbolRef}, - }, - rhai::{Dynamic, EvalAltResult, ImmutableString, Position}, - }; - - // These types represent operand types to be inserted - pub type R = u8; - pub type B = i8; - pub type H = i16; - pub type W = i32; - pub type D = i64; - - pub type A = Dynamic; - pub type O = Dynamic; - pub type P = Dynamic; - - /// Insert relocation into code - /// - /// - If integer, just write it to the code - /// - Otherwise insert entry into relocation table - /// and fill zeroes - pub fn insert_reloc( - obj: &mut Object, - ty: RelocType, - val: &Dynamic, - ) -> Result<(), EvalAltResult> { - match () { - // Direct references – insert directly to table - _ if val.is::() => { - obj.relocation(RelocKey::Symbol(val.clone_cast::().0), ty) - } - _ if val.is::() => { - obj.relocation(RelocKey::Symbol(val.clone_cast::().0), ty) - } - _ if val.is::() => { - obj.relocation(RelocKey::Symbol(val.clone_cast::().symbol.0), ty) - } - - // String (indirect) reference - _ if val.is_string() => { - obj.relocation(RelocKey::Label(val.clone_cast::()), ty) - } - - // Manual offset - _ if val.is_int() => { - let int = val.clone_cast::(); - match ty { - RelocType::Rel32 => obj.sections.text.extend((int as i32).to_le_bytes()), - RelocType::Rel16 => obj.sections.text.extend((int as i16).to_le_bytes()), - RelocType::Abs64 => obj.sections.text.extend(int.to_le_bytes()), - } - } - - _ => { - return Err(EvalAltResult::ErrorMismatchDataType( - "SymbolRef, UnboundLabel, String or Int".to_owned(), - val.type_name().to_owned(), - Position::NONE, - )) - } - } - - Ok(()) - } - - /// Generate macro for inserting item into the output object - /// - /// Pre-defines inserts for absolute address and relative offsets. - /// These are inserted with function [`insert_reloc`] - /// # le_bytes - /// `gen_insert!(le_bytes: [B, …]);` - /// - /// Takes sequence of operand types which should be inserted - /// by invoking `to_le_bytes` method on it. - macro_rules! gen_insert { - (le_bytes: [$($lety:ident),* $(,)?]) => { - /// `insert!($thing, $obj, $type)` where - /// - `$thing`: Value you want to insert - /// - `$obj`: Code object - /// - `$type`: Type of inserted value - /// - /// Eg. `insert!(69_u8, obj, B);` - macro_rules! insert { - $(($thing:expr, $obj: expr, $lety) => { - $obj.sections.text.extend($thing.to_le_bytes()); - };)* - - ($thing:expr, $obj:expr, A) => { - $crate::ins::optypes::insert_reloc( - $obj, - $crate::object::RelocType::Abs64, - $thing - )? - }; - ($thing:expr, $obj:expr, O) => { - $crate::ins::optypes::insert_reloc( - $obj, - $crate::object::RelocType::Rel32, - $thing - )? - }; - ($thing:expr, $obj:expr, P) => { - $crate::ins::optypes::insert_reloc( - $obj, - $crate::object::RelocType::Rel16, - $thing - )? - }; - } - }; - } - - gen_insert!(le_bytes: [R, B, H, W, D]); - - #[allow(clippy::single_component_path_imports)] - pub(super) use insert; - - use crate::data::DataRef; -} - -/// Rhai Types (types for function parameters as Rhai uses only 64bit signed integers) -pub mod rity { - pub use super::optypes::{A, O, P, R}; - pub type B = i64; - pub type H = i64; - pub type W = i64; - pub type D = i64; -} - -/// Generic instruction (instruction of certain operands type) inserts -pub mod generic { - use {crate::object::Object, rhai::EvalAltResult}; - - pub(super) fn convert_op(from: A) -> Result - where - B: TryFrom, - >::Error: std::error::Error + Sync + Send + 'static, - { - B::try_from(from).map_err(|e| { - EvalAltResult::ErrorSystem("Data conversion error".to_owned(), Box::new(e)) - }) - } - - /// Generate opcode-generic instruction insert macro - macro_rules! gen_ins { - ($($($name:ident : $ty:ty),*;)*) => { - paste::paste! { - $( - /// Instruction-generic opcode insertion function - /// - `obj`: Code object - /// - `opcode`: opcode, not checked if valid for instruction type - /// - … for operands - #[inline] - pub fn [<$($ty:lower)*>]( - obj: &mut Object, - opcode: u8, - $($name: $crate::ins::optypes::$ty),*, - ) -> Result<(), EvalAltResult> { - // Push opcode - obj.sections.text.push(opcode); - - // Insert based on type - $($crate::ins::optypes::insert!(&$name, obj, $ty);)* - Ok(()) - } - )* - - /// Generate Rhai opcode-specific instruction insertion functions - /// - /// `gen_ins_fn!($obj, $opcode, $optype);` where: - /// - `$obj`: Code object - /// - `$opcode`: Opcode value - macro_rules! gen_ins_fn { - $( - ($obj:expr, $opcode:expr, [<$($ty)*>]) => { - // Opcode-specific insertion function - // - Parameters = operands - move |$($name: $crate::ins::rity::$ty),*| { - // Invoke generic function - $crate::ins::generic::[<$($ty:lower)*>]( - &mut *$obj.borrow_mut(), - $opcode, - $( - // Convert to desired type (from Rhai-provided values) - $crate::ins::generic::convert_op::< - _, - $crate::ins::optypes::$ty - >($name)? - ),* - )?; - Ok(()) - } - }; - - // Internal-use: count args - (@arg_count [<$($ty)*>]) => { - { ["", $(stringify!($ty)),*].len() - 1 } - }; - )* - - // Specialisation for no-operand instructions - ($obj:expr, $opcode:expr, N) => { - move || { - $crate::ins::generic::n(&mut *$obj.borrow_mut(), $opcode); - Ok(()) - } - }; - - // Internal-use specialisation: no-operand instructions - (@arg_count N) => { - { 0 } - }; - } - } - }; - } - - /// Specialisation for no-operand instructions – simply just push opcode - #[inline] - pub fn n(obj: &mut Object, opcode: u8) { - obj.sections.text.push(opcode); - } - - // Generate opcode-generic instruction inserters - // (operand identifiers are arbitrary) - // - // New instruction types have to be added manually here - gen_ins! { - o0: R, o1: R; - o0: R, o1: R, o2: R; - o0: R, o1: R, o2: R, o3: R; - o0: R, o1: R, o2: B; - o0: R, o1: R, o2: H; - o0: R, o1: R, o2: W; - o0: R, o1: R, o2: D; - o0: R, o1: B; - o0: R, o1: H; - o0: R, o1: W; - o0: R, o1: D; - o0: R, o1: R, o2: A; - o0: R, o1: R, o2: A, o3: H; - o0: R, o1: R, o2: O, o3: H; - o0: R, o1: R, o2: P, o3: H; - o0: R, o1: R, o2: O; - o0: R, o1: R, o2: P; - o0: O; - o0: P; - } - - #[allow(clippy::single_component_path_imports)] - pub(super) use gen_ins_fn; -} - -/// Generate instructions from instruction table -/// -/// ```ignore -/// instructions!(($module, $obj) { -/// // Data from instruction table -/// $opcode, $mnemonic, $opty, $doc; -/// … -/// }); -/// ``` -/// - `$module`: Rhai module -/// - `$obj`: Code object -macro_rules! instructions { - ( - ($module:expr, $obj:expr $(,)?) - { $($opcode:expr, $mnemonic:ident, $ops:tt, $doc:literal;)* } - ) => {{ - paste::paste! { - let (module, obj) = ($module, $obj); - $({ - // Object is shared across all functions - let obj = Rc::clone(&obj); - - // Register newly generated function for each instruction - FuncRegistration::new(stringify!([<$mnemonic:lower>])) - .with_namespace(rhai::FnNamespace::Global) - .set_into_module::<_, { generic::gen_ins_fn!(@arg_count $ops) }, false, _, true, _>( - module, - generic::gen_ins_fn!( - obj, - $opcode, - $ops - ) - ); - })* - } - }}; -} - -/// Setup instruction insertors -pub fn setup(module: &mut Module, obj: Rc>) { - // Import instructions table and use it for generation - with_builtin_macros::with_builtin! { - let $spec = include_from_root!("../hbbytecode/instructions.in") in { - instructions!((module, obj) { $spec }); - } - } -} diff --git a/hbasm/src/label.rs b/hbasm/src/label.rs deleted file mode 100644 index 86142df..0000000 --- a/hbasm/src/label.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Stuff related to labels - -use { - crate::SharedObject, - rhai::{Engine, FuncRegistration, ImmutableString, Module}, -}; - -/// Macro for creating functions for Rhai which -/// is bit more friendly -/// -/// ```ignore -/// shdm_fns!{ -/// module: $module; -/// shared: $shared => $shname; -/// -/// $vis fn $name($param_name: $param_ty, …) -> $ret { … } -/// … -/// } -/// ``` -/// - `$module`: Rhai module -/// - `$shared`: Data to be shared across the functions -/// - `$shname`: The binding name inside functions -/// - `$vis`: Function visibility for Rhai -/// - Lowercased [`rhai::FnNamespace`] variants -/// - `$name`: Function name -/// - `$param_name`: Parameter name -/// - `$param_ty`: Rust parameter type -/// - `$ret`: Optional return type (otherwise infer) -macro_rules! shdm_fns { - ( - module: $module:expr; - shared: $shared:expr => $shname:ident; - - $( - $vis:ident fn $name:ident($($param_name:ident: $param_ty:ty),*) $(-> $ret:ty)? $blk:block - )* - ) => {{ - let module = $module; - let shared = $shared; - paste::paste! { - $({ - - let $shname = SharedObject::clone(&shared); - - FuncRegistration::new(stringify!($name)) - .with_namespace(rhai::FnNamespace::[<$vis:camel>]) - .set_into_module::<_, { ["", $(stringify!($param_name)),*].len() - 1 }, false, _, true, _>( - module, - move |$($param_name: $param_ty),*| $(-> $ret)? { - let mut $shname = $shname.borrow_mut(); - $blk - } - ); - })* - } - }}; -} - -/// Label without any place bound -#[derive(Clone, Copy, Debug)] -pub struct UnboundLabel(pub usize); - -pub fn setup(engine: &mut Engine, module: &mut Module, object: SharedObject) { - shdm_fns! { - module: module; - shared: object => obj; - - // Insert unnamed label - global fn label() { - let symbol = obj.symbol(crate::object::Section::Text); - Ok(symbol) - } - - // Insert string-labeled label - global fn label(label: ImmutableString) { - let symbol = obj.symbol(crate::object::Section::Text); - obj.labels.insert(label, symbol.0); - - Ok(symbol) - } - - // Declare unbound label (to be bound later) - global fn declabel() { - let index = obj.symbols.len(); - obj.symbols.push(None); - - Ok(UnboundLabel(index)) - } - - // Declare unbound label (to be bound later) - // with string label - global fn declabel(label: ImmutableString) { - let index = obj.symbols.len(); - obj.symbols.push(None); - obj.labels.insert(label, index); - - Ok(UnboundLabel(index)) - } - - // Set location for unbound label - global fn here(label: UnboundLabel) { - obj.symbols[label.0] = Some(crate::object::SymbolEntry { - location: crate::object::Section::Text, - offset: obj.sections.text.len(), - }); - - Ok(()) - } - } - - engine.register_type_with_name::("UnboundLabel"); -} diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs deleted file mode 100644 index 21c2910..0000000 --- a/hbasm/src/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -pub mod data; -pub mod ins; -pub mod label; -pub mod linker; -pub mod object; - -use { - object::Object, - rhai::{Engine, Module}, - std::{cell::RefCell, rc::Rc}, -}; - -type SharedObject = Rc>; - -pub fn assembler( - linkout: &mut impl std::io::Write, - loader: impl FnOnce(&mut Engine) -> Result<(), Box>, -) -> Result<(), Box> { - let mut engine = Engine::new(); - let mut module = Module::new(); - let obj = Rc::new(RefCell::new(Object::default())); - ins::setup(&mut module, Rc::clone(&obj)); - label::setup(&mut engine, &mut module, Rc::clone(&obj)); - - // Registers - for n in 0_u8..=255 { - module.set_var(format!("r{n}"), n); - } - - module.set_native_fn("reg", |n: i64| { - Ok(u8::try_from(n).map_err(|_| { - rhai::EvalAltResult::ErrorRuntime("Invalid register value".into(), rhai::Position::NONE) - })?) - }); - - module.set_native_fn("as_i64", |n: u8| Ok(n as i64)); - - let datamod = Rc::new(data::module(&mut engine, SharedObject::clone(&obj))); - engine.register_global_module(Rc::new(module)); - engine.register_static_module("data", datamod); - engine.register_type_with_name::("SymbolRef"); - loader(&mut engine)?; - linker::link(obj, linkout)?; - Ok(()) -} diff --git a/hbasm/src/linker.rs b/hbasm/src/linker.rs deleted file mode 100644 index 8096884..0000000 --- a/hbasm/src/linker.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Simple flat-bytecode linker - -use { - crate::{ - object::{RelocKey, RelocType, Section}, - SharedObject, - }, - std::io::Write, -}; - -pub fn link(object: SharedObject, out: &mut impl Write) -> std::io::Result<()> { - let obj = &mut *object.borrow_mut(); - - // Walk relocation table entries - for (&loc, entry) in &obj.relocs { - let value = match &entry.key { - // Symbol – direct reference - RelocKey::Symbol(sym) => obj.symbols[*sym], - - // Label – indirect label reference - RelocKey::Label(label) => obj.symbols[obj.labels[label]], - } - .ok_or_else(|| std::io::Error::other("Invalid symbol"))?; - - let offset = match value.location { - // Text section is on the beginning - Section::Text => value.offset, - - // Data section follows text section immediately - Section::Data => value.offset + obj.sections.text.len(), - }; - - // Insert address or calulate relative offset - match entry.ty { - RelocType::Rel32 => obj.sections.text[loc..loc + 4] - .copy_from_slice(&((offset as isize - loc as isize) as i32).to_le_bytes()), - RelocType::Rel16 => obj.sections.text[loc..loc + 2] - .copy_from_slice(&((offset as isize - loc as isize) as i16).to_le_bytes()), - RelocType::Abs64 => obj.sections.text[loc..loc + 8] - .copy_from_slice(&(offset as isize - loc as isize).to_le_bytes()), - } - } - - // Write to output - out.write_all(&obj.sections.text)?; - out.write_all(&obj.sections.data) -} diff --git a/hbasm/src/main.rs b/hbasm/src/main.rs deleted file mode 100644 index ca9a258..0000000 --- a/hbasm/src/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::{io::stdout, path::PathBuf}; - -fn main() -> Result<(), Box> { - let path = PathBuf::from(std::env::args().nth(1).ok_or("Missing path")?); - hbasm::assembler(&mut stdout(), |engine| engine.run_file(path))?; - - Ok(()) -} diff --git a/hbasm/src/object.rs b/hbasm/src/object.rs deleted file mode 100644 index 073a808..0000000 --- a/hbasm/src/object.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! Code object - -use {rhai::ImmutableString, std::collections::HashMap}; - -/// Section tabel -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Section { - Text, - Data, -} - -/// Symbol entry (in what section, where) -#[derive(Clone, Copy, Debug)] -pub struct SymbolEntry { - pub location: Section, - pub offset: usize, -} - -/// Relocation table key -#[derive(Clone, Debug)] -pub enum RelocKey { - /// Direct reference - Symbol(usize), - /// Indirect reference - Label(ImmutableString), -} - -/// Relocation type -#[derive(Clone, Copy, Debug)] -pub enum RelocType { - Rel32, - Rel16, - Abs64, -} - -/// Relocation table entry -#[derive(Clone, Debug)] -pub struct RelocEntry { - pub key: RelocKey, - pub ty: RelocType, -} - -/// Object code -#[derive(Clone, Debug, Default)] -pub struct Sections { - pub text: Vec, - pub data: Vec, -} - -/// Object -#[derive(Clone, Debug, Default)] -pub struct Object { - /// Vectors with sections - pub sections: Sections, - /// Symbol table - pub symbols: Vec>, - /// Labels to symbols table - pub labels: HashMap, - /// Relocation table - pub relocs: HashMap, -} - -#[derive(Clone, Copy, Debug)] -#[repr(transparent)] -pub struct SymbolRef(pub usize); - -impl Object { - /// Insert symbol at current location in specified section - pub fn symbol(&mut self, section: Section) -> SymbolRef { - let section_buf = match section { - Section::Text => &mut self.sections.text, - Section::Data => &mut self.sections.data, - }; - - self.symbols.push(Some(SymbolEntry { - location: section, - offset: section_buf.len(), - })); - - SymbolRef(self.symbols.len() - 1) - } - - /// Insert to relocation table and write zeroes to code - pub fn relocation(&mut self, key: RelocKey, ty: RelocType) { - self.relocs - .insert(self.sections.text.len(), RelocEntry { key, ty }); - - self.sections.text.extend(match ty { - RelocType::Rel32 => &[0_u8; 4] as &[u8], - RelocType::Rel16 => &[0; 2], - RelocType::Abs64 => &[0; 8], - }); - } -} diff --git a/hbbytecode/src/lib.rs b/hbbytecode/src/lib.rs index 1d260c1..bcebd5b 100644 --- a/hbbytecode/src/lib.rs +++ b/hbbytecode/src/lib.rs @@ -28,16 +28,14 @@ unsafe impl BytecodeItem for u8 {} pub enum RoundingMode { NearestEven = 0, Truncate = 1, - Up = 2, - Down = 3, + Up = 2, + Down = 3, } impl TryFrom for RoundingMode { type Error = (); fn try_from(value: u8) -> Result { - (value <= 3) - .then(|| unsafe { core::mem::transmute(value) }) - .ok_or(()) + (value <= 3).then(|| unsafe { core::mem::transmute(value) }).ok_or(()) } } diff --git a/hblang/build.rs b/hblang/build.rs index e6f5f25..5cf605c 100644 --- a/hblang/build.rs +++ b/hblang/build.rs @@ -7,10 +7,7 @@ fn main() -> Result<(), Box> { let mut generated = String::new(); - writeln!( - generated, - "#![allow(dead_code)] #![allow(clippy::upper_case_acronyms)]" - )?; + writeln!(generated, "#![allow(dead_code)] #![allow(clippy::upper_case_acronyms)]")?; gen_max_size(&mut generated)?; gen_encodes(&mut generated)?; gen_structs(&mut generated)?; @@ -22,11 +19,7 @@ fn main() -> Result<(), Box> { } fn gen_name_list(generated: &mut String) -> Result<(), Box> { - writeln!( - generated, - "pub const NAMES: [&str; {}] = [", - instructions().count() - )?; + writeln!(generated, "pub const NAMES: [&str; {}] = [", instructions().count())?; for [_, name, _, _] in instructions() { writeln!(generated, " \"{}\",", name.to_lowercase())?; } @@ -59,15 +52,9 @@ fn gen_encodes(generated: &mut String) -> Result<(), Box> let args = comma_sep( iter_args(ty).map(|(i, c)| format!("{}{i}: {}", arg_to_name(c), arg_to_type(c))), ); - writeln!( - generated, - "pub fn {name}({args}) -> (usize, [u8; MAX_SIZE]) {{" - )?; + writeln!(generated, "pub fn {name}({args}) -> (usize, [u8; MAX_SIZE]) {{")?; let arg_names = comma_sep(iter_args(ty).map(|(i, c)| format!("{}{i}", arg_to_name(c)))); - writeln!( - generated, - " unsafe {{ crate::encode({ty}({op}, {arg_names})) }}" - )?; + writeln!(generated, " unsafe {{ crate::encode({ty}({op}, {arg_names})) }}")?; writeln!(generated, "}}")?; } @@ -88,10 +75,7 @@ fn gen_structs(generated: &mut String) -> Result<(), Box> } fn comma_sep(items: impl Iterator) -> String { - items - .map(|item| item.to_string()) - .collect::>() - .join(", ") + items.map(|item| item.to_string()).collect::>().join(", ") } fn instructions() -> impl Iterator { diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 23e3521..b5cb9f9 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -1,24 +1,24 @@ use { + self::reg::{RET_ADDR, STACK_PTR, ZERO}, crate::{ ident::{self, Ident}, instrs::{self, *}, lexer::TokenKind, log, - parser::{self, find_symbol, idfl, Expr, ExprRef, FileId, Pos}, + parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos}, HashMap, }, std::{ops::Range, rc::Rc}, }; -use self::reg::{RET_ADDR, STACK_PTR, ZERO}; - type Offset = u32; type Size = u32; mod stack { - use std::num::NonZeroU32; - - use super::{Offset, Size}; + use { + super::{Offset, Size}, + std::num::NonZeroU32, + }; #[derive(Debug, PartialEq, Eq)] pub struct Id(NonZeroU32); @@ -51,9 +51,9 @@ mod stack { #[derive(PartialEq)] struct Meta { - size: Size, + size: Size, offset: Offset, - rc: u32, + rc: u32, } #[derive(Default)] @@ -65,11 +65,7 @@ mod stack { impl Alloc { pub fn allocate(&mut self, size: Size) -> Id { - self.meta.push(Meta { - size, - offset: 0, - rc: 1, - }); + self.meta.push(Meta { size, offset: 0, rc: 1 }); self.height += size; self.max_height = self.max_height.max(self.height); @@ -91,6 +87,15 @@ mod stack { self.height -= meta.size; } + pub fn dup_id(&mut self, id: &Id) -> Id { + if id.is_ref() { + return id.as_ref(); + } + + self.meta[id.index()].rc += 1; + Id(id.0) + } + pub fn finalize_leaked(&mut self) { for meta in self.meta.iter_mut().filter(|m| m.rc > 0) { meta.offset = self.height; @@ -154,7 +159,7 @@ mod reg { #[derive(Default, PartialEq, Eq)] pub struct Alloc { - free: Vec, + free: Vec, max_used: Reg, } @@ -185,11 +190,12 @@ mod reg { } pub mod ty { - use std::{num::NonZeroU32, ops::Range}; - - use crate::{ - lexer::TokenKind, - parser::{self, Expr}, + use { + crate::{ + lexer::TokenKind, + parser::{self, Expr}, + }, + std::{num::NonZeroU32, ops::Range}, }; pub type Builtin = u32; @@ -205,8 +211,8 @@ pub mod ty { impl Tuple { const LEN_BITS: u32 = 5; - const MAX_LEN: usize = 1 << Self::LEN_BITS; const LEN_MASK: usize = Self::MAX_LEN - 1; + const MAX_LEN: usize = 1 << Self::LEN_BITS; pub fn new(pos: usize, len: usize) -> Option { if len >= Self::MAX_LEN { @@ -420,9 +426,9 @@ pub mod ty { } pub struct Display<'a> { - tys: &'a super::Types, + tys: &'a super::Types, files: &'a [parser::Ast], - ty: Id, + ty: Id, } impl<'a> Display<'a> { @@ -482,11 +488,11 @@ pub mod ty { #[derive(Clone, Copy, Debug)] struct Reloc { - offset: Offset, + offset: Offset, sub_offset: u8, - width: u8, + width: u8, #[cfg(debug_assertions)] - shifted: bool, + shifted: bool, } impl Reloc { @@ -539,37 +545,25 @@ impl Reloc { } struct Value { - ty: ty::Id, + ty: ty::Id, loc: Loc, } impl Value { fn new(ty: impl Into, loc: impl Into) -> Self { - Self { - ty: ty.into(), - loc: loc.into(), - } + Self { ty: ty.into(), loc: loc.into() } } fn void() -> Self { - Self { - ty: ty::VOID.into(), - loc: Loc::imm(0), - } + Self { ty: ty::VOID.into(), loc: Loc::imm(0) } } fn imm(value: u64) -> Self { - Self { - ty: ty::UINT.into(), - loc: Loc::imm(value), - } + Self { ty: ty::UINT.into(), loc: Loc::imm(value) } } fn ty(ty: ty::Id) -> Self { - Self { - ty: ty::TYPE.into(), - loc: Loc::ct((ty.repr() as u64).to_ne_bytes()), - } + Self { ty: ty::TYPE.into(), loc: Loc::ct((ty.repr() as u64).to_ne_bytes()) } } } @@ -601,36 +595,19 @@ impl<'a> From for LocCow<'a> { #[derive(Debug, PartialEq, Eq)] pub enum Loc { - Rt { - derefed: bool, - reg: reg::Id, - stack: Option, - offset: Offset, - }, - Ct { - value: [u8; 8], - }, + Rt { derefed: bool, reg: reg::Id, stack: Option, offset: Offset }, + Ct { value: [u8; 8] }, } impl Loc { fn stack(stack: stack::Id) -> Self { - Self::Rt { - stack: Some(stack), - reg: reg::STACK_PTR.into(), - derefed: true, - offset: 0, - } + Self::Rt { stack: Some(stack), reg: reg::STACK_PTR.into(), derefed: true, offset: 0 } } fn reg(reg: impl Into) -> Self { let reg = reg.into(); assert!(reg.get() != 0); - Self::Rt { - derefed: false, - reg, - stack: None, - offset: 0, - } + Self::Rt { derefed: false, reg, stack: None, offset: 0 } } fn imm(value: u64) -> Self { @@ -655,12 +632,7 @@ impl Loc { fn as_ref(&self) -> Self { match *self { - Loc::Rt { - derefed, - ref reg, - ref stack, - offset, - } => Loc::Rt { + Loc::Rt { derefed, ref reg, ref stack, offset } => Loc::Rt { derefed, reg: reg.as_ref(), stack: stack.as_ref().map(stack::Id::as_ref), @@ -715,61 +687,53 @@ impl Default for Loc { } struct Loop { - var_count: u32, - offset: u32, + var_count: u32, + offset: u32, reloc_base: u32, } struct Variable { - id: Ident, + id: Ident, value: Value, } #[derive(Default)] struct ItemCtx { - file: FileId, - id: ty::Kind, - ret: ty::Id, + file: FileId, + id: ty::Kind, + ret: ty::Id, ret_reg: reg::Id, task_base: usize, - snap: Snapshot, + snap: Snapshot, stack: stack::Alloc, - regs: reg::Alloc, + regs: reg::Alloc, stack_relocs: Vec, - ret_relocs: Vec, - loop_relocs: Vec, - loops: Vec, - vars: Vec, + ret_relocs: Vec, + loop_relocs: Vec, + loops: Vec, + vars: Vec, } impl ItemCtx { - // pub fn dup_loc(&mut self, loc: &Loc) -> Loc { - // match *loc { - // Loc::Rt { - // derefed, - // ref reg, - // ref stack, - // offset, - // } => Loc::Rt { - // reg: reg.as_ref(), - // derefed, - // stack: stack.as_ref().map(|s| self.stack.dup_id(s)), - // offset, - // }, - // Loc::Ct { value } => Loc::Ct { value }, - // } - // } + pub fn dup_loc(&mut self, loc: &Loc) -> Loc { + match *loc { + Loc::Rt { derefed, ref reg, ref stack, offset } => Loc::Rt { + reg: reg.as_ref(), + derefed, + stack: stack.as_ref().map(|s| self.stack.dup_id(s)), + offset, + }, + Loc::Ct { value } => Loc::Ct { value }, + } + } fn finalize(&mut self, output: &mut Output) { let len = output.code.len() as Offset; let base = self.snap.code as Offset; - for reloc in output - .reloc_iter_mut(&self.snap) - .chain(&mut self.ret_relocs) - { + for reloc in output.reloc_iter_mut(&self.snap).chain(&mut self.ret_relocs) { #[cfg(debug_assertions)] { if std::mem::replace(&mut reloc.shifted, true) { @@ -807,10 +771,7 @@ impl ItemCtx { let mut exmpl = Output::default(); exmpl.emit_prelude(); - debug_assert_eq!( - exmpl.code.as_slice(), - &output.code[self.snap.code..][..exmpl.code.len()], - ); + debug_assert_eq!(exmpl.code.as_slice(), &output.code[self.snap.code..][..exmpl.code.len()],); write_reloc(&mut output.code, allocate(3), -(pushed + stack), 8); write_reloc(&mut output.code, allocate(8 + 3), stack, 8); @@ -837,41 +798,38 @@ fn write_reloc(doce: &mut [u8], offset: usize, value: i64, size: u16) { #[derive(PartialEq, Eq, Hash)] struct SymKey { - file: u32, + file: u32, ident: u32, } impl SymKey { pub fn pointer_to(ty: ty::Id) -> Self { - Self { - file: u32::MAX, - ident: ty.repr(), - } + Self { file: u32::MAX, ident: ty.repr() } } } #[derive(Clone, Copy)] struct Sig { args: ty::Tuple, - ret: ty::Id, + ret: ty::Id, } #[derive(Clone, Copy)] struct Func { - file: FileId, - expr: ExprRef, - sig: Option, + file: FileId, + expr: ExprRef, + sig: Option, offset: Offset, } struct Global { offset: Offset, - ty: ty::Id, + ty: ty::Id, } struct Field { name: Rc, - ty: ty::Id, + ty: ty::Id, } struct Struct { @@ -898,11 +856,11 @@ impl ParamAlloc { struct Types { syms: HashMap, - funcs: Vec, - args: Vec, + funcs: Vec, + args: Vec, globals: Vec, structs: Vec, - ptrs: Vec, + ptrs: Vec, } impl Types { @@ -910,19 +868,14 @@ impl Types { ParamAlloc(2 + (9..=16).contains(&self.size_of(ret.into())) as u8..12) } - fn offset_of(&self, idx: ty::Struct, field: Result<&str, usize>) -> Option<(Offset, ty::Id)> { + fn offset_of(&self, idx: ty::Struct, field: &str) -> Option<(Offset, ty::Id)> { let record = &self.structs[idx as usize]; - let until = match field { - Ok(str) => record.fields.iter().position(|f| f.name.as_ref() == str)?, - Err(i) => i, - }; - + let until = record.fields.iter().position(|f| f.name.as_ref() == field)?; let mut offset = 0; for &Field { ty, .. } in &record.fields[..until] { offset = Self::align_up(offset, self.align_of(ty)); offset += self.size_of(ty); } - Some((offset, record.fields[until].ty)) } @@ -1001,25 +954,25 @@ mod task { struct FTask { file: FileId, - id: ty::Func, + id: ty::Func, } #[derive(Default, Clone, Copy, PartialEq, Eq, Debug)] pub struct Snapshot { - code: usize, + code: usize, string_data: usize, - funcs: usize, - globals: usize, - strings: usize, + funcs: usize, + globals: usize, + strings: usize, } #[derive(Default)] struct Output { - code: Vec, + code: Vec, string_data: Vec, - funcs: Vec<(ty::Func, Reloc)>, - globals: Vec<(ty::Global, Reloc)>, - strings: Vec, + funcs: Vec<(ty::Func, Reloc)>, + globals: Vec<(ty::Global, Reloc)>, + strings: Vec, } impl Output { @@ -1040,12 +993,7 @@ impl Output { "{:08x}: {}: {}", self.code.len(), name, - instr - .iter() - .take(len) - .skip(1) - .map(|b| format!("{:02x}", b)) - .collect::() + instr.iter().take(len).skip(1).map(|b| format!("{:02x}", b)).collect::() ); self.code.extend_from_slice(&instr[..len]); } @@ -1065,11 +1013,7 @@ impl Output { .iter_mut() .chain(&mut self.funcs[snap.funcs..]) .map(|(_, rel)| rel) - .chain( - self.strings[snap.strings..] - .iter_mut() - .map(|rl| &mut rl.reloc), - ) + .chain(self.strings[snap.strings..].iter_mut().map(|rl| &mut rl.reloc)) } fn append(&mut self, val: &mut Self) { @@ -1080,38 +1024,30 @@ impl Output { let init_code = stash.code.len(); stash.code.extend(self.code.drain(snap.code..)); - stash - .string_data - .extend(self.string_data.drain(snap.string_data..)); - stash - .funcs - .extend(self.funcs.drain(snap.funcs..).inspect(|(_, rel)| { - #[cfg(debug_assertions)] - assert!(!rel.shifted); - debug_assert!( - rel.offset as usize + init_code < stash.code.len(), - "{} {} {}", - rel.offset, - init_code, - stash.code.len() - ) - })); - stash - .globals - .extend(self.globals.drain(snap.globals..).inspect(|(_, rel)| { - log::dbg!( - "reloc: {rel:?} {init_code} {} {} {}", - stash.code.len(), - self.code.len(), - snap.code - ); - debug_assert!(rel.offset as usize + init_code < stash.code.len()) - })); - stash - .strings - .extend(self.strings.drain(snap.strings..).inspect(|str| { - debug_assert!(str.reloc.offset as usize + init_code < stash.code.len()) - })); + stash.string_data.extend(self.string_data.drain(snap.string_data..)); + stash.funcs.extend(self.funcs.drain(snap.funcs..).inspect(|(_, rel)| { + #[cfg(debug_assertions)] + assert!(!rel.shifted); + debug_assert!( + rel.offset as usize + init_code < stash.code.len(), + "{} {} {}", + rel.offset, + init_code, + stash.code.len() + ) + })); + stash.globals.extend(self.globals.drain(snap.globals..).inspect(|(_, rel)| { + log::dbg!( + "reloc: {rel:?} {init_code} {} {} {}", + stash.code.len(), + self.code.len(), + snap.code + ); + debug_assert!(rel.offset as usize + init_code < stash.code.len()) + })); + stash.strings.extend(self.strings.drain(snap.strings..).inspect(|str| { + debug_assert!(str.reloc.offset as usize + init_code < stash.code.len()) + })); } fn trunc(&mut self, snap: &Snapshot) { @@ -1130,11 +1066,11 @@ impl Output { fn snap(&mut self) -> Snapshot { Snapshot { - code: self.code.len(), + code: self.code.len(), string_data: self.string_data.len(), - funcs: self.funcs.len(), - globals: self.globals.len(), - strings: self.strings.len(), + funcs: self.funcs.len(), + globals: self.globals.len(), + strings: self.strings.len(), } } } @@ -1142,45 +1078,33 @@ impl Output { #[derive(Default, Debug)] struct Ctx { loc: Option, - ty: Option, + ty: Option, } impl Ctx { pub fn with_loc(self, loc: Loc) -> Self { - Self { - loc: Some(loc), - ..self - } + Self { loc: Some(loc), ..self } } pub fn with_ty(self, ty: impl Into) -> Self { - Self { - ty: Some(ty.into()), - ..self - } + Self { ty: Some(ty.into()), ..self } } fn into_value(self) -> Option { - Some(Value { - ty: self.ty.unwrap(), - loc: self.loc?, - }) + Some(Value { ty: self.ty.unwrap(), loc: self.loc? }) } } impl From for Ctx { fn from(value: Value) -> Self { - Self { - loc: Some(value.loc), - ty: Some(value.ty), - } + Self { loc: Some(value.loc), ty: Some(value.ty) } } } #[derive(Default)] struct Pool { - cis: Vec, - outputs: Vec, + cis: Vec, + outputs: Vec, arg_locs: Vec, } @@ -1250,7 +1174,7 @@ impl hbvm::mem::Memory for LoggedMem { const VM_STACK_SIZE: usize = 1024 * 1024 * 2; struct Comptime { - vm: hbvm::Vm, + vm: hbvm::Vm, _stack: Box<[u8; VM_STACK_SIZE]>, } @@ -1261,23 +1185,17 @@ impl Default for Comptime { let ptr = unsafe { stack.as_mut_ptr().cast::().add(VM_STACK_SIZE) as u64 }; log::dbg!("stack_ptr: {:x}", ptr); vm.write_reg(STACK_PTR, ptr); - Self { - vm, - _stack: unsafe { stack.assume_init() }, - } + Self { vm, _stack: unsafe { stack.assume_init() } } } } enum Trap { - MakeStruct { - file: FileId, - struct_expr: ExprRef, - }, + MakeStruct { file: FileId, struct_expr: ExprRef }, } struct StringReloc { - reloc: Reloc, - range: std::ops::Range, + reloc: Reloc, + range: std::ops::Range, #[cfg(debug_assertions)] shifted: bool, } @@ -1285,13 +1203,13 @@ struct StringReloc { #[derive(Default)] pub struct Codegen { pub files: Vec, - tasks: Vec>, + tasks: Vec>, - tys: Types, - ci: ItemCtx, + tys: Types, + ci: ItemCtx, output: Output, - pool: Pool, - ct: Comptime, + pool: Pool, + ct: Comptime, } impl Codegen { @@ -1316,10 +1234,7 @@ impl Codegen { fn build_struct(&mut self, fields: &[(&str, Expr)]) -> ty::Struct { let fields = fields .iter() - .map(|&(name, ty)| Field { - name: name.into(), - ty: self.ty(&ty), - }) + .map(|&(name, ty)| Field { name: name.into(), ty: self.ty(&ty) }) .collect(); self.tys.structs.push(Struct { fields }); self.tys.structs.len() as u32 - 1 @@ -1329,28 +1244,17 @@ impl Codegen { use {Expr as E, TokenKind as T}; let value = match *expr { E::Mod { id, .. } => Some(Value::ty(ty::Kind::Module(id).compress())), - E::Struct { - fields, captured, .. - } => { + E::Struct { fields, captured, .. } => { if captured.is_empty() { - Some(Value::ty( - ty::Kind::Struct(self.build_struct(fields)).compress(), - )) + Some(Value::ty(ty::Kind::Struct(self.build_struct(fields)).compress())) } else { let values = captured .iter() - .map(|&id| E::Ident { - pos: 0, - id, - name: "booodab", - index: u16::MAX, - }) + .map(|&id| E::Ident { pos: 0, id, name: "booodab", index: u16::MAX }) .map(|expr| self.expr(&expr)) .collect::>>()?; - let values_size = values - .iter() - .map(|value| 4 + self.tys.size_of(value.ty)) - .sum::(); + let values_size = + values.iter().map(|value| 4 + self.tys.size_of(value.ty)).sum::(); let stack = self.ci.stack.allocate(values_size); let mut ptr = Loc::stack(stack.as_ref()); @@ -1364,38 +1268,25 @@ impl Codegen { self.stack_offset(2, STACK_PTR, Some(&stack), 0); let val = self.eca( - Trap::MakeStruct { - file: self.ci.file, - struct_expr: ExprRef::new(expr), - }, + Trap::MakeStruct { file: self.ci.file, struct_expr: ExprRef::new(expr) }, ty::TYPE, ); self.ci.free_loc(Loc::stack(stack)); Some(val) } } - E::UnOp { - op: T::Xor, val, .. - } => { + E::UnOp { op: T::Xor, val, .. } => { let val = self.ty(val); Some(Value::ty(self.tys.make_ptr(val))) } - E::Directive { - name: "TypeOf", - args: [expr], - .. - } => { + E::Directive { name: "TypeOf", args: [expr], .. } => { let snap = self.output.snap(); let value = self.expr(expr).unwrap(); self.ci.free_loc(value.loc); self.output.trunc(&snap); Some(Value::ty(value.ty)) } - E::Directive { - name: "eca", - args: [ret_ty, args @ ..], - .. - } => { + E::Directive { name: "eca", args: [ret_ty, args @ ..], .. } => { let ty = self.ty(ret_ty); let mut parama = self.tys.parama(ty); @@ -1417,27 +1308,15 @@ impl Codegen { return Some(Value { ty, loc }); } - E::Directive { - name: "sizeof", - args: [ty], - .. - } => { + E::Directive { name: "sizeof", args: [ty], .. } => { let ty = self.ty(ty); return Some(Value::imm(self.tys.size_of(ty) as _)); } - E::Directive { - name: "alignof", - args: [ty], - .. - } => { + E::Directive { name: "alignof", args: [ty], .. } => { let ty = self.ty(ty); return Some(Value::imm(self.tys.align_of(ty) as _)); } - E::Directive { - name: "intcast", - args: [val], - .. - } => { + E::Directive { name: "intcast", args: [val], .. } => { let Some(ty) = ctx.ty else { self.report( expr.pos(), @@ -1458,11 +1337,7 @@ impl Codegen { Some(Value { ty, loc: val.loc }) } - E::Directive { - name: "bitcast", - args: [val], - .. - } => { + E::Directive { name: "bitcast", args: [val], .. } => { let Some(ty) = ctx.ty else { self.report( expr.pos(), @@ -1496,19 +1371,14 @@ impl Codegen { return Some(Value { ty, loc: val.loc }); } - E::Directive { - name: "as", - args: [ty, val], - .. - } => { + E::Directive { name: "as", args: [ty, val], .. } => { let ty = self.ty(ty); ctx.ty = Some(ty); return self.expr_ctx(val, ctx); } - E::Bool { value, .. } => Some(Value { - ty: ty::BOOL.into(), - loc: Loc::imm(value as u64), - }), + E::Bool { value, .. } => { + Some(Value { ty: ty::BOOL.into(), loc: Loc::imm(value as u64) }) + } E::String { pos, mut literal } => { literal = literal.trim_matches('"'); @@ -1560,11 +1430,7 @@ impl Codegen { decode_braces(self, &mut bytes); continue; } - _ => report( - self, - &bytes, - "unknown escape sequence, expected [nrt\\\"'{0]", - ), + _ => report(self, &bytes, "unknown escape sequence, expected [nrt\\\"'{0]"), }; self.output.string_data.push(b); } @@ -1581,28 +1447,21 @@ impl Codegen { self.output.emit(instrs::lra(reg.get(), 0, 0)); Some(Value::new(self.tys.make_ptr(ty::U8.into()), reg)) } - E::Ctor { - pos, ty, fields, .. - } => { + E::Ctor { pos, ty, fields, .. } => { let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len()); - for (name, field) in fields { - let Some((offset, ty)) = self.tys.offset_of(stuct, Ok(name)) else { + for &CtorField { pos, name, ref value, .. } in fields { + let Some((offset, ty)) = self.tys.offset_of(stuct, name) else { self.report(pos, format_args!("field not found: {name:?}")); }; let loc = loc.as_ref().offset(offset); - let value = self.expr_ctx( - field.as_ref().expect("TODO"), - Ctx::default().with_loc(loc).with_ty(ty), - )?; + let value = self.expr_ctx(value, Ctx::default().with_loc(loc).with_ty(ty))?; self.ci.free_loc(value.loc); } let ty = ty::Kind::Struct(stuct).compress(); return Some(Value { ty, loc }); } - E::Tupl { - pos, ty, fields, .. - } => { + E::Tupl { pos, ty, fields, .. } => { let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len()); let mut offset = 0; let sfields = self.tys.structs[stuct as usize].fields.clone(); @@ -1618,7 +1477,7 @@ impl Codegen { let ty = ty::Kind::Struct(stuct).compress(); return Some(Value { ty, loc }); } - E::Field { target, field } => { + E::Field { target, name: field } => { let checkpoint = self.local_snap(); let mut tal = self.expr(target)?; @@ -1629,13 +1488,10 @@ impl Codegen { match tal.ty.expand() { ty::Kind::Struct(idx) => { - let Some((offset, ty)) = self.tys.offset_of(idx, Ok(field)) else { + let Some((offset, ty)) = self.tys.offset_of(idx, field) else { self.report(target.pos(), format_args!("field not found: {field:?}")); }; - Some(Value { - ty, - loc: tal.loc.offset(offset), - }) + Some(Value { ty, loc: tal.loc.offset(offset) }) } ty::Kind::Builtin(ty::TYPE) => { self.ci.free_loc(tal.loc); @@ -1657,19 +1513,9 @@ impl Codegen { ), } } - E::UnOp { - op: T::Band, - val, - pos, - } => { + E::UnOp { op: T::Band, val, pos } => { let mut val = self.expr(val)?; - let Loc::Rt { - derefed: drfd @ true, - reg, - stack, - offset, - } = &mut val.loc - else { + let Loc::Rt { derefed: drfd @ true, reg, stack, offset } = &mut val.loc else { self.report( pos, format_args!( @@ -1693,20 +1539,13 @@ impl Codegen { // FIXME: we might be able to track this but it will be pain std::mem::forget(stack.take()); - Some(Value { - ty: self.tys.make_ptr(val.ty), - loc: val.loc, - }) + Some(Value { ty: self.tys.make_ptr(val.ty), loc: val.loc }) } - E::UnOp { - op: T::Mul, - val, - pos, - } => { + E::UnOp { op: T::Mul, val, pos } => { let val = self.expr(val)?; match val.ty.expand() { ty::Kind::Ptr(ty) => Some(Value { - ty: self.tys.ptrs[ty as usize].base, + ty: self.tys.ptrs[ty as usize].base, loc: Loc::reg(self.loc_to_reg(val.loc, self.tys.size_of(val.ty))) .into_derefed(), }), @@ -1716,26 +1555,12 @@ impl Codegen { ), } } - E::BinOp { - left: &E::Ident { id, .. }, - op: T::Decl, - right, - } => { - let val = self.expr(right)?; - let mut loc = self.make_loc_owned(val.loc, val.ty); - let sym = parser::find_symbol(&self.cfile().symbols, id); - if sym.flags & idfl::REFERENCED != 0 { - loc = self.spill(loc, self.tys.size_of(val.ty)); - } - self.ci.vars.push(Variable { - id, - value: Value { ty: val.ty, loc }, - }); - Some(Value::void()) + E::BinOp { left, op: T::Decl, right } => { + let value = self.expr(right)?; + + self.assign_pattern(left, value) } - E::Call { - func: fast, args, .. - } => { + E::Call { func: fast, args, .. } => { log::dbg!("call {fast}"); let func_ty = self.ty(fast); let ty::Kind::Func(mut func_id) = func_ty.expand() else { @@ -1744,13 +1569,8 @@ impl Codegen { let func = self.tys.funcs[func_id as usize]; let ast = self.files[func.file as usize].clone(); - let E::BinOp { - right: - &E::Closure { - args: cargs, ret, .. - }, - .. - } = func.expr.get(&ast).unwrap() + let E::BinOp { right: &E::Closure { args: cargs, ret, .. }, .. } = + func.expr.get(&ast).unwrap() else { unreachable!(); }; @@ -1780,33 +1600,27 @@ impl Codegen { arg.loc }; - self.ci.vars.push(Variable { - id: carg.id, - value: Value { ty, loc }, - }); + self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } }); } let args = self.pack_args(expr.pos(), arg_base); let ret = self.ty(ret); self.ci.vars.truncate(scope); - let sym = SymKey { - file: !args.repr(), - ident: func_id, - }; + let sym = SymKey { file: !args.repr(), ident: func_id }; let ct = || { let func_id = self.tys.funcs.len(); self.tys.funcs.push(Func { - file: func.file, + file: func.file, offset: task::id(func_id), - sig: Some(Sig { args, ret }), - expr: func.expr, + sig: Some(Sig { args, ret }), + expr: func.expr, }); self.tasks.push(Some(FTask { // FIXME: this will fuck us file: self.ci.file, - id: func_id as _, + id: func_id as _, })); ty::Kind::Func(func_id as _).compress() @@ -1850,37 +1664,23 @@ impl Codegen { } E::Ident { id, .. } if ident::is_null(id) => Some(Value::ty(id.into())), E::Ident { id, index, .. } - if let Some((var_index, var)) = self - .ci - .vars - .iter_mut() - .enumerate() - .find(|(_, v)| v.id == id) => + if let Some((var_index, var)) = + self.ci.vars.iter_mut().enumerate().find(|(_, v)| v.id == id) => { let sym = parser::find_symbol(&self.files[self.ci.file as usize].symbols, id); let loc = match idfl::index(sym.flags) == index - && !self - .ci - .loops - .last() - .is_some_and(|l| l.var_count > var_index as u32) + && !self.ci.loops.last().is_some_and(|l| l.var_count > var_index as u32) { true => std::mem::take(&mut var.value.loc), false => var.value.loc.as_ref(), }; - Some(Value { - ty: self.ci.vars[var_index].value.ty, - loc, - }) + Some(Value { ty: self.ci.vars[var_index].value.ty, loc }) } E::Ident { id, name, .. } => match self .tys .syms - .get(&SymKey { - ident: id, - file: self.ci.file, - }) + .get(&SymKey { ident: id, file: self.ci.file }) .copied() .map(ty::Kind::from_ty) .unwrap_or_else(|| self.find_or_declare(ident::pos(id), self.ci.file, Ok(id), name)) @@ -1898,9 +1698,7 @@ impl Codegen { }; self.expr_ctx(val, Ctx::default().with_ty(self.ci.ret).with_loc(loc))?; } - self.ci - .ret_relocs - .push(Reloc::new(self.local_offset(), 1, 4)); + self.ci.ret_relocs.push(Reloc::new(self.local_offset(), 1, 4)); self.output.emit(jmp(0)); None } @@ -1911,12 +1709,10 @@ impl Codegen { Some(Value::void()) } E::Number { value, .. } => Some(Value { - ty: ctx.ty.map(ty::Id::strip_pointer).unwrap_or(ty::INT.into()), + ty: ctx.ty.map(ty::Id::strip_pointer).unwrap_or(ty::INT.into()), loc: Loc::imm(value), }), - E::If { - cond, then, else_, .. - } => { + E::If { cond, then, else_, .. } => { log::dbg!("if-cond"); let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?; let reg = self.loc_to_reg(&cond.loc, 1); @@ -1957,8 +1753,8 @@ impl Codegen { let loop_start = self.local_offset(); self.ci.loops.push(Loop { - var_count: self.ci.vars.len() as _, - offset: loop_start, + var_count: self.ci.vars.len() as _, + offset: loop_start, reloc_base: self.ci.loop_relocs.len() as u32, }); let body_unreachable = self.expr(body).is_none(); @@ -1991,9 +1787,7 @@ impl Codegen { Some(Value::void()) } E::Break { .. } => { - self.ci - .loop_relocs - .push(Reloc::shifted(self.local_offset(), 1, 4)); + self.ci.loop_relocs.push(Reloc::shifted(self.local_offset(), 1, 4)); self.output.emit(jmp(0)); None } @@ -2003,11 +1797,7 @@ impl Codegen { self.output.emit(jmp(loop_.offset as i32 - offset as i32)); None } - E::BinOp { - left, - op: op @ (T::And | T::Or), - right, - } => { + E::BinOp { left, op: op @ (T::And | T::Or), right } => { let lhs = self.expr_ctx(left, Ctx::default().with_ty(ty::BOOL))?; let lhs = self.loc_to_reg(lhs.loc, 1); let jump_offset = self.output.code.len() + 3; @@ -2022,12 +1812,9 @@ impl Codegen { let jump = self.output.code.len() as i64 - jump_offset as i64; write_reloc(&mut self.output.code, jump_offset, jump, 2); - Some(Value { - ty: ty::BOOL.into(), - loc: Loc::reg(lhs), - }) + Some(Value { ty: ty::BOOL.into(), loc: Loc::reg(lhs) }) } - E::BinOp { left, op, right } => 'ops: { + E::BinOp { left, op, right } if op != T::Decl => 'ops: { let left = self.expr(left)?; if op == T::Assign { @@ -2085,9 +1872,7 @@ impl Codegen { (lhs.get(), right.ty) }; - let ty::Kind::Ptr(ty) = ty.expand() else { - unreachable!() - }; + let ty::Kind::Ptr(ty) = ty.expand() else { unreachable!() }; let size = self.tys.size_of(self.tys.ptrs[ty as usize].base); self.output.emit(muli64(offset, offset, size as _)); @@ -2122,7 +1907,15 @@ impl Codegen { unimplemented!("{:#?}", op) } E::Comment { .. } => Some(Value::void()), - ast => unimplemented!("{:#?}", ast), + ast => self.report( + ast.pos(), + format_args!( + "compiler does not (yet) konw how to handle:\n\ + {ast:}\n\ + info for weak people:\n\ + {ast:#?}" + ), + ), }?; if let Some(ty) = ctx.ty { @@ -2133,15 +1926,51 @@ impl Codegen { Some(dest) => { let ty = ctx.ty.unwrap_or(value.ty); self.store_typed(value.loc, dest, ty); - Value { - ty, - loc: Loc::imm(0), - } + Value { ty, loc: Loc::imm(0) } } None => value, }) } + fn assign_pattern(&mut self, pat: &Expr, right: Value) -> Option { + match *pat { + Expr::Ident { id, .. } => { + let mut loc = self.make_loc_owned(right.loc, right.ty); + let sym = parser::find_symbol(&self.cfile().symbols, id); + if sym.flags & idfl::REFERENCED != 0 { + loc = self.spill(loc, self.tys.size_of(right.ty)); + } + self.ci.vars.push(Variable { id, value: Value { ty: right.ty, loc } }); + } + Expr::Ctor { pos, fields, .. } => { + let ty::Kind::Struct(idx) = right.ty.expand() else { + self.report(pos, "can't use struct destruct on non struct value (TODO: shold work with modules)"); + }; + + for &CtorField { pos, name, ref value } in fields { + let Some((offset, ty)) = self.tys.offset_of(idx, name) else { + self.report(pos, format_args!("field not found: {name:?}")); + }; + let loc = self.ci.dup_loc(&right.loc).offset(offset); + self.assign_pattern(value, Value::new(ty, loc)); + } + + self.ci.free_loc(right.loc); + } + pat => self.report( + pat.pos(), + format_args!( + "compiler does not (yet) konw how to handle:\n\ + {pat:}\n\ + info for weak people:\n\ + {pat:#?}" + ), + ), + }; + + Some(Value::void()) + } + fn prepare_struct_ctor( &mut self, pos: Pos, @@ -2154,19 +1983,14 @@ impl Codegen { }; let size = self.tys.size_of(ty); - let loc = ctx - .loc - .unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size))); + let loc = ctx.loc.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size))); let ty::Kind::Struct(stuct) = ty.expand() else { self.report(pos, "expected expression to evaluate to struct") }; let field_count = self.tys.structs[stuct as usize].fields.len(); if field_count != field_len { - self.report( - pos, - format_args!("expected {field_count} fields, got {field_len}"), - ); + self.report(pos, format_args!("expected {field_count} fields, got {field_len}")); } (stuct, loc) @@ -2189,10 +2013,7 @@ impl Codegen { for &Field { ty, .. } in self.tys.structs[stuct as usize].fields.clone().iter() { offset = Types::align_up(offset, self.tys.align_of(ty)); let size = self.tys.size_of(ty); - let ctx = Ctx::from(Value { - ty, - loc: loc.as_ref().offset(offset), - }); + let ctx = Ctx::from(Value { ty, loc: loc.as_ref().offset(offset) }); let left = left.as_ref().offset(offset); let right = right.as_ref().offset(offset); let value = self.struct_op(op, ty, ctx, left, right)?; @@ -2213,16 +2034,12 @@ impl Codegen { if let Loc::Ct { value } = right && let Some(op) = Self::imm_math_op(op, signed, size) { - self.output - .emit(op(lhs.get(), lhs.get(), u64::from_ne_bytes(value))); + self.output.emit(op(lhs.get(), lhs.get(), u64::from_ne_bytes(value))); return Some(if let Some(value) = ctx.into_value() { self.store_typed(Loc::reg(lhs.as_ref()), value.loc, value.ty); Value::void() } else { - Value { - ty, - loc: Loc::reg(lhs), - } + Value { ty, loc: Loc::reg(lhs) } }); } @@ -2235,10 +2052,7 @@ impl Codegen { self.store_typed(Loc::reg(lhs), value.loc, value.ty); Some(Value::void()) } else { - Some(Value { - ty, - loc: Loc::reg(lhs), - }) + Some(Value { ty, loc: Loc::reg(lhs) }) }; } @@ -2324,10 +2138,7 @@ impl Codegen { log::dbg!("{}", self.output.globals.len() - self.ci.snap.globals); self.output.emit(instrs::lra(ptr.get(), 0, 0)); - Some(Value { - ty: global.ty, - loc: Loc::reg(ptr).into_derefed(), - }) + Some(Value { ty: global.ty, loc: Loc::reg(ptr).into_derefed() }) } fn spill(&mut self, loc: Loc, size: Size) -> Loc { @@ -2423,10 +2234,7 @@ impl Codegen { true => Loc::ty(self.tys.args[sig_args.next().unwrap()]), false => self.load_arg(sym.flags, ty, &mut parama), }; - self.ci.vars.push(Variable { - id: arg.id, - value: Value { ty, loc }, - }); + self.ci.vars.push(Variable { id: arg.id, value: Value { ty, loc } }); } if self.tys.size_of(self.ci.ret) > 16 { @@ -2466,24 +2274,15 @@ impl Codegen { ..=8 if flags & idfl::REFERENCED == 0 => { (Loc::reg(parama.next()), Loc::reg(self.ci.regs.allocate())) } - 1..=8 => ( - Loc::reg(parama.next()), - Loc::stack(self.ci.stack.allocate(size)), - ), - 9..=16 => ( - Loc::reg(parama.next_wide()), - Loc::stack(self.ci.stack.allocate(size)), - ), + 1..=8 => (Loc::reg(parama.next()), Loc::stack(self.ci.stack.allocate(size))), + 9..=16 => (Loc::reg(parama.next_wide()), Loc::stack(self.ci.stack.allocate(size))), _ if flags & (idfl::MUTABLE | idfl::REFERENCED) == 0 => { let ptr = parama.next(); let reg = self.ci.regs.allocate(); self.output.emit(instrs::cp(reg.get(), ptr)); return Loc::reg(reg).into_derefed(); } - _ => ( - Loc::reg(parama.next()).into_derefed(), - Loc::stack(self.ci.stack.allocate(size)), - ), + _ => (Loc::reg(parama.next()).into_derefed(), Loc::stack(self.ci.stack.allocate(size))), }; self.store_sized(src, &dst, size); @@ -2493,10 +2292,7 @@ impl Codegen { fn eca(&mut self, trap: Trap, ret: impl Into) -> Value { self.output.emit(eca()); self.output.write_trap(trap); - Value { - ty: ret.into(), - loc: Loc::reg(1), - } + Value { ty: ret.into(), loc: Loc::reg(1) } } fn alloc_ret(&mut self, ret: ty::Id, ctx: Ctx) -> Loc { @@ -2506,13 +2302,8 @@ impl Codegen { 1..=8 => Loc::reg(1), 9..=16 => Loc::stack(self.ci.stack.allocate(size)), _ => { - let loc = ctx - .loc - .unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size))); - let Loc::Rt { - reg, stack, offset, .. - } = &loc - else { + let loc = ctx.loc.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size))); + let Loc::Rt { reg, stack, offset, .. } = &loc else { todo!("old man with the beard looks at the sky scared"); }; self.stack_offset(1, reg.get(), stack.as_ref(), *offset); @@ -2523,12 +2314,7 @@ impl Codegen { fn loc_to_reg(&mut self, loc: impl Into, size: Size) -> reg::Id { match loc.into() { - LocCow::Owned(Loc::Rt { - derefed: false, - mut reg, - offset, - stack, - }) => { + LocCow::Owned(Loc::Rt { derefed: false, mut reg, offset, stack }) => { debug_assert!(stack.is_none(), "TODO"); assert_eq!(offset, 0, "TODO"); if reg.is_ref() { @@ -2538,12 +2324,7 @@ impl Codegen { } reg } - LocCow::Ref(&Loc::Rt { - derefed: false, - ref reg, - offset, - ref stack, - }) => { + LocCow::Ref(&Loc::Rt { derefed: false, ref reg, offset, ref stack }) => { debug_assert!(stack.is_none(), "TODO"); assert_eq!(offset, 0, "TODO"); reg.as_ref() @@ -2569,12 +2350,7 @@ impl Codegen { fn pass_arg_low(&mut self, loc: &Loc, size: Size, parama: &mut ParamAlloc) { if size > 16 { - let Loc::Rt { - reg, stack, offset, .. - } = loc - else { - unreachable!() - }; + let Loc::Rt { reg, stack, offset, .. } = loc else { unreachable!() }; self.stack_offset(parama.next(), reg.get(), stack.as_ref(), *offset as _); return; } @@ -2627,8 +2403,7 @@ impl Codegen { let dst_off = self.ci.regs.allocate(); self.stack_offset(src_off.get(), src.get(), ssta.as_ref(), soff); self.stack_offset(dst_off.get(), dst.get(), dsta.as_ref(), doff); - self.output - .emit(bmc(src_off.get(), dst_off.get(), size as _)); + self.output.emit(bmc(src_off.get(), dst_off.get(), size as _)); self.ci.regs.free(src_off); self.ci.regs.free(dst_off); } @@ -2666,17 +2441,13 @@ impl Codegen { } fn opt_stack_reloc(&mut self, stack: Option<&stack::Id>, off: Offset, sub_offset: u8) -> u64 { - stack - .map(|s| self.stack_reloc(s, off, sub_offset)) - .unwrap_or(off as _) + stack.map(|s| self.stack_reloc(s, off, sub_offset)).unwrap_or(off as _) } fn stack_reloc(&mut self, stack: &stack::Id, off: Offset, sub_offset: u8) -> u64 { log::dbg!("whaaaaatahack: {:b}", stack.repr()); let offset = self.local_offset(); - self.ci - .stack_relocs - .push(Reloc::shifted(offset, sub_offset, 8)); + self.ci.stack_relocs.push(Reloc::shifted(offset, sub_offset, 8)); Reloc::pack_srel(stack, off) } @@ -2699,8 +2470,7 @@ impl Codegen { for srel in self.output.strings.drain(..) { #[cfg(debug_assertions)] assert!(srel.shifted); - srel.reloc - .apply_jump(&mut self.output.code, srel.range.start); + srel.reloc.apply_jump(&mut self.output.code, srel.range.start); } } @@ -2747,10 +2517,7 @@ impl Codegen { s.output.emit_prelude(); if s.expr_ctx( - &Expr::Return { - pos: 0, - val: Some(expr), - }, + &Expr::Return { pos: 0, val: Some(expr) }, Ctx::default().with_ty(ty::TYPE), ) .is_some() @@ -2787,9 +2554,7 @@ impl Codegen { match trap { Trap::MakeStruct { file, struct_expr } => { let cfile = self.files[file as usize].clone(); - let &Expr::Struct { - fields, captured, .. - } = struct_expr.get(&cfile).unwrap() + let &Expr::Struct { fields, captured, .. } = struct_expr.get(&cfile).unwrap() else { unreachable!() }; @@ -2890,16 +2655,9 @@ impl Codegen { op: TokenKind::Decl, right: Expr::Struct { fields, .. }, } => ty::Kind::Struct(self.build_struct(fields)), - Expr::BinOp { - left: &Expr::Ident { .. }, - op: TokenKind::Decl, - right, - } => { + Expr::BinOp { left, op: TokenKind::Decl, right } => { let gid = self.tys.globals.len() as ty::Global; - self.tys.globals.push(Global { - offset: u32::MAX, - ty: Default::default(), - }); + self.tys.globals.push(Global { offset: u32::MAX, ty: Default::default() }); let ci = ItemCtx { file, @@ -2907,9 +2665,10 @@ impl Codegen { ..self.pool.cis.pop().unwrap_or_default() }; - self.tys.globals[gid as usize] = self - .ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(right))) - .into_ok(); + _ = left.find_pattern_path(ident, right, |expr| { + self.tys.globals[gid as usize] = + self.ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr))).into_ok(); + }); ty::Kind::Global(gid) } @@ -2945,10 +2704,7 @@ impl Codegen { let ret_loc = unsafe { self.output.code.as_mut_ptr().add(offset) }; self.ct.vm.write_reg(1, ret_loc as u64); - Global { - ty: ret.ty, - offset: offset as _, - } + Global { ty: ret.ty, offset: offset as _ } } fn dunp_imported_fns(&mut self) { @@ -2989,10 +2745,7 @@ impl Codegen { if ret.is_ok() { self.link(); - self.output.trunc(&Snapshot { - code: self.output.code.len(), - ..self.ci.snap - }); + self.output.trunc(&Snapshot { code: self.output.code.len(), ..self.ci.snap }); log::dbg!("{} {}", self.output.code.len(), self.ci.snap.code); let entry = &mut self.output.code[self.ci.snap.code] as *mut _ as _; let prev_pc = std::mem::replace(&mut self.ct.vm.pc, hbvm::mem::Address::new(entry)); @@ -3053,26 +2806,20 @@ impl Codegen { fn local_snap(&self) -> Snapshot { Snapshot { - code: self.output.code.len() - self.ci.snap.code, + code: self.output.code.len() - self.ci.snap.code, string_data: self.output.string_data.len() - self.ci.snap.string_data, - funcs: self.output.funcs.len() - self.ci.snap.funcs, - globals: self.output.globals.len() - self.ci.snap.globals, - strings: self.output.strings.len() - self.ci.snap.strings, + funcs: self.output.funcs.len() - self.ci.snap.funcs, + globals: self.output.globals.len() - self.ci.snap.globals, + strings: self.output.strings.len() - self.ci.snap.strings, } } fn pop_local_snap(&mut self, snap: Snapshot) { self.output.code.truncate(snap.code + self.ci.snap.code); - self.output - .string_data - .truncate(snap.string_data + self.ci.snap.string_data); + self.output.string_data.truncate(snap.string_data + self.ci.snap.string_data); self.output.funcs.truncate(snap.funcs + self.ci.snap.funcs); - self.output - .globals - .truncate(snap.globals + self.ci.snap.globals); - self.output - .strings - .truncate(snap.strings + self.ci.snap.strings); + self.output.globals.truncate(snap.globals + self.ci.snap.globals); + self.output.strings.truncate(snap.strings + self.ci.snap.strings); } fn pack_args(&mut self, pos: Pos, arg_base: usize) -> ty::Tuple { @@ -3083,12 +2830,7 @@ impl Codegen { let len = needle.len(); // FIXME: maybe later when this becomes a bottleneck we use more // efficient search (SIMD?, indexing?) - let sp = self - .tys - .args - .windows(needle.len()) - .position(|val| val == needle) - .unwrap(); + let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap(); self.tys.args.truncate((sp + needle.len()).max(arg_base)); ty::Tuple::new(sp, len) .unwrap_or_else(|| self.report(pos, "amount of arguments not supported")) @@ -3097,9 +2839,10 @@ impl Codegen { #[cfg(test)] mod tests { - use crate::{codegen::LoggedMem, log}; - - use super::parser; + use { + super::parser, + crate::{codegen::LoggedMem, log}, + }; const README: &str = include_str!("../README.md"); @@ -3151,10 +2894,7 @@ mod tests { ) }; - vm.write_reg( - super::STACK_PTR, - unsafe { stack.as_mut_ptr().add(stack.len()) } as u64, - ); + vm.write_reg(super::STACK_PTR, unsafe { stack.as_mut_ptr().add(stack.len()) } as u64); let stat = loop { match vm.run() { diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index f1b3d57..cbcf1a3 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -13,9 +13,9 @@ const fn ascii_mask(chars: &[u8]) -> u128 { #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Token { - pub kind: TokenKind, + pub kind: TokenKind, pub start: u32, - pub end: u32, + pub end: u32, } impl Token { @@ -82,31 +82,31 @@ macro_rules! gen_token_kind { #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[repr(u8)] pub enum TokenKind { - Not = b'!', - DQuote = b'"', - Pound = b'#', + Not = b'!', + DQuote = b'"', + Pound = b'#', CtIdent = b'$', - Mod = b'%', - Band = b'&', - Quote = b'\'', - LParen = b'(', - RParen = b')', - Mul = b'*', - Add = b'+', - Comma = b',', - Sub = b'-', - Dot = b'.', - Div = b'/', + Mod = b'%', + Band = b'&', + Quote = b'\'', + LParen = b'(', + RParen = b')', + Mul = b'*', + Add = b'+', + Comma = b',', + Sub = b'-', + Dot = b'.', + Div = b'/', // Unused = 2-6 - Shr = b'<' - 5, + Shr = b'<' - 5, // Unused = 8 - Shl = b'>' - 5, - Colon = b':', - Semi = b';', - Lt = b'<', - Assign = b'=', - Gt = b'>', - Que = b'?', + Shl = b'>' - 5, + Colon = b':', + Semi = b';', + Lt = b'<', + Assign = b'=', + Gt = b'>', + Que = b'?', Directive = b'@', Comment, @@ -132,37 +132,37 @@ pub enum TokenKind { And, // Unused = R-Z - LBrack = b'[', - BSlash = b'\\', - RBrack = b']', - Xor = b'^', - Tick = b'`', + LBrack = b'[', + BSlash = b'\\', + RBrack = b']', + Xor = b'^', + Tick = b'`', // Unused = a-z - LBrace = b'{', - Bor = b'|', - RBrace = b'}', - Tilde = b'~', + LBrace = b'{', + Bor = b'|', + RBrace = b'}', + Tilde = b'~', - Decl = b':' + 128, - Eq = b'=' + 128, - Ne = b'!' + 128, - Le = b'<' + 128, - Ge = b'>' + 128, + Decl = b':' + 128, + Eq = b'=' + 128, + Ne = b'!' + 128, + Le = b'<' + 128, + Ge = b'>' + 128, - BorAss = b'|' + 128, - AddAss = b'+' + 128, - SubAss = b'-' + 128, - MulAss = b'*' + 128, - DivAss = b'/' + 128, - ModAss = b'%' + 128, - XorAss = b'^' + 128, + BorAss = b'|' + 128, + AddAss = b'+' + 128, + SubAss = b'-' + 128, + MulAss = b'*' + 128, + DivAss = b'/' + 128, + ModAss = b'%' + 128, + XorAss = b'^' + 128, BandAss = b'&' + 128, - ShlAss = b'0' + 128, - ShrAss = b'1' + 128, + ShlAss = b'0' + 128, + ShrAss = b'1' + 128, } impl TokenKind { - pub fn assign_op(self) -> Option { + pub fn ass_op(self) -> Option { let id = (self as u8).saturating_sub(128); if ascii_mask(b"|+-*/%^&01") & (1u128 << id) == 0 { return None; @@ -228,7 +228,7 @@ gen_token_kind! { } pub struct Lexer<'a> { - pos: u32, + pos: u32, bytes: &'a [u8], } @@ -238,10 +238,7 @@ impl<'a> Lexer<'a> { } pub fn restore(input: &'a str, pos: u32) -> Self { - Self { - pos, - bytes: input.as_bytes(), - } + Self { pos, bytes: input.as_bytes() } } pub fn slice(&self, tok: std::ops::Range) -> &'a str { @@ -268,11 +265,7 @@ impl<'a> Lexer<'a> { let mut start = self.pos; let Some(c) = self.advance() else { - return Token { - kind: T::Eof, - start, - end: self.pos, - }; + return Token { kind: T::Eof, start, end: self.pos }; }; let advance_ident = |s: &mut Self| { @@ -345,11 +338,7 @@ impl<'a> Lexer<'a> { _ => identity(c), }; - return Token { - kind, - start, - end: self.pos, - }; + return Token { kind, start, end: self.pos }; } } @@ -416,10 +405,8 @@ impl LineMap { let query = std::simd::u8x16::splat(b'\n'); let nl_count = start.iter().map(|&b| (b == b'\n') as usize).sum::() - + simd_mid - .iter() - .map(|s| s.simd_eq(query).to_bitmask().count_ones()) - .sum::() as usize + + simd_mid.iter().map(|s| s.simd_eq(query).to_bitmask().count_ones()).sum::() + as usize + end.iter().map(|&b| (b == b'\n') as usize).sum::(); let mut lines = Vec::with_capacity(nl_count); @@ -457,9 +444,7 @@ impl LineMap { handle_rem(bytes.len() - end.len(), end, &mut last_nl, &mut lines); - Self { - lines: Box::from(lines), - } + Self { lines: Box::from(lines) } } } diff --git a/hblang/src/lib.rs b/hblang/src/lib.rs index d032e56..53326b2 100644 --- a/hblang/src/lib.rs +++ b/hblang/src/lib.rs @@ -20,15 +20,16 @@ #![allow(internal_features)] #![allow(clippy::format_collect)] -use std::{ - collections::VecDeque, - io::{self, Read}, - path::{Path, PathBuf}, - sync::Mutex, +use { + parser::Ast, + std::{ + collections::VecDeque, + io::{self, Read}, + path::{Path, PathBuf}, + sync::Mutex, + }, }; -use parser::Ast; - #[macro_export] macro_rules! run_tests { ($runner:path: $($name:ident => $input:expr;)*) => {$( @@ -137,9 +138,7 @@ struct TaskQueue { impl TaskQueue { fn new(max_waiters: usize) -> Self { - Self { - inner: Mutex::new(TaskQueueInner::new(max_waiters)), - } + Self { inner: Mutex::new(TaskQueueInner::new(max_waiters)) } } pub fn push(&self, message: T) { @@ -163,8 +162,8 @@ enum TaskSlot { struct TaskQueueInner { max_waiters: usize, - messages: VecDeque, - parked: VecDeque<(*mut TaskSlot, std::thread::Thread)>, + messages: VecDeque, + parked: VecDeque<(*mut TaskSlot, std::thread::Thread)>, } unsafe impl Send for TaskQueueInner {} @@ -172,11 +171,7 @@ unsafe impl Sync for TaskQueueInner {} impl TaskQueueInner { fn new(max_waiters: usize) -> Self { - Self { - max_waiters, - messages: Default::default(), - parked: Default::default(), - } + Self { max_waiters, messages: Default::default(), parked: Default::default() } } fn push(&mut self, messages: impl IntoIterator) { @@ -232,17 +227,9 @@ pub fn parse_from_fs(threads: usize, root: &str) -> io::Result> { } enum ImportPath<'a> { - Root { - path: &'a str, - }, - Rel { - path: &'a str, - }, - Git { - link: &'a str, - path: &'a str, - chk: Option>, - }, + Root { path: &'a str }, + Rel { path: &'a str }, + Git { link: &'a str, path: &'a str, chk: Option> }, } impl<'a> TryFrom<&'a str> for ImportPath<'a> { @@ -258,15 +245,14 @@ pub fn parse_from_fs(threads: usize, root: &str) -> io::Result> { let (link, path) = path.split_once(':').ok_or(ParseImportError::ExpectedPath)?; let (link, params) = link.split_once('?').unwrap_or((link, "")); - let chk = params - .split('&') - .filter_map(|s| s.split_once('=')) - .find_map(|(key, value)| match key { + let chk = params.split('&').filter_map(|s| s.split_once('=')).find_map( + |(key, value)| match key { "branch" => Some(Chk::Branch(value)), "rev" => Some(Chk::Rev(value)), "tag" => Some(Chk::Tag(value)), _ => None, - }); + }, + ); Ok(Self::Git { link, path, chk }) } _ => Err(ParseImportError::InvalidPrefix), @@ -296,8 +282,8 @@ pub fn parse_from_fs(threads: usize, root: &str) -> io::Result> { path.canonicalize().map_err(|e| CantLoadFile { file_name: path, directory: PathBuf::from(root), - from: PathBuf::from(from), - source: e, + from: PathBuf::from(from), + source: e, }) } } @@ -331,8 +317,8 @@ pub fn parse_from_fs(threads: usize, root: &str) -> io::Result> { struct CantLoadFile { file_name: PathBuf, directory: PathBuf, - from: PathBuf, - source: io::Error, + from: PathBuf, + source: io::Error, } impl std::fmt::Display for CantLoadFile { @@ -439,10 +425,8 @@ pub fn parse_from_fs(threads: usize, root: &str) -> io::Result> { if let Some(mut command) = command { let output = command.output()?; if !output.status.success() { - let msg = format!( - "git command failed: {}", - String::from_utf8_lossy(&output.stderr) - ); + let msg = + format!("git command failed: {}", String::from_utf8_lossy(&output.stderr)); return Err(io::Error::new(io::ErrorKind::Other, msg)); } } @@ -478,10 +462,7 @@ pub fn parse_from_fs(threads: usize, root: &str) -> io::Result> { std::thread::scope(|s| (0..threads).for_each(|_| _ = s.spawn(thread))); - ast.into_inner() - .unwrap() - .into_iter() - .collect::>>() + ast.into_inner().unwrap().into_iter().collect::>>() } type HashMap = std::collections::HashMap>; @@ -530,10 +511,7 @@ pub fn run_test( std::env::var("PT_TEST_ROOT") .unwrap_or(concat!(env!("CARGO_MANIFEST_DIR"), "/tests").to_string()), ); - root.push( - name.replace("::", "_") - .replace(concat!(env!("CARGO_PKG_NAME"), "_"), ""), - ); + root.push(name.replace("::", "_").replace(concat!(env!("CARGO_PKG_NAME"), "_"), "")); root.set_extension("txt"); let expected = std::fs::read_to_string(&root).unwrap_or_default(); @@ -562,11 +540,7 @@ pub fn run_test( .spawn() .unwrap(); - proc.stdin - .as_mut() - .unwrap() - .write_all(output.as_bytes()) - .unwrap(); + proc.stdin.as_mut().unwrap().write_all(output.as_bytes()).unwrap(); proc.wait().unwrap(); @@ -575,7 +549,7 @@ pub fn run_test( #[derive(Default)] pub struct Options { - pub fmt: bool, + pub fmt: bool, pub fmt_current: bool, } diff --git a/hblang/src/main.rs b/hblang/src/main.rs index d4f06bf..593035e 100644 --- a/hblang/src/main.rs +++ b/hblang/src/main.rs @@ -11,7 +11,7 @@ fn main() -> std::io::Result<()> { hblang::run_compiler( args.get(1).copied().unwrap_or("main.hb"), hblang::Options { - fmt: args.contains(&"--fmt"), + fmt: args.contains(&"--fmt"), fmt_current: args.contains(&"--fmt-current"), }, &mut std::io::stdout(), diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index fc6a560..a5145df 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -1,22 +1,24 @@ -use std::{ - cell::{Cell, UnsafeCell}, - io, - ops::{Deref, Not}, - ptr::NonNull, - sync::atomic::AtomicUsize, -}; - -use crate::{ - codegen, - ident::{self, Ident}, - lexer::{Lexer, LineMap, Token, TokenKind}, - log, +use { + crate::{ + codegen, + ident::{self, Ident}, + lexer::{Lexer, LineMap, Token, TokenKind}, + log, + }, + std::{ + cell::{Cell, UnsafeCell}, + io, + ops::{Deref, Not}, + ptr::NonNull, + sync::atomic::AtomicUsize, + }, }; pub type Pos = u32; pub type IdentFlags = u32; pub type Symbols = Vec; pub type FileId = u32; +pub type IdentIndex = u16; pub type Loader<'a> = &'a (dyn Fn(&str, &str) -> io::Result + 'a); pub mod idfl { @@ -35,7 +37,7 @@ pub mod idfl { COMPTIME, } - pub fn index(i: IdentFlags) -> u16 { + pub fn index(i: IdentFlags) -> IdentIndex { (i & !ALL) as _ } } @@ -46,28 +48,28 @@ pub fn no_loader(_: &str, _: &str) -> io::Result { #[derive(Debug)] pub struct Symbol { - pub name: Ident, + pub name: Ident, pub flags: IdentFlags, } #[derive(Clone, Copy)] struct ScopeIdent { - ident: Ident, + ident: Ident, declared: bool, - flags: IdentFlags, + flags: IdentFlags, } pub struct Parser<'a, 'b> { - path: &'b str, - loader: Loader<'b>, - lexer: Lexer<'b>, - arena: &'b Arena<'a>, - token: Token, - symbols: &'b mut Symbols, - ns_bound: usize, + path: &'b str, + loader: Loader<'b>, + lexer: Lexer<'b>, + arena: &'b Arena<'a>, + token: Token, + symbols: &'b mut Symbols, + ns_bound: usize, trailing_sep: bool, - idents: Vec, - captured: Vec, + idents: Vec, + captured: Vec, } impl<'a, 'b> Parser<'a, 'b> { @@ -92,7 +94,7 @@ impl<'a, 'b> Parser<'a, 'b> { self.lexer = Lexer::new(input); self.token = self.lexer.next(); - let f = self.collect_list(TokenKind::Semi, TokenKind::Eof, Self::expr); + let f = self.collect_list(TokenKind::Semi, TokenKind::Eof, |s| s.expr_low(true)); self.pop_scope(0); let has_undeclared = !self.idents.is_empty(); @@ -123,12 +125,16 @@ impl<'a, 'b> Parser<'a, 'b> { self.arena.alloc(self.expr()) } - fn expr(&mut self) -> Expr<'a> { + fn expr_low(&mut self, top_level: bool) -> Expr<'a> { let left = self.unit_expr(); - self.bin_expr(left, 0) + self.bin_expr(left, 0, top_level) } - fn bin_expr(&mut self, mut fold: Expr<'a>, min_prec: u8) -> Expr<'a> { + fn expr(&mut self) -> Expr<'a> { + self.expr_low(false) + } + + fn bin_expr(&mut self, mut fold: Expr<'a>, min_prec: u8, top_level: bool) -> Expr<'a> { loop { let Some(prec) = self.token.kind.precedence() else { break; @@ -141,7 +147,11 @@ impl<'a, 'b> Parser<'a, 'b> { let checkpoint = self.token.start; let op = self.next().kind; - let op_ass = op.assign_op().map(|op| { + if op == TokenKind::Decl { + self.declare_rec(&fold, top_level); + } + + let op_ass = op.ass_op().map(|op| { // this abomination reparses the left side, so that the desubaring adheres to the // parser invariants. let source = self.lexer.slice(0..checkpoint as usize); @@ -156,23 +166,15 @@ impl<'a, 'b> Parser<'a, 'b> { }); let right = self.unit_expr(); - let right = self.bin_expr(right, prec); + let right = self.bin_expr(right, prec, false); let right = self.arena.alloc(right); let left = self.arena.alloc(fold); if let Some((op, clone)) = op_ass { self.flag_idents(*left, idfl::MUTABLE); - let right = Expr::BinOp { - left: self.arena.alloc(clone), - op, - right, - }; - fold = Expr::BinOp { - left, - op: TokenKind::Assign, - right: self.arena.alloc(right), - }; + let right = Expr::BinOp { left: self.arena.alloc(clone), op, right }; + fold = Expr::BinOp { left, op: TokenKind::Assign, right: self.arena.alloc(right) }; } else { fold = Expr::BinOp { left, right, op }; if op == TokenKind::Assign { @@ -184,7 +186,42 @@ impl<'a, 'b> Parser<'a, 'b> { fold } - fn resolve_ident(&mut self, token: Token, decl: bool) -> (Ident, u16) { + fn declare_rec(&mut self, expr: &Expr, top_level: bool) { + let idx = |idx| top_level.not().then_some(idx); + match *expr { + Expr::Ident { pos, id, index, .. } => self.declare(pos, id, idx(index)), + Expr::Ctor { fields, .. } => { + for CtorField { value, .. } in fields { + self.declare_rec(value, top_level) + } + } + _ => self.report_pos(expr.pos(), "cant declare this shit (yet)"), + } + } + + fn declare(&mut self, pos: Pos, id: Ident, index_to_check: Option) { + if let Some(index) = index_to_check + && index != 0 + { + self.report_pos( + pos, + format_args!( + "out of order declaration not allowed: {}", + self.lexer.slice(ident::range(id)) + ), + ); + } + + let index = self.idents.binary_search_by_key(&id, |s| s.ident).expect("fck up"); + if std::mem::replace(&mut self.idents[index].declared, true) { + self.report_pos( + pos, + format_args!("redeclaration of identifier: {}", self.lexer.slice(ident::range(id))), + ) + } + } + + fn resolve_ident(&mut self, token: Token) -> (Ident, IdentIndex) { let is_ct = token.kind == TokenKind::CtIdent; let name = self.lexer.slice(token.range()); @@ -198,25 +235,17 @@ impl<'a, 'b> Parser<'a, 'b> { .enumerate() .rfind(|(_, elem)| self.lexer.slice(ident::range(elem.ident)) == name) { - Some((_, elem)) if decl && elem.declared => { - self.report(format_args!("redeclaration of identifier: {name}")) - } Some((i, elem)) => { elem.flags += 1; (i, elem) } None => { let id = ident::new(token.start, name.len() as _); - self.idents.push(ScopeIdent { - ident: id, - declared: false, - flags: 0, - }); + self.idents.push(ScopeIdent { ident: id, declared: false, flags: 0 }); (self.idents.len() - 1, self.idents.last_mut().unwrap()) } }; - id.declared |= decl; id.flags |= idfl::COMPTIME * is_ct as u32; if id.declared && self.ns_bound > i { id.flags |= idfl::COMPTIME; @@ -244,32 +273,26 @@ impl<'a, 'b> Parser<'a, 'b> { let path = self.lexer.slice(str.range()).trim_matches('"'); E::Mod { - pos: token.start, + pos: token.start, path: self.arena.alloc_str(path), - id: match (self.loader)(path, self.path) { + id: match (self.loader)(path, self.path) { Ok(id) => id, Err(e) => self.report(format_args!("error loading dependency: {e:#}")), }, } } T::Directive => E::Directive { - pos: token.start, + pos: token.start, name: self.move_str(token), args: { self.expect_advance(T::LParen); self.collect_list(T::Comma, T::RParen, Self::expr) }, }, - T::True => E::Bool { - pos: token.start, - value: true, - }, - T::DQuote => E::String { - pos: token.start, - literal: self.move_str(token), - }, + T::True => E::Bool { pos: token.start, value: true }, + T::DQuote => E::String { pos: token.start, literal: self.move_str(token) }, T::Struct => E::Struct { - fields: { + fields: { self.ns_bound = self.idents.len(); self.expect_advance(T::LBrace); self.collect_list(T::Comma, T::RBrace, |s| { @@ -285,7 +308,7 @@ impl<'a, 'b> Parser<'a, 'b> { self.captured.truncate(prev_captured + preserved); self.arena.alloc_slice(&self.captured[prev_captured..]) }, - pos: { + pos: { if self.ns_bound == 0 { // we might save some memory self.captured.clear(); @@ -294,25 +317,17 @@ impl<'a, 'b> Parser<'a, 'b> { }, }, T::Ident | T::CtIdent => { - let (id, index) = self.resolve_ident(token, self.token.kind == T::Decl); + let (id, index) = self.resolve_ident(token); let name = self.move_str(token); - E::Ident { - pos: token.start, - name, - id, - index, - } + E::Ident { pos: token.start, name, id, index } } T::If => E::If { - pos: token.start, - cond: self.ptr_expr(), - then: self.ptr_expr(), + pos: token.start, + cond: self.ptr_expr(), + then: self.ptr_expr(), else_: self.advance_if(T::Else).then(|| self.ptr_expr()), }, - T::Loop => E::Loop { - pos: token.start, - body: self.ptr_expr(), - }, + T::Loop => E::Loop { pos: token.start, body: self.ptr_expr() }, T::Break => E::Break { pos: token.start }, T::Continue => E::Continue { pos: token.start }, T::Return => E::Return { @@ -320,22 +335,18 @@ impl<'a, 'b> Parser<'a, 'b> { val: (self.token.kind != T::Semi).then(|| self.ptr_expr()), }, T::Fn => E::Closure { - pos: token.start, + pos: token.start, args: { self.expect_advance(T::LParen); self.collect_list(T::Comma, T::RParen, |s| { let name = s.advance_ident(); - let (id, index) = s.resolve_ident(name, true); + let (id, index) = s.resolve_ident(name); + s.declare(name.start, id, None); s.expect_advance(T::Colon); - Arg { - name: s.move_str(name), - id, - index, - ty: s.expr(), - } + Arg { name: s.move_str(name), id, index, ty: s.expr() } }) }, - ret: { + ret: { self.expect_advance(T::Colon); self.ptr_expr() }, @@ -345,7 +356,7 @@ impl<'a, 'b> Parser<'a, 'b> { T::Tupl => self.tupl(token.start, None), T::Band | T::Mul | T::Xor => E::UnOp { pos: token.start, - op: token.kind, + op: token.kind, val: { let expr = if token.kind == T::Xor { let expr = self.expr(); @@ -360,11 +371,11 @@ impl<'a, 'b> Parser<'a, 'b> { }, }, T::LBrace => E::Block { - pos: token.start, + pos: token.start, stmts: self.collect_list(T::Semi, T::RBrace, Self::expr), }, T::Number => E::Number { - pos: token.start, + pos: token.start, value: match self.lexer.slice(token.range()).parse() { Ok(value) => value, Err(e) => self.report(format_args!("invalid number: {e}")), @@ -375,10 +386,7 @@ impl<'a, 'b> Parser<'a, 'b> { self.expect_advance(T::RParen); expr } - T::Comment => Expr::Comment { - pos: token.start, - literal: self.move_str(token), - }, + T::Comment => Expr::Comment { pos: token.start, literal: self.move_str(token) }, tok => self.report(format_args!("unexpected token: {tok:?}")), }; @@ -398,7 +406,7 @@ impl<'a, 'b> Parser<'a, 'b> { T::Tupl => self.tupl(token.start, Some(expr)), T::Dot => E::Field { target: self.arena.alloc(expr), - field: { + name: { let token = self.expect_advance(T::Ident); self.move_str(token) }, @@ -432,9 +440,18 @@ impl<'a, 'b> Parser<'a, 'b> { pos, ty: ty.map(|ty| self.arena.alloc(ty)), fields: self.collect_list(TokenKind::Comma, TokenKind::RBrace, |s| { - let name = s.advance_ident(); - let value = s.advance_if(TokenKind::Colon).then(|| s.expr()); - (s.move_str(name), value) + let name_tok = s.advance_ident(); + let name = s.move_str(name_tok); + CtorField { + pos: name_tok.start, + name, + value: if s.advance_if(TokenKind::Colon) { + s.expr() + } else { + let (id, index) = s.resolve_ident(name_tok); + Expr::Ident { pos: name_tok.start, id, name, index } + }, + } }), trailing_comma: std::mem::take(&mut self.trailing_sep), } @@ -444,10 +461,7 @@ impl<'a, 'b> Parser<'a, 'b> { if matches!(self.token.kind, TokenKind::Ident | TokenKind::CtIdent) { self.next() } else { - self.report(format_args!( - "expected identifier, found {:?}", - self.token.kind - )) + self.report(format_args!("expected identifier, found {:?}", self.token.kind)) } } @@ -462,10 +476,7 @@ impl<'a, 'b> Parser<'a, 'b> { self.idents .drain(undeclared_count..) - .map(|ident| Symbol { - name: ident.ident, - flags: ident.flags, - }) + .map(|ident| Symbol { name: ident.ident, flags: ident.flags }) .collect_into(self.symbols); } @@ -489,6 +500,7 @@ impl<'a, 'b> Parser<'a, 'b> { } fn collect(&mut self, mut f: impl FnMut(&mut Self) -> Option) -> &'a [T] { + // TODO: avoid this allocation let vec = std::iter::from_fn(|| f(self)).collect::>(); self.arena.alloc_slice(&vec) } @@ -504,10 +516,7 @@ impl<'a, 'b> Parser<'a, 'b> { fn expect_advance(&mut self, kind: TokenKind) -> Token { if self.token.kind != kind { - self.report(format_args!( - "expected {:?}, found {:?}", - kind, self.token.kind - )); + self.report(format_args!("expected {:?}, found {:?}", kind, self.token.kind)); } self.next() } @@ -534,25 +543,19 @@ impl<'a, 'b> Parser<'a, 'b> { } fn find_ident(idents: &mut [ScopeIdent], id: Ident) -> &mut ScopeIdent { - idents - .binary_search_by_key(&id, |si| si.ident) - .map(|i| &mut idents[i]) - .unwrap() + idents.binary_search_by_key(&id, |si| si.ident).map(|i| &mut idents[i]).unwrap() } pub fn find_symbol(symbols: &[Symbol], id: Ident) -> &Symbol { - symbols - .binary_search_by_key(&id, |s| s.name) - .map(|i| &symbols[i]) - .unwrap() + symbols.binary_search_by_key(&id, |s| s.name).map(|i| &symbols[i]).unwrap() } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Arg<'a> { - pub name: &'a str, - pub id: Ident, - pub index: u16, - pub ty: Expr<'a>, + pub name: &'a str, + pub id: Ident, + pub index: IdentIndex, + pub ty: Expr<'a>, } macro_rules! generate_expr { @@ -632,7 +635,7 @@ generate_expr! { pos: Pos, id: Ident, name: &'a str, - index: u16, + index: IdentIndex, }, Block { pos: Pos, @@ -670,7 +673,7 @@ generate_expr! { Ctor { pos: Pos, ty: Option<&'a Self>, - fields: &'a [(&'a str, Option)], + fields: &'a [CtorField<'a>], trailing_comma: bool, }, Tupl { @@ -681,7 +684,7 @@ generate_expr! { }, Field { target: &'a Self, - field: &'a str, + name: &'a str, }, Bool { pos: Pos, @@ -700,6 +703,48 @@ generate_expr! { } } +impl<'a> Expr<'a> { + pub fn declares(&self, iden: Result) -> Option { + match *self { + Self::Ident { id, name, .. } if iden == Ok(id) || iden == Err(name) => Some(id), + Self::Ctor { fields, .. } => fields.iter().find_map(|f| f.value.declares(iden)), + _ => None, + } + } + + pub fn find_pattern_path( + &self, + ident: Ident, + target: &Expr, + mut with_final: F, + ) -> Result<(), F> { + match *self { + Self::Ident { id, .. } if id == ident => { + with_final(target); + Ok(()) + } + Self::Ctor { fields, .. } => { + for CtorField { name, value, .. } in fields { + match value.find_pattern_path(ident, &Expr::Field { target, name }, with_final) + { + Ok(()) => return Ok(()), + Err(e) => with_final = e, + } + } + Err(with_final) + } + _ => Err(with_final), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CtorField<'a> { + pub pos: Pos, + pub name: &'a str, + pub value: Expr<'a>, +} + trait Poser { fn posi(self) -> Pos; } @@ -813,42 +858,30 @@ impl<'a> std::fmt::Display for Expr<'a> { Self::String { literal, .. } => write!(f, "{}", literal), Self::Comment { literal, .. } => write!(f, "{}", literal.trim_end()), Self::Mod { path, .. } => write!(f, "@mod(\"{path}\")"), - Self::Field { target, field } => write!(f, "{}.{field}", Postfix(target)), + Self::Field { target, name: field } => write!(f, "{}.{field}", Postfix(target)), Self::Directive { name, args, .. } => { write!(f, "@{name}(")?; fmt_list(f, false, ")", args, std::fmt::Display::fmt) } Self::Struct { fields, .. } => { write!(f, "struct {{")?; - fmt_list(f, true, "}", fields, |(name, val), f| { - write!(f, "{name}: {val}",) - }) + fmt_list(f, true, "}", fields, |(name, val), f| write!(f, "{name}: {val}",)) } - Self::Ctor { - ty, - fields, - trailing_comma, - .. - } => { + Self::Ctor { ty, fields, trailing_comma, .. } => { if let Some(ty) = ty { write!(f, "{}", Unary(ty))?; } write!(f, ".{{")?; - let fmt_field = |(name, val): &_, f: &mut std::fmt::Formatter| { - if let Some(val) = val { - write!(f, "{name}: {val}") - } else { + let fmt_field = |CtorField { name, value, .. }: &_, f: &mut std::fmt::Formatter| { + if matches!(value, Expr::Ident { name: n, .. } if name == n) { write!(f, "{name}") + } else { + write!(f, "{name}: {value}") } }; fmt_list(f, trailing_comma, "}", fields, fmt_field) } - Self::Tupl { - ty, - fields, - trailing_comma, - .. - } => { + Self::Tupl { ty, fields, trailing_comma, .. } => { if let Some(ty) = ty { write!(f, "{}", Unary(ty))?; } @@ -858,9 +891,7 @@ impl<'a> std::fmt::Display for Expr<'a> { Self::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)), Self::Break { .. } => write!(f, "break"), Self::Continue { .. } => write!(f, "continue"), - Self::If { - cond, then, else_, .. - } => { + Self::If { cond, then, else_, .. } => { write!(f, "if {cond} {}", Consecutive(then))?; if let Some(else_) = else_ { write!(f, " else {else_}")?; @@ -868,24 +899,16 @@ impl<'a> std::fmt::Display for Expr<'a> { Ok(()) } Self::Loop { body, .. } => write!(f, "loop {body}"), - Self::Closure { - ret, body, args, .. - } => { + Self::Closure { ret, body, args, .. } => { write!(f, "fn(")?; - fmt_list(f, false, "", args, |arg, f| { - write!(f, "{}: {}", arg.name, arg.ty) - })?; + fmt_list(f, false, "", args, |arg, f| write!(f, "{}: {}", arg.name, arg.ty))?; write!(f, "): {ret} {body}")?; if !matches!(body, Self::Block { .. }) { write!(f, ";")?; } Ok(()) } - Self::Call { - func, - args, - trailing_comma, - } => { + Self::Call { func, args, trailing_comma } => { write!(f, "{}(", Postfix(func))?; fmt_list(f, trailing_comma, ")", args, std::fmt::Display::fmt) } @@ -936,11 +959,11 @@ impl<'a> std::fmt::Display for Expr<'a> { #[repr(C)] pub struct AstInner { ref_count: AtomicUsize, - mem: ArenaChunk, - exprs: *const [Expr<'static>], + mem: ArenaChunk, + exprs: *const [Expr<'static>], - pub path: Box, - pub nlines: LineMap, + pub path: Box, + pub nlines: LineMap, pub symbols: T, } @@ -966,17 +989,14 @@ impl AstInner<[Symbol]> { let ptr = std::alloc::alloc(layout); let inner: *mut Self = std::ptr::from_raw_parts_mut(ptr as *mut _, syms.len()); - std::ptr::write( - inner as *mut AstInner<()>, - AstInner { - ref_count: AtomicUsize::new(1), - mem: arena.chunk.into_inner(), - exprs, - path: path.into(), - nlines: LineMap::new(content), - symbols: (), - }, - ); + std::ptr::write(inner as *mut AstInner<()>, AstInner { + ref_count: AtomicUsize::new(1), + mem: arena.chunk.into_inner(), + exprs, + path: path.into(), + nlines: LineMap::new(content), + symbols: (), + }); std::ptr::addr_of_mut!((*inner).symbols) .as_mut_ptr() .copy_from_nonoverlapping(syms.as_ptr(), syms.len()); @@ -1004,11 +1024,7 @@ impl Ast { pub fn find_decl(&self, id: Result) -> Option<(&Expr, Ident)> { self.exprs().iter().find_map(|expr| match expr { - Expr::BinOp { - left: &Expr::Ident { id: iden, name, .. }, - op: TokenKind::Decl, - .. - } if Ok(iden) == id || Err(name) == id => Some((expr, iden)), + Expr::BinOp { left, op: TokenKind::Decl, .. } => left.declares(id).map(|id| (expr, id)), _ => None, }) } @@ -1052,9 +1068,7 @@ unsafe impl Sync for Ast {} impl Clone for Ast { fn clone(&self) -> Self { - unsafe { self.0.as_ref() } - .ref_count - .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + unsafe { self.0.as_ref() }.ref_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed); Self(self.0) } } @@ -1062,11 +1076,7 @@ impl Clone for Ast { impl Drop for Ast { fn drop(&mut self) { let inner = unsafe { self.0.as_ref() }; - if inner - .ref_count - .fetch_sub(1, std::sync::atomic::Ordering::Relaxed) - == 1 - { + if inner.ref_count.fetch_sub(1, std::sync::atomic::Ordering::Relaxed) == 1 { unsafe { std::ptr::drop_in_place(self.0.as_ptr()) }; let layout = AstInner::layout(inner.symbols.len()); @@ -1088,7 +1098,7 @@ impl Deref for Ast { #[derive(Default)] pub struct Arena<'a> { chunk: UnsafeCell, - ph: std::marker::PhantomData<&'a ()>, + ph: std::marker::PhantomData<&'a ()>, } impl<'a> Arena<'a> { @@ -1103,8 +1113,7 @@ impl<'a> Arena<'a> { let layout = unsafe { std::alloc::Layout::from_size_align_unchecked(size, align) }; let ptr = self.alloc_low(layout); unsafe { - ptr.cast::() - .copy_from_nonoverlapping(NonNull::from(&expr).cast(), size / 8) + ptr.cast::().copy_from_nonoverlapping(NonNull::from(&expr).cast(), size / 8) }; unsafe { ptr.cast::>().as_ref() } } @@ -1116,11 +1125,7 @@ impl<'a> Arena<'a> { let layout = std::alloc::Layout::array::(slice.len()).unwrap(); let ptr = self.alloc_low(layout); - unsafe { - ptr.as_ptr() - .cast::() - .copy_from_nonoverlapping(slice.as_ptr(), slice.len()) - }; + unsafe { ptr.as_ptr().cast::().copy_from_nonoverlapping(slice.as_ptr(), slice.len()) }; unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, slice.len()) } } @@ -1144,24 +1149,21 @@ impl<'a> Arena<'a> { struct ArenaChunk { base: *mut u8, - end: *mut u8, + end: *mut u8, } impl Default for ArenaChunk { fn default() -> Self { - Self { - base: std::ptr::null_mut(), - end: std::ptr::null_mut(), - } + Self { base: std::ptr::null_mut(), end: std::ptr::null_mut() } } } impl ArenaChunk { - const CHUNK_SIZE: usize = 1 << 16; const ALIGN: usize = std::mem::align_of::(); - const NEXT_OFFSET: usize = Self::CHUNK_SIZE - std::mem::size_of::<*mut u8>(); + const CHUNK_SIZE: usize = 1 << 16; const LAYOUT: std::alloc::Layout = unsafe { std::alloc::Layout::from_size_align_unchecked(Self::CHUNK_SIZE, Self::ALIGN) }; + const NEXT_OFFSET: usize = Self::CHUNK_SIZE - std::mem::size_of::<*mut u8>(); fn new(next: *mut u8) -> Self { let base = unsafe { std::alloc::alloc(Self::LAYOUT) }; diff --git a/hblang/text-prj/main.hb b/hblang/text-prj/main.hb index f36f2fe..4c7bc19 100644 --- a/hblang/text-prj/main.hb +++ b/hblang/text-prj/main.hb @@ -1,5 +1,5 @@ -pkg := @use("pkg.hb"); +.{ global, fib } := @use("pkg.hb"); main := fn(a: int): int { - return pkg.fib(pkg.global); + return fib(global); } diff --git a/hbvm/src/bmc.rs b/hbvm/src/bmc.rs index 4a7919b..e87421e 100644 --- a/hbvm/src/bmc.rs +++ b/hbvm/src/bmc.rs @@ -16,25 +16,20 @@ struct AlignedBuf([MaybeUninit; BUF_SIZE]); /// State for block memory copy pub struct BlockCopier { /// Source address - src: Address, + src: Address, /// Destination address - dst: Address, + dst: Address, /// How many buffer sizes to copy? n_buffers: usize, /// …and what remainds after? - rem: usize, + rem: usize, } impl BlockCopier { /// Construct a new one #[inline] pub fn new(src: Address, dst: Address, count: usize) -> Self { - Self { - src, - dst, - n_buffers: count / BUF_SIZE, - rem: count % BUF_SIZE, - } + Self { src, dst, n_buffers: count / BUF_SIZE, rem: count % BUF_SIZE } } /// Copy one block @@ -47,15 +42,9 @@ impl BlockCopier { // We have at least one buffer size to copy if self.n_buffers != 0 { - if let Err(e) = unsafe { - act( - memory, - self.src, - self.dst, - buf.0.as_mut_ptr().cast(), - BUF_SIZE, - ) - } { + if let Err(e) = + unsafe { act(memory, self.src, self.dst, buf.0.as_mut_ptr().cast(), BUF_SIZE) } + { return Poll::Ready(Err(e)); } @@ -75,15 +64,9 @@ impl BlockCopier { } if self.rem != 0 { - if let Err(e) = unsafe { - act( - memory, - self.src, - self.dst, - buf.0.as_mut_ptr().cast(), - self.rem, - ) - } { + if let Err(e) = + unsafe { act(memory, self.src, self.dst, buf.0.as_mut_ptr().cast(), self.rem) } + { return Poll::Ready(Err(e)); } } @@ -103,20 +86,16 @@ unsafe fn act( ) -> Result<(), BlkCopyError> { unsafe { // Load to buffer - memory - .load(src, buf, count) - .map_err(|super::mem::LoadError(addr)| BlkCopyError { - access_reason: MemoryAccessReason::Load, - addr, - })?; + memory.load(src, buf, count).map_err(|super::mem::LoadError(addr)| BlkCopyError { + access_reason: MemoryAccessReason::Load, + addr, + })?; // Store from buffer - memory - .store(dst, buf, count) - .map_err(|super::mem::StoreError(addr)| BlkCopyError { - access_reason: MemoryAccessReason::Store, - addr, - })?; + memory.store(dst, buf, count).map_err(|super::mem::StoreError(addr)| BlkCopyError { + access_reason: MemoryAccessReason::Store, + addr, + })?; } Ok(()) diff --git a/hbvm/src/float/mod.rs b/hbvm/src/float/mod.rs index 5206f70..9b876a8 100644 --- a/hbvm/src/float/mod.rs +++ b/hbvm/src/float/mod.rs @@ -12,7 +12,7 @@ macro_rules! arch_specific { #[cfg($($cfg)*)] pub const FL_ARCH_SPECIFIC_SUPPORTED: bool = true; )* - + #[cfg(not(any($($($cfg)*),*)))] mod unsupported; diff --git a/hbvm/src/lib.rs b/hbvm/src/lib.rs index 565fc72..0527c73 100644 --- a/hbvm/src/lib.rs +++ b/hbvm/src/lib.rs @@ -26,7 +26,6 @@ mod utils; mod vmrun; pub use float::FL_ARCH_SPECIFIC_SUPPORTED; - use { bmc::BlockCopier, mem::{Address, Memory}, @@ -58,10 +57,10 @@ impl Default for Vm Self { Self { registers: [Value::from(0_u64); 256], - memory: Mem::default(), - pc: Address::default(), - timer: 0, - copier: None, + memory: Mem::default(), + pc: Address::default(), + timer: 0, + copier: None, } } } @@ -75,13 +74,7 @@ where /// # Safety /// Program code has to be validated pub unsafe fn new(memory: Mem, entry: Address) -> Self { - Self { - registers: [Value::from(0_u64); 256], - memory, - pc: entry, - timer: 0, - copier: None, - } + Self { registers: [Value::from(0_u64); 256], memory, pc: entry, timer: 0, copier: None } } /// Read register diff --git a/hbvm/src/mem/mod.rs b/hbvm/src/mem/mod.rs index c90096a..0767614 100644 --- a/hbvm/src/mem/mod.rs +++ b/hbvm/src/mem/mod.rs @@ -4,9 +4,8 @@ pub mod softpaging; pub(crate) mod addr; -pub use addr::Address; - use crate::utils::impl_display; +pub use addr::Address; /// Load-store memory access pub trait Memory { diff --git a/hbvm/src/mem/softpaging/icache.rs b/hbvm/src/mem/softpaging/icache.rs index 84f4c33..5928cc6 100644 --- a/hbvm/src/mem/softpaging/icache.rs +++ b/hbvm/src/mem/softpaging/icache.rs @@ -1,9 +1,8 @@ //! Program instruction cache -use crate::mem::Address; - use { super::{lookup::AddrPageLookuper, paging::PageTable, PageSize}, + crate::mem::Address, core::{ mem::{size_of, MaybeUninit}, ptr::{copy_nonoverlapping, NonNull}, @@ -46,9 +45,8 @@ impl ICache { ) -> Option { let mut ret = MaybeUninit::::uninit(); - let pbase = self - .data - .or_else(|| unsafe { self.fetch_page(self.base + self.size, root_pt) })?; + let pbase = + self.data.or_else(|| unsafe { self.fetch_page(self.base + self.size, root_pt) })?; // Get address base let base = addr.map(|x| x & self.mask); @@ -62,9 +60,7 @@ impl ICache { let requ_size = size_of::(); // Page overflow - let rem = (offset as usize) - .saturating_add(requ_size) - .saturating_sub(self.size as _); + let rem = (offset as usize).saturating_add(requ_size).saturating_sub(self.size as _); let first_copy = requ_size.saturating_sub(rem); // Copy non-overflowing part diff --git a/hbvm/src/mem/softpaging/lookup.rs b/hbvm/src/mem/softpaging/lookup.rs index 04b17d2..3c4668f 100644 --- a/hbvm/src/mem/softpaging/lookup.rs +++ b/hbvm/src/mem/softpaging/lookup.rs @@ -1,11 +1,12 @@ //! Address lookup -use crate::mem::addr::Address; - -use super::{ - addr_extract_index, - paging::{PageTable, Permission}, - PageSize, +use { + super::{ + addr_extract_index, + paging::{PageTable, Permission}, + PageSize, + }, + crate::mem::addr::Address, }; /// Good result from address split @@ -48,11 +49,7 @@ impl AddrPageLookuper { /// Create a new page lookuper #[inline] pub const fn new(addr: Address, size: usize, pagetable: *const PageTable) -> Self { - Self { - addr, - size, - pagetable, - } + Self { addr, size, pagetable } } /// Bump address by size X @@ -78,9 +75,8 @@ impl Iterator for AddrPageLookuper { for lvl in (0..5).rev() { // Get an entry unsafe { - let entry = (*current_pt) - .table - .get_unchecked(addr_extract_index(self.addr, lvl)); + let entry = + (*current_pt).table.get_unchecked(addr_extract_index(self.addr, lvl)); let ptr = entry.ptr(); match entry.permission() { diff --git a/hbvm/src/mem/softpaging/mapping.rs b/hbvm/src/mem/softpaging/mapping.rs index 3f131f4..0bf9a38 100644 --- a/hbvm/src/mem/softpaging/mapping.rs +++ b/hbvm/src/mem/softpaging/mapping.rs @@ -1,13 +1,12 @@ //! Automatic memory mapping -use crate::{mem::addr::Address, utils::impl_display}; - use { super::{ addr_extract_index, paging::{PageTable, Permission, PtEntry, PtPointedData}, PageSize, SoftPagedMem, }, + crate::{mem::addr::Address, utils::impl_display}, alloc::boxed::Box, }; @@ -36,11 +35,8 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> { // Walk pagetable levels for lvl in (lookup_depth + 1..5).rev() { - let entry = unsafe { - (*current_pt) - .table - .get_unchecked_mut(addr_extract_index(target, lvl)) - }; + let entry = + unsafe { (*current_pt).table.get_unchecked_mut(addr_extract_index(target, lvl)) }; let ptr = entry.ptr(); match entry.permission() { @@ -50,9 +46,7 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> { // Increase children count unsafe { *current_pt }.childen += 1; - let table = Box::into_raw(Box::new(PtPointedData { - pt: PageTable::default(), - })); + let table = Box::into_raw(Box::new(PtPointedData { pt: PageTable::default() })); unsafe { core::ptr::write(entry, PtEntry::new(table, Permission::Node)) }; current_pt = table as _; @@ -66,9 +60,7 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> { } let node = unsafe { - (*current_pt) - .table - .get_unchecked_mut(addr_extract_index(target, lookup_depth)) + (*current_pt).table.get_unchecked_mut(addr_extract_index(target, lookup_depth)) }; // Check if node is not mapped @@ -95,11 +87,8 @@ impl<'p, A, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, A, OUT_PROG_EXEC> { // Walk page table in reverse for lvl in (0..5).rev() { - let entry = unsafe { - (*current_pt) - .table - .get_unchecked_mut(addr_extract_index(addr, lvl)) - }; + let entry = + unsafe { (*current_pt).table.get_unchecked_mut(addr_extract_index(addr, lvl)) }; let ptr = entry.ptr(); match entry.permission() { diff --git a/hbvm/src/mem/softpaging/mod.rs b/hbvm/src/mem/softpaging/mod.rs index 6696ead..22761ac 100644 --- a/hbvm/src/mem/softpaging/mod.rs +++ b/hbvm/src/mem/softpaging/mod.rs @@ -23,13 +23,13 @@ use { #[derive(Clone, Debug)] pub struct SoftPagedMem<'p, PfH, const OUT_PROG_EXEC: bool = true> { /// Root page table - pub root_pt: *mut PageTable, + pub root_pt: *mut PageTable, /// Page fault handler pub pf_handler: PfH, /// Program memory segment - pub program: &'p [u8], + pub program: &'p [u8], /// Program instruction cache - pub icache: ICache, + pub icache: ICache, } impl<'p, PfH: HandlePageFault, const OUT_PROG_EXEC: bool> Memory @@ -127,10 +127,7 @@ impl<'p, PfH: HandlePageFault, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, PfH, ); // Return shifted from what we've already copied - ( - src.saturating_add(to_copy as u64), - len.saturating_sub(to_copy), - ) + (src.saturating_add(to_copy as u64), len.saturating_sub(to_copy)) } else { (src, len) // Nothing weird! }; @@ -145,12 +142,7 @@ impl<'p, PfH: HandlePageFault, const OUT_PROG_EXEC: bool> SoftPagedMem<'p, PfH, loop { match pspl.next() { // Page is found - Some(Ok(AddrPageLookupOk { - vaddr, - ptr, - size, - perm, - })) => { + Some(Ok(AddrPageLookupOk { vaddr, ptr, size, perm })) => { if !permission_check(perm) { return Err(vaddr); } @@ -243,10 +235,7 @@ pub mod perm_check { /// Page is readable #[inline(always)] pub const fn readable(perm: Permission) -> bool { - matches!( - perm, - Permission::Readonly | Permission::Write | Permission::Exec - ) + matches!(perm, Permission::Readonly | Permission::Write | Permission::Exec) } /// Page is writable diff --git a/hbvm/src/mem/softpaging/paging.rs b/hbvm/src/mem/softpaging/paging.rs index c1ab842..38deed6 100644 --- a/hbvm/src/mem/softpaging/paging.rs +++ b/hbvm/src/mem/softpaging/paging.rs @@ -62,16 +62,13 @@ pub struct PageTable { /// How much entries are in use pub childen: u8, /// Entries - pub table: [PtEntry; 256], + pub table: [PtEntry; 256], } impl Default for PageTable { fn default() -> Self { // SAFETY: It's fine, zeroed page table entry is valid (= empty) - Self { - childen: 0, - table: unsafe { MaybeUninit::zeroed().assume_init() }, - } + Self { childen: 0, table: unsafe { MaybeUninit::zeroed().assume_init() } } } } @@ -80,7 +77,7 @@ impl Default for PageTable { #[repr(C, align(4096))] pub union PtPointedData { /// Node - next page table - pub pt: PageTable, + pub pt: PageTable, /// Leaf pub page: u8, } diff --git a/hbvm/src/vmrun.rs b/hbvm/src/vmrun.rs index fc7645e..603dac3 100644 --- a/hbvm/src/vmrun.rs +++ b/hbvm/src/vmrun.rs @@ -173,9 +173,7 @@ where LI64 => handler!(self, |OpsRD(tg, imm)| self.write_reg(tg, imm)), LRA => handler!(self, |OpsRRO(tg, reg, off)| self.write_reg( tg, - self.pcrel(off) - .wrapping_add(self.read_reg(reg).cast::()) - .get(), + self.pcrel(off).wrapping_add(self.read_reg(reg).cast::()).get(), )), // Load. If loading more than register size, continue on adjecent registers LD => handler!(self, |OpsRRAH(dst, base, off, count)| self @@ -251,9 +249,7 @@ where let OpsRRO(save, reg, offset) = self.decode(); self.write_reg(save, self.pc.next::()); - self.pc = self - .pcrel(offset) - .wrapping_add(self.read_reg(reg).cast::()); + self.pc = self.pcrel(offset).wrapping_add(self.read_reg(reg).cast::()); } JALA => { // Jump and link. Save PC after this instruction to @@ -375,10 +371,7 @@ where /// Bump instruction pointer #[inline(always)] fn bump_pc(&mut self) { - self.pc = self - .pc - .wrapping_add(core::mem::size_of::()) - .wrapping_add(1); + self.pc = self.pc.wrapping_add(core::mem::size_of::()).wrapping_add(1); } /// Decode instruction operands @@ -404,10 +397,7 @@ where unsafe { self.memory.load( self.ldst_addr_uber(dst, base, offset, count, n)?, - self.registers - .as_mut_ptr() - .add(usize::from(dst) + usize::from(n)) - .cast(), + self.registers.as_mut_ptr().add(usize::from(dst) + usize::from(n)).cast(), usize::from(count).saturating_sub(n.into()), ) }?; @@ -444,10 +434,7 @@ where #[inline(always)] unsafe fn binary_op(&mut self, op: impl Fn(T, T) -> T) { let OpsRRR(tg, a0, a1) = unsafe { self.decode() }; - self.write_reg( - tg, - op(self.read_reg(a0).cast::(), self.read_reg(a1).cast::()), - ); + self.write_reg(tg, op(self.read_reg(a0).cast::(), self.read_reg(a1).cast::())); self.bump_pc::(); } @@ -467,13 +454,7 @@ where #[inline(always)] unsafe fn binary_op_shift(&mut self, op: impl Fn(T, u32) -> T) { let OpsRRR(tg, a0, a1) = unsafe { self.decode() }; - self.write_reg( - tg, - op( - self.read_reg(a0).cast::(), - self.read_reg(a1).cast::(), - ), - ); + self.write_reg(tg, op(self.read_reg(a0).cast::(), self.read_reg(a1).cast::())); self.bump_pc::(); } @@ -540,12 +521,7 @@ where #[inline(always)] unsafe fn cond_jmp(&mut self, expected: Ordering) { let OpsRRP(a0, a1, ja) = unsafe { self.decode() }; - if self - .read_reg(a0) - .cast::() - .cmp(&self.read_reg(a1).cast::()) - == expected - { + if self.read_reg(a0).cast::().cmp(&self.read_reg(a1).cast::()) == expected { self.pc = self.pcrel(ja); } else { self.bump_pc::(); diff --git a/hbxrt/src/main.rs b/hbxrt/src/main.rs index 2c0dde0..bde59af 100644 --- a/hbxrt/src/main.rs +++ b/hbxrt/src/main.rs @@ -53,20 +53,16 @@ fn main() -> Result<(), Box> { eprintln!("[I] Image loaded at {:p}", mmap.as_ptr()); let mut vm = unsafe { - Vm::<_, 0>::new( - hbvm::mem::HostMemory, - Address::new(mmap.as_ptr().add(stack.len()) as u64), - ) + Vm::<_, 0>::new(hbvm::mem::HostMemory, Address::new(mmap.as_ptr().add(stack.len()) as u64)) }; vm.write_reg(254, stack.as_mut_ptr() as u64); // Execute program let stat = loop { match vm.run() { - Ok(VmRunOk::Breakpoint) => eprintln!( - "[I] Hit breakpoint\nIP: {}\n== Registers ==\n{:?}", - vm.pc, vm.registers - ), + Ok(VmRunOk::Breakpoint) => { + eprintln!("[I] Hit breakpoint\nIP: {}\n== Registers ==\n{:?}", vm.pc, vm.registers) + } Ok(VmRunOk::Timer) => (), Ok(VmRunOk::Ecall) if dsls => unsafe { std::arch::asm!( diff --git a/rustfmt.toml b/rustfmt.toml index 907ba34..4ac15f1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,7 @@ -hex_literal_case = "Upper" imports_granularity = "One" -struct_field_align_threshold = 8 -enum_discrim_align_threshold = 8 \ No newline at end of file +group_imports = "One" +reorder_impl_items = true +unstable_features = false +overflow_delimited_expr = true +use_small_heuristics = "Max" +use_field_init_shorthand = true diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index cde8bef..a8494b7 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -5,5 +5,4 @@ edition = "2021" [dependencies] argh = "0.1" -color-eyre = "0.6" once_cell = "1.18" diff --git a/xtask/src/fmt.rs b/xtask/src/fmt.rs index 4cce8d7..4be107a 100644 --- a/xtask/src/fmt.rs +++ b/xtask/src/fmt.rs @@ -1,10 +1,9 @@ use { crate::{utils::IterExt, ROOT}, argh::FromArgs, - color_eyre::{eyre::eyre, Result}, std::{ fs::File, - io::{BufRead, BufReader, BufWriter, Seek, Write}, + io::{self, BufRead, BufReader, BufWriter, Seek, Write}, }, }; @@ -17,11 +16,9 @@ pub struct Command { renumber: bool, } -pub fn command(args: Command) -> Result<()> { - let mut file = File::options() - .read(true) - .write(true) - .open(ROOT.join("hbbytecode/instructions.in"))?; +pub fn command(args: Command) -> io::Result<()> { + let mut file = + File::options().read(true).write(true).open(ROOT.join("hbbytecode/instructions.in"))?; // Extract records let reader = BufReader::new(&file); @@ -36,14 +33,11 @@ pub fn command(args: Command) -> Result<()> { return None; } - s.split(',') - .map(|s| Box::::from(s.trim())) - .collect_array::<4>() - .map(Ok::<_, ()>) + s.split(',').map(|s| Box::::from(s.trim())).collect_array::<4>().map(Ok::<_, ()>) }) .transpose() }) { - let rec = rec?.map_err(|_| eyre!("Invalid record format"))?; + let rec = rec?.expect("Valid record format"); for (current, next) in lens.iter_mut().zip(rec.iter()) { *current = (*current).max(next.len()); } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 8468a8f..0fc50f7 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,7 +1,11 @@ mod fmt; mod utils; -use {argh::FromArgs, color_eyre::Result, once_cell::sync::Lazy, std::path::Path}; +use { + argh::FromArgs, + once_cell::sync::Lazy, + std::{io, path::Path}, +}; static ROOT: Lazy<&Path> = Lazy::new(|| Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap()); @@ -18,7 +22,7 @@ enum Subcommands { Format(fmt::Command), } -fn main() -> Result<()> { +fn main() -> io::Result<()> { match argh::from_env::().subcom { Subcommands::Format(com) => fmt::command(com), }