diff --git a/src/ast.rs b/src/ast.rs index 17dff97..10b22cc 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -25,14 +25,22 @@ pub enum Expr { Num(Number), Comment, Error(String), - List(Box), + Cons(Box), Nil, NoMatch, } impl Expr { - pub fn make_list(first: Expr, rest: Expr) -> Expr { - Expr::List(Box::new(collections::List::new(first, rest))) + pub fn make_list(elements: &[Expr]) -> Expr { + Expr::Cons(Box::new(collections::List::new(elements))) + } + + pub fn list_to_cons(l: collections::List) -> Expr { + Expr::Cons(Box::new(l)) + } + + pub fn make_empty_list() -> collections::List { + collections::List::new_empty() } pub fn make_symbol(v: String) -> Expr { diff --git a/src/builtins/def.rs b/src/builtins/def.rs index 570ba0f..e9c06d6 100644 --- a/src/builtins/def.rs +++ b/src/builtins/def.rs @@ -14,26 +14,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +use crate::ast::Expr; use crate::compiler::Compiler; use crate::types::collections::core::{first, rest}; use crate::types::{ExprResult, List}; pub fn def<'a>(compiler: &'a Compiler, args: &'a List) -> ExprResult<'a> { // TODO: We need to support docstrings for def - if args.length != 3 { - // TODO: Raise a meaningful error by including the location - panic!(format!( - "`def` expects 2 parameters, '{}' given.", - args.length - )); - } + // if args.length != 3 { + // // TODO: Raise a meaningful error by including the location + // panic!(format!( + // "`def` expects 2 parameters, '{}' given.", + // args.length + // )); + // } - //let def_ = &args.first;1 - let name = first(rest(args)); - //let value = first(rest(rest(args))); + // //let def_ = &args.first;1 + // let name = first(rest(args)); + // //let value = first(rest(rest(args))); - println!("<<<< {:?}", name); - // TODO: make sure that `def_` is a symbol and its name is "def" + // println!("<<<< {:?}", name); + // // TODO: make sure that `def_` is a symbol and its name is "def" Err("Is not completed".to_string()) } diff --git a/src/reader.rs b/src/reader.rs index 544ded6..fcc45e9 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -91,10 +91,9 @@ impl ExprReader { fn read_quoted_expr(&mut self, reader: &mut BufReader) -> ReadResult { let rest = self.read_expr(reader)?; - Ok(Expr::make_list( - Expr::make_symbol("quote".to_string()), - rest, - )) + let elements = vec![Expr::make_symbol("quote".to_string()), rest]; + + Ok(Expr::make_list(&elements)) } fn read_unquoted_expr(&mut self, reader: &mut BufReader) -> ReadResult { @@ -103,50 +102,47 @@ impl ExprReader { // Move forward in the buffer since we peeked it let _ = self.get_char(reader, true); let rest = self.read_expr(reader)?; - Ok(Expr::make_list( - Expr::make_symbol("unquote-splicing".to_string()), - rest, - )) + let elements = vec![Expr::make_symbol("unquote-splicing".to_string()), rest]; + Ok(Expr::make_list(&elements)) } _ => { let rest = self.read_expr(reader)?; - Ok(Expr::make_list( - Expr::make_symbol("unquote".to_string()), - rest, - )) + let elements = vec![Expr::make_symbol("unquote".to_string()), rest]; + Ok(Expr::make_list(&elements)) } } } fn read_quasiquoted_expr(&mut self, reader: &mut BufReader) -> ReadResult { let rest = self.read_expr(reader)?; - Ok(Expr::make_list( - Expr::make_symbol("quasiquote".to_string()), - rest, - )) + let elements = vec![Expr::make_symbol("quasiquote".to_string()), rest]; + Ok(Expr::make_list(&elements)) } // TODO: We might want to replace Cons with an actual List struct fn read_list(&mut self, reader: &mut BufReader) -> ReadResult { - let first = match self.read_expr(reader) { - Ok(value) => value, + let mut result = Expr::make_empty_list(); + + match self.read_expr(reader) { + Ok(value) => result.push(value), Err(e) => match self.get_char(reader, true) { // is it an empty list ? // TODO: we might want to return an actual empty list here - Some(')') => return Ok(Expr::Nil), + Some(')') => return Ok(Expr::list_to_cons(result)), _ => return Err(e), }, }; - let rest = match self.get_char(reader, true) { - Some(e) => { - self.unget_char(e); - self.read_list(reader)? - } - None => return Err("Unexpected EOF while parsing a list.".to_string()), - }; - - Ok(Expr::make_list(first, rest)) + loop { + let next = match self.get_char(reader, true) { + Some(')') => return Ok(Expr::list_to_cons(result)), + Some(e) => { + self.unget_char(e); + result.push(self.read_expr(reader)?) + } + None => return Err("Unexpected EOF while parsing a list.".to_string()), + }; + } } fn is_valid_for_identifier(&self, c: char) -> bool { diff --git a/src/types/collections/list.rs b/src/types/collections/list.rs index 526da24..2d001e2 100644 --- a/src/types/collections/list.rs +++ b/src/types/collections/list.rs @@ -22,34 +22,27 @@ use crate::types::core::{ExprResult, Expression}; #[derive(Debug, Eq, PartialEq, Clone)] pub struct List { - pub car: Expr, - pub cdr: Expr, - pub length: u64, + elements: Vec, } -//pub enum List { Nil, Cons(T, Box>) } impl List { - pub fn new(first: Expr, rest: Expr) -> List { - // The order of field definition is important here. - // If we move the `length` after `rest` we're going - // to break the ownership rule of rust because `rest: rest` - // is going to move it to the new list and we can not - // borrow it afterward. + pub fn new_empty() -> List { + List { elements: vec![] } + } + + pub fn new(elems: &[Expr]) -> List { List { - length: match &rest { - Expr::Cons(v) => v.length + 1, - _ => { - if let Expr::Nil = first { - 0 - } else { - 1 - } - } - }, - car: first, - cdr: rest, + elements: elems.to_vec(), } } + + pub fn push(&mut self, elem: Expr) { + self.elements.push(elem) + } + + // pub fn new(first: T, rest: List) -> List { + // List::Cons(first, Box::new(rest)) + // } } impl Expression for List { @@ -59,21 +52,21 @@ impl Expression for List { // Expr::Sym(s) => def(compiler, self), // _ => , // } - def(compiler, self); + //def(compiler, self); Err("Not implemented on list".to_string()) } } -impl Seq for List { - fn first<'a>(&'a self) -> &'a Expr { - &self.car - } +// impl Seq for List { +// fn first<'a>(&'a self) -> &'a Expr { +// &self.car +// } - fn rest<'a>(&'a self) -> Option<&'a List> { - match &self.cdr { - Expr::Nil => None, - Expr::Cons(v) => Some(v), - _ => panic!("'rest' should not match anything else!"), - } - } -} +// fn rest<'a>(&'a self) -> Option<&'a List> { +// match &self.cdr { +// Expr::Nil => None, +// Expr::Cons(v) => Some(v), +// _ => panic!("'rest' should not match anything else!"), +// } +// } +// }