402 lines
9.1 KiB
Rust
402 lines
9.1 KiB
Rust
use std::{collections::HashMap, fmt};
|
|
|
|
use crate::PreLispValue;
|
|
|
|
pub struct LispState {
|
|
table: HashMap<String, LispValue>,
|
|
}
|
|
|
|
fn add_function<T: Into<String> + Clone>(table: &mut HashMap<String, LispValue>, name: T, func: fn(Vec<LispValue>) -> Vec<LispValue>) {
|
|
table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func));
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum LispValue {
|
|
Nil,
|
|
String(String),
|
|
Integer(i32),
|
|
Float(f32),
|
|
List(Vec<LispValue>, bool),
|
|
LispFunction(String, Vec<LispValue>),
|
|
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
|
|
}
|
|
|
|
impl fmt::Display for LispValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
LispValue::Nil => write!(f, "nil"),
|
|
LispValue::String(str) => write!(f, "{}", str),
|
|
LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name),
|
|
LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name),
|
|
LispValue::Integer(num) => write!(f, "{}", num),
|
|
LispValue::Float(num) => write!(f, "{}", num),
|
|
val => {
|
|
write!(f, "{}", format!("{:?}", val))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&str> for LispValue {
|
|
fn from(value: &str) -> Self {
|
|
LispValue::String(value.to_string())
|
|
}
|
|
}
|
|
impl From<String> for LispValue {
|
|
fn from(value: String) -> Self {
|
|
LispValue::String(value)
|
|
}
|
|
}
|
|
impl From<i32> for LispValue {
|
|
fn from(value: i32) -> Self {
|
|
LispValue::Integer(value)
|
|
}
|
|
}
|
|
impl From<f32> for LispValue {
|
|
fn from(value: f32) -> Self {
|
|
LispValue::Float(value)
|
|
}
|
|
}
|
|
|
|
impl LispState {
|
|
pub fn new() -> LispState {
|
|
let mut table = HashMap::new();
|
|
|
|
add_function(&mut table, "print", |x| {
|
|
let mut strings = Vec::new();
|
|
for val in x {
|
|
strings.push(val.to_string());
|
|
}
|
|
|
|
let str = strings.join(" ");
|
|
println!("{}", str);
|
|
|
|
vec![LispValue::Nil]
|
|
});
|
|
|
|
add_function(&mut table, "concat", |x| {
|
|
let mut strings = Vec::new();
|
|
for val in x {
|
|
strings.push(val.to_string());
|
|
}
|
|
|
|
let str = strings.concat();
|
|
vec![LispValue::String(str)]
|
|
});
|
|
|
|
add_function(&mut table, "add", |x| {
|
|
if x.len() < 1 {
|
|
return vec![LispValue::Nil]
|
|
} else if x.len() == 1 {
|
|
return vec![x[0].clone()];
|
|
}
|
|
|
|
let mut t = "int";
|
|
for v in &x {
|
|
match v {
|
|
LispValue::Float(_) => t = "float",
|
|
LispValue::Integer(_) => (),
|
|
_ => return vec![LispValue::Nil]
|
|
}
|
|
}
|
|
|
|
match t {
|
|
"int" => {
|
|
let mut sum = 0;
|
|
for v in &x {
|
|
if let LispValue::Integer(n) = v {
|
|
sum += n;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Integer(sum)];
|
|
},
|
|
"float" => {
|
|
let mut sum = 0.0 as f32;
|
|
for v in &x {
|
|
if let LispValue::Float(n) = v {
|
|
sum += n;
|
|
} else if let LispValue::Integer(n) = v{
|
|
sum += *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(sum)];
|
|
},
|
|
_ => unreachable!()
|
|
}
|
|
});
|
|
|
|
add_function(&mut table, "sub", |x| {
|
|
if x.len() < 1 {
|
|
return vec![LispValue::Nil]
|
|
} else if x.len() == 1 {
|
|
return vec![x[0].clone()];
|
|
}
|
|
|
|
let mut t = "int";
|
|
for v in &x {
|
|
match v {
|
|
LispValue::Float(_) => t = "float",
|
|
LispValue::Integer(_) => (),
|
|
_ => return vec![LispValue::Nil]
|
|
}
|
|
}
|
|
|
|
match t {
|
|
"int" => {
|
|
if let LispValue::Integer(n) = x[0] {
|
|
let mut sum = n;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Integer(n) = &x[i] {
|
|
sum -= n;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Integer(sum)];
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
},
|
|
"float" => {
|
|
if let LispValue::Float(n) = x[0] {
|
|
let mut sum = n;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Float(n) = &x[i] {
|
|
sum -= *n;
|
|
} else if let LispValue::Integer(n) = &x[i] {
|
|
sum -= *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(sum)];
|
|
} else if let LispValue::Integer(n) = x[0] {
|
|
let mut sum = n as f32;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Float(n) = &x[i] {
|
|
sum -= *n;
|
|
} else if let LispValue::Integer(n) = &x[i] {
|
|
sum -= *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(sum)];
|
|
} {
|
|
unreachable!()
|
|
}
|
|
},
|
|
_ => unreachable!()
|
|
}
|
|
});
|
|
|
|
add_function(&mut table, "mul", |x| {
|
|
if x.len() < 1 {
|
|
return vec![LispValue::Nil]
|
|
} else if x.len() == 1 {
|
|
return vec![x[0].clone()];
|
|
}
|
|
|
|
let mut t = "int";
|
|
for v in &x {
|
|
match v {
|
|
LispValue::Float(_) => t = "float",
|
|
LispValue::Integer(_) => (),
|
|
_ => return vec![LispValue::Nil]
|
|
}
|
|
}
|
|
|
|
match t {
|
|
"int" => {
|
|
if let LispValue::Integer(n) = x[0] {
|
|
let mut sum = n;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Integer(n) = &x[i] {
|
|
sum *= n;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Integer(sum)];
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
},
|
|
"float" => {
|
|
if let LispValue::Float(n) = x[0] {
|
|
let mut product = n;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Float(n) = &x[i] {
|
|
product *= *n;
|
|
} else if let LispValue::Integer(n) = &x[i] {
|
|
product *= *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(product)];
|
|
} else if let LispValue::Integer(n) = x[0] {
|
|
let mut product = n as f32;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Float(n) = &x[i] {
|
|
product *= *n;
|
|
} else if let LispValue::Integer(n) = &x[i] {
|
|
product *= *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(product)];
|
|
} {
|
|
unreachable!()
|
|
}
|
|
},
|
|
_ => unreachable!()
|
|
}
|
|
});
|
|
|
|
add_function(&mut table, "div", |x| {
|
|
if x.len() < 1 {
|
|
return vec![LispValue::Nil]
|
|
} else if x.len() == 1 {
|
|
return vec![x[0].clone()];
|
|
}
|
|
|
|
let mut t = "int";
|
|
for v in &x {
|
|
match v {
|
|
LispValue::Float(_) => t = "float",
|
|
LispValue::Integer(_) => (),
|
|
_ => return vec![LispValue::Nil]
|
|
}
|
|
}
|
|
|
|
match t {
|
|
"int" => {
|
|
if let LispValue::Integer(n) = x[0] {
|
|
let mut sum = n;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Integer(n) = &x[i] {
|
|
sum /= n;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Integer(sum)];
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
},
|
|
"float" => {
|
|
if let LispValue::Float(n) = x[0] {
|
|
let mut product = n;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Float(n) = &x[i] {
|
|
product /= *n;
|
|
} else if let LispValue::Integer(n) = &x[i] {
|
|
product /= *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(product)];
|
|
} else if let LispValue::Integer(n) = x[0] {
|
|
let mut product = n as f32;
|
|
for i in 1..x.len() {
|
|
if let LispValue::Float(n) = &x[i] {
|
|
product /= *n;
|
|
} else if let LispValue::Integer(n) = &x[i] {
|
|
product /= *n as f32;
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
return vec![LispValue::Float(product)];
|
|
} {
|
|
unreachable!()
|
|
}
|
|
},
|
|
_ => unreachable!()
|
|
}
|
|
});
|
|
|
|
LispState {
|
|
table
|
|
}
|
|
}
|
|
|
|
fn handle_prevalues(&self, input: Vec<PreLispValue>) -> Vec<LispValue> {
|
|
let mut out = Vec::new();
|
|
|
|
for v in input {
|
|
out.push(match v {
|
|
PreLispValue::Nil => LispValue::Nil,
|
|
PreLispValue::String(str) => LispValue::String(str),
|
|
PreLispValue::Integer(num) => LispValue::Integer(num),
|
|
PreLispValue::Float(num) => LispValue::Float(num),
|
|
PreLispValue::List(list, quoted) => {
|
|
LispValue::List(Self::handle_prevalues(self, list), quoted)
|
|
},
|
|
PreLispValue::LispFunction(name, instructions) => {
|
|
LispValue::LispFunction(name, Self::handle_prevalues(self, instructions))
|
|
},
|
|
PreLispValue::Var(name) => {
|
|
self.table.get(&name).unwrap_or(&LispValue::Nil).to_owned()
|
|
}
|
|
})
|
|
}
|
|
|
|
out
|
|
}
|
|
|
|
fn eval_list(list: &Vec<LispValue>, quoted: bool) -> (Vec<LispValue>, bool) {
|
|
if list.len() < 1 {
|
|
return (vec![LispValue::List(Vec::new(), quoted)], false);
|
|
}
|
|
|
|
let list = &mut list.clone();
|
|
|
|
for i in 0..list.len() {
|
|
if let LispValue::List(elements, quoted) = &list[i] {
|
|
let (elems, astuple) = Self::eval_list(elements, *quoted);
|
|
if astuple {
|
|
list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned();
|
|
for j in 1..elems.len() {
|
|
list.insert(i, elems[j].to_owned());
|
|
}
|
|
} else {
|
|
list[i] = LispValue::List(elems, *quoted);
|
|
}
|
|
}
|
|
}
|
|
|
|
if quoted {
|
|
return (list.to_vec(), false);
|
|
}
|
|
|
|
if let LispValue::RustFunction(_name, f) = &list[0] {
|
|
(f(list[1..].to_vec()), true)
|
|
} else if let LispValue::LispFunction(_name, ins) = &list[0] {
|
|
(Self::call_lisp_func(&list[0], list[1..].to_vec()), true)
|
|
} else {
|
|
(list.to_vec(), false)
|
|
}
|
|
}
|
|
|
|
fn call_lisp_func(f: &LispValue, args: Vec<LispValue>) -> Vec<LispValue> {
|
|
todo!()
|
|
}
|
|
|
|
pub fn execute(&self, instructions: Vec<PreLispValue>) {
|
|
let instructions = Self::handle_prevalues(self, instructions);
|
|
for val in instructions {
|
|
if let LispValue::List(elements, quoted) = val {
|
|
Self::eval_list(&elements, quoted);
|
|
}
|
|
}
|
|
}
|
|
}
|