Use the delimiter macro in a few places

Made it capable of handling the strict <item> <delim> behavior necessary
for non-blocks, as well as teh loose behavior necessary for blocks,
added a test for a parse error.
This commit is contained in:
greg 2017-09-30 13:04:56 -07:00
parent 1ae9dbcba7
commit 90cf7db609
1 changed files with 33 additions and 44 deletions

View File

@ -330,7 +330,7 @@ digits := (DIGIT_GROUP underscore)+
type TokenIter = Peekable<IntoIter<Token>>; type TokenIter = Peekable<IntoIter<Token>>;
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub struct ParseError { pub struct ParseError {
pub msg: String, pub msg: String,
} }
@ -502,24 +502,41 @@ macro_rules! parse_method {
} }
macro_rules! delimited { macro_rules! delimited {
($self:expr, $start:pat, $parse_fn:ident, $delim:pat, $end:pat) => { ($self:expr, $start:pat, $parse_fn:ident, $( $delim:pat )|+, $end:pat) => {
delimited!($self, $start, $parse_fn, $( $delim )|*, $end, strict_delimiters)
};
($self:expr, $start:pat, $parse_fn:ident, $( $delim:pat )|+, $end:pat, nonstrict) => {
delimited!($self, $start, $parse_fn, $( $delim )|*, $end, nonstrict_delimiters)
};
(_internal nonstrict_delimiters $self:expr, $( $delim:pat )|+, $end:pat) => {
match $self.peek() {
$end | EOF => break,
$( $delim )|* => { $self.next(); continue },
_ => (),
}
};
(_internal strict_delimiters $self:expr, $( $delim:pat )|+, $end:pat) => {
match $self.peek() {
$end | EOF => break,
_ => (),
}
};
($self:expr, $start:pat, $parse_fn:ident, $( $delim:pat )|+, $end:pat, $strictness:tt) => {
{ {
expect!($self, $start, "Expected <start symbol figure out string interpol in macros>"); expect!($self, $start, "Expected <start symbol figure out string interpol in macros>");
let mut acc = vec![]; let mut acc = vec![];
loop { loop {
if let $end = $self.peek() { delimited!(_internal $strictness $self, $( $delim )|*, $end);
break;
}
acc.push($self.$parse_fn()?); acc.push($self.$parse_fn()?);
match $self.peek() { match $self.peek() {
$delim => { $self.next(); continue }, $( $delim )|* => { $self.next(); continue },
_ => break _ => break
}; };
} }
expect!($self, $end, "Expected <end symbol figure out string interpol in macros>"); expect!($self, $end, "Expected <end symbol figure out string interpol in macros>");
acc acc
} }
} };
} }
impl Parser { impl Parser {
@ -621,15 +638,11 @@ impl Parser {
parse_method!(type_name(&mut self) -> ParseResult<TypeAnno> { parse_method!(type_name(&mut self) -> ParseResult<TypeAnno> {
Ok(match self.peek() { Ok(match self.peek() {
LParen => TypeAnno::Tuple(delimited!(self, LParen, type_name, Comma, RParen)), LParen => TypeAnno::Tuple(delimited!(self, LParen, type_name, Comma, RParen)),
_ => { _ => TypeAnno::Singleton {
let type_name = self.identifier()?; name: self.identifier()?,
let params = match self.peek() { params: match self.peek() {
LAngleBracket => delimited!(self, LAngleBracket, type_name, Comma, RAngleBracket), LAngleBracket => delimited!(self, LAngleBracket, type_name, Comma, RAngleBracket),
_ => vec![], _ => vec![],
};
TypeAnno::Singleton {
name: type_name,
params: params,
} }
} }
}) })
@ -723,20 +736,7 @@ impl Parser {
}); });
parse_method!(call_expr(&mut self) -> ParseResult<Vec<Expression>> { parse_method!(call_expr(&mut self) -> ParseResult<Vec<Expression>> {
let mut exprs = Vec::new(); Ok(delimited!(self, LParen, expression, Comma, RParen))
expect!(self, LParen, "Expected '('");
loop {
if let RParen = self.peek() {
break;
}
exprs.push(self.expression()?);
match self.peek() {
Comma => { self.next(); },
_ => break,
}
}
expect!(self, RParen, "Expected ')'");
Ok(exprs)
}); });
parse_method!(index_expr(&mut self) -> ParseResult<Vec<Expression>> { parse_method!(index_expr(&mut self) -> ParseResult<Vec<Expression>> {
@ -774,20 +774,7 @@ impl Parser {
}); });
parse_method!(block(&mut self) -> ParseResult<Vec<Statement>> { parse_method!(block(&mut self) -> ParseResult<Vec<Statement>> {
expect!(self, LCurlyBrace, "Expected '{'"); Ok(delimited!(self, LCurlyBrace, statement, Newline | Semicolon, RCurlyBrace, nonstrict))
let mut statements = Vec::new();
loop {
match self.peek() {
EOF | RCurlyBrace => break,
Newline | Semicolon => {
self.next();
continue;
},
_ => statements.push(self.statement()?),
}
}
expect!(self, RCurlyBrace, "Expected '}'");
Ok(statements)
}); });
parse_method!(match_expr(&mut self) -> ParseResult<Expression> { parse_method!(match_expr(&mut self) -> ParseResult<Expression> {
@ -940,11 +927,12 @@ mod parse_tests {
macro_rules! rc { macro_rules! rc {
($string:tt) => { Rc::new(stringify!($string).to_string()) } ($string:tt) => { Rc::new(stringify!($string).to_string()) }
} }
macro_rules! parse_test { macro_rules! parse_test {
($string:expr, $correct:expr) => { assert_eq!(parse(tokenize($string)).0.unwrap(), $correct) } ($string:expr, $correct:expr) => { assert_eq!(parse(tokenize($string)).0.unwrap(), $correct) }
} }
macro_rules! parse_error {
($string:expr) => { assert!(parse(tokenize($string)).0.is_err()) }
}
macro_rules! binexp { macro_rules! binexp {
($op:expr, $lhs:expr, $rhs:expr) => { BinExp(op!($op), Box::new(Expression($lhs, None)), Box::new(Expression($rhs, None))) } ($op:expr, $lhs:expr, $rhs:expr) => { BinExp(op!($op), Box::new(Expression($lhs, None)), Box::new(Expression($rhs, None))) }
} }
@ -1035,6 +1023,7 @@ mod parse_tests {
{ name: rc!(oi), { name: rc!(oi),
params: vec![ex!(var!("a")), ex!(binexp!("+", IntLiteral(2), IntLiteral(2)))] params: vec![ex!(var!("a")), ex!(binexp!("+", IntLiteral(2), IntLiteral(2)))]
})])); })]));
parse_error!("a(b,,c)");
} }
#[test] #[test]