Skip to main content

rustscript_embedded/
host.rs

1use std::fmt;
2use std::path::Path;
3
4pub use vm::Value;
5use vm::{
6    JitConfig, SourceMap, Vm, VmStatus, compile_source, compile_source_file,
7    compile_source_for_repl, render_source_error,
8};
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum RunOutcome {
12    Halted { stack: Vec<Value> },
13}
14
15#[derive(Debug)]
16pub enum EmbeddedError {
17    Compile(String),
18    Runtime(String),
19    Io(std::io::Error),
20}
21
22impl fmt::Display for EmbeddedError {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::Compile(message) | Self::Runtime(message) => f.write_str(message),
26            Self::Io(err) => write!(f, "{err}"),
27        }
28    }
29}
30
31impl std::error::Error for EmbeddedError {}
32
33impl From<std::io::Error> for EmbeddedError {
34    fn from(err: std::io::Error) -> Self {
35        Self::Io(err)
36    }
37}
38
39pub type EmbeddedResult<T> = Result<T, EmbeddedError>;
40
41pub fn run_source(source: &str) -> EmbeddedResult<RunOutcome> {
42    let compiled = compile_source(source)
43        .map_err(|err| render_source_compile_error("<memory>", source, err))?;
44    run_program(compiled.program.with_local_count(compiled.locals))
45}
46
47pub fn run_source_file(path: impl AsRef<Path>) -> EmbeddedResult<RunOutcome> {
48    let path = path.as_ref();
49    let compiled =
50        compile_source_file(path).map_err(|err| EmbeddedError::Compile(err.to_string()))?;
51    run_program(compiled.program.with_local_count(compiled.locals))
52}
53
54pub fn eval_repl_entry(source: &str) -> EmbeddedResult<RunOutcome> {
55    let compiled = compile_source_for_repl(source)
56        .map_err(|err| render_source_compile_error("<repl>", source, err))?;
57    run_program(compiled.program.with_local_count(compiled.locals))
58}
59
60pub fn embedded_jit_config() -> JitConfig {
61    JitConfig {
62        enabled: false,
63        ..JitConfig::default()
64    }
65}
66
67pub fn new_vm(program: vm::Program) -> Vm {
68    let mut vm = Vm::new_with_jit_config(program, embedded_jit_config());
69    vm.set_runtime_print_sink(|rendered| {
70        print!("{rendered}");
71    });
72    vm
73}
74
75pub fn render_value(value: &Value) -> String {
76    vm::format_value(value)
77}
78
79fn run_program(program: vm::Program) -> EmbeddedResult<RunOutcome> {
80    let mut vm = new_vm(program);
81    loop {
82        match vm.run() {
83            Ok(VmStatus::Halted) => {
84                return Ok(RunOutcome::Halted {
85                    stack: vm.stack().to_vec(),
86                });
87            }
88            Ok(VmStatus::Yielded) => continue,
89            Ok(VmStatus::Waiting(_)) => vm
90                .wait_for_host_op_blocking()
91                .map_err(|err| EmbeddedError::Runtime(vm::render_vm_error(&vm, &err)))?,
92            Err(err) => return Err(EmbeddedError::Runtime(vm::render_vm_error(&vm, &err))),
93        }
94    }
95}
96
97fn render_source_compile_error(path: &str, source: &str, err: vm::SourceError) -> EmbeddedError {
98    match err {
99        vm::SourceError::Parse(parse) => {
100            let mut source_map = SourceMap::new();
101            let source_id = source_map.add_source(path.to_string(), source.to_string());
102            let parse = parse.with_line_span_from_source(&source_map, source_id);
103            EmbeddedError::Compile(render_source_error(&source_map, &parse, true))
104        }
105        vm::SourceError::Compile(compile) => {
106            let mut source_map = SourceMap::new();
107            source_map.add_source(path.to_string(), source.to_string());
108            EmbeddedError::Compile(vm::render_compile_error(&source_map, &compile, true))
109        }
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn jit_is_disabled() {
119        assert!(!embedded_jit_config().enabled);
120    }
121
122    #[test]
123    fn runs_basic_program() {
124        let _ = eval_repl_entry("print(1 + 2);").expect("program should run");
125    }
126}