Create a new list implementation based on vectors

This commit is contained in:
Sameer Rahmani 2020-09-19 00:28:40 +01:00
parent bb83142ffd
commit 298dc89025
4 changed files with 76 additions and 78 deletions

View File

@ -25,14 +25,22 @@ pub enum Expr {
Num(Number),
Comment,
Error(String),
List(Box<collections::List>),
Cons(Box<collections::List>),
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 {

View File

@ -14,26 +14,27 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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())
}

View File

@ -91,10 +91,9 @@ impl ExprReader {
fn read_quoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> 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<T: Read>(&mut self, reader: &mut BufReader<T>) -> 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<T: Read>(&mut self, reader: &mut BufReader<T>) -> 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<T: Read>(&mut self, reader: &mut BufReader<T>) -> 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 {

View File

@ -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<Expr>,
}
//pub enum List<T> { Nil, Cons(T, Box<List<T>>) }
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<T>) -> List<T> {
// 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<Expr> for List {
fn first<'a>(&'a self) -> &'a Expr {
&self.car
}
// impl Seq<Expr> for List<T> {
// 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!"),
// }
// }
// }