This repository has been archived on 2024-07-15. You can view files and clone it, but cannot push or open issues or pull requests.
holy_lisp_archive/src/executor.rs
2024-06-16 14:29:46 -05:00

376 lines
8.2 KiB
Rust

use std::{collections::HashMap, fmt};
use crate::{OpCode, 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>),
LispFunction(String, Vec<OpCode>),
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 do_call(&self, opcode: &OpCode) -> Vec<LispValue> {
if let OpCode::Call(func, args) = opcode {
let f = self.table.get(func).unwrap();
let mut args: Vec<LispValue> = args.clone();
for i in 0..args.len() {
let arg = &args[i];
if let LispValue::Eval(OpCode::Exp(opcodes)) = arg {
if opcodes.len() < 1 {
args[i] = LispValue::Nil;
continue;
}
let call_opcode = opcodes.last().unwrap();
let mut res = self.do_call(call_opcode);
args.remove(i);
for j in 0..res.len() {
args.insert(i + j, res.remove(0));
}
}
}
if let LispValue::RustFunction(_, f) = f {
return f(args.to_vec());
} else {
todo!();
}
} else {
panic!("Bad OpCode: expected OpCode::Call")
}
}
pub fn execute(&self, instructions: Vec<OpCode>) {
for op in instructions {
match op {
OpCode::Call(func, args) => {
self.do_call(&OpCode::Call(func, args));
},
OpCode::Exp(ins) => {
self.execute(ins);
}
}
}
}
}