stak_sac/
lib.rs

1//! Utilities to build executable binaries from bytecode files.
2
3#![cfg_attr(all(doc, not(doctest)), feature(doc_cfg))]
4#![no_std]
5
6#[cfg(feature = "std")]
7#[doc(hidden)]
8pub extern crate std;
9
10#[doc(hidden)]
11pub mod __private {
12    #[cfg(feature = "std")]
13    pub use clap;
14    #[cfg(feature = "libc")]
15    pub use libc;
16    #[cfg(feature = "std")]
17    pub use main_error;
18    pub use stak_configuration;
19    pub use stak_device;
20    pub use stak_file;
21    #[cfg(feature = "libc")]
22    pub use stak_libc;
23    pub use stak_macro;
24    pub use stak_process_context;
25    pub use stak_r7rs;
26    pub use stak_time;
27    pub use stak_vm;
28    #[cfg(feature = "std")]
29    pub use std;
30}
31
32/// Defines a `main` function that runs a given source file.
33///
34/// The R7RS standard libraries are based on [the `std` crate](https://doc.rust-lang.org/std/).
35///
36/// The given source file is compiled into bytecode and bundled into a
37/// resulting binary.
38///
39/// # Examples
40///
41/// ```rust
42/// use stak::sac::main;
43///
44/// main!("main.scm");
45/// ```
46#[cfg(feature = "std")]
47#[macro_export]
48macro_rules! main {
49    ($path:expr) => {
50        $crate::main!(
51            $path,
52            $crate::__private::stak_configuration::DEFAULT_HEAP_SIZE
53        );
54    };
55    ($path:expr, $heap_size:expr) => {
56        use $crate::__private::{
57            clap::{self, Parser},
58            main_error::MainError,
59            stak_device::StdioDevice,
60            stak_file::OsFileSystem,
61            stak_macro::include_r7rs,
62            stak_process_context::OsProcessContext,
63            stak_r7rs::SmallPrimitiveSet,
64            stak_time::OsClock,
65            stak_vm::Vm,
66        };
67
68        #[derive(clap::Parser)]
69        #[command(disable_help_flag = true, ignore_errors = true, version)]
70        struct Arguments {
71            #[arg()]
72            arguments: Vec<String>,
73            #[arg(short = 's', long, default_value_t = $heap_size)]
74            heap_size: usize,
75        }
76
77        fn main() -> Result<(), MainError> {
78            let arguments = Arguments::parse();
79
80            let mut heap = vec![Default::default(); arguments.heap_size];
81            let mut vm = Vm::new(
82                &mut heap,
83                SmallPrimitiveSet::new(
84                    StdioDevice::new(),
85                    OsFileSystem::new(),
86                    OsProcessContext::new(),
87                    OsClock::new(),
88                ),
89            )?;
90
91            vm.initialize(include_r7rs!($path).iter().copied())?;
92
93            Ok(vm.run()?)
94        }
95    };
96}
97
98/// Defines a `main` function that runs a given source file.
99///
100/// The R7RS standard libraries are based on [the `libc` crate](https://docs.rs/libc).
101///
102/// The given source file is compiled into bytecode and bundled into a
103/// resulting binary.
104#[cfg(feature = "libc")]
105#[macro_export]
106macro_rules! libc_main {
107    ($path:expr) => {
108        $crate::libc_main!(
109            $path,
110            $crate::__private::stak_configuration::DEFAULT_HEAP_SIZE
111        );
112    };
113    ($path:expr, $heap_size:expr) => {
114        use $crate::__private::{
115            libc::exit,
116            stak_device::libc::{ReadWriteDevice, Stderr, Stdin, Stdout},
117            stak_file::LibcFileSystem,
118            stak_libc::Heap,
119            stak_macro::include_r7rs,
120            stak_process_context::LibcProcessContext,
121            stak_r7rs::SmallPrimitiveSet,
122            stak_time::LibcClock,
123            stak_vm::Vm,
124        };
125
126        #[cfg(not(test))]
127        #[panic_handler]
128        fn panic(_info: &core::panic::PanicInfo) -> ! {
129            unsafe { exit(1) }
130        }
131
132        #[cfg_attr(not(test), unsafe(no_mangle))]
133        unsafe extern "C" fn main(argc: isize, argv: *const *const i8) -> isize {
134            let mut heap = Heap::new($heap_size, Default::default);
135            let mut vm = Vm::new(
136                heap.as_slice_mut(),
137                SmallPrimitiveSet::new(
138                    ReadWriteDevice::new(Stdin::new(), Stdout::new(), Stderr::new()),
139                    LibcFileSystem::new(),
140                    LibcProcessContext::new(argc, argv),
141                    LibcClock::new(),
142                ),
143            )
144            .unwrap();
145
146            vm.initialize(include_r7rs!($path).iter().copied()).unwrap();
147            vm.run().unwrap();
148
149            0
150        }
151    };
152}