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_BYTECODE: &[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 error_message = vec![];
45 let device = ReadWriteDevice::new(source, target, &mut error_message);
46 Vm::new(
47 vec![Default::default(); DEFAULT_HEAP_SIZE],
49 SmallPrimitiveSet::new(
50 device,
51 VoidFileSystem::new(),
52 VoidProcessContext::new(),
53 VoidClock::new(),
54 ),
55 )?
56 .run(COMPILER_BYTECODE.iter().copied())
57 .map_err(|error| {
58 if error_message.is_empty() {
59 CompileError::Run(error)
60 } else {
61 CompileError::User(String::from_utf8_lossy(&error_message).into_owned())
62 }
63 })?;
64
65 Ok(())
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use indoc::indoc;
72
73 mod bare {
74 use super::*;
75
76 #[test]
77 fn compile_nothing() {
78 compile_bare(b"".as_slice(), &mut vec![]).unwrap();
79 }
80
81 #[test]
82 fn compile_define() {
83 compile_bare(b"($$define x 42)".as_slice(), &mut vec![]).unwrap();
84 }
85 }
86
87 mod r7rs {
88 use super::*;
89
90 #[test]
91 fn compile_nothing() {
92 compile_r7rs(b"".as_slice(), &mut vec![]).unwrap();
93 }
94
95 #[test]
96 fn compile_define() {
97 compile_r7rs(b"(define x 42)".as_slice(), &mut vec![]).unwrap();
98 }
99
100 #[test]
101 fn compile_invalid_macro_call() {
102 let Err(CompileError::User(message)) = compile_r7rs(
103 indoc!(
104 r#"
105 (import (scheme base))
106
107 (define-syntax foo
108 (syntax-rules ()
109 ((_)
110 #f)))
111
112 (foo 42)
113 "#
114 )
115 .as_bytes(),
116 &mut vec![],
117 ) else {
118 panic!()
119 };
120
121 assert!(message.contains("invalid syntax"));
122 }
123
124 #[test]
125 fn compile_write_library() {
126 compile_r7rs(b"(import (scheme write))".as_slice(), &mut vec![]).unwrap();
127 }
128 }
129}