diff --git a/parser/src/parsers/list.rs b/parser/src/parsers/list.rs index f15f492..14ec700 100644 --- a/parser/src/parsers/list.rs +++ b/parser/src/parsers/list.rs @@ -10,20 +10,25 @@ use parsers::sym::SymParser; #[derive(Debug)] pub struct ListParser { - pairs: Option> + pairs: Option>, + waiting_for_final: bool, } impl ListParser { pub fn new() -> ListParser { - ListParser { pairs: None } + ListParser { + pairs: None, + waiting_for_final: false, + } } fn assemble(&mut self) -> Result { match self.pairs.take() { - Some(pairs) => { - let obj = pairs.into_iter().rfold(Obj::Null, |acc, mut pair| { + Some(mut pairs) => { + let last = pairs.last_mut().and_then(|p| Some(p.cdr.take())).unwrap_or(Obj::Null); + let obj = pairs.into_iter().rfold(last, |acc, mut pair| { pair.cdr = acc; - Obj::Ptr(Box::new(pair)) + Obj::new(pair) }); Ok(obj) }, @@ -38,7 +43,11 @@ impl NodeParser for ListParser { Token::Bool(_) => { let parser = BoolParser{}; NodeParseResult::Push { next: Box::new(parser) } - } + }, + Token::Dot => { + self.waiting_for_final = true; + NodeParseResult::Continue + }, Token::LeftParen => { match self.pairs { None => { @@ -57,6 +66,12 @@ impl NodeParser for ListParser { let next = Box::new(SymParser{}); NodeParseResult::Push { next } }, + Token::Num(n) => { + panic!("TODO: Handle numbrs."); + }, + Token::Quote => { + panic!("TODO: Handle quotes."); + }, Token::RightParen => { match self.pairs { None => { @@ -71,7 +86,7 @@ impl NodeParser for ListParser { } } } - } + }, } } @@ -81,12 +96,26 @@ impl NodeParser for ListParser { } fn subparser_completed(&mut self, obj: Obj) -> NodeParseResult { - if let Some(ref mut pairs) = self.pairs { - pairs.push(Pair::with_car(obj)); - NodeParseResult::Continue - } else { - let msg = format!("what happened here???"); - NodeParseResult::error(msg) + match self.pairs { + Some(ref mut pairs) if self.waiting_for_final => match pairs.last_mut() { + Some(ref mut last) => { + last.cdr = obj; + // Waiting for RightParen to close list. + NodeParseResult::Continue + }, + None => { + let msg = "Found dot before any pairs parsed".to_string(); + NodeParseResult::error(msg) + }, + }, + Some(ref mut pairs) => { + pairs.push(Pair::with_car(obj)); + NodeParseResult::Continue + }, + None => { + let msg = "While attempting to parse list, found token before opening paren".to_string(); + NodeParseResult::error(msg) + }, } } } diff --git a/parser/src/parsers/program.rs b/parser/src/parsers/program.rs index 6165468..3a8c610 100644 --- a/parser/src/parsers/program.rs +++ b/parser/src/parsers/program.rs @@ -37,7 +37,10 @@ impl NodeParser for ProgramParser { let parser = SymParser{}; let parser = Box::new(parser); NodeParseResult::Push { next: parser } - } + }, + _ => { + panic!("unhandled symbol"); + }, } } diff --git a/parser/tests/lists.rs b/parser/tests/lists.rs index e3ade69..e030d3e 100644 --- a/parser/tests/lists.rs +++ b/parser/tests/lists.rs @@ -32,3 +32,16 @@ fn list_of_four_tokens() { assert_eq!(parser.next(), Some(Ok(ex_list))); assert_eq!(parser.next(), None); } + +#[test] +fn single_dotted_pair() { + let tokens = vec![Ok(Lex::new(Token::LeftParen, "(", 0, 0)), + Ok(Lex::new(Token::Id, "ab", 0, 0)), + Ok(Lex::new(Token::Dot, ".", 0, 0)), + Ok(Lex::new(Token::Id, "cd", 0, 0)), + Ok(Lex::new(Token::RightParen, ")", 0, 0))].into_iter(); + let mut parser = Parser::new(tokens); + let ex_list = Obj::new(Pair::new(Obj::new(Sym::with_str("ab")), Obj::new(Sym::with_str("cd")))); + assert_eq!(parser.next(), Some(Ok(ex_list))); + assert_eq!(parser.next(), None); +} diff --git a/parser/tests/single_item.rs b/parser/tests/single_item.rs index 108fc37..795aaea 100644 --- a/parser/tests/single_item.rs +++ b/parser/tests/single_item.rs @@ -11,7 +11,7 @@ extern crate sibiltypes; use sibillexer::{Lex, Token}; use sibillexer::Result as LexerResult; use sibilparser::Parser; -use sibiltypes::{Bool, Obj, Pair, Sym}; +use sibiltypes::{Bool, Obj, Sym}; #[test] fn single_sym() {