diff --git a/src/executor.rs b/src/executor.rs index 1ac0451..dfa1a2d 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -6,11 +6,15 @@ pub struct LispState { table: HashMap, } +fn add_function + Clone>(table: &mut HashMap, name: T, func: fn(Vec) -> Vec) { + table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func)); +} + impl LispState { pub fn new() -> LispState { let mut table = HashMap::new(); - table.insert(String::from("print"), LispValue::RustFunction(String::from("print"), |x| { + add_function(&mut table, "print", |x| { let mut strings = Vec::new(); for val in x { strings.push(val.to_string()); @@ -19,24 +23,66 @@ impl LispState { let str = strings.join(" "); println!("{}", str); - LispValue::Nil - })); + vec![LispValue::Nil] + }); + + add_function(&mut table, "add", |x| { + if x.len() != 2 { + return vec![LispValue::Nil] + } + + if let (LispValue::Integer(lhs), LispValue::Integer(rhs)) = (&x[0], &x[1]) { + return vec![LispValue::Integer(lhs + rhs)]; + } else if let (LispValue::String(lhs), LispValue::String(rhs)) = (&x[0], &x[1]) { + return vec![LispValue::String(lhs.to_owned() + rhs)]; + } else { + return vec![LispValue::Nil]; + } + }); LispState { table } } + fn do_call(&self, opcode: &OpCode) -> Vec { + if let OpCode::Call(func, args) = opcode { + let f = self.table.get(func).unwrap(); + + 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; + } + + 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) { + println!("{:?}", instructions); for op in instructions { match op { OpCode::Call(func, args) => { - let f = self.table.get(&func).unwrap(); - if let LispValue::RustFunction(_, f) = f { - f(args); - } else { - todo!(); - } + self.do_call(&OpCode::Call(func, args)); }, OpCode::Exp(ins) => { self.execute(ins); diff --git a/src/main.rs b/src/main.rs index 802ed59..3e1bf0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,6 @@ fn main() { Vec::new() } }; - println!("{:?}", tokens); let instructions = parse(tokens); let state = LispState::new(); diff --git a/src/parser.rs b/src/parser.rs index 54b3487..77d4745 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,12 +2,15 @@ use std::fmt; use crate::Token; +#[derive(Debug, Clone)] pub enum LispValue { Nil, String(String), + Integer(i32), LispFunction(String, Vec), - RustFunction(String, fn(Vec) -> LispValue), - Exp(OpCode) + RustFunction(String, fn(Vec) -> Vec), + Ref(String), + Eval(OpCode) } impl fmt::Display for LispValue { @@ -17,6 +20,8 @@ impl fmt::Display for LispValue { 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::Ref(name) => write!(f, "<'{}': Reference>", name), _ => todo!() } } @@ -34,6 +39,13 @@ impl From for LispValue { } } +impl From for LispValue { + fn from(value: i32) -> Self { + LispValue::Integer(value) + } +} + +#[derive(Debug, Clone)] pub enum OpCode { Call(String, Vec), Exp(Vec) @@ -44,7 +56,7 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec) -> Option<(Vec, u let mut tkns = Vec::new(); let mut depth = 0; - for i in open_paren_idx..tokens.len() - 1 { + for i in open_paren_idx..tokens.len() { match &tokens[i] { Token::OpenParen => { if depth != 0 { @@ -56,6 +68,8 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec) -> Option<(Vec, u depth -= 1; if depth == 0 { return Some((tkns, i)); + } else { + tkns.push(Token::CloseParen) } } token => { @@ -68,14 +82,50 @@ fn read_exp(open_paren_idx: usize, tokens: &Vec) -> Option<(Vec, u } fn parse_exp(tokens: Vec) -> Vec { - todo!() + let mut opcodes = Vec::new(); + + if tokens.len() < 1 { + return opcodes; + } + + if let Token::Identifier(name) = &tokens[0] { + let mut args = Vec::new(); + + 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::String(str) => { + args.push(LispValue::String(str.to_owned())); + } + Token::CloseParen => { + panic!("Unexpected closing parenthesis"); + }, + _ => todo!() + } + + i += 1; + } + + opcodes.push(OpCode::Call(name.to_owned(), args)) + } + + opcodes } pub fn parse(tokens: Vec) -> Vec { let mut opcodes = Vec::new(); - - let mut current_depth = 0; - let mut seeking = false; let mut i = 0; while i < tokens.len() { @@ -86,13 +136,13 @@ pub fn parse(tokens: Vec) -> Vec { i = close_paren_idx; } tkn => { + // TODO: Include more error data panic!("Unexpected token {:?}", tkn); } } i += 1; } - // opcodes.push(OpCode::Call("print".to_string(), vec![ // LispValue::from("Hello, World!") // ])); diff --git a/src/test.lisp b/src/test.lisp index ace40ce..f4e800a 100644 --- a/src/test.lisp +++ b/src/test.lisp @@ -1,10 +1,5 @@ ; This is a comment -(print "Hello, World") ; OpCode::Call("print", {"Hello, World"}) +(print "Hello, World") -(print (add 1 2)) -; OpCode::Call("print", { -; OpCode::Exp({ -; OpCode::Call("add", 1, 2) -; }) -; }) \ No newline at end of file +(print (add 1 2)) \ No newline at end of file diff --git a/src/tokenizer.rs b/src/tokenizer.rs index c09ec19..10d86b5 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -154,8 +154,10 @@ impl Tokenizer { self.storage.push(c); continue; + // Allow numbers to also start with _ for fun // ______100_0__: 1,000 + // TODO: delete this when I expand identifiers to include more symbols } else if c.is_numeric() || c == '_' { self.reading_num = true;