stak_wasm/
lib.rs

1//! A Stak Scheme interpreter in WASM.
2
3mod repl;
4
5use core::str;
6pub use repl::repl;
7use stak_compiler::compile_r7rs;
8use stak_device::ReadWriteDevice;
9use stak_file::{MemoryFileSystem, VoidFileSystem};
10use stak_macro::include_module;
11use stak_module::Module;
12use stak_process_context::{MemoryProcessContext, VoidProcessContext};
13use stak_r7rs::SmallPrimitiveSet;
14use stak_time::VoidClock;
15use stak_vm::Vm;
16use wasm_bindgen::prelude::*;
17
18/// Compiles source codes in Scheme.
19#[wasm_bindgen]
20pub fn compile(source: &str) -> Result<Vec<u8>, JsError> {
21    let mut target = vec![];
22    compile_r7rs(source.as_bytes(), &mut target)?;
23    Ok(target)
24}
25
26/// Interprets bytecode with standard input and returns its standard output.
27#[wasm_bindgen]
28pub fn interpret(bytecode: &[u8], input: &[u8], heap_size: usize) -> Result<Vec<u8>, JsError> {
29    let mut heap = vec![Default::default(); heap_size];
30    let mut output = vec![];
31    let mut error = vec![];
32
33    let mut vm = Vm::new(
34        &mut heap,
35        SmallPrimitiveSet::new(
36            ReadWriteDevice::new(input, &mut output, &mut error),
37            VoidFileSystem::new(),
38            VoidProcessContext::new(),
39            VoidClock::new(),
40        ),
41    )?;
42
43    vm.initialize(bytecode.iter().copied())?;
44    vm.run()?;
45
46    Ok(output)
47}
48
49/// Runs a Scheme script with standard input and returns its standard output.
50#[wasm_bindgen]
51pub fn run(source: &str, input: &[u8], heap_size: usize) -> Result<Vec<u8>, JsError> {
52    const MAIN_FILE: &str = "main.scm";
53
54    let mut heap = vec![Default::default(); heap_size];
55    let mut output = vec![];
56    let mut error = vec![];
57    let files = [(MAIN_FILE.as_bytes(), source.as_bytes())];
58    let mut file_entries = [Default::default(); 1];
59
60    let mut vm = Vm::new(
61        &mut heap,
62        SmallPrimitiveSet::new(
63            ReadWriteDevice::new(input, &mut output, &mut error),
64            MemoryFileSystem::new(&files, &mut file_entries),
65            MemoryProcessContext::new(&["scheme", MAIN_FILE], &[]),
66            VoidClock::new(),
67        ),
68    )?;
69
70    vm.initialize(
71        include_module!("run.scm", stak_module)
72            .bytecode()
73            .iter()
74            .copied(),
75    )?;
76    vm.run().map_err(|vm_error| match str::from_utf8(&error) {
77        Ok(error) if !error.is_empty() => JsError::new(error),
78        Ok(_) => JsError::from(vm_error),
79        Err(error) => JsError::from(error),
80    })?;
81
82    Ok(output)
83}