stak_wasm/
repl.rs

1use cfg_elif::item;
2use stak_device::Device;
3use stak_file::VoidFileSystem;
4use stak_macro::include_module;
5use stak_module::Module;
6use stak_process_context::VoidProcessContext;
7use stak_r7rs::SmallPrimitiveSet;
8use stak_time::VoidClock;
9use stak_vm::Vm;
10use std::io;
11use wasm_bindgen::prelude::*;
12use winter_maybe_async::{maybe_async, maybe_await};
13
14item::feature!(if ("async") {
15    // `maybe_async` does not work here because `wasm_bindgen`'s expansion happens
16    // first.
17    #[wasm_bindgen]
18    extern "C" {
19        async fn read_stdin() -> JsValue;
20        async fn write_stdout(byte: u8);
21        async fn write_stderr(byte: u8);
22    }
23} else {
24    #[wasm_bindgen]
25    extern "C" {
26        fn read_stdin() -> JsValue;
27        fn write_stdout(byte: u8);
28        fn write_stderr(byte: u8);
29    }
30});
31
32/// Runs a REPL interpreter.
33#[maybe_async]
34#[wasm_bindgen]
35pub fn repl(heap_size: usize) -> Result<(), JsError> {
36    let mut vm = Vm::new(
37        vec![Default::default(); heap_size],
38        SmallPrimitiveSet::new(
39            JsDevice {},
40            VoidFileSystem::new(),
41            VoidProcessContext::new(),
42            VoidClock::new(),
43        ),
44    )?;
45
46    maybe_await!(
47        vm.run_async(
48            include_module!("repl.scm", stak_module)
49                .bytecode()
50                .iter()
51                .copied()
52        )
53    )?;
54
55    Ok(())
56}
57
58struct JsDevice {}
59
60impl Device for JsDevice {
61    type Error = io::Error;
62
63    #[maybe_async]
64    fn read(&mut self) -> Result<Option<u8>, Self::Error> {
65        let byte = maybe_await!(read_stdin());
66
67        if byte.is_null() {
68            Ok(None)
69        } else {
70            Ok(Some(byte.as_f64().unwrap() as _))
71        }
72    }
73
74    #[maybe_async]
75    fn write(&mut self, byte: u8) -> Result<(), Self::Error> {
76        maybe_await!(write_stdout(byte));
77        Ok(())
78    }
79
80    #[maybe_async]
81    fn write_error(&mut self, byte: u8) -> Result<(), Self::Error> {
82        maybe_await!(write_stderr(byte));
83        Ok(())
84    }
85}