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 #[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#[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}