1mod error;
4
5pub use self::error::CompileError;
6use core::env;
7use stak_configuration::DEFAULT_HEAP_SIZE;
8use stak_device::ReadWriteDevice;
9use stak_file::VoidFileSystem;
10use stak_process_context::VoidProcessContext;
11use stak_r7rs::SmallPrimitiveSet;
12use stak_time::VoidClock;
13use stak_vm::Vm;
14use std::io::{Read, Write};
15
16const PRELUDE_SOURCE: &str = include_str!("prelude.scm");
17const COMPILER_BYTECODES: &[u8] = include_bytes!(env!("STAK_BYTECODE_FILE"));
18
19pub fn compile_r7rs(source: impl Read, target: impl Write) -> Result<(), CompileError> {
30 compile_bare(PRELUDE_SOURCE.as_bytes().chain(source), target)
31}
32
33pub fn compile_bare(source: impl Read, target: impl Write) -> Result<(), CompileError> {
44 let mut heap = vec![Default::default(); DEFAULT_HEAP_SIZE];
46 let mut error_message = vec![];
47 let device = ReadWriteDevice::new(source, target, &mut error_message);
48 let mut vm = Vm::new(
49 &mut heap,
50 SmallPrimitiveSet::new(
51 device,
52 VoidFileSystem::new(),
53 VoidProcessContext::new(),
54 VoidClock::new(),
55 ),
56 )?;
57
58 vm.initialize(COMPILER_BYTECODES.iter().copied())?;
59
60 vm.run().map_err(|error| {
61 if error_message.is_empty() {
62 CompileError::Run(error)
63 } else {
64 CompileError::User(String::from_utf8_lossy(&error_message).into_owned())
65 }
66 })?;
67
68 Ok(())
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use indoc::indoc;
75
76 mod bare {
77 use super::*;
78
79 #[test]
80 fn compile_nothing() {
81 compile_bare(b"".as_slice(), &mut vec![]).unwrap();
82 }
83
84 #[test]
85 fn compile_define() {
86 compile_bare(b"($$define x 42)".as_slice(), &mut vec![]).unwrap();
87 }
88 }
89
90 mod r7rs {
91 use super::*;
92
93 #[test]
94 fn compile_nothing() {
95 compile_r7rs(b"".as_slice(), &mut vec![]).unwrap();
96 }
97
98 #[test]
99 fn compile_define() {
100 compile_r7rs(b"(define x 42)".as_slice(), &mut vec![]).unwrap();
101 }
102
103 #[test]
104 fn compile_invalid_macro_call() {
105 let Err(CompileError::User(message)) = compile_r7rs(
106 indoc!(
107 r#"
108 (import (scheme base))
109
110 (define-syntax foo
111 (syntax-rules ()
112 ((_)
113 #f)))
114
115 (foo 42)
116 "#
117 )
118 .as_bytes(),
119 &mut vec![],
120 ) else {
121 panic!()
122 };
123
124 assert!(message.contains("invalid syntax"));
125 }
126
127 #[test]
128 fn compile_write_library() {
129 compile_r7rs(b"(import (scheme write))".as_slice(), &mut vec![]).unwrap();
130 }
131 }
132}