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:
parent
0e4a95f54d
commit
4d27cd7ae3
4 changed files with 369 additions and 177 deletions
340
src/executor.rs
340
src/executor.rs
|
@ -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,11 +421,16 @@ 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)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match t {
|
match t {
|
||||||
"int" => {
|
"int" => {
|
||||||
|
@ -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,11 +473,16 @@ 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)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match t {
|
match t {
|
||||||
"int" => {
|
"int" => {
|
||||||
|
@ -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,11 +546,16 @@ 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)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match t {
|
match t {
|
||||||
"int" => {
|
"int" => {
|
||||||
|
@ -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,11 +619,16 @@ 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)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match t {
|
match t {
|
||||||
"int" => {
|
"int" => {
|
||||||
|
@ -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,11 +802,18 @@ 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();
|
||||||
|
@ -649,7 +832,10 @@ 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();
|
||||||
|
|
|
@ -17,15 +17,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
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(())
|
||||||
}
|
}
|
||||||
|
|
132
src/parser.rs
132
src/parser.rs
|
@ -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![list(
|
||||||
vec![
|
vec![
|
||||||
list(vec![
|
|
||||||
var("print"),
|
var("print"),
|
||||||
list(vec![
|
list(
|
||||||
|
vec![
|
||||||
var("add"),
|
var("add"),
|
||||||
list(vec![
|
list(
|
||||||
|
vec![
|
||||||
var("div"),
|
var("div"),
|
||||||
float(4.5),
|
float(4.5),
|
||||||
list(vec![
|
list(vec![var("sub"), float(0.5), float(0.2)], false)
|
||||||
var("sub"),
|
|
||||||
float(0.5),
|
|
||||||
float(0.2)
|
|
||||||
], false)
|
|
||||||
], false),
|
|
||||||
list(vec![
|
|
||||||
var("mul"),
|
|
||||||
int(21),
|
|
||||||
float(0.05)
|
|
||||||
], false)
|
|
||||||
], false)
|
|
||||||
], false)
|
|
||||||
],
|
],
|
||||||
quick_parse("
|
false
|
||||||
|
),
|
||||||
|
list(vec![var("mul"), int(21), float(0.05)], false)
|
||||||
|
],
|
||||||
|
false
|
||||||
|
)
|
||||||
|
],
|
||||||
|
false
|
||||||
|
)],
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -182,43 +185,52 @@ fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue {
|
||||||
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) => {
|
|
||||||
if name == &String::from("nil") {
|
|
||||||
values.push(PreLispValue::Nil);
|
|
||||||
} else {
|
|
||||||
values.push(PreLispValue::Var(name.to_owned()));
|
|
||||||
}
|
}
|
||||||
|
Token::Identifier(name) => match name.as_str() {
|
||||||
|
"nil" => values.push(PreLispValue::Nil),
|
||||||
|
"true" => values.push(PreLispValue::True),
|
||||||
|
"false" => values.push(PreLispValue::False),
|
||||||
|
_ => values.push(PreLispValue::Var(name.to_owned())),
|
||||||
},
|
},
|
||||||
Token::Index(map, idx) => {
|
Token::Index(map, idx) => {
|
||||||
values.push(PreLispValue::List(vec![
|
values.push(PreLispValue::List(
|
||||||
|
vec![
|
||||||
PreLispValue::Var(String::from("get")),
|
PreLispValue::Var(String::from("get")),
|
||||||
PreLispValue::Var(map.to_owned()),
|
PreLispValue::Var(map.to_owned()),
|
||||||
PreLispValue::String(idx.to_owned())
|
PreLispValue::String(idx.to_owned()),
|
||||||
], false));
|
],
|
||||||
|
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,8 +246,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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> {
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in a new issue