diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1208f767e..78bbf8b9a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -94,7 +94,7 @@ jobs: tags: not @library - name: stak-tools - name: mstak - tags: not @command-line and not @environment-variable and not @library + tags: not @environment-variable and not @library - name: mstak-tools tags: not @environment-variable exclude: diff --git a/Cargo.lock b/Cargo.lock index 42c6ad3ad..c23268df1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -620,6 +620,7 @@ name = "stak-sac" version = "0.1.44" dependencies = [ "clap", + "libc", "main_error", "stak-configuration", "stak-device", @@ -627,9 +628,17 @@ dependencies = [ "stak-macro", "stak-primitive", "stak-process-context", + "stak-util", "stak-vm", ] +[[package]] +name = "stak-util" +version = "0.1.18" +dependencies = [ + "libc", +] + [[package]] name = "stak-vm" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 8ebff89b1..5f36276e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "process_context", "profiler", "sac", + "util", "vm", "wasm", ] @@ -61,6 +62,12 @@ codegen-units = 1 lto = true panic = "abort" +[profile.release_test] +inherits = "release" +debug = "line-tables-only" +debug-assertions = true +overflow-checks = true + [profile.dev.build-override] opt-level = 3 debug-assertions = false @@ -71,8 +78,7 @@ opt-level = 3 debug-assertions = false overflow-checks = false -[profile.release_test] -inherits = "release" -debug = "line-tables-only" -debug-assertions = true -overflow-checks = true +[profile.release_test.build-override] +opt-level = 3 +debug-assertions = false +overflow-checks = false diff --git a/cmd/compile/Cargo.toml b/cmd/compile/Cargo.toml index 09211d89e..5264d0b9c 100644 --- a/cmd/compile/Cargo.toml +++ b/cmd/compile/Cargo.toml @@ -9,7 +9,7 @@ readme.workspace = true repository.workspace = true [dependencies] -stak-sac = { version = "0.1", path = "../../sac" } +stak-sac = { version = "0.1", path = "../../sac", features = ["std"] } [lints] workspace = true diff --git a/cmd/minify/Cargo.toml b/cmd/minify/Cargo.toml index 69aff2d4a..952de5ea6 100644 --- a/cmd/minify/Cargo.toml +++ b/cmd/minify/Cargo.toml @@ -9,7 +9,7 @@ readme.workspace = true repository.workspace = true [dependencies] -stak-sac = { version = "0.1.44", path = "../../sac" } +stak-sac = { version = "0.1.44", path = "../../sac", features = ["std"] } [lints] workspace = true diff --git a/cmd/minimal/Cargo.lock b/cmd/minimal/Cargo.lock index efc09a379..c69e192f9 100644 --- a/cmd/minimal/Cargo.lock +++ b/cmd/minimal/Cargo.lock @@ -37,14 +37,7 @@ checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" name = "mstak" version = "0.1.18" dependencies = [ - "libc", - "mstak-util", - "stak-configuration", - "stak-device", - "stak-file", - "stak-primitive", - "stak-process-context", - "stak-vm", + "stak-sac", ] [[package]] @@ -52,19 +45,30 @@ name = "mstak-interpret" version = "0.1.17" dependencies = [ "libc", - "mstak-util", "stak-device", "stak-file", "stak-primitive", "stak-process-context", + "stak-util", "stak-vm", ] [[package]] -name = "mstak-util" -version = "0.1.18" +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ - "libc", + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", ] [[package]] @@ -77,6 +81,18 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "stak-code" version = "0.2.41" +[[package]] +name = "stak-compiler" +version = "0.1.46" +dependencies = [ + "stak-configuration", + "stak-device", + "stak-file", + "stak-primitive", + "stak-process-context", + "stak-vm", +] + [[package]] name = "stak-configuration" version = "0.1.38" @@ -95,6 +111,26 @@ dependencies = [ "libc", ] +[[package]] +name = "stak-macro" +version = "0.1.43" +dependencies = [ + "proc-macro2", + "quote", + "stak-compiler", + "stak-macro-util", + "syn", +] + +[[package]] +name = "stak-macro-util" +version = "0.1.19" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "stak-primitive" version = "0.5.0" @@ -110,9 +146,48 @@ dependencies = [ name = "stak-process-context" version = "0.2.0" +[[package]] +name = "stak-sac" +version = "0.1.44" +dependencies = [ + "libc", + "stak-configuration", + "stak-device", + "stak-file", + "stak-macro", + "stak-primitive", + "stak-process-context", + "stak-util", + "stak-vm", +] + +[[package]] +name = "stak-util" +version = "0.1.18" +dependencies = [ + "libc", +] + [[package]] name = "stak-vm" version = "0.5.0" dependencies = [ "stak-code", ] + +[[package]] +name = "syn" +version = "2.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/cmd/minimal/Cargo.toml b/cmd/minimal/Cargo.toml index f79480410..eb331aa78 100644 --- a/cmd/minimal/Cargo.toml +++ b/cmd/minimal/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["interpret", "run", "util"] +members = ["interpret", "run"] [workspace.package] edition = "2021" @@ -23,13 +23,23 @@ todo = "deny" unimplemented = "deny" use_self = "deny" +[profile.dev] +lto = true +opt-level = 3 +panic = "abort" + [profile.release] codegen-units = 1 lto = true panic = "abort" strip = true -[profile.dev] -lto = true +[profile.dev.build-override] opt-level = 3 -panic = "abort" +debug-assertions = false +overflow-checks = false + +[profile.release.build-override] +opt-level = 3 +debug-assertions = false +overflow-checks = false diff --git a/cmd/minimal/interpret/Cargo.toml b/cmd/minimal/interpret/Cargo.toml index b8c1eec3b..6284875e6 100644 --- a/cmd/minimal/interpret/Cargo.toml +++ b/cmd/minimal/interpret/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true [dependencies] libc = { version = "0.2", default-features = false } -mstak-util = { version = "0.1.18", path = "../util" } +stak-util = { version = "0.1.18", path = "../../../util" } stak-device = { version = "0.2.24", path = "../../../device", features = [ "libc", ] } @@ -24,12 +24,12 @@ stak-vm = { version = "0.5.0", path = "../../../vm" } [lints] workspace = true -[profile.release] -codegen-units = 1 +[profile.dev] lto = true +opt-level = 3 panic = "abort" -[profile.dev] +[profile.release] +codegen-units = 1 lto = true -opt-level = 3 panic = "abort" diff --git a/cmd/minimal/interpret/src/main.rs b/cmd/minimal/interpret/src/main.rs index 248303998..f7d8ebd32 100644 --- a/cmd/minimal/interpret/src/main.rs +++ b/cmd/minimal/interpret/src/main.rs @@ -10,11 +10,11 @@ #![cfg_attr(not(test), no_main)] use core::{ffi::CStr, mem::size_of, slice}; -use mstak_util::Mmap; use stak_device::libc::{ReadWriteDevice, Stderr, Stdin, Stdout}; use stak_file::LibcFileSystem; use stak_primitive::SmallPrimitiveSet; use stak_process_context::LibcProcessContext; +use stak_util::Mmap; use stak_vm::{Value, Vm}; const HEAP_SIZE: usize = 1 << 19; diff --git a/cmd/minimal/run/Cargo.toml b/cmd/minimal/run/Cargo.toml index 0a5fc580b..4d35d4e49 100644 --- a/cmd/minimal/run/Cargo.toml +++ b/cmd/minimal/run/Cargo.toml @@ -9,26 +9,17 @@ readme.workspace = true repository.workspace = true [dependencies] -libc = { version = "0.2", default-features = false } -mstak-util = { version = "0.1.18", path = "../util" } -stak-configuration = { version = "0.1.20", path = "../../../configuration" } -stak-device = { version = "0.2.24", path = "../../../device", features = [ - "libc", -] } -stak-file = { version = "0.4.0", path = "../../../file", features = ["libc"] } -stak-primitive = { version = "0.5.0", path = "../../../primitive" } -stak-process-context = { version = "0.2.0", path = "../../../process_context" } -stak-vm = { version = "0.5.0", path = "../../../vm" } +stak-sac = { version = "0.1.44", path = "../../../sac", features = ["libc"] } [lints] workspace = true -[profile.release] -codegen-units = 1 +[profile.dev] lto = true +opt-level = 3 panic = "abort" -[profile.dev] +[profile.release] +codegen-units = 1 lto = true -opt-level = 3 panic = "abort" diff --git a/cmd/minimal/run/build.rs b/cmd/minimal/run/build.rs deleted file mode 100644 index e74961f40..000000000 --- a/cmd/minimal/run/build.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! A build script. - -use std::{ - env, - error::Error, - fs::{self, File}, - io::{self, Write}, - path::Path, - process::{Command, Stdio}, -}; - -const PRELUDE_SOURCE_FILE: &str = "src/prelude.scm"; -const COMPILER_SOURCE_FILE: &str = "src/compile.scm"; -const MINIFIER_SOURCE_FILE: &str = "src/minify.scm"; - -fn main() -> Result<(), Box> { - build( - MINIFIER_SOURCE_FILE, - &[PRELUDE_SOURCE_FILE], - "prelude.scm", - "STAK_PRELUDE_FILE", - )?; - build( - COMPILER_SOURCE_FILE, - &[PRELUDE_SOURCE_FILE, COMPILER_SOURCE_FILE], - "compile.bc", - "STAK_COMPILER_FILE", - )?; - - Ok(()) -} - -fn build( - script_file: &str, - input_files: &[&str], - output_file: &str, - environment_variable: &str, -) -> Result<(), Box> { - let target_file = Path::new(&env::var("OUT_DIR")?).join(output_file); - - println!( - "cargo:rustc-env={environment_variable}={}", - target_file.display() - ); - - let mut command = Command::new(option_env!("STAK_HOST_INTERPRETER").unwrap_or("stak")) - .arg(script_file) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - let stdin = command.stdin.as_mut().expect("stdin"); - - for file in input_files { - println!("cargo:rerun-if-changed={file}"); - stdin.write_all(&fs::read(file)?)?; - } - - command.wait()?; - - io::copy( - &mut command.stdout.expect("stdout"), - &mut File::options() - .create(true) - .write(true) - .truncate(true) - .open(target_file)?, - )?; - - Ok(()) -} diff --git a/cmd/minimal/run/src/compile.scm b/cmd/minimal/run/src/compile.scm deleted file mode 120000 index 7af38ed16..000000000 --- a/cmd/minimal/run/src/compile.scm +++ /dev/null @@ -1 +0,0 @@ -../../../../compile.scm \ No newline at end of file diff --git a/cmd/minimal/run/src/main.rs b/cmd/minimal/run/src/main.rs index 6bbc5857f..acef2aefb 100644 --- a/cmd/minimal/run/src/main.rs +++ b/cmd/minimal/run/src/main.rs @@ -9,84 +9,4 @@ #![no_std] #![cfg_attr(not(test), no_main)] -use core::{array, env, ffi::CStr, slice}; -use mstak_util::{Heap, Mmap}; -use stak_configuration::DEFAULT_HEAP_SIZE; -use stak_device::libc::{Buffer, BufferMut, Read, ReadWriteDevice, Stderr, Stdin, Stdout, Write}; -use stak_file::{LibcFileSystem, VoidFileSystem}; -use stak_primitive::SmallPrimitiveSet; -use stak_process_context::VoidProcessContext; -use stak_vm::{Value, Vm}; - -const PRELUDE_SOURCE: &str = include_str!(env!("STAK_PRELUDE_FILE")); -const COMPILER_BYTECODES: &[u8] = include_bytes!(env!("STAK_COMPILER_FILE")); - -const DEFAULT_BUFFER_SIZE: usize = 1 << 18; -const MAX_SOURCE_FILE_COUNT: usize = 4; - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - unsafe { libc::exit(1) } -} - -#[cfg_attr(not(test), no_mangle)] -unsafe extern "C" fn main(argc: isize, argv: *const *const i8) -> isize { - let arguments = &slice::from_raw_parts(argv, argc as _)[1..]; - - if arguments.is_empty() { - return 1; - } - - let mut mmaps = array::from_fn::<_, MAX_SOURCE_FILE_COUNT, _>(|_| None); - - for (index, &path) in arguments.iter().enumerate() { - mmaps[index] = Some(Mmap::new(CStr::from_ptr(path))); - } - - let mut sources = [Default::default(); MAX_SOURCE_FILE_COUNT + 1]; - - sources[0] = PRELUDE_SOURCE.as_bytes(); - - for (index, mmap) in mmaps.iter().enumerate() { - if let Some(mmap) = mmap { - sources[index + 1] = mmap.as_slice(); - } - } - - let mut buffer = Heap::new(DEFAULT_BUFFER_SIZE, Default::default); - let mut target = BufferMut::new(buffer.as_slice_mut()); - let mut heap = Heap::new(DEFAULT_HEAP_SIZE, Default::default); - - compile(Buffer::new(&sources), &mut target, heap.as_slice_mut()); - - let mut vm = Vm::new( - heap.as_slice_mut(), - SmallPrimitiveSet::new( - ReadWriteDevice::new(Stdin::new(), Stdout::new(), Stderr::new()), - LibcFileSystem::new(), - VoidProcessContext::new(), - ), - ) - .unwrap(); - - vm.initialize(target.as_bytes().iter().copied()).unwrap(); - vm.run().unwrap(); - - 0 -} - -fn compile(source: impl Read, target: impl Write, heap: &mut [Value]) { - let mut vm = Vm::new( - heap, - SmallPrimitiveSet::new( - ReadWriteDevice::new(source, target, Stderr::new()), - VoidFileSystem::new(), - VoidProcessContext::new(), - ), - ) - .unwrap(); - - vm.initialize(COMPILER_BYTECODES.iter().copied()).unwrap(); - vm.run().unwrap() -} +stak_sac::libc_main!("main.scm"); diff --git a/cmd/minimal/run/src/main.scm b/cmd/minimal/run/src/main.scm new file mode 120000 index 000000000..bd9938175 --- /dev/null +++ b/cmd/minimal/run/src/main.scm @@ -0,0 +1 @@ +../../../run/src/main.scm \ No newline at end of file diff --git a/cmd/minimal/run/src/minify.scm b/cmd/minimal/run/src/minify.scm deleted file mode 120000 index c9138e18e..000000000 --- a/cmd/minimal/run/src/minify.scm +++ /dev/null @@ -1 +0,0 @@ -../../../../minify.scm \ No newline at end of file diff --git a/cmd/minimal/run/src/prelude.scm b/cmd/minimal/run/src/prelude.scm deleted file mode 120000 index 0b75ea0f5..000000000 --- a/cmd/minimal/run/src/prelude.scm +++ /dev/null @@ -1 +0,0 @@ -../../../../prelude.scm \ No newline at end of file diff --git a/cmd/run/Cargo.toml b/cmd/run/Cargo.toml index 996063143..d0f90395b 100644 --- a/cmd/run/Cargo.toml +++ b/cmd/run/Cargo.toml @@ -9,7 +9,7 @@ readme.workspace = true repository.workspace = true [dependencies] -stak-sac = { version = "0.1.44", path = "../../sac" } +stak-sac = { version = "0.1.44", path = "../../sac", features = ["std"] } [lints] workspace = true diff --git a/sac/Cargo.toml b/sac/Cargo.toml index 9aa30ba6a..5935a3955 100644 --- a/sac/Cargo.toml +++ b/sac/Cargo.toml @@ -8,17 +8,29 @@ license-file.workspace = true readme.workspace = true repository.workspace = true +[features] +libc = ["dep:libc", "dep:stak-util", "stak-device/libc", "stak-file/libc"] +std = [ + "dep:clap", + "dep:main_error", + "stak-device/std", + "stak-file/std", + "stak-primitive/std", + "stak-process-context/std", + "stak-vm/std", +] + [dependencies] -clap = { version = "4.5.9", features = ["derive"] } -main_error = "0.1.2" +clap = { version = "4.5.9", features = ["derive"], optional = true } +libc = { version = "0.2", default-features = false, optional = true } +main_error = { version = "0.1.2", optional = true } stak-configuration = { version = "0.1.38", path = "../configuration" } -stak-device = { version = "0.2.42", path = "../device", features = ["std"] } -stak-file = { version = "0.4.0", path = "../file", features = ["std"] } +stak-device = { version = "0.2.42", path = "../device" } +stak-file = { version = "0.4.0", path = "../file" } stak-macro = { version = "0.1.43", path = "../macro" } -stak-primitive = { version = "0.5.0", path = "../primitive", features = [ - "std", -] } +stak-primitive = { version = "0.5.0", path = "../primitive" } stak-process-context = { version = "0.2.0", path = "../process_context", features = [ - "std", + "libc", ] } -stak-vm = { version = "0.5.0", path = "../vm", features = ["std"] } +stak-util = { version = "0.1.18", path = "../util", optional = true } +stak-vm = { version = "0.5.0", path = "../vm" } diff --git a/sac/src/lib.rs b/sac/src/lib.rs index 1c98145e0..6d6377e48 100644 --- a/sac/src/lib.rs +++ b/sac/src/lib.rs @@ -1,8 +1,17 @@ //! Utilities to build executable binaries from bytecode files. +#![no_std] + +#[cfg(feature = "std")] +pub extern crate std; + #[doc(hidden)] pub mod __private { + #[cfg(feature = "std")] pub use clap; + #[cfg(feature = "libc")] + pub use libc; + #[cfg(feature = "std")] pub use main_error; pub use stak_configuration; pub use stak_device; @@ -10,13 +19,18 @@ pub mod __private { pub use stak_macro; pub use stak_primitive; pub use stak_process_context; + #[cfg(feature = "libc")] + pub use stak_util; pub use stak_vm; + #[cfg(feature = "std")] pub use std; } -/// Defines a `main` function that executes a bytecode file at a given path. +/// Defines a `main` function that executes a source file at a given path. /// -/// The given bytecode file is bundled into a resulting binary. +/// The given source file is compiled into bytecodes and bundled into a +/// resulting binary. +#[cfg(feature = "std")] #[macro_export] macro_rules! main { ($path:expr) => { @@ -35,7 +49,6 @@ macro_rules! main { stak_primitive::SmallPrimitiveSet, stak_process_context::OsProcessContext, stak_vm::Vm, - std::{env, error::Error}, }; #[derive(clap::Parser)] @@ -66,3 +79,55 @@ macro_rules! main { } }; } + +/// Defines a `main` function that executes a source file at a given path. +/// +/// The given source file is compiled into bytecodes and bundled into a +/// resulting binary. +#[cfg(feature = "libc")] +#[macro_export] +macro_rules! libc_main { + ($path:expr) => { + $crate::libc_main!( + $path, + $crate::__private::stak_configuration::DEFAULT_HEAP_SIZE + ); + }; + ($path:expr, $heap_size:expr) => { + use $crate::__private::{ + libc::exit, + stak_device::libc::{ReadWriteDevice, Stderr, Stdin, Stdout}, + stak_file::LibcFileSystem, + stak_macro::include_r7rs, + stak_primitive::SmallPrimitiveSet, + stak_process_context::LibcProcessContext, + stak_util::Heap, + stak_vm::Vm, + }; + + #[cfg(not(test))] + #[panic_handler] + fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { exit(1) } + } + + #[cfg_attr(not(test), no_mangle)] + unsafe extern "C" fn main(argc: isize, argv: *const *const i8) -> isize { + let mut heap = Heap::new($heap_size, Default::default); + let mut vm = Vm::new( + heap.as_slice_mut(), + SmallPrimitiveSet::new( + ReadWriteDevice::new(Stdin::new(), Stdout::new(), Stderr::new()), + LibcFileSystem::new(), + LibcProcessContext::new(argc, argv), + ), + ) + .unwrap(); + + vm.initialize(include_r7rs!($path).iter().copied()).unwrap(); + vm.run().unwrap(); + + 0 + } + }; +} diff --git a/cmd/minimal/util/Cargo.toml b/util/Cargo.toml similarity index 79% rename from cmd/minimal/util/Cargo.toml rename to util/Cargo.toml index dc0839e3e..00dc26051 100644 --- a/cmd/minimal/util/Cargo.toml +++ b/util/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "mstak-util" -description = "Minimal Stak Scheme utilities" +name = "stak-util" +description = "Stak Scheme utilities" version = "0.1.18" edition.workspace = true keywords.workspace = true diff --git a/cmd/minimal/util/src/heap.rs b/util/src/heap.rs similarity index 100% rename from cmd/minimal/util/src/heap.rs rename to util/src/heap.rs diff --git a/cmd/minimal/util/src/lib.rs b/util/src/lib.rs similarity index 100% rename from cmd/minimal/util/src/lib.rs rename to util/src/lib.rs diff --git a/cmd/minimal/util/src/mmap.rs b/util/src/mmap.rs similarity index 96% rename from cmd/minimal/util/src/mmap.rs rename to util/src/mmap.rs index 8d299ffc8..461965b55 100644 --- a/cmd/minimal/util/src/mmap.rs +++ b/util/src/mmap.rs @@ -29,7 +29,7 @@ impl Mmap { } /// Returns a slice of bytes. - pub fn as_slice(&self) -> &[u8] { + pub const fn as_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.ptr, self.len) } } } diff --git a/cmd/minimal/util/src/validate.rs b/util/src/validate.rs similarity index 100% rename from cmd/minimal/util/src/validate.rs rename to util/src/validate.rs