Implement closures+upvalues, rework virtual machine

This commit is contained in:
2026-05-18 17:02:58 +03:00
parent 4131cb121b
commit 92d0a80fb1
64 changed files with 4469 additions and 3517 deletions
+174 -174
View File
@@ -1,174 +1,174 @@
use std::io::{self, BufReader, Read};
use lysp::{
error::{EvalError, MachineError, MachineErrorKind},
read::{FileReader, read},
vm::{env::Environment, machine::Machine, prelude, value::Value},
};
struct SliceReader<'a>(&'a [u8]);
impl Read for SliceReader<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let count = self.0.len().min(buf.len());
buf[..count].copy_from_slice(&self.0[..count]);
self.0 = &self.0[count..];
Ok(count)
}
}
fn eval_str_in(code: &str, env: &mut Environment) -> Result<Value, EvalError> {
let mut machine = Machine::default();
let reader = BufReader::new(SliceReader(code.as_bytes()));
let mut reader = FileReader::new(reader);
let mut last_value = None;
loop {
let value = match read(&mut reader, &mut machine, env) {
Ok(Some(value)) => value,
Ok(None) => break,
Err(error) => panic!("{error}"),
};
last_value = Some(machine.eval_value(Default::default(), env, value, false));
}
last_value.expect("no expressions evaluated")
}
fn eval_str(code: &str) -> Value {
let mut env = Environment::default();
prelude::load(&mut env);
eval_str_in(code, &mut env).expect("expression evaluation failed")
}
fn eval_str_err(code: &str) -> EvalError {
let mut env = Environment::default();
prelude::load(&mut env);
eval_str_in(code, &mut env).expect_err("expression was expected to fail")
}
#[test]
fn test_math() {
// math
assert_eq!(eval_str("(+ 1 2 3)"), Value::Integer(6));
assert_eq!(eval_str("(- 3 2 1)"), Value::Integer(0));
assert_eq!(eval_str("(* 2 3 4)"), Value::Integer(24));
assert_eq!(eval_str("(/ 16 4 2)"), Value::Integer(2));
assert_eq!(eval_str("(% 35 16)"), Value::Integer(3));
assert_eq!(eval_str("(| 1 2 4)"), Value::Integer(7));
assert_eq!(eval_str("(& 1 2 4)"), Value::Integer(0));
assert_eq!(eval_str("(& 1 3 7)"), Value::Integer(1));
assert_eq!(eval_str("(^ 1 3 8)"), Value::Integer(10));
// comparison
assert_eq!(eval_str("(< 1 2 3 4 5)"), Value::Boolean(true));
assert_eq!(eval_str("(< 1 2 3 3 4 5)"), Value::Boolean(false));
assert_eq!(eval_str("(> 1 2 3 4 5)"), Value::Boolean(false));
assert_eq!(eval_str("(>= 5 5 4 3 2 1)"), Value::Boolean(true));
assert_eq!(eval_str("(> 5 5 4 3 2 1)"), Value::Boolean(false));
assert_eq!(eval_str("(<= 1 2 3 3 3 4)"), Value::Boolean(true));
assert_eq!(eval_str("(/= 1 2 3 4)"), Value::Boolean(true));
assert_eq!(eval_str("(/= 1 2 2 4)"), Value::Boolean(false));
assert_eq!(eval_str("(= 1 2 3 4)"), Value::Boolean(false));
assert_eq!(eval_str("(= 1 1 1 1)"), Value::Boolean(true));
// logic
assert_eq!(eval_str("(&& 1 0)"), Value::Boolean(false));
assert_eq!(eval_str("(&& #t 1 \"yes\")"), Value::Boolean(true));
assert_eq!(eval_str("(|| #f NIL \"\" ())"), Value::Boolean(false));
assert_eq!(eval_str("(|| #f '(1 2 3) \"\" ())"), Value::Boolean(true));
}
#[test]
fn test_abort() {
let err = eval_str_err("(assert (= 1 (+ 1 1)))");
let EvalError::Machine(MachineError {
error: MachineErrorKind::Aborted(message),
..
}) = err
else {
panic!("Invalid error returned")
};
assert_eq!(&message, "<undefined>: assertion failed: (= 1 (+ 1 1))");
let err = eval_str_err("(abort 1234)");
let EvalError::Machine(MachineError {
error: MachineErrorKind::Aborted(message),
..
}) = err
else {
panic!("Invalid error returned")
};
assert_eq!(&message, "1234");
}
#[test]
fn test_lambda() {
assert_eq!(eval_str("((lambda (x) (+ x 1)) 1)"), Value::Integer(2));
assert_eq!(
eval_str("((lambda (x) (+ ((lambda () 2)) 1)) 1)"),
Value::Integer(3)
);
}
#[test]
fn test_math_behaves_the_same_inside_apply() {
assert_eq!(eval_str("(apply + '(1 2 3 4))"), eval_str("(+ 1 2 3 4)"));
assert_eq!(eval_str("(apply * '(1 2 3 4))"), eval_str("(* 1 2 3 4)"));
assert_eq!(eval_str("(apply - '(1 2 3 4))"), eval_str("(- 1 2 3 4)"));
assert_eq!(eval_str("(apply / '(100 25 2))"), eval_str("(/ 100 25 2)"));
assert_eq!(eval_str("(apply % '(90 37))"), eval_str("(% 90 37)"));
assert_eq!(eval_str("(apply | '(1 2 4))"), eval_str("(| 1 2 4)"));
assert_eq!(eval_str("(apply & '(1 3 7))"), eval_str("(& 1 3 7)"));
assert_eq!(eval_str("(apply ^ '(1 3 7))"), eval_str("(^ 1 3 7)"));
assert_eq!(eval_str("(apply < '(1 2 3 4))"), eval_str("(< 1 2 3 4)"));
assert_eq!(eval_str("(apply > '(1 2 3 4))"), eval_str("(> 1 2 3 4)"));
}
#[test]
fn test_setq() {
assert_eq!(eval_str("(setq a 1234) a\n"), Value::Integer(1234));
}
#[test]
fn test_let() {
// Should fail
eval_str_err("(let (a 1234 b (+ a 1)) NIL)");
assert_eq!(
eval_str("(let (a 1234 b 4321) (+ a b))"),
Value::Integer(5555)
);
assert_eq!(
eval_str("(let* (a 1234 b (+ a 4321)) (+ b 4444))"),
Value::Integer(9999)
);
// Nested let
assert_eq!(
eval_str("(let (a 1234) (let (b 4321) (+ a b)))"),
Value::Integer(5555)
);
// Doesn't shadow
assert_eq!(
eval_str("(let (a 1234) (let (a 9999 b (+ a 4321)) b))"),
Value::Integer(5555)
);
// Does shadow
assert_eq!(
eval_str("(let (a 1234) (let* (a 9999 b (+ a 4321)) b))"),
Value::Integer(14320)
);
}
#[test]
fn test_macro() {
assert_eq!(
eval_str("(defmacro stringify (x) (cons 'list `,x)) (stringify (1 2 3 4))"),
Value::list_or_nil([
Value::Integer(1),
Value::Integer(2),
Value::Integer(3),
Value::Integer(4)
])
);
}
// use std::io::{self, BufReader, Read};
//
// use lysp::{
// error::{EvalError, MachineError, MachineErrorKind},
// read::{FileReader, read},
// vm::{env::Environment, machine::Machine, prelude, value::Value},
// };
//
// struct SliceReader<'a>(&'a [u8]);
//
// impl Read for SliceReader<'_> {
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// let count = self.0.len().min(buf.len());
// buf[..count].copy_from_slice(&self.0[..count]);
// self.0 = &self.0[count..];
// Ok(count)
// }
// }
//
// fn eval_str_in(code: &str, env: &mut Environment) -> Result<Value, EvalError> {
// let mut machine = Machine::default();
// let reader = BufReader::new(SliceReader(code.as_bytes()));
// let mut reader = FileReader::new(reader);
//
// let mut last_value = None;
// loop {
// let value = match read(&mut reader, &mut machine, env) {
// Ok(Some(value)) => value,
// Ok(None) => break,
// Err(error) => panic!("{error}"),
// };
//
// last_value = Some(machine.eval_value(Default::default(), env, value, false));
// }
//
// last_value.expect("no expressions evaluated")
// }
//
// fn eval_str(code: &str) -> Value {
// let mut env = Environment::default();
// prelude::load(&mut env);
// eval_str_in(code, &mut env).expect("expression evaluation failed")
// }
//
// fn eval_str_err(code: &str) -> EvalError {
// let mut env = Environment::default();
// prelude::load(&mut env);
// eval_str_in(code, &mut env).expect_err("expression was expected to fail")
// }
//
// #[test]
// fn test_math() {
// // math
// assert_eq!(eval_str("(+ 1 2 3)"), Value::Integer(6));
// assert_eq!(eval_str("(- 3 2 1)"), Value::Integer(0));
// assert_eq!(eval_str("(* 2 3 4)"), Value::Integer(24));
// assert_eq!(eval_str("(/ 16 4 2)"), Value::Integer(2));
// assert_eq!(eval_str("(% 35 16)"), Value::Integer(3));
// assert_eq!(eval_str("(| 1 2 4)"), Value::Integer(7));
// assert_eq!(eval_str("(& 1 2 4)"), Value::Integer(0));
// assert_eq!(eval_str("(& 1 3 7)"), Value::Integer(1));
// assert_eq!(eval_str("(^ 1 3 8)"), Value::Integer(10));
// // comparison
// assert_eq!(eval_str("(< 1 2 3 4 5)"), Value::Boolean(true));
// assert_eq!(eval_str("(< 1 2 3 3 4 5)"), Value::Boolean(false));
// assert_eq!(eval_str("(> 1 2 3 4 5)"), Value::Boolean(false));
// assert_eq!(eval_str("(>= 5 5 4 3 2 1)"), Value::Boolean(true));
// assert_eq!(eval_str("(> 5 5 4 3 2 1)"), Value::Boolean(false));
// assert_eq!(eval_str("(<= 1 2 3 3 3 4)"), Value::Boolean(true));
// assert_eq!(eval_str("(/= 1 2 3 4)"), Value::Boolean(true));
// assert_eq!(eval_str("(/= 1 2 2 4)"), Value::Boolean(false));
// assert_eq!(eval_str("(= 1 2 3 4)"), Value::Boolean(false));
// assert_eq!(eval_str("(= 1 1 1 1)"), Value::Boolean(true));
// // logic
// assert_eq!(eval_str("(&& 1 0)"), Value::Boolean(false));
// assert_eq!(eval_str("(&& #t 1 \"yes\")"), Value::Boolean(true));
// assert_eq!(eval_str("(|| #f NIL \"\" ())"), Value::Boolean(false));
// assert_eq!(eval_str("(|| #f '(1 2 3) \"\" ())"), Value::Boolean(true));
// }
//
// #[test]
// fn test_abort() {
// let err = eval_str_err("(assert (= 1 (+ 1 1)))");
// let EvalError::Machine(MachineError {
// error: MachineErrorKind::Aborted(message),
// ..
// }) = err
// else {
// panic!("Invalid error returned")
// };
// assert_eq!(&message, "<undefined>: assertion failed: (= 1 (+ 1 1))");
//
// let err = eval_str_err("(abort 1234)");
// let EvalError::Machine(MachineError {
// error: MachineErrorKind::Aborted(message),
// ..
// }) = err
// else {
// panic!("Invalid error returned")
// };
// assert_eq!(&message, "1234");
// }
//
// #[test]
// fn test_lambda() {
// assert_eq!(eval_str("((lambda (x) (+ x 1)) 1)"), Value::Integer(2));
// assert_eq!(
// eval_str("((lambda (x) (+ ((lambda () 2)) 1)) 1)"),
// Value::Integer(3)
// );
// }
//
// #[test]
// fn test_math_behaves_the_same_inside_apply() {
// assert_eq!(eval_str("(apply + '(1 2 3 4))"), eval_str("(+ 1 2 3 4)"));
// assert_eq!(eval_str("(apply * '(1 2 3 4))"), eval_str("(* 1 2 3 4)"));
// assert_eq!(eval_str("(apply - '(1 2 3 4))"), eval_str("(- 1 2 3 4)"));
// assert_eq!(eval_str("(apply / '(100 25 2))"), eval_str("(/ 100 25 2)"));
// assert_eq!(eval_str("(apply % '(90 37))"), eval_str("(% 90 37)"));
// assert_eq!(eval_str("(apply | '(1 2 4))"), eval_str("(| 1 2 4)"));
// assert_eq!(eval_str("(apply & '(1 3 7))"), eval_str("(& 1 3 7)"));
// assert_eq!(eval_str("(apply ^ '(1 3 7))"), eval_str("(^ 1 3 7)"));
// assert_eq!(eval_str("(apply < '(1 2 3 4))"), eval_str("(< 1 2 3 4)"));
// assert_eq!(eval_str("(apply > '(1 2 3 4))"), eval_str("(> 1 2 3 4)"));
// }
//
// #[test]
// fn test_setq() {
// assert_eq!(eval_str("(setq a 1234) a\n"), Value::Integer(1234));
// }
//
// #[test]
// fn test_let() {
// // Should fail
// eval_str_err("(let (a 1234 b (+ a 1)) NIL)");
//
// assert_eq!(
// eval_str("(let (a 1234 b 4321) (+ a b))"),
// Value::Integer(5555)
// );
// assert_eq!(
// eval_str("(let* (a 1234 b (+ a 4321)) (+ b 4444))"),
// Value::Integer(9999)
// );
//
// // Nested let
// assert_eq!(
// eval_str("(let (a 1234) (let (b 4321) (+ a b)))"),
// Value::Integer(5555)
// );
// // Doesn't shadow
// assert_eq!(
// eval_str("(let (a 1234) (let (a 9999 b (+ a 4321)) b))"),
// Value::Integer(5555)
// );
// // Does shadow
// assert_eq!(
// eval_str("(let (a 1234) (let* (a 9999 b (+ a 4321)) b))"),
// Value::Integer(14320)
// );
// }
//
// #[test]
// fn test_macro() {
// assert_eq!(
// eval_str("(defmacro stringify (x) (cons 'list `,x)) (stringify (1 2 3 4))"),
// Value::list_or_nil([
// Value::Integer(1),
// Value::Integer(2),
// Value::Integer(3),
// Value::Integer(4)
// ])
// );
// }