diff --git a/src/executor.rs b/src/executor.rs index f50de47..fa09d70 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::{OpCode, 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), + 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(); diff --git a/src/parser.rs b/src/parser.rs index 822a42e..f0de0a8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,54 +3,55 @@ 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), + RustFunction(String, fn(Vec) -> 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::RustFunction(name, _) => write!(f, "<'{}': Rust 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,49 +84,53 @@ 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 = 1; + 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 { @@ -136,7 +141,7 @@ pub fn parse(tokens: Vec) -> Vec { match &tokens[i] { Token::OpenParen => { let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap(); - opcodes.push(OpCode::Exp(parse_exp(tkns))); + opcodes.push(parse_exp(tkns, false)); i = close_paren_idx; } tkn => { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e3385f6..53e7703 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), @@ -164,6 +166,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;