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