Create a new list implementation based on vectors
This commit is contained in:
parent
bb83142ffd
commit
298dc89025
14
src/ast.rs
14
src/ast.rs
|
@ -25,14 +25,22 @@ pub enum Expr {
|
||||||
Num(Number),
|
Num(Number),
|
||||||
Comment,
|
Comment,
|
||||||
Error(String),
|
Error(String),
|
||||||
List(Box<collections::List>),
|
Cons(Box<collections::List>),
|
||||||
Nil,
|
Nil,
|
||||||
NoMatch,
|
NoMatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
pub fn make_list(first: Expr, rest: Expr) -> Expr {
|
pub fn make_list(elements: &[Expr]) -> Expr {
|
||||||
Expr::List(Box::new(collections::List::new(first, rest)))
|
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 {
|
pub fn make_symbol(v: String) -> Expr {
|
||||||
|
|
|
@ -14,26 +14,27 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
use crate::ast::Expr;
|
||||||
use crate::compiler::Compiler;
|
use crate::compiler::Compiler;
|
||||||
use crate::types::collections::core::{first, rest};
|
use crate::types::collections::core::{first, rest};
|
||||||
use crate::types::{ExprResult, List};
|
use crate::types::{ExprResult, List};
|
||||||
|
|
||||||
pub fn def<'a>(compiler: &'a Compiler, args: &'a List) -> ExprResult<'a> {
|
pub fn def<'a>(compiler: &'a Compiler, args: &'a List) -> ExprResult<'a> {
|
||||||
// TODO: We need to support docstrings for def
|
// TODO: We need to support docstrings for def
|
||||||
if args.length != 3 {
|
// if args.length != 3 {
|
||||||
// TODO: Raise a meaningful error by including the location
|
// // TODO: Raise a meaningful error by including the location
|
||||||
panic!(format!(
|
// panic!(format!(
|
||||||
"`def` expects 2 parameters, '{}' given.",
|
// "`def` expects 2 parameters, '{}' given.",
|
||||||
args.length
|
// args.length
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
|
|
||||||
//let def_ = &args.first;1
|
// //let def_ = &args.first;1
|
||||||
let name = first(rest(args));
|
// let name = first(rest(args));
|
||||||
//let value = first(rest(rest(args)));
|
// //let value = first(rest(rest(args)));
|
||||||
|
|
||||||
println!("<<<< {:?}", name);
|
// println!("<<<< {:?}", name);
|
||||||
// TODO: make sure that `def_` is a symbol and its name is "def"
|
// // TODO: make sure that `def_` is a symbol and its name is "def"
|
||||||
|
|
||||||
Err("Is not completed".to_string())
|
Err("Is not completed".to_string())
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,10 +91,9 @@ impl ExprReader {
|
||||||
|
|
||||||
fn read_quoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
fn read_quoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::make_list(
|
let elements = vec![Expr::make_symbol("quote".to_string()), rest];
|
||||||
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 {
|
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
|
// Move forward in the buffer since we peeked it
|
||||||
let _ = self.get_char(reader, true);
|
let _ = self.get_char(reader, true);
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::make_list(
|
let elements = vec![Expr::make_symbol("unquote-splicing".to_string()), rest];
|
||||||
Expr::make_symbol("unquote-splicing".to_string()),
|
Ok(Expr::make_list(&elements))
|
||||||
rest,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::make_list(
|
let elements = vec![Expr::make_symbol("unquote".to_string()), rest];
|
||||||
Expr::make_symbol("unquote".to_string()),
|
Ok(Expr::make_list(&elements))
|
||||||
rest,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_quasiquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
fn read_quasiquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::make_list(
|
let elements = vec![Expr::make_symbol("quasiquote".to_string()), rest];
|
||||||
Expr::make_symbol("quasiquote".to_string()),
|
Ok(Expr::make_list(&elements))
|
||||||
rest,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We might want to replace Cons with an actual List struct
|
// TODO: We might want to replace Cons with an actual List struct
|
||||||
fn read_list<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
fn read_list<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
||||||
let first = match self.read_expr(reader) {
|
let mut result = Expr::make_empty_list();
|
||||||
Ok(value) => value,
|
|
||||||
|
match self.read_expr(reader) {
|
||||||
|
Ok(value) => result.push(value),
|
||||||
Err(e) => match self.get_char(reader, true) {
|
Err(e) => match self.get_char(reader, true) {
|
||||||
// is it an empty list ?
|
// is it an empty list ?
|
||||||
// TODO: we might want to return an actual empty list here
|
// 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),
|
_ => return Err(e),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let rest = match self.get_char(reader, true) {
|
loop {
|
||||||
Some(e) => {
|
let next = match self.get_char(reader, true) {
|
||||||
self.unget_char(e);
|
Some(')') => return Ok(Expr::list_to_cons(result)),
|
||||||
self.read_list(reader)?
|
Some(e) => {
|
||||||
}
|
self.unget_char(e);
|
||||||
None => return Err("Unexpected EOF while parsing a list.".to_string()),
|
result.push(self.read_expr(reader)?)
|
||||||
};
|
}
|
||||||
|
None => return Err("Unexpected EOF while parsing a list.".to_string()),
|
||||||
Ok(Expr::make_list(first, rest))
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_for_identifier(&self, c: char) -> bool {
|
fn is_valid_for_identifier(&self, c: char) -> bool {
|
||||||
|
|
|
@ -22,34 +22,27 @@ use crate::types::core::{ExprResult, Expression};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
pub struct List {
|
pub struct List {
|
||||||
pub car: Expr,
|
elements: Vec<Expr>,
|
||||||
pub cdr: Expr,
|
|
||||||
pub length: u64,
|
|
||||||
}
|
}
|
||||||
//pub enum List<T> { Nil, Cons(T, Box<List<T>>) }
|
|
||||||
|
|
||||||
impl List {
|
impl List {
|
||||||
pub fn new(first: Expr, rest: Expr) -> List {
|
pub fn new_empty() -> List {
|
||||||
// The order of field definition is important here.
|
List { elements: vec![] }
|
||||||
// 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
|
pub fn new(elems: &[Expr]) -> List {
|
||||||
// borrow it afterward.
|
|
||||||
List {
|
List {
|
||||||
length: match &rest {
|
elements: elems.to_vec(),
|
||||||
Expr::Cons(v) => v.length + 1,
|
|
||||||
_ => {
|
|
||||||
if let Expr::Nil = first {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
car: first,
|
|
||||||
cdr: rest,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl Expression for List {
|
||||||
|
@ -59,21 +52,21 @@ impl Expression for List {
|
||||||
// Expr::Sym(s) => def(compiler, self),
|
// Expr::Sym(s) => def(compiler, self),
|
||||||
// _ => ,
|
// _ => ,
|
||||||
// }
|
// }
|
||||||
def(compiler, self);
|
//def(compiler, self);
|
||||||
Err("Not implemented on list".to_string())
|
Err("Not implemented on list".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Seq<Expr> for List {
|
// impl Seq<Expr> for List<T> {
|
||||||
fn first<'a>(&'a self) -> &'a Expr {
|
// fn first<'a>(&'a self) -> &'a Expr {
|
||||||
&self.car
|
// &self.car
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn rest<'a>(&'a self) -> Option<&'a List> {
|
// fn rest<'a>(&'a self) -> Option<&'a List> {
|
||||||
match &self.cdr {
|
// match &self.cdr {
|
||||||
Expr::Nil => None,
|
// Expr::Nil => None,
|
||||||
Expr::Cons(v) => Some(v),
|
// Expr::Cons(v) => Some(v),
|
||||||
_ => panic!("'rest' should not match anything else!"),
|
// _ => panic!("'rest' should not match anything else!"),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in New Issue