sexprs_vm/
virtual_machine.rs1use 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}