diff --git a/src/executor.rs b/src/executor.rs index f50de47..bc64881 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt}; -use crate::{OpCode, LispValue}; +use crate::PreLispValue; pub struct LispState { table: HashMap, @@ -10,6 +10,54 @@ fn add_function + Clone>(table: &mut HashMap, 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, bool), + LispFunction(String, Vec), + RustFunction(String, fn(Vec) -> Vec), +} + +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 for LispValue { + fn from(value: String) -> Self { + LispValue::String(value) + } +} +impl From for LispValue { + fn from(value: i32) -> Self { + LispValue::Integer(value) + } +} +impl From for LispValue { + fn from(value: f32) -> Self { + LispValue::Float(value) + } +} + impl LispState { pub fn new() -> LispState { let mut table = HashMap::new(); @@ -281,47 +329,73 @@ impl LispState { } } - fn do_call(&self, opcode: &OpCode) -> Vec { - if let OpCode::Call(func, args) = opcode { - let f = self.table.get(func).unwrap(); + fn handle_prevalues(&self, input: Vec) -> Vec { + let mut out = Vec::new(); - let mut args: Vec = 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; - } + 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() + } + }) + } - 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)); + out + } + + fn eval_list(list: &Vec, quoted: bool) -> (Vec, 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 let LispValue::RustFunction(_, f) = f { - return f(args.to_vec()); - } else { - todo!(); - } + } + 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 { - panic!("Bad OpCode: expected OpCode::Call") + (list.to_vec(), false) } } - pub fn execute(&self, instructions: Vec) { - for op in instructions { - match op { - OpCode::Call(func, args) => { - self.do_call(&OpCode::Call(func, args)); - }, - OpCode::Exp(ins) => { - self.execute(ins); - } + fn call_lisp_func(f: &LispValue, args: Vec) -> Vec { + todo!() + } + + pub fn execute(&self, instructions: Vec) { + let instructions = Self::handle_prevalues(self, instructions); + for val in instructions { + if let LispValue::List(elements, quoted) = val { + Self::eval_list(&elements, quoted); } } } diff --git a/src/main.rs b/src/main.rs index 3e1bf0c..2493f98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use executor::*; fn main() { let source = std::fs::read_to_string("src/test.lisp").unwrap(); + let mut tokenizer = Tokenizer::new(source); let tokens = match tokenizer.tokenize() { Ok(tokens) => tokens, diff --git a/src/parser.rs b/src/parser.rs index 822a42e..b443505 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,54 +3,53 @@ use std::fmt; use crate::Token; #[derive(Debug, Clone)] -pub enum LispValue { +pub enum PreLispValue { Nil, String(String), + Var(String), Integer(i32), Float(f32), - LispFunction(String, Vec), - RustFunction(String, fn(Vec) -> Vec), - Ref(String), - Eval(OpCode) + List(Vec, bool), // Values, Quoted + LispFunction(String, Vec), } -impl fmt::Display for LispValue { +impl fmt::Display for PreLispValue { 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), - LispValue::Ref(name) => write!(f, "<'{}': Reference>", name), + PreLispValue::Nil => write!(f, "nil"), + PreLispValue::String(str) => write!(f, "{}", str), + PreLispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name), + PreLispValue::Integer(num) => write!(f, "{}", num), + PreLispValue::Float(num) => write!(f, "{}", num), _ => todo!() } } } -impl From<&str> for LispValue { +impl From<&str> for PreLispValue { fn from(value: &str) -> Self { - LispValue::String(value.to_string()) + PreLispValue::String(value.to_string()) } } - -impl From for LispValue { +impl From for PreLispValue { fn from(value: String) -> Self { - LispValue::String(value) + PreLispValue::String(value) } } - -impl From for LispValue { +impl From for PreLispValue { fn from(value: i32) -> Self { - LispValue::Integer(value) + PreLispValue::Integer(value) } } - -#[derive(Debug, Clone)] -pub enum OpCode { - Call(String, Vec), - Exp(Vec) +impl From for PreLispValue { + fn from(value: f32) -> Self { + PreLispValue::Float(value) + } +} +impl From> for PreLispValue { + fn from(value: Vec) -> Self { + PreLispValue::List(value, false) + } } // TODO: Handle failure @@ -83,60 +82,64 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec) -> Option<(Vec, u None } -fn parse_exp(tokens: Vec) -> Vec { - let mut opcodes = Vec::new(); +fn parse_exp(tokens: Vec, quoted: bool) -> PreLispValue { + let mut values = Vec::new(); if tokens.len() < 1 { - return opcodes; + return PreLispValue::List(values, false); } - if let Token::Identifier(name) = &tokens[0] { - let mut args = Vec::new(); + let mut quote_next_list = false; + let mut unquote_next_list = false; - let mut i = 1; - while i < tokens.len() { - let tkn = &tokens[i]; - match tkn { - Token::OpenParen => { - let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap(); - args.push(LispValue::Eval(OpCode::Exp(parse_exp(tkns)))); - i = close_paren_idx; - }, - Token::Identifier(name) => { - args.push(LispValue::Ref(name.to_owned())); - }, - Token::Integer(num) => { - args.push(LispValue::Integer(*num)); - }, - Token::Float(num) => { - args.push(LispValue::Float(*num)); - }, - Token::String(str) => { - args.push(LispValue::String(str.to_owned())); - }, - Token::CloseParen => { - panic!("Unexpected closing parenthesis"); - }, + let mut i = 0; + while i < tokens.len() { + let tkn = &tokens[i]; + match tkn { + Token::Quote => { + quote_next_list = true; + }, + Token::Unquote => { + unquote_next_list = true; } - - i += 1; + Token::OpenParen => { + 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})); + i = close_paren_idx; + quote_next_list = false; + unquote_next_list = false; + }, + Token::Identifier(name) => { + values.push(PreLispValue::Var(name.to_owned())); + }, + Token::Integer(num) => { + values.push(PreLispValue::Integer(*num)); + }, + Token::Float(num) => { + values.push(PreLispValue::Float(*num)); + }, + Token::String(str) => { + values.push(PreLispValue::String(str.to_owned())); + }, + Token::CloseParen => { + panic!("Unexpected closing parenthesis"); + }, } - - opcodes.push(OpCode::Call(name.to_owned(), args)) + i += 1; } - opcodes + PreLispValue::List(values, quoted) } -pub fn parse(tokens: Vec) -> Vec { - let mut opcodes = Vec::new(); +pub fn parse(tokens: Vec) -> Vec { + let mut values = Vec::new(); let mut i = 0; while i < tokens.len() { match &tokens[i] { Token::OpenParen => { let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap(); - opcodes.push(OpCode::Exp(parse_exp(tkns))); + values.push(parse_exp(tkns, false)); i = close_paren_idx; } tkn => { @@ -147,5 +150,5 @@ pub fn parse(tokens: Vec) -> Vec { i += 1; } - opcodes + values } \ No newline at end of file diff --git a/src/test.lisp b/src/test.lisp index 9d552d0..c1b62fc 100644 --- a/src/test.lisp +++ b/src/test.lisp @@ -1,8 +1,14 @@ ; This is a comment (print - (add - 1.0 - (mul 2 3) - ) -) \ No newline at end of file + (add 0.5 3) +) + +; LispValue::List({ +; LispValue::RustFunction("print", ), +; LispValue::List({ +; LispValue::RustFunction("add", ), +; LispValue::Float(1.0), +; LispValue::Integer(3) +; }) +; }) \ No newline at end of file diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e3385f6..745b5ab 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -4,6 +4,8 @@ use std::fmt; pub enum Token { OpenParen, CloseParen, + Quote, + Unquote, Identifier(String), String(String), Integer(i32), @@ -113,6 +115,8 @@ impl Tokenizer { tokens.push(Token::Integer(self.storage.iter().collect::().parse().unwrap())); } + self.is_float = false; + self.storage.clear(); } else { if char == '.' { @@ -164,6 +168,8 @@ impl Tokenizer { self.reading_string = true; self.storage.clear(); }, + '\'' => tokens.push(Token::Quote), + ',' => tokens.push(Token::Unquote), c => { if c.is_alphabetic() { self.reading_identifier = true;