poco_scheme/
vm.rs

1use std::{fmt, io, rc::Rc};
2
3use gc::{Finalize, Gc, GcCell};
4use log::debug;
5
6use crate::{
7    ast::{Application, Ast, EnvIndex, EnvStack, Lambda, SyntaxError, TailPosition::*},
8    prim,
9    value::{Closure, Exception, PrimOp, Value},
10};
11
12macro_rules! prim_op {
13    ($name:tt, $func:expr) => {{
14        static OP: PrimOp = PrimOp {
15            name: $name,
16            func: $func,
17        };
18        ($name, Value::PrimOp(&OP))
19    }};
20}
21
22fn initial_env() -> Vec<(&'static str, Value)> {
23    vec![
24        prim_op!("+", prim::plus),
25        prim_op!("-", prim::minus),
26        prim_op!("*", prim::times),
27        prim_op!("<", prim::lt),
28        prim_op!("<=", prim::le),
29        prim_op!(">", prim::gt),
30        prim_op!(">=", prim::ge),
31        prim_op!("=", prim::eq),
32        prim_op!("modulo", prim::modulo),
33        prim_op!("sqrt", prim::sqrt),
34        prim_op!("display", prim::display),
35        prim_op!("newline", prim::newline),
36    ]
37}
38
39#[derive(Debug)]
40pub struct Vm {
41    env: VmEnv,
42    stack: EnvStack,
43}
44
45impl Default for Vm {
46    fn default() -> Self {
47        Vm::new()
48    }
49}
50
51#[derive(Debug)]
52enum VmEnv {
53    Reified(Gc<GcCell<Env>>),
54    Open {
55        parent: Gc<GcCell<Env>>,
56        locals: Vec<Value>,
57    },
58}
59
60impl VmEnv {
61    fn new(lambda: &Lambda, args: Vec<Value>, parent: Gc<GcCell<Env>>) -> Result<Self, Value> {
62        let locals = lambda.alloc_locals(args)?;
63        Ok(VmEnv::Open { parent, locals })
64    }
65}
66
67impl Vm {
68    pub fn new() -> Self {
69        let (idents, values): (Vec<_>, _) = initial_env().iter().cloned().unzip();
70        Vm {
71            env: VmEnv::Reified(Gc::new(GcCell::new(Env::initial(values)))),
72            stack: EnvStack::initial(idents),
73        }
74    }
75
76    pub fn eval(&mut self, expr: &lexpr::Value) -> Result<Value, EvalError> {
77        if let Some(ast) = Ast::definition(&expr, &mut self.stack, NonTail)? {
78            self.eval_ast(&ast)
79                .into_result()
80                .map_err(EvalError::Exception)
81        } else {
82            let bodies = self.stack.reap_rec_bodies()?;
83            let pos = self.local_alloc(bodies.len());
84            self.resolve_bodies(&bodies, pos)?;
85            Ok(Value::Unspecified)
86        }
87    }
88
89    pub fn process<S, E>(&mut self, source: S) -> Processor<S::IntoIter>
90    where
91        S: IntoIterator<Item = Result<lexpr::Value, E>>,
92    {
93        Processor {
94            vm: self,
95            source: source.into_iter(),
96        }
97    }
98
99    fn resolve_bodies(&mut self, bodies: &[Ast], offset: usize) -> Result<(), Box<Exception>> {
100        for (i, body) in bodies.iter().enumerate() {
101            let value = self.eval_ast(body).into_result()?;
102            debug!("resolved body [{}] {:?} -> {}", i, body, value);
103            self.local_set(offset + i, value);
104        }
105        Ok(())
106    }
107
108    fn local_alloc(&mut self, n: usize) -> usize {
109        match &mut self.env {
110            VmEnv::Open { locals, .. } => {
111                let pos = locals.len();
112                locals.resize(pos + n, Value::Unspecified);
113                pos
114            }
115            VmEnv::Reified(env) => env.borrow_mut().local_alloc(n),
116        }
117    }
118
119    fn local_set(&mut self, slot: usize, value: Value) {
120        match &mut self.env {
121            VmEnv::Open { locals, .. } => locals[slot] = value,
122            VmEnv::Reified(env) => env.borrow_mut().local_set(slot, value),
123        }
124    }
125
126    fn eval_ast(&mut self, ast: &Ast) -> Value {
127        match self.eval_step(ast) {
128            Thunk::Resolved(v) => v,
129            Thunk::Eval(ast) => {
130                let mut ast = ast;
131                loop {
132                    match self.eval_step(&ast) {
133                        Thunk::Resolved(v) => break v,
134                        Thunk::Eval(thunk_ast) => {
135                            ast = thunk_ast;
136                        }
137                    }
138                }
139            }
140        }
141    }
142
143    fn eval_step(&mut self, ast: &Ast) -> Thunk {
144        debug!("eval-step: {:?} in {:?}", &ast, &self.env);
145        match &*ast {
146            Ast::EnvRef(idx) => Thunk::Resolved(self.env_lookup(idx)),
147            Ast::Datum(value) => Thunk::Resolved(value.into()),
148            Ast::Lambda(lambda) => {
149                let closure = Value::Closure(Box::new(Closure {
150                    lambda: Rc::clone(lambda),
151                    env: self.reify_env(),
152                }));
153                Thunk::Resolved(closure)
154            }
155            Ast::Seq(exprs, last) => {
156                for expr in exprs {
157                    if let v @ Value::Exception(_) = self.eval_ast(expr) {
158                        return Thunk::Resolved(v);
159                    }
160                }
161                self.eval_step(last)
162            }
163            Ast::Bind(body) => {
164                let pos = self.local_alloc(body.bound_exprs.len());
165                try_result!(self.resolve_bodies(&body.bound_exprs, pos));
166                self.eval_step(&body.expr)
167            }
168            Ast::If(c) => {
169                let cond = try_value!(self.eval_ast(&c.cond));
170                if cond.is_true() {
171                    Thunk::Eval(Rc::clone(&c.consequent))
172                } else {
173                    Thunk::Eval(Rc::clone(&c.alternative))
174                }
175            }
176            Ast::Apply(app) => {
177                let (op, operands) = match self.eval_app(&app) {
178                    Ok(v) => v,
179                    Err(e) => return e.into(),
180                };
181                Thunk::Resolved(self.apply(op, operands))
182            }
183            Ast::TailCall(app) => {
184                let (op, operands) = match self.eval_app(&app) {
185                    Ok(v) => v,
186                    Err(e) => return e.into(),
187                };
188                self.tail_call(op, operands)
189            }
190        }
191    }
192
193    fn eval_app(&mut self, app: &Application) -> Result<(Value, Vec<Value>), Box<Exception>> {
194        let op = self.eval_ast(&app.op).into_result()?;
195        let operands = app
196            .operands
197            .iter()
198            .map(|operand| self.eval_ast(operand).into_result())
199            .collect::<Result<Vec<_>, _>>()?;
200        Ok((op, operands))
201    }
202
203    fn with_env<F, R>(&mut self, env: VmEnv, f: F) -> R
204    where
205        F: FnOnce(&mut Vm) -> R,
206    {
207        let mut tmp = env;
208        std::mem::swap(&mut self.env, &mut tmp);
209        let res = f(self);
210        std::mem::swap(&mut self.env, &mut tmp);
211        res
212    }
213
214    fn tail_call(&mut self, op: Value, args: Vec<Value>) -> Thunk {
215        match op {
216            Value::PrimOp(op) => Thunk::Resolved((op.func)(&args)),
217            Value::Closure(boxed) => {
218                let Closure { lambda, env } = boxed.as_ref();
219                self.env = try_result!(VmEnv::new(lambda, args, env.clone()));
220                try_result!(
221                    self.resolve_bodies(&lambda.body.bound_exprs, lambda.params.env_slots())
222                );
223                self.eval_step(&lambda.body.expr)
224            }
225            _ => make_error!(
226                "non-applicable object in operator position";
227                op
228            )
229            .into(),
230        }
231    }
232
233    fn apply(&mut self, op: Value, args: Vec<Value>) -> Value {
234        match op {
235            Value::PrimOp(op) => (op.func)(&args),
236            Value::Closure(boxed) => {
237                let Closure { lambda, env } = boxed.as_ref();
238                let new_env = try_result!(VmEnv::new(lambda, args, env.clone()));
239                self.with_env(new_env, move |vm| {
240                    try_result!(
241                        vm.resolve_bodies(&lambda.body.bound_exprs, lambda.params.env_slots())
242                    );
243                    vm.eval_ast(&lambda.body.expr)
244                })
245            }
246            _ => make_error!(
247                "non-applicable object in operator position";
248                op
249            ),
250        }
251    }
252
253    fn reify_env(&mut self) -> Gc<GcCell<Env>> {
254        match &mut self.env {
255            VmEnv::Reified(env) => env.clone(),
256            VmEnv::Open { parent, locals } => {
257                let mut new_locals = Vec::new();
258                std::mem::swap(locals, &mut new_locals);
259                let env = Gc::new(GcCell::new(Env::new(parent.clone(), new_locals)));
260                self.env = VmEnv::Reified(env.clone());
261                env
262            }
263        }
264    }
265
266    fn env_lookup(&self, idx: &EnvIndex) -> Value {
267        match &self.env {
268            VmEnv::Open { locals, parent } => {
269                if idx.level() == 0 {
270                    locals[idx.slot()].clone()
271                } else {
272                    parent.borrow().lookup(idx.level() - 1, idx.slot())
273                }
274            }
275            VmEnv::Reified(env) => env.borrow().lookup(idx.level(), idx.slot()),
276        }
277    }
278}
279
280pub struct Processor<'a, S> {
281    vm: &'a mut Vm,
282    source: S,
283}
284
285impl<'a, S, E> Iterator for Processor<'a, S>
286where
287    S: Iterator<Item = Result<lexpr::Value, E>>,
288    E: Into<EvalError>,
289{
290    type Item = Result<Value, EvalError>;
291
292    fn next(&mut self) -> Option<Self::Item> {
293        while let Some(expr) = self.source.next() {
294            let res = expr
295                .map_err(Into::into)
296                .and_then(|expr| Ok(Ast::definition(&expr, &mut self.vm.stack, NonTail)?));
297            if let Some(ast) = res.transpose() {
298                let bodies = match self.vm.stack.reap_rec_bodies() {
299                    Err(e) => return Some(Err(e.into())),
300                    Ok(bodies) => bodies,
301                };
302                let pos = self.vm.local_alloc(bodies.len());
303                return Some(
304                    self.vm
305                        .resolve_bodies(&bodies, pos)
306                        .map_err(Into::into)
307                        .and_then(|_| {
308                            ast.and_then(|ast| {
309                                self.vm
310                                    .eval_ast(&ast)
311                                    .into_result()
312                                    .map_err(EvalError::Exception)
313                            })
314                        }),
315                );
316            }
317        }
318        let res = self
319            .vm
320            .stack
321            .reap_rec_bodies()
322            .map_err(Into::into)
323            .and_then(|bodies| {
324                let pos = self.vm.local_alloc(bodies.len());
325                Ok(self.vm.resolve_bodies(&bodies, pos)?)
326            });
327        // Force syntax check of accumulated bodies
328        match res {
329            Ok(_) => None,
330            Err(e) => Some(Err(e)),
331        }
332    }
333}
334
335#[derive(Default, Clone, Debug)]
336pub struct Env {
337    parent: Option<Gc<GcCell<Env>>>,
338    values: Vec<Value>,
339}
340
341impl Env {
342    pub fn initial(values: Vec<Value>) -> Self {
343        Env {
344            parent: None,
345            values,
346        }
347    }
348
349    pub fn new(parent: Gc<GcCell<Env>>, values: Vec<Value>) -> Self {
350        Env {
351            parent: Some(parent),
352            values,
353        }
354    }
355
356    fn local_alloc(&mut self, n: usize) -> usize {
357        let pos = self.values.len();
358        self.values.resize(pos + n, Value::Unspecified);
359        pos
360    }
361
362    fn local_set(&mut self, offset: usize, value: Value) {
363        self.values[offset] = value;
364    }
365
366    fn lookup(&self, level: usize, slot: usize) -> Value {
367        // Use recursion to get arround the borrow checker here. Should be
368        // turned into an iterative solution, but should not matter too much for
369        // now.
370        if level == 0 {
371            self.values[slot].clone()
372        } else {
373            self.parent
374                .as_ref()
375                .expect("invalid environment reference")
376                .borrow()
377                .lookup(level - 1, slot)
378        }
379    }
380}
381
382impl gc::Finalize for Env {
383    fn finalize(&self) {}
384}
385
386unsafe impl gc::Trace for Env {
387    unsafe fn trace(&self) {
388        if let Some(parent) = &self.parent {
389            parent.trace();
390        }
391        for value in &self.values {
392            value.trace()
393        }
394    }
395    unsafe fn root(&self) {
396        if let Some(parent) = &self.parent {
397            parent.root();
398        }
399        for value in &self.values {
400            value.root()
401        }
402    }
403    unsafe fn unroot(&self) {
404        if let Some(parent) = &self.parent {
405            parent.unroot();
406        }
407        for value in &self.values {
408            value.unroot()
409        }
410    }
411    fn finalize_glue(&self) {
412        self.finalize();
413        if let Some(parent) = &self.parent {
414            parent.finalize();
415        }
416        for value in &self.values {
417            value.finalize()
418        }
419    }
420}
421
422#[derive(Debug)]
423pub enum Thunk {
424    Resolved(Value),
425    Eval(Rc<Ast>),
426}
427
428impl From<Value> for Thunk {
429    fn from(v: Value) -> Self {
430        Thunk::Resolved(v)
431    }
432}
433
434impl From<Box<Exception>> for Thunk {
435    fn from(e: Box<Exception>) -> Self {
436        Thunk::Resolved(Value::Exception(e))
437    }
438}
439
440#[derive(Debug)]
441pub enum EvalError {
442    Io(io::Error),
443    Parse(lexpr::parse::Error),
444    Syntax(SyntaxError),
445    Exception(Box<Exception>),
446}
447
448impl fmt::Display for EvalError {
449    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450        use EvalError::*;
451        match self {
452            Io(e) => write!(f, "I/O error: {}", e),
453            Parse(e) => write!(f, "parse error: {}", e),
454            Exception(e) => write!(f, "runtime exception: {}", e),
455            Syntax(e) => write!(f, "syntax error: {}", e),
456        }
457    }
458}
459
460impl std::error::Error for EvalError {
461    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
462        use EvalError::*;
463        match self {
464            Io(e) => Some(e),
465            Parse(e) => Some(e),
466            Exception(_) => None,
467            Syntax(e) => Some(e),
468        }
469    }
470}
471
472impl From<lexpr::parse::Error> for EvalError {
473    fn from(e: lexpr::parse::Error) -> Self {
474        EvalError::Parse(e)
475    }
476}
477
478impl From<SyntaxError> for EvalError {
479    fn from(e: SyntaxError) -> Self {
480        EvalError::Syntax(e)
481    }
482}
483
484impl From<io::Error> for EvalError {
485    fn from(e: io::Error) -> Self {
486        EvalError::Io(e)
487    }
488}
489
490impl From<Exception> for EvalError {
491    fn from(e: Exception) -> Self {
492        EvalError::Exception(Box::new(e))
493    }
494}
495
496impl From<Box<Exception>> for EvalError {
497    fn from(e: Box<Exception>) -> Self {
498        EvalError::Exception(e)
499    }
500}