diff --git a/src/compile/mod.rs b/src/compile/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index c65e2da..e2e28ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use std::{process::exit, fs::read_to_string}; pub mod parser; +pub mod compile; const EXECUTABLE_NAME: &str = env!("CARGO_PKG_NAME"); const HELP_MESSAGE: &str = "\ @@ -35,10 +36,19 @@ fn main() { if args_index < args.len() { let file_path: &str = &args[args_index]; let file_content: String = read_to_string(file_path).unwrap(); - let ast = parser::parse(&file_content); - for node in ast { - println!("{:?}", node); + + let parsed = parser::parse(&file_content); + let mut ast = Vec::new(); + for node in parsed { + match node { + Ok(node) => { ast.push(node); }, + Err(error) => { + eprintln!("ERROR: {}", error); + exit(1); + } + } } + println!("{:#?}", ast); } else { println!("No file provided."); display_help(1); diff --git a/src/parser.rs b/src/parser.rs index 471d4c7..a0a6f50 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,25 +2,7 @@ // brundonsmith/rust_lisp (https://github.com/brundonsmith/rust_lisp) // go check them out! -use std::{ rc::Rc, cell::RefCell }; - -/// A List in Sexpr -#[derive(Debug, Clone)] -pub struct List { - pub value: Option>>, -} - -impl List { - pub const NIL: List = List { value: None }; -} - -/// Cons -> (car, [cdr]) -#[derive(Debug, Clone)] -pub struct Cons { - pub car: Value, - pub cdr: Option>>, -} - +use std::{ rc::Rc, fmt }; #[derive(Debug, Clone)] pub enum Value { @@ -30,11 +12,9 @@ pub enum Value { Int(i64), Float(f64), String(String), Symbol(String), - List(List), -} + List(Rc, Rc>), -impl Value { - pub const NIL: Value = Value::List(List::NIL); + Nil, } #[derive(Debug, Clone)] @@ -48,36 +28,25 @@ impl Tree { match self { Tree::Atom { atom, quote } => { if quote { - Value::List(List { - value: Some(Rc::new(RefCell::new(Cons { - car: Value::Symbol(String::from("quote")), - cdr: Some(Rc::new(RefCell::new(Cons { - car: atom, // car vroom vroom 🚗 - cdr: None, - }))), - }))), - }) + Value::List( + Rc::new(Value::Symbol(String::from("quote"))), + Rc::new(vec![atom]) + ) } else { atom } }, Tree::List { vec, quote } => { let list = Value::List( - vec.into_iter() - .map(|tree| tree.into_expr()) - .collect::(), + Rc::new(vec[0].clone().into_expr()), + Rc::new(vec[1..].iter().map(|a| a.clone().into_expr()).collect()) ); if quote { - Value::List(List { - value: Some(Rc::new(RefCell::new(Cons { - car: Value::Symbol(String::from("quote")), - cdr: Some(Rc::new(RefCell::new(Cons { - car: list, // car vroom vroom 🚗 - cdr: None, - }))), - }))), - }) + Value::List( + Rc::new(Value::Symbol(String::from("quote"))), + Rc::new(vec![list]) + ) } else { list } @@ -86,30 +55,6 @@ impl Tree { } } -impl FromIterator for List { - fn from_iter>(iter: I) -> Self { - let mut list = List { value: None }; - let mut tail: Option>> = None; - - for value in iter { - let new_cons = Rc::new(RefCell::new(Cons { - car: value, - cdr: None, - })); - - if list.value.is_none() { - list.value = Some(new_cons.clone()); - } else if let Some(ref tail_cons) = tail { - tail_cons.as_ref().borrow_mut().cdr = Some(new_cons.clone()); - } - - tail = Some(new_cons); - } - - list - } -} - // --- Start tokenizer --- const SPECIAL_CHARS: [&str; 4] = ["(", ")", "'", "..."]; @@ -205,16 +150,29 @@ pub fn tokenize(src: &str) -> impl Iterator { #[derive(Debug)] pub enum ParseErrorKind { - UnexpectedParenOpen, UnexpectedParenClose, } +impl fmt::Display for ParseErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ParseErrorKind::UnexpectedParenClose => write!(f, "Unexpected ')'"), + } + } +} + #[derive(Debug)] pub struct ParseError { pub kind: ParseErrorKind, pub pos: (usize, usize), } +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} at {}", self.kind, self.pos.0) + } +} + impl ParseError { fn new(kind: ParseErrorKind, pos: (usize, usize)) -> Self { ParseError { kind, pos } @@ -266,7 +224,7 @@ fn read<'a>( if let Tree::List { vec, quote } = &finished { if vec.is_empty() { finished = Tree::Atom { - atom: Value::NIL, + atom: Value::Nil, quote: *quote, }; } @@ -305,7 +263,7 @@ fn read_atom(token: &str) -> Value { match lower.as_str() { "true" => Value::True, "false" => Value::False, - "nil" => Value::NIL, + "nil" => Value::Nil, _ => { // Parse number if let Ok(int) = token.parse::() { Value::Int(int) }