sexprs_vm/
virtual_machine.rs

1use std::collections::VecDeque;
2use std::fmt::Debug;
3
4use sexprs_data_structures::{Symbol, Value};
5use sexprs_util::try_result;
6use unique_pointer::UniquePointer;
7
8use crate::{
9    Context, Result, Sym, SymTable,
10    SymbolTable,
11};
12
13#[derive(Clone)]
14pub struct VirtualMachine<'c> {
15    pub symbols: SymbolTable<'c>,
16    stack: VecDeque<UniquePointer<Context<'c>>>,
17}
18
19impl<'c> Debug for VirtualMachine<'c> {
20    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
21        write!(
22            f,
23            "VirtualMachine {{
24    symbols: {:#?},
25    stack_size: {:#?}
26}}",
27            &self.symbols,
28            self.stack.len()
29        )
30    }
31}
32
33impl<'c> VirtualMachine<'c> {
34    pub fn new() -> VirtualMachine<'c> {
35        let vm = VirtualMachine {
36            symbols: SymbolTable::new(),
37            stack: VecDeque::new(),
38        };
39        vm
40    }
41
42    pub fn setq(&mut self, symbol: Symbol<'c>, value: Value<'c>) -> Result<Value<'c>> {
43        let context = self.push_context();
44        let previous = try_result!(self.symbols.set_global(context, &symbol, &Sym::Value(value)));
45        self.update_symbols();
46        Ok(previous)
47    }
48    pub fn symbols(&self) -> SymTable<'c> {
49        self.symbols.locals.clone()
50    }
51
52    pub(crate) fn push_context(&mut self) -> UniquePointer<Context<'c>> {
53        let context = UniquePointer::<Context<'c>>::from(Context::new(
54            UniquePointer::read_only(self),
55            self.symbols.clone(),
56        ));
57        self.stack.push_front(context.clone());
58        context
59    }
60
61    pub(crate) fn last_context(&self) -> Option<&UniquePointer<Context<'c>>> {
62        self.stack.front()
63    }
64
65    pub(crate) fn update_symbols(&mut self) {
66        if let Some(context) = self.last_context() {
67            self.symbols.extend(context.symbols.clone());
68        }
69    }
70
71    pub fn eval_string(&mut self, string: &'c str) -> Result<Value<'c>> {
72        let value = try_result!(self.push_context().eval_string(string));
73        self.update_symbols();
74        Ok(value)
75    }
76
77    pub fn eval(&mut self, item: Value<'c>) -> Result<Value<'c>> {
78        let value = try_result!(self.push_context().eval(item));
79        self.update_symbols();
80        Ok(value)
81    }
82
83    pub fn eval_symbol_function(
84        &mut self,
85        sym: &Symbol<'c>,
86        list: Value<'c>,
87    ) -> Result<Value<'c>> {
88        let value = try_result!(self
89            .push_context()
90            .eval_symbol_function(sym, list));
91        self.update_symbols();
92        Ok(value)
93    }
94}