Add bools and instants, add a few functions

Light formatting as well

Signed-off-by: Apache <apache.software.foundation@gmail.com>
This commit is contained in:
Apache 2024-06-29 02:32:50 -05:00
parent 0e4a95f54d
commit 4d27cd7ae3
Signed by: apache
GPG key ID: 7588DF761684C654
4 changed files with 369 additions and 177 deletions

View file

@ -1,17 +1,19 @@
use std::{collections::HashMap, fmt}; use std::{collections::HashMap, fmt, time::Instant};
use crate::PreLispValue; use crate::PreLispValue;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Parser, LispState, LispValue, Tokenizer}; use crate::{LispState, LispValue, Parser, Tokenizer};
use super::add_function; use super::add_function;
fn get_exec_result(source: &str) -> Result<Vec<LispValue>, Box<dyn std::error::Error>> { fn get_exec_result(source: &str) -> Result<Vec<LispValue>, Box<dyn std::error::Error>> {
let mut state = LispState::new(); let mut state = LispState::new();
state.table.insert(String::from("output"), LispValue::List(vec![], false)); state
.table
.insert(String::from("output"), LispValue::List(vec![], false));
add_function(&mut state.table, "print", |st, args| { add_function(&mut state.table, "print", |st, args| {
if let LispValue::List(v, _) = st.table.get_mut("output").unwrap() { if let LispValue::List(v, _) = st.table.get_mut("output").unwrap() {
v.push(LispValue::List(args, false)) v.push(LispValue::List(args, false))
@ -43,12 +45,12 @@ mod tests {
#[test] #[test]
fn test_hello_world() -> Result<(), Box<dyn std::error::Error>> { fn test_hello_world() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!( assert_eq!(
vec![ vec![LispValue::String(String::from("Hello, World!"))],
LispValue::String(String::from("Hello, World!")) get_exec_result(
], "
get_exec_result("
(print \"Hello, World!\") (print \"Hello, World!\")
")? "
)?
); );
Ok(()) Ok(())
} }
@ -56,10 +58,9 @@ mod tests {
#[test] #[test]
fn test_math() -> Result<(), Box<dyn std::error::Error>> { fn test_math() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!( assert_eq!(
vec![ vec![LispValue::Float(16.05)],
LispValue::Float(16.05) get_exec_result(
], "
get_exec_result("
(print (print
(add (add
(div (div
@ -69,7 +70,8 @@ mod tests {
(mul 21 0.05) (mul 21 0.05)
) )
) )
")? "
)?
); );
Ok(()) Ok(())
} }
@ -79,7 +81,6 @@ pub struct LispState {
table: HashMap<String, LispValue>, table: HashMap<String, LispValue>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct RuntimeError { pub struct RuntimeError {
message: String, message: String,
@ -98,10 +99,13 @@ type RustFunctionType = fn(&mut LispState, Vec<LispValue>) -> Result<Vec<LispVal
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum LispValue { pub enum LispValue {
Nil, Nil,
True,
False,
String(String), String(String),
Integer(i32), Integer(i32),
Float(f32), Float(f32),
List(Vec<LispValue>, bool), List(Vec<LispValue>, bool),
Instant(Instant),
LispFunction(String, Vec<String>, Vec<LispValue>), LispFunction(String, Vec<String>, Vec<LispValue>),
RustFunction(String, RustFunctionType), RustFunction(String, RustFunctionType),
Map(HashMap<String, LispValue>), Map(HashMap<String, LispValue>),
@ -113,6 +117,8 @@ impl fmt::Display for LispValue {
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
match self { match self {
LispValue::Nil => write!(f, "nil"), LispValue::Nil => write!(f, "nil"),
LispValue::True => write!(f, "true"),
LispValue::False => write!(f, "false"),
LispValue::String(str) => write!(f, "\"{}\"", str), LispValue::String(str) => write!(f, "\"{}\"", str),
LispValue::LispFunction(name, _, _) => write!(f, "<function {}>", name), LispValue::LispFunction(name, _, _) => write!(f, "<function {}>", name),
LispValue::RustFunction(name, _) => write!(f, "<function {}>", name), LispValue::RustFunction(name, _) => write!(f, "<function {}>", name),
@ -130,7 +136,7 @@ impl fmt::Display for LispValue {
} else { } else {
write!(f, "({})", strs.join(" ")) write!(f, "({})", strs.join(" "))
} }
}, }
val => { val => {
write!(f, "{}", format!("{:?}", val)) write!(f, "{}", format!("{:?}", val))
} }
@ -142,6 +148,8 @@ fn lisp_display(v: LispValue) -> String {
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
match v { match v {
LispValue::Nil => String::from("nil"), LispValue::Nil => String::from("nil"),
LispValue::True => String::from("true"),
LispValue::False => String::from("false"),
LispValue::String(str) => str, LispValue::String(str) => str,
LispValue::LispFunction(name, _, _) => format!("<function {}>", name), LispValue::LispFunction(name, _, _) => format!("<function {}>", name),
LispValue::RustFunction(name, _) => format!("<function {}>", name), LispValue::RustFunction(name, _) => format!("<function {}>", name),
@ -159,7 +167,7 @@ fn lisp_display(v: LispValue) -> String {
} else { } else {
format!("({})", strs.join(" ")) format!("({})", strs.join(" "))
} }
}, }
val => { val => {
format!("{}", val) format!("{}", val)
} }
@ -169,10 +177,13 @@ fn lisp_display(v: LispValue) -> String {
fn get_type(v: &LispValue) -> String { fn get_type(v: &LispValue) -> String {
match v { match v {
LispValue::Nil => String::from("nil"), LispValue::Nil => String::from("nil"),
LispValue::True => String::from("bool"),
LispValue::False => String::from("bool"),
LispValue::Integer(_) => String::from("int"), LispValue::Integer(_) => String::from("int"),
LispValue::Float(_) => String::from("float"), LispValue::Float(_) => String::from("float"),
LispValue::String(_) => String::from("string"), LispValue::String(_) => String::from("string"),
LispValue::List(_, _) => String::from("list"), LispValue::List(_, _) => String::from("list"),
LispValue::Instant(_) => String::from("instant"),
LispValue::LispFunction(_, _, _) => String::from("function"), LispValue::LispFunction(_, _, _) => String::from("function"),
LispValue::RustFunction(_, _) => String::from("function"), LispValue::RustFunction(_, _) => String::from("function"),
LispValue::Map(_) => String::from("map"), LispValue::Map(_) => String::from("map"),
@ -180,6 +191,18 @@ fn get_type(v: &LispValue) -> String {
} }
} }
fn is_falsy(v: &LispValue) -> bool {
match v {
LispValue::Nil => true,
LispValue::False => true,
_ => false,
}
}
fn is_truthy(v: &LispValue) -> bool {
!is_falsy(v)
}
impl From<&str> for LispValue { impl From<&str> for LispValue {
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
LispValue::String(value.to_string()) LispValue::String(value.to_string())
@ -200,20 +223,117 @@ impl From<f32> for LispValue {
LispValue::Float(value) LispValue::Float(value)
} }
} }
impl From<bool> for LispValue {
fn from(value: bool) -> Self {
match value {
true => LispValue::True,
false => LispValue::False,
}
}
}
impl From<Vec<LispValue>> for LispValue { impl From<Vec<LispValue>> for LispValue {
fn from(value: Vec<LispValue>) -> Self { fn from(value: Vec<LispValue>) -> Self {
LispValue::List(value, false) LispValue::List(value, false)
} }
} }
fn add_function<T: Into<String> + Clone>(table: &mut HashMap<String, LispValue>, name: T, func: RustFunctionType) { fn add_function<T: Into<String> + Clone>(
table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func)); table: &mut HashMap<String, LispValue>,
name: T,
func: RustFunctionType,
) {
table.insert(
name.clone().into(),
LispValue::RustFunction(name.into(), func),
);
} }
impl LispState { impl LispState {
pub fn new() -> LispState { pub fn new() -> LispState {
let mut table = HashMap::new(); let mut table = HashMap::new();
add_function(&mut table, "now", |_, _| {
Ok(vec![LispValue::Instant(Instant::now())])
});
add_function(&mut table, "since", |_, args| {
if args.len() != 1 {
return Err(RuntimeError {
message: format!("Bad arguments to since (expected 1, got {})", args.len()),
});
}
if let LispValue::Instant(i) = args[0] {
Ok(vec![LispValue::Float(
Instant::now().duration_since(i).as_secs_f32(),
)])
} else {
Err(RuntimeError {
message: format!(
"Bad arguments to since (expected instant, got {})",
get_type(&args[0])
),
})
}
});
add_function(&mut table, "type", |_, args| {
if args.len() != 1 {
return Err(RuntimeError {
message: format!("Bad arguments to type (expected 1, got {})", args.len()),
});
}
Ok(vec![LispValue::String(get_type(&args[0]))])
});
add_function(&mut table, "sleep", |_, args| {
if args.len() != 1 {
return Err(RuntimeError {
message: format!("Bad arguments to sleep (expected 1, got {})", args.len()),
});
}
if let LispValue::Float(n) = args[0] {
std::thread::sleep(std::time::Duration::from_secs_f32(n));
} else if let LispValue::Integer(n) = args[0] {
std::thread::sleep(std::time::Duration::from_secs(n as u64));
} else {
return Err(RuntimeError {
message: format!(
"Bad arguments to sleep (expected float or int, got {})",
get_type(&args[0])
),
});
}
Ok(vec![LispValue::Nil])
});
add_function(&mut table, "or", |_, args| {
if args.len() != 2 {
return Err(RuntimeError {
message: format!("Bad arguments to or (expected 2, got {})", args.len()),
});
}
if is_truthy(&args[0]) {
Ok(vec![args[0].clone()])
} else {
Ok(vec![args[1].clone()])
}
});
add_function(&mut table, "and", |_, args| {
if args.len() != 2 {
return Err(RuntimeError {
message: format!("Bad arguments to and (expected 2, got {})", args.len()),
});
}
if is_truthy(&args[0]) {
Ok(vec![args[1].clone()])
} else {
Ok(vec![args[0].clone()])
}
});
add_function(&mut table, "echo", |_, args| { add_function(&mut table, "echo", |_, args| {
return Ok(args); return Ok(args);
}); });
@ -221,26 +341,29 @@ impl LispState {
add_function(&mut table, "set", |state, args| { add_function(&mut table, "set", |state, args| {
if args.len() != 2 { if args.len() != 2 {
return Err(RuntimeError { return Err(RuntimeError {
message: format!("Bad arguments to set (expected 2, got {})", args.len()) message: format!("Bad arguments to set (expected 2, got {})", args.len()),
}) });
} }
if let LispValue::String(name) = &args[0] { if let LispValue::String(name) = &args[0] {
state.table.insert(name.to_owned(), args[1].clone()); state.table.insert(name.to_owned(), args[1].clone());
} else { } else {
return Err(RuntimeError { return Err(RuntimeError {
message: format!("Bad argument 1 to set (expected string, got {})", get_type(&args[0])) message: format!(
}) "Bad argument 1 to set (expected string, got {})",
get_type(&args[0])
),
});
} }
Ok(vec![args[1].clone()]) Ok(vec![args[1].clone()])
}); });
add_function(&mut table, "get", |_,args| { add_function(&mut table, "get", |_, args| {
if args.len() != 2 { if args.len() != 2 {
return Err(RuntimeError { return Err(RuntimeError {
message: format!("Bad arguments to get (expected 2, got {})", args.len()) message: format!("Bad arguments to get (expected 2, got {})", args.len()),
}) });
} }
if let LispValue::Map(map) = &args[0] { if let LispValue::Map(map) = &args[0] {
@ -248,13 +371,19 @@ impl LispState {
return Ok(vec![map.get(str).unwrap_or(&LispValue::Nil).to_owned()]); return Ok(vec![map.get(str).unwrap_or(&LispValue::Nil).to_owned()]);
} else { } else {
return Err(RuntimeError { return Err(RuntimeError {
message: format!("Bad argument 2 to get (expected string, got {})", get_type(&args[0])) message: format!(
}) "Bad argument 2 to get (expected string, got {})",
get_type(&args[0])
),
});
} }
} else { } else {
return Err(RuntimeError { return Err(RuntimeError {
message: format!("Bad argument 1 to get (expected map, got {})", get_type(&args[0])) message: format!(
}) "Bad argument 1 to get (expected map, got {})",
get_type(&args[0])
),
});
} }
}); });
@ -282,7 +411,7 @@ impl LispState {
add_function(&mut table, "add", |_, args| { add_function(&mut table, "add", |_, args| {
if args.len() < 1 { if args.len() < 1 {
return Ok(vec![LispValue::Nil]) return Ok(vec![LispValue::Nil]);
} else if args.len() == 1 { } else if args.len() == 1 {
return Ok(vec![args[0].clone()]); return Ok(vec![args[0].clone()]);
} }
@ -292,9 +421,14 @@ impl LispState {
match v { match v {
LispValue::Float(_) => t = "float", LispValue::Float(_) => t = "float",
LispValue::Integer(_) => (), LispValue::Integer(_) => (),
_ => return Err(RuntimeError { _ => {
message: format!("Invalid argument to 'add' (expected float or int, got {}", get_type(v)) return Err(RuntimeError {
}) message: format!(
"Invalid argument to 'add' (expected float or int, got {}",
get_type(v)
),
})
}
} }
} }
@ -309,21 +443,21 @@ impl LispState {
} }
} }
return Ok(vec![LispValue::Integer(sum)]); return Ok(vec![LispValue::Integer(sum)]);
}, }
"float" => { "float" => {
let mut sum = 0.0 as f32; let mut sum = 0.0 as f32;
for v in &args { for v in &args {
if let LispValue::Float(n) = v { if let LispValue::Float(n) = v {
sum += n; sum += n;
} else if let LispValue::Integer(n) = v{ } else if let LispValue::Integer(n) = v {
sum += *n as f32; sum += *n as f32;
} else { } else {
unreachable!() unreachable!()
} }
} }
return Ok(vec![LispValue::Float(sum)]); return Ok(vec![LispValue::Float(sum)]);
}, }
_ => unreachable!() _ => unreachable!(),
} }
}); });
@ -339,9 +473,14 @@ impl LispState {
match v { match v {
LispValue::Float(_) => t = "float", LispValue::Float(_) => t = "float",
LispValue::Integer(_) => (), LispValue::Integer(_) => (),
_ => return Err(RuntimeError { _ => {
message: format!("Invalid argument to 'sub' (expected float or int, got {}", get_type(v)) return Err(RuntimeError {
}) message: format!(
"Invalid argument to 'sub' (expected float or int, got {}",
get_type(v)
),
})
}
} }
} }
@ -360,7 +499,7 @@ impl LispState {
} else { } else {
unreachable!() unreachable!()
} }
}, }
"float" => { "float" => {
if let LispValue::Float(n) = args[0] { if let LispValue::Float(n) = args[0] {
let mut sum = n; let mut sum = n;
@ -386,11 +525,12 @@ impl LispState {
} }
} }
return Ok(vec![LispValue::Float(sum)]); return Ok(vec![LispValue::Float(sum)]);
} { }
{
unreachable!() unreachable!()
} }
}, }
_ => unreachable!() _ => unreachable!(),
} }
}); });
@ -406,9 +546,14 @@ impl LispState {
match v { match v {
LispValue::Float(_) => t = "float", LispValue::Float(_) => t = "float",
LispValue::Integer(_) => (), LispValue::Integer(_) => (),
_ => return Err(RuntimeError { _ => {
message: format!("Invalid argument to 'mul' (expected float or int, got {}", get_type(v)) return Err(RuntimeError {
}) message: format!(
"Invalid argument to 'mul' (expected float or int, got {}",
get_type(v)
),
})
}
} }
} }
@ -427,7 +572,7 @@ impl LispState {
} else { } else {
unreachable!() unreachable!()
} }
}, }
"float" => { "float" => {
if let LispValue::Float(n) = args[0] { if let LispValue::Float(n) = args[0] {
let mut product = n; let mut product = n;
@ -453,11 +598,12 @@ impl LispState {
} }
} }
return Ok(vec![LispValue::Float(product)]); return Ok(vec![LispValue::Float(product)]);
} { }
{
unreachable!() unreachable!()
} }
}, }
_ => unreachable!() _ => unreachable!(),
} }
}); });
@ -473,9 +619,14 @@ impl LispState {
match v { match v {
LispValue::Float(_) => t = "float", LispValue::Float(_) => t = "float",
LispValue::Integer(_) => (), LispValue::Integer(_) => (),
_ => return Err(RuntimeError { _ => {
message: format!("Invalid argument to 'div' (expected float or int, got {}", get_type(v)) return Err(RuntimeError {
}) message: format!(
"Invalid argument to 'div' (expected float or int, got {}",
get_type(v)
),
})
}
} }
} }
@ -494,7 +645,7 @@ impl LispState {
} else { } else {
unreachable!() unreachable!()
} }
}, }
"float" => { "float" => {
if let LispValue::Float(n) = args[0] { if let LispValue::Float(n) = args[0] {
let mut product = n; let mut product = n;
@ -520,17 +671,16 @@ impl LispState {
} }
} }
return Ok(vec![LispValue::Float(product)]); return Ok(vec![LispValue::Float(product)]);
} { }
{
unreachable!() unreachable!()
} }
}, }
_ => unreachable!() _ => unreachable!(),
} }
}); });
LispState { LispState { table }
table
}
} }
fn handle_prevalues(&self, input: Vec<PreLispValue>) -> Vec<LispValue> { fn handle_prevalues(&self, input: Vec<PreLispValue>) -> Vec<LispValue> {
@ -539,25 +689,34 @@ impl LispState {
for v in input { for v in input {
out.push(match v { out.push(match v {
PreLispValue::Nil => LispValue::Nil, PreLispValue::Nil => LispValue::Nil,
PreLispValue::True => LispValue::True,
PreLispValue::False => LispValue::False,
PreLispValue::String(str) => LispValue::String(str), PreLispValue::String(str) => LispValue::String(str),
PreLispValue::Integer(num) => LispValue::Integer(num), PreLispValue::Integer(num) => LispValue::Integer(num),
PreLispValue::Float(num) => LispValue::Float(num), PreLispValue::Float(num) => LispValue::Float(num),
PreLispValue::List(list, quoted) => { PreLispValue::List(list, quoted) => {
LispValue::List(Self::handle_prevalues(self, list), quoted) LispValue::List(Self::handle_prevalues(self, list), quoted)
},
PreLispValue::LispFunction(name, arg_names, instructions) => {
LispValue::LispFunction(name, arg_names, Self::handle_prevalues(self, instructions))
},
PreLispValue::Var(name) => {
LispValue::Var(name)
} }
PreLispValue::LispFunction(name, arg_names, instructions) => {
LispValue::LispFunction(
name,
arg_names,
Self::handle_prevalues(self, instructions),
)
}
PreLispValue::Var(name) => LispValue::Var(name),
}) })
} }
out out
} }
fn eval_list(&mut self, env: &mut HashMap<String, LispValue>, list: &Vec<LispValue>, quoted: bool) -> Result<(Vec<LispValue>, bool), RuntimeError> { fn eval_list(
&mut self,
env: &mut HashMap<String, LispValue>,
list: &Vec<LispValue>,
quoted: bool,
) -> Result<(Vec<LispValue>, bool), RuntimeError> {
if list.len() < 1 { if list.len() < 1 {
return Ok((vec![LispValue::List(Vec::new(), quoted)], false)); return Ok((vec![LispValue::List(Vec::new(), quoted)], false));
} }
@ -566,7 +725,10 @@ impl LispState {
for i in 0..list.len() { for i in 0..list.len() {
if let LispValue::Var(name) = &list[i] { if let LispValue::Var(name) = &list[i] {
list[i] = env.get(name).unwrap_or_else(|| self.table.get(name).unwrap_or(&LispValue::Nil)).to_owned(); list[i] = env
.get(name)
.unwrap_or_else(|| self.table.get(name).unwrap_or(&LispValue::Nil))
.to_owned();
} }
if let LispValue::List(elements, quoted) = &list[i] { if let LispValue::List(elements, quoted) = &list[i] {
let (elems, astuple) = self.eval_list(env, elements, *quoted)?; let (elems, astuple) = self.eval_list(env, elements, *quoted)?;
@ -588,24 +750,38 @@ impl LispState {
if let LispValue::RustFunction(_name, f) = &list[0] { if let LispValue::RustFunction(_name, f) = &list[0] {
Ok((f(self, list[1..].to_vec())?, true)) Ok((f(self, list[1..].to_vec())?, true))
} else if let LispValue::LispFunction(_name, _, _) = &list[0] { } else if let LispValue::LispFunction(_name, _, _) = &list[0] {
Ok((self.call_lisp_func_internal(env, &list[0], list[1..].to_vec())?, true)) Ok((
self.call_lisp_func_internal(env, &list[0], list[1..].to_vec())?,
true,
))
} else { } else {
Ok((list.to_vec(), false)) Ok((list.to_vec(), false))
} }
} }
fn call_lisp_func_internal(&mut self, env: &mut HashMap<String, LispValue>, f: &LispValue, args: Vec<LispValue>) -> Result<Vec<LispValue>, RuntimeError> { fn call_lisp_func_internal(
&mut self,
env: &mut HashMap<String, LispValue>,
f: &LispValue,
args: Vec<LispValue>,
) -> Result<Vec<LispValue>, RuntimeError> {
let (arg_names, instructions) = match f { let (arg_names, instructions) = match f {
LispValue::LispFunction(_, arg_names, i) => { LispValue::LispFunction(_, arg_names, i) => (arg_names, i),
(arg_names, i) _ => {
}, return Err(RuntimeError {
_ => return Err(RuntimeError { message: format!(
message: format!("Invalid argument to call_lisp_func_internal (expected function, got {})", get_type(f)) "Invalid argument to call_lisp_func_internal (expected function, got {})",
}) get_type(f)
),
})
}
}; };
for i in 0..arg_names.len() { for i in 0..arg_names.len() {
env.insert(arg_names[i].to_owned(), args.get(i).unwrap_or(&LispValue::Nil).to_owned()); env.insert(
arg_names[i].to_owned(),
args.get(i).unwrap_or(&LispValue::Nil).to_owned(),
);
} }
let mut out = Vec::new(); let mut out = Vec::new();
@ -626,18 +802,25 @@ impl LispState {
Ok(out) Ok(out)
} }
pub fn call_lisp_func(&mut self, f: &LispValue, args: Vec<impl Into<LispValue>>) -> Result<Vec<LispValue>, RuntimeError> { pub fn call_lisp_func(
&mut self,
f: &LispValue,
args: Vec<impl Into<LispValue>>,
) -> Result<Vec<LispValue>, RuntimeError> {
if !matches!(f, LispValue::LispFunction(_, _, _)) { if !matches!(f, LispValue::LispFunction(_, _, _)) {
return Err(RuntimeError { return Err(RuntimeError {
message: format!("Invalid argument to call_lisp_func_internal (expected function, got {})", get_type(&f)) message: format!(
}) "Invalid argument to call_lisp_func_internal (expected function, got {})",
get_type(&f)
),
});
} }
let mut vargs = Vec::new(); let mut vargs = Vec::new();
for v in args { for v in args {
vargs.push(v.into()); vargs.push(v.into());
} }
self.call_lisp_func_internal(&mut HashMap::new(), &f, vargs) self.call_lisp_func_internal(&mut HashMap::new(), &f, vargs)
} }
@ -649,9 +832,12 @@ impl LispState {
} }
} }
pub fn execute(&mut self, instructions: Vec<PreLispValue>) -> Result<Vec<LispValue>, RuntimeError> { pub fn execute(
&mut self,
instructions: Vec<PreLispValue>,
) -> Result<Vec<LispValue>, RuntimeError> {
let instructions = Self::handle_prevalues(self, instructions); let instructions = Self::handle_prevalues(self, instructions);
let mut outs = Vec::new(); let mut outs = Vec::new();
let mut env = HashMap::new(); let mut env = HashMap::new();

View file

@ -8,24 +8,16 @@ mod executor;
use executor::*; use executor::*;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = std::fs::read_to_string("src/test.lisp").unwrap(); let source = std::fs::read_to_string("src/test.lisp").unwrap();
let mut tokenizer = Tokenizer::new(source); let mut tokenizer = Tokenizer::new(source);
let tokens = tokenizer.tokenize()?; let tokens = tokenizer.tokenize()?;
let mut parser = Parser::new(tokens); let mut parser = Parser::new(tokens);
let instructions = parser.parse(); let instructions = parser.parse();
let mut state = LispState::new(); let mut state = LispState::new();
let mut some_map = std::collections::HashMap::new();
some_map.insert(String::from("x"), LispValue::Float(0.0));
some_map.insert(String::from("y"), LispValue::Float(0.0));
state.execute(instructions)?; state.execute(instructions)?;
let f = state.get_func("takevalue").unwrap();
state.call_lisp_func(&f, vec![LispValue::Map(some_map)])?;
Ok(()) Ok(())
} }

View file

@ -2,7 +2,7 @@ use std::{collections::HashMap, fmt};
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Parser, PreLispValue, Tokenizer, TokenizerError}; use crate::{Parser, PreLispValue, Tokenizer, TokenizerError};
fn quick_parse(source: &str) -> Result<Vec<PreLispValue>, TokenizerError> { fn quick_parse(source: &str) -> Result<Vec<PreLispValue>, TokenizerError> {
let mut tokenizer = Tokenizer::new(String::from(source)); let mut tokenizer = Tokenizer::new(String::from(source));
@ -30,15 +30,12 @@ mod tests {
#[test] #[test]
fn test_hello_world() -> Result<(), TokenizerError> { fn test_hello_world() -> Result<(), TokenizerError> {
assert_eq!( assert_eq!(
vec![ vec![list(vec![var("print"), string("Hello, World!")], false)],
list(vec![ quick_parse(
var("print"), "
string("Hello, World!")
], false)
],
quick_parse("
(print \"Hello, World!\") (print \"Hello, World!\")
")? "
)?
); );
Ok(()) Ok(())
} }
@ -46,29 +43,29 @@ mod tests {
#[test] #[test]
fn test_math() -> Result<(), TokenizerError> { fn test_math() -> Result<(), TokenizerError> {
assert_eq!( assert_eq!(
vec![ vec![list(
list(vec![ vec![
var("print"), var("print"),
list(vec![ list(
var("add"), vec![
list(vec![ var("add"),
var("div"), list(
float(4.5), vec![
list(vec![ var("div"),
var("sub"), float(4.5),
float(0.5), list(vec![var("sub"), float(0.5), float(0.2)], false)
float(0.2) ],
], false) false
], false), ),
list(vec![ list(vec![var("mul"), int(21), float(0.05)], false)
var("mul"), ],
int(21), false
float(0.05) )
], false) ],
], false) false
], false) )],
], quick_parse(
quick_parse(" "
(print (print
(add (add
(div (div
@ -78,7 +75,8 @@ mod tests {
(mul 21 0.05) (mul 21 0.05)
) )
) )
")? "
)?
); );
Ok(()) Ok(())
} }
@ -89,6 +87,8 @@ use crate::Token;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum PreLispValue { pub enum PreLispValue {
Nil, Nil,
True,
False,
String(String), String(String),
Var(String), Var(String),
Integer(i32), Integer(i32),
@ -101,11 +101,13 @@ impl fmt::Display for PreLispValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
PreLispValue::Nil => write!(f, "nil"), PreLispValue::Nil => write!(f, "nil"),
PreLispValue::True => write!(f, "true"),
PreLispValue::False => write!(f, "false"),
PreLispValue::String(str) => write!(f, "{}", str), PreLispValue::String(str) => write!(f, "{}", str),
PreLispValue::LispFunction(name, _, _) => write!(f, "<'{}': Lisp Function>", name), PreLispValue::LispFunction(name, _, _) => write!(f, "<function {}>", name),
PreLispValue::Integer(num) => write!(f, "{}", num), PreLispValue::Integer(num) => write!(f, "{}", num),
PreLispValue::Float(num) => write!(f, "{}", num), PreLispValue::Float(num) => write!(f, "{}", num),
_ => todo!() _ => todo!(),
} }
} }
} }
@ -137,7 +139,8 @@ impl From<Vec<PreLispValue>> for PreLispValue {
} }
// TODO: Handle failure // TODO: Handle failure
fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, usize)> /* Option<tokens, close_paren_idx> */ { fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, usize)> /* Option<tokens, close_paren_idx> */
{
let mut tkns = Vec::new(); let mut tkns = Vec::new();
let mut depth = 0; let mut depth = 0;
@ -168,57 +171,66 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, u
fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue { fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue {
let mut values = Vec::new(); let mut values = Vec::new();
if tokens.len() < 1 { if tokens.len() < 1 {
return PreLispValue::List(values, false); return PreLispValue::List(values, false);
} }
let mut quote_next_list = false; let mut quote_next_list = false;
let mut unquote_next_list = false; let mut unquote_next_list = false;
let mut i = 0; let mut i = 0;
while i < tokens.len() { while i < tokens.len() {
let tkn = &tokens[i]; let tkn = &tokens[i];
match tkn { match tkn {
Token::Quote => { Token::Quote => {
quote_next_list = true; quote_next_list = true;
}, }
Token::Unquote => { Token::Unquote => {
unquote_next_list = true; unquote_next_list = true;
} }
Token::OpenParen => { Token::OpenParen => {
let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap(); let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap();
values.push(parse_exp(tkns, if unquote_next_list {false} else {quote_next_list || quoted})); values.push(parse_exp(
tkns,
if unquote_next_list {
false
} else {
quote_next_list || quoted
},
));
i = close_paren_idx; i = close_paren_idx;
quote_next_list = false; quote_next_list = false;
unquote_next_list = false; unquote_next_list = false;
}, }
Token::Identifier(name) => { Token::Identifier(name) => match name.as_str() {
if name == &String::from("nil") { "nil" => values.push(PreLispValue::Nil),
values.push(PreLispValue::Nil); "true" => values.push(PreLispValue::True),
} else { "false" => values.push(PreLispValue::False),
values.push(PreLispValue::Var(name.to_owned())); _ => values.push(PreLispValue::Var(name.to_owned())),
}
}, },
Token::Index(map, idx) => { Token::Index(map, idx) => {
values.push(PreLispValue::List(vec![ values.push(PreLispValue::List(
PreLispValue::Var(String::from("get")), vec![
PreLispValue::Var(map.to_owned()), PreLispValue::Var(String::from("get")),
PreLispValue::String(idx.to_owned()) PreLispValue::Var(map.to_owned()),
], false)); PreLispValue::String(idx.to_owned()),
],
false,
));
} }
Token::Integer(num) => { Token::Integer(num) => {
values.push(PreLispValue::Integer(*num)); values.push(PreLispValue::Integer(*num));
}, }
Token::Float(num) => { Token::Float(num) => {
values.push(PreLispValue::Float(*num)); values.push(PreLispValue::Float(*num));
}, }
Token::String(str) => { Token::String(str) => {
values.push(PreLispValue::String(str.to_owned())); values.push(PreLispValue::String(str.to_owned()));
}, }
Token::CloseParen => { Token::CloseParen => {
panic!("Unexpected closing parenthesis"); panic!("Unexpected closing parenthesis");
}, }
} }
i += 1; i += 1;
} }
@ -234,9 +246,9 @@ pub struct Parser {
fn add_macro( fn add_macro(
macros: &mut HashMap<String, fn(Vec<PreLispValue>) -> Vec<PreLispValue>>, macros: &mut HashMap<String, fn(Vec<PreLispValue>) -> Vec<PreLispValue>>,
name: impl Into<String>, name: impl Into<String>,
mac: fn(Vec<PreLispValue>) -> Vec<PreLispValue>) { mac: fn(Vec<PreLispValue>) -> Vec<PreLispValue>,
) {
macros.insert(name.into(), mac); macros.insert(name.into(), mac);
} }
impl Parser { impl Parser {
@ -244,11 +256,10 @@ impl Parser {
let mut macros = HashMap::new(); let mut macros = HashMap::new();
add_macro(&mut macros, "set", |x| { add_macro(&mut macros, "set", |x| {
if x.len() != 3 || if x.len() != 3
( || (!matches!(x[1], PreLispValue::Var(_))
!matches!(x[1], PreLispValue::Var(_)) && && !matches!(x[1], PreLispValue::String(_)))
!matches!(x[1], PreLispValue::String(_)) {
) {
return x; return x;
} }
@ -271,9 +282,8 @@ impl Parser {
let mut list: &Vec<PreLispValue> = &Vec::new(); let mut list: &Vec<PreLispValue> = &Vec::new();
if x.len() == 3 { if x.len() == 3 {
if if !matches!(x[1], PreLispValue::List(_, _))
!matches!(x[1], PreLispValue::List(_, _)) || || !matches!(x[2], PreLispValue::List(_, _))
!matches!(x[2], PreLispValue::List(_, _))
{ {
return x; return x;
} }
@ -285,10 +295,9 @@ impl Parser {
list = l; list = l;
} }
} else if x.len() == 4 { } else if x.len() == 4 {
if if !matches!(x[1], PreLispValue::Var(_))
!matches!(x[1], PreLispValue::Var(_)) || || !matches!(x[2], PreLispValue::List(_, _))
!matches!(x[2], PreLispValue::List(_, _)) || || !matches!(x[3], PreLispValue::List(_, _))
!matches!(x[3], PreLispValue::List(_, _))
{ {
return x; return x;
} }
@ -315,16 +324,13 @@ impl Parser {
let func = PreLispValue::LispFunction(name.clone(), arg_names, list.to_owned()); let func = PreLispValue::LispFunction(name.clone(), arg_names, list.to_owned());
if x.len() == 4 { if x.len() == 4 {
return vec![PreLispValue::Var(String::from("set")), name.into(), func] return vec![PreLispValue::Var(String::from("set")), name.into(), func];
} }
return vec![PreLispValue::Var(String::from("echo")), func]; return vec![PreLispValue::Var(String::from("echo")), func];
}); });
Parser { Parser { tokens, macros }
tokens,
macros
}
} }
fn macro_check(&mut self, input: Vec<PreLispValue>, quoted: bool) -> Vec<PreLispValue> { fn macro_check(&mut self, input: Vec<PreLispValue>, quoted: bool) -> Vec<PreLispValue> {
@ -351,7 +357,7 @@ impl Parser {
pub fn parse(&mut self) -> Vec<PreLispValue> { pub fn parse(&mut self) -> Vec<PreLispValue> {
let mut values = Vec::new(); let mut values = Vec::new();
let mut i = 0; let mut i = 0;
while i < self.tokens.len() { while i < self.tokens.len() {
match &self.tokens[i] { match &self.tokens[i] {
@ -367,7 +373,7 @@ impl Parser {
} }
i += 1; i += 1;
} }
self.macro_check(values, false) self.macro_check(values, false)
} }
} }

View file

@ -1,5 +1,13 @@
(fn takevalue(origin) ( (fn countuntil(until n) (
(print (concat "Origin: (" origin.x ", " origin.y ")")) ; => Origin: (0, 0) (set n (add (or n 0) 1))
(print origin) ; => Map({"x": Float(0.0), "y": Float(0.0)})
)) ))
(set start (now))
(countuntil 100)
(print (since start))