Proper quasiquote expansion rules, unquote-splice
This commit is contained in:
+51
-33
@@ -1,57 +1,56 @@
|
||||
use std::{
|
||||
io::{self, BufReader, Read},
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{fs, path::Path, rc::Rc};
|
||||
|
||||
use lysp::{
|
||||
error::MachineErrorAt,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn eval_str_in(code: &str, env: &Rc<Environment>) -> Result<Value, MachineErrorAt> {
|
||||
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.evaluate_value(Default::default(), None, env, value));
|
||||
}
|
||||
|
||||
last_value.expect("no expressions evaluated")
|
||||
machine.evaluate_str(Default::default(), None, env, code)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn eval_str(code: &str) -> Value {
|
||||
let env = Rc::new(Environment::default());
|
||||
prelude::load(&env);
|
||||
eval_str_in(code, &env).expect("expression evaluation failed")
|
||||
match eval_str_in(code, &env) {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
eprintln!("Couldn't evaluate expression:");
|
||||
eprintln!();
|
||||
eprintln!(" {code}");
|
||||
eprintln!();
|
||||
eprintln!(":: {error}");
|
||||
panic!("TEST FAILED");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn eval_str_err(code: &str) -> MachineErrorAt {
|
||||
let env = Rc::new(Environment::default());
|
||||
prelude::load(&env);
|
||||
eval_str_in(code, &env).expect_err("expression was expected to fail")
|
||||
match eval_str_in(code, &env) {
|
||||
Ok(value) => {
|
||||
eprintln!("Expected the code to fail to evaluate, but it returned success:");
|
||||
eprintln!();
|
||||
eprintln!(" {code}");
|
||||
eprintln!();
|
||||
eprintln!("Returned");
|
||||
eprintln!();
|
||||
eprintln!(":: {value}");
|
||||
panic!("TEST FAILED");
|
||||
}
|
||||
Err(error) => error,
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn eval_file<P: AsRef<Path>>(path: P) -> Value {
|
||||
let code = fs::read_to_string(path).expect("file read failed");
|
||||
eval_str(&code)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -186,3 +185,22 @@ fn test_macro() {
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_examples_work() {
|
||||
const EXCLUDE: &[&str] = &["repl.lysp", "echo.lysp", "io.lysp"];
|
||||
|
||||
// None of them should crash at least
|
||||
for file in fs::read_dir("examples").unwrap() {
|
||||
let entry = file.unwrap();
|
||||
let filename = entry.file_name();
|
||||
let filename = filename.to_str().unwrap();
|
||||
|
||||
if !filename.ends_with(".lysp") || EXCLUDE.contains(&filename) {
|
||||
continue;
|
||||
}
|
||||
|
||||
eprintln!("Eval {}", entry.path().display());
|
||||
eval_file(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user