use crate::syn::{ast::*, error::*, lexer::Lexer, op::*, span::*, token::*}; use lazy_static::lazy_static; use std::{convert::TryFrom, mem}; lazy_static! { static ref BASE_EXPR_START: Vec = vec![ TokenKind::Ident, TokenKind::Num, TokenKind::Str, TokenKind::Sym, TokenKind::LParen, TokenKind::LBracket, TokenKind::LBrace, TokenKind::ObjBrace, ]; static ref UN_EXPR_START: Vec = vec![TokenKind::Plus, TokenKind::Minus, TokenKind::Bang]; static ref EXPR_START: Vec = { let mut start = BASE_EXPR_START.clone(); start.extend(UN_EXPR_START.iter()); start }; static ref EOL: Vec = vec![TokenKind::Eol, TokenKind::Newline]; } pub struct Parser<'t> { lexer: Lexer<'t>, curr_token: Option, skip_newlines: bool, } impl<'t> Parser<'t> { pub fn new(lexer: Lexer<'t>) -> Result { let mut parser = Parser { lexer, curr_token: None, skip_newlines: false, }; parser.adv_token()?; Ok(parser) } pub fn is_eof(&self) -> bool { self.lexer.is_eof() } pub fn pos(&self) -> Pos { self.span().start } pub fn set_skip_newlines(&mut self, skip: bool) -> Result { let prev = mem::replace(&mut self.skip_newlines, skip); match self.skip_newlines() { Ok(()) => Ok(prev), Err(e) => { self.skip_newlines = prev; Err(e) } } } pub fn is_skip_newlines(&self) -> bool { self.skip_newlines } fn skip_newlines(&mut self) -> Result<()> { if self.is_skip_newlines() && self.is_token_kind(TokenKind::Newline) { self.adv_token()?; } Ok(()) } } //////////////////////////////////////////////////////////////////////////////// // Statement parsing //////////////////////////////////////////////////////////////////////////////// impl<'t> Parser<'t> { /// Gets the remaining list of statements in this file, expecting EOF at the end. pub fn next_body(&mut self) -> Result> { let body = self.next_block_body()?; if let Some(token) = self.curr_token { return Err(Error::ExpectedGot { expected: "EOF, statement, or expression".to_string(), got: token.kind().to_string(), pos: token.span().start, }); } Ok(body) } pub fn next_stmt(&mut self) -> Result> { // skip any leading EOL tokens while self.match_any_token_kind(&EOL)?.is_some() {} if self.is_eof() { return Ok(None); } if self.is_any_token_kind(&EXPR_START) { let expr = self.next_expr()?; if self.match_token_kind(TokenKind::Eq)?.is_some() { let rhs = self.next_expr()?; let span = expr.span().union(rhs.span()); Ok(Some(Stmt::Assign(AssignStmt { lhs: expr, rhs, span, }))) } else { self.expect_eol_or_eof("end-of-line after expression")?; Ok(Some(Stmt::Expr(expr))) } } else { Ok(None) } } /// Parses a list of statements until it reaches a right curly brace. fn next_block_body(&mut self) -> Result> { let mut body = Vec::new(); // end of body token if self.is_token_kind(TokenKind::RBrace) { self.expect_eol_or_eof("end-of-line after assignment")?; return Ok(body); } while let Some(stmt) = self.next_stmt()? { body.push(stmt); // end of body token if self.is_token_kind(TokenKind::RBrace) { break; } } Ok(body) } } //////////////////////////////////////////////////////////////////////////////// // Expression parsing //////////////////////////////////////////////////////////////////////////////// macro_rules! bin_expr { ($name:ident, $op_tokens:expr, $next:ident) => { fn $name(&mut self) -> Result { let lhs = self.$next()?; if let Some(token) = self.match_any_token_kind($op_tokens)? { let op = BinOp::from(token); let rhs = self.$name()?; let span = lhs.span().union(rhs.span()); Ok(BinExpr { lhs, op, rhs, span }.into()) } else { Ok(lhs) } } }; } impl<'t> Parser<'t> { pub fn next_expr(&mut self) -> Result { self.next_bin_cmp_expr() } // == < > <= >= bin_expr!( next_bin_cmp_expr, &[ TokenKind::EqEq, TokenKind::Lt, TokenKind::Gt, TokenKind::LtEq, TokenKind::GtEq ], next_bin_add_expr ); // + - bin_expr!( next_bin_add_expr, &[TokenKind::Plus, TokenKind::Minus], next_bin_mul_expr ); // * / bin_expr!( next_bin_mul_expr, &[TokenKind::FSlash, TokenKind::Splat], next_dot_expr ); // . bin_expr!(next_dot_expr, &[TokenKind::Dot], next_un_expr); fn next_un_expr(&mut self) -> Result { if let Some(un_op) = self.match_any_token_kind(&UN_EXPR_START)? { let start = un_op.span(); let expr = self.next_un_expr()?; let end = expr.span(); Ok(UnExpr { op: un_op.kind().into(), expr, span: start.union(end), } .into()) } else { self.next_base_expr() } } fn next_base_expr(&mut self) -> Result { let token = self.expect_any_token_kind(&BASE_EXPR_START, "base expression")?; let expr: Expr = match token.kind() { TokenKind::Ident => BaseExpr { kind: BaseExprKind::Ident, span: token.span(), } .into(), TokenKind::Num => BaseExpr { kind: BaseExprKind::Num, span: token.span(), } .into(), TokenKind::Str => BaseExpr { kind: BaseExprKind::Str, span: token.span(), } .into(), TokenKind::Sym => BaseExpr { kind: BaseExprKind::Sym, span: token.span(), } .into(), TokenKind::LBracket => { let prev_skip = self.set_skip_newlines(true)?; let expr_list = self.next_expr_list(TokenKind::RBracket)?; self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind(TokenKind::RBracket, "end of list (right bracket)")?; let span = token.span().union(end_token.span()); BaseExpr { kind: BaseExprKind::List(expr_list), span, } .into() } TokenKind::LBrace => { // turn on newline parsing because we're going to start parsing statements again let prev_skip = self.set_skip_newlines(false)?; let body = self.next_block_body()?; self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind(TokenKind::RBrace, "end of block (right curly brace)")?; let span = token.span().union(end_token.span()); Expr::Base(BaseExpr { kind: BaseExprKind::Block(body), span, }) } TokenKind::ObjBrace => { let prev_skip = self.set_skip_newlines(true)?; let object = self.next_obj_list()?; self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind(TokenKind::RBrace, "end of object (right curly brace)")?; let span = token.span().union(end_token.span()); Expr::Base(BaseExpr { kind: BaseExprKind::Object(object), span, }) } TokenKind::LParen => { let prev_skip = self.set_skip_newlines(true)?; if let Some(end_token) = self.match_token_kind(TokenKind::RParen)? { // empty tuple let span = token.span().union(end_token.span()); Expr::Base(BaseExpr { kind: BaseExprKind::Tuple(Default::default()), span, }) } else { let first = self.next_expr()?; if let Some(_) = self.match_token_kind(TokenKind::Comma)? { let mut list = self.next_expr_list(TokenKind::RParen)?; self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind(TokenKind::RParen, "end of tuple")?; let span = token.span().union(end_token.span()); list.insert(0, first); Expr::Base( BaseExpr { kind: BaseExprKind::Tuple(list), span, } .into(), ) } else { self.set_skip_newlines(prev_skip)?; self.expect_token_kind(TokenKind::RParen, "end of expression")?; first } } } _ => unreachable!(), }; self.next_suffix_expr(expr) } /// Takes an expression and attempts to match a suffix for it - either a function call or /// index access. fn next_suffix_expr(&mut self, expr: Expr) -> Result { if self.match_token_kind(TokenKind::LParen)?.is_some() { // function call let prev_skip = self.set_skip_newlines(true)?; let args = self.next_expr_list(TokenKind::RParen)?; self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind(TokenKind::RParen, "end of function call (right paren)")?; let span = expr.span().union(end_token.span()); let fun_call = Expr::FunCall(FunCallExpr { expr, args, span }.into()); self.next_suffix_expr(fun_call) } else if self.match_token_kind(TokenKind::LBracket)?.is_some() { // indexing let prev_skip = self.set_skip_newlines(true)?; let index = self.next_expr()?; self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind( TokenKind::RBracket, "end of index expression (right square bracket)", )?; let span = expr.span().union(end_token.span()); let index_expr = Expr::Index(IndexExpr { expr, index, span }.into()); self.next_suffix_expr(index_expr) } else if self.match_token_kind(TokenKind::Arrow)?.is_some() { // check that the LHS is a tuple of idents, and get the parameters as well. let mut params: Vec; match expr { Expr::Base(BaseExpr { kind: BaseExprKind::Tuple(ref tuple), .. }) => { // Multi-parameter case params = Vec::with_capacity(tuple.len()); for param_expr in tuple.iter() { if let Expr::Base(BaseExpr { kind: BaseExprKind::Ident, span, }) = ¶m_expr { let name = span.text_at(self.lexer.text()); params.push(name.to_string()); } else { return Err(Error::ExpectedGot { expected: "identifier".to_string(), // TODO : something more specific got: "some other expression".to_string(), pos: param_expr.span().start, }); } } } Expr::Base(BaseExpr { kind: BaseExprKind::Ident, span, }) => { // Single parameter case params = vec![span.text_at(self.lexer.text()).to_string()] } _ => { return Err(Error::ExpectedGot { expected: "tuple of function parameters".to_string(), // TODO : something more specific got: "something else".to_string(), pos: expr.span().start, }); } } // function definition let rhs = self.next_expr()?; let span = expr.span().union(rhs.span()); Ok(Expr::Fun( FunExpr { params, expr: rhs, span, } .into(), )) } else { Ok(expr) } } /// Gets a list of expressions separated by commas, stopping when EOF or specified end token is /// reached. fn next_expr_list(&mut self, stop_before: TokenKind) -> Result> { let mut list_items = Vec::new(); while !self.is_token_kind(stop_before) { list_items.push(self.next_expr()?); // match a comma, otherwise exit the loop if self.match_token_kind(TokenKind::Comma)?.is_none() { break; } } Ok(list_items) } /// Parses the tail of a `BaseExprKind::Object` expression. /// /// This function expects that the initial object brace `%{` has already been eaten. fn next_obj_list(&mut self) -> Result> { let mut object = Vec::new(); // Parses this pattern: // ( key EQ value ( COMMA key = value )* COMMA? )? while !self.is_token_kind(TokenKind::RBrace) { let key = self.next_expr()?; self.expect_token_kind(TokenKind::Eq, "equals sign for object item")?; let value = self.next_expr()?; object.push((key, value)); // match a comma, otherwise exit the loop if self.match_token_kind(TokenKind::Comma)?.is_none() { break; } } Ok(object) } //////////////////////////////////////////////////////////////////////////////// // Token matching functions //////////////////////////////////////////////////////////////////////////////// fn adv_token(&mut self) -> Result> { let mut next_token = self.lexer.next_token()?; if self.is_skip_newlines() { while next_token .map(|t| t.kind() == TokenKind::Newline) .unwrap_or(false) { next_token = self.lexer.next_token()?; } if self.is_token_kind(TokenKind::Newline) { self.curr_token = next_token; while next_token .map(|t| t.kind() == TokenKind::Newline) .unwrap_or(false) { next_token = self.lexer.next_token()?; } } } Ok(mem::replace(&mut self.curr_token, next_token)) } fn match_token_where

(&mut self, pred: P) -> Result> where P: Fn(Token) -> bool, { if self.is_token_match(pred) { self.adv_token() } else { Ok(None) } } fn match_token_kind(&mut self, kind: TokenKind) -> Result> { if self.is_token_kind(kind) { self.adv_token() } else { Ok(None) } } fn match_any_token_kind(&mut self, kinds: &[TokenKind]) -> Result> { if self.is_any_token_kind(kinds) { self.adv_token() } else { Ok(None) } } fn is_token_match

(&self, pred: P) -> bool where P: Fn(Token) -> bool, { match self.curr_token { Some(token) => (pred)(token), None => false, } } fn is_token_kind(&self, kind: TokenKind) -> bool { self.is_token_match(|t| t.kind() == kind) } fn is_any_token_kind(&self, kinds: &[TokenKind]) -> bool { self.is_token_match(|t| kinds.contains(&t.kind())) } fn expect_token_where

(&mut self, pred: P, expected: impl ToString) -> Result where P: Fn(Token) -> bool, { self.match_token_where(pred)? .ok_or_else(|| Error::ExpectedGot { expected: expected.to_string(), got: self .curr_token .map(|token| token.kind().to_string()) .unwrap_or_else(|| "EOF".to_string()), pos: self.pos(), }) } fn expect_token_kind(&mut self, kind: TokenKind, expected: impl ToString) -> Result { self.expect_token_where(|t| t.kind() == kind, expected) } fn expect_any_token_kind( &mut self, kinds: &[TokenKind], expected: impl ToString, ) -> Result { self.expect_token_where(|t| kinds.contains(&t.kind()), expected) } fn expect_eol_or_eof(&mut self, expected: impl ToString) -> Result> { if self.curr_token.is_none() { Ok(None) } else { self.expect_any_token_kind(&EOL, expected).map(Some) } } } impl<'t> Spanned for Parser<'t> { fn span(&self) -> Span { self.curr_token .as_ref() .map(Spanned::span) .unwrap_or(Span::default()) } } impl<'t> TryFrom> for Parser<'t> { type Error = Error; fn try_from(lexer: Lexer<'t>) -> Result { Parser::new(lexer) } } impl<'t> TryFrom<&'t str> for Parser<'t> { type Error = Error; fn try_from(text: &'t str) -> Result { Parser::new(Lexer::new(text)) } } #[cfg(test)] mod test { use super::*; #[test] fn test_adv_token() { const EXPECTED: &'static [TokenKind] = &[ TokenKind::Num, TokenKind::Ident, TokenKind::Sym, TokenKind::Str, ]; let mut parser = Parser::try_from("1 ident :sym 'string'").unwrap(); for expected in EXPECTED.iter().copied() { let token = parser.adv_token().unwrap(); let kind = token.unwrap().kind(); assert_eq!(kind, expected); } assert!(parser.is_eof()); } #[test] fn test_match_token_where() { let mut parser = Parser::try_from("1 ident :sym 'string'").unwrap(); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Num), Ok(Some(_)) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Num), Ok(None) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Ident), Ok(Some(_)) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Ident), Ok(None) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Sym), Ok(Some(_)) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Sym), Ok(None) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Str), Ok(Some(_)) )); assert!(matches!( parser.match_token_where(|token| token.kind() == TokenKind::Str), Ok(None) )); assert!(parser.is_eof()); } macro_rules! test_parser { ($parser:expr, $($tail:tt)+) => {{ let mut parser = $parser; test_parser!(@TAIL, &mut parser, $($tail)+); }}; (@TAIL, $parser:expr, $method:ident, $expected:expr) => {{ assert_eq!($parser.$method().unwrap(), $expected); }}; (@TAIL, $parser:expr, $method:ident, $expected:expr, $($tail:tt)+) => {{ test_parser!(@TAIL, $parser, $method, $expected); test_parser!(@TAIL, $parser, $($tail)*); }}; (@TAIL, $parser:expr) => { assert!($parser.is_eof()); }; (@TAIL, $parser:expr,) => { assert!($parser.is_eof()); }; } //////////////////////////////////////////////////////////////////////////////// // Expr testing //////////////////////////////////////////////////////////////////////////////// fn bin_expr(lhs: Expr, op: BinOp, rhs: Expr) -> Expr { Expr::Bin( BinExpr { lhs, op, rhs, span: Default::default(), } .into(), ) } fn un_expr(op: UnOp, expr: Expr) -> Expr { Expr::Un( UnExpr { op, expr, span: Default::default(), } .into(), ) } fn base_expr(kind: BaseExprKind) -> Expr { Expr::Base(BaseExpr { kind, span: Default::default(), }) } fn fun_call_expr(expr: Expr, args: Vec) -> Expr { Expr::FunCall( FunCallExpr { expr, args, span: Default::default(), } .into(), ) } fn index_expr(expr: Expr, index: Expr) -> Expr { Expr::Index( IndexExpr { expr, index, span: Default::default(), } .into(), ) } fn fun_expr(params: Vec, expr: Expr) -> Expr { Expr::Fun( FunExpr { params, expr, span: Default::default(), } .into(), ) } #[test] fn test_base_expr() { test_parser!( Parser::try_from("1 x 'value' :sym").unwrap(), // 1 next_expr, base_expr(BaseExprKind::Num), // x next_expr, base_expr(BaseExprKind::Ident), // 'value' next_expr, base_expr(BaseExprKind::Str), // :sym next_expr, base_expr(BaseExprKind::Sym) ); } #[test] fn test_list_expr() { test_parser!( Parser::try_from("[1, x, 'value', :sym]").unwrap(), next_expr, base_expr(BaseExprKind::List(vec![ base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Str), base_expr(BaseExprKind::Sym), ])) ); test_parser!( Parser::try_from("[1, x, 'value', :sym,]").unwrap(), next_expr, base_expr(BaseExprKind::List(vec![ base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Str), base_expr(BaseExprKind::Sym), ])) ); } #[test] fn test_tuple_expr() { test_parser!( Parser::try_from("(1, :sym)").unwrap(), next_expr, base_expr(BaseExprKind::Tuple(vec![ base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Sym), ])) ); test_parser!( Parser::try_from("(:sym,)").unwrap(), next_expr, base_expr(BaseExprKind::Tuple(vec![base_expr(BaseExprKind::Sym),])) ); test_parser!( Parser::try_from("(:sym)").unwrap(), next_expr, base_expr(BaseExprKind::Sym) ); } #[test] fn test_block_expr() { test_parser!( Parser::try_from( r#"{ value = :sym key = "value" :ok }"# ) .unwrap(), next_expr, base_expr(BaseExprKind::Block(vec![ assign_stmt(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Sym)), assign_stmt(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Str)), Stmt::Expr(base_expr(BaseExprKind::Sym)) ])) ); } #[test] fn test_object_expr() { test_parser!( Parser::try_from( r#"%{ :sym = value, key = "value", "lit" = 1, }"# ) .unwrap(), next_expr, base_expr(BaseExprKind::Object(vec![ (base_expr(BaseExprKind::Sym), base_expr(BaseExprKind::Ident)), (base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Str)), (base_expr(BaseExprKind::Str), base_expr(BaseExprKind::Num)), ])) ); } #[test] fn test_fun_expr() { test_parser!( Parser::try_from(r#"() -> ()"#).unwrap(), next_expr, fun_expr(vec![], base_expr(BaseExprKind::Tuple(vec![]))) ); test_parser!( Parser::try_from(r#"() -> 1"#).unwrap(), next_expr, fun_expr(vec![], base_expr(BaseExprKind::Num),) ); test_parser!( Parser::try_from(r#"(a) -> 1"#).unwrap(), next_expr, fun_expr(vec![String::from("a"),], base_expr(BaseExprKind::Num),) ); test_parser!( Parser::try_from(r#"(a, b) -> a + b"#).unwrap(), next_expr, fun_expr( vec![String::from("a"), String::from("b"),], bin_expr( base_expr(BaseExprKind::Ident), BinOp::Plus, base_expr(BaseExprKind::Ident) ) ) ); } #[test] fn test_bin_expr() { test_parser!( Parser::try_from("x + 2").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Ident), BinOp::Plus, base_expr(BaseExprKind::Num) ) ); test_parser!( Parser::try_from("1 + 2 * 3 - 4 / 5").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, bin_expr( bin_expr( base_expr(BaseExprKind::Num), BinOp::Times, base_expr(BaseExprKind::Num) ), BinOp::Minus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Div, base_expr(BaseExprKind::Num) ) ) ) ); test_parser!( Parser::try_from("1+2*3-4/5").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, bin_expr( bin_expr( base_expr(BaseExprKind::Num), BinOp::Times, base_expr(BaseExprKind::Num) ), BinOp::Minus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Div, base_expr(BaseExprKind::Num) ) ) ) ); test_parser!( Parser::try_from("1 - -1 * 8").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Num), BinOp::Minus, bin_expr( un_expr(UnOp::Minus, base_expr(BaseExprKind::Num)), BinOp::Times, base_expr(BaseExprKind::Num) ) ) ); test_parser!( Parser::try_from("1--1*8").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Num), BinOp::Minus, bin_expr( un_expr(UnOp::Minus, base_expr(BaseExprKind::Num)), BinOp::Times, base_expr(BaseExprKind::Num) ) ) ); test_parser!( Parser::try_from("1 + 1 == 2").unwrap(), next_expr, bin_expr( bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, base_expr(BaseExprKind::Num) ), BinOp::EqEq, base_expr(BaseExprKind::Num) ) ); test_parser!( Parser::try_from("3 >= 1 + 2").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Num), BinOp::GtEq, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, base_expr(BaseExprKind::Num) ) ) ); test_parser!( Parser::try_from("foo.bar().baz(qux)").unwrap(), next_expr, bin_expr( base_expr(BaseExprKind::Ident), BinOp::Dot, bin_expr( fun_call_expr(base_expr(BaseExprKind::Ident), vec![]), BinOp::Dot, fun_call_expr( base_expr(BaseExprKind::Ident), vec![base_expr(BaseExprKind::Ident)] ), ) ) ); } #[test] fn test_multiline_exprs() { test_parser!( Parser::try_from( r"[ 1, x, ['value', :value], :sym ]" ) .unwrap(), next_expr, base_expr(BaseExprKind::List(vec![ base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::List(vec![ base_expr(BaseExprKind::Str), base_expr(BaseExprKind::Sym), ])), base_expr(BaseExprKind::Sym), ])) ); test_parser!( Parser::try_from( r"( 1, x, [ :key, 'value', ], :sym )" ) .unwrap(), next_expr, base_expr(BaseExprKind::Tuple(vec![ base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::List(vec![ base_expr(BaseExprKind::Sym), base_expr(BaseExprKind::Str), ])), base_expr(BaseExprKind::Sym), ])) ); test_parser!( Parser::try_from( r"( + 1 + 2 + 3 + 4 )" ) .unwrap(), next_expr, bin_expr( un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)), BinOp::Plus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, base_expr(BaseExprKind::Num) ) ) ) ); test_parser!( Parser::try_from( r"( + 1 + 2 + 3 + 4 , )" ) .unwrap(), next_expr, base_expr(BaseExprKind::Tuple(vec![bin_expr( un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)), BinOp::Plus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Plus, base_expr(BaseExprKind::Num) ) ) )])) ); } #[test] fn test_suffix_expr() { test_parser!( Parser::try_from(r"foo()").unwrap(), next_expr, fun_call_expr(base_expr(BaseExprKind::Ident), vec![]) ); test_parser!( Parser::try_from(r"foo(bar)").unwrap(), next_expr, fun_call_expr( base_expr(BaseExprKind::Ident), vec![base_expr(BaseExprKind::Ident)] ) ); test_parser!( Parser::try_from(r"foo(bar, 1, :sym)").unwrap(), next_expr, fun_call_expr( base_expr(BaseExprKind::Ident), vec![ base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Sym) ] ) ); test_parser!( Parser::try_from( r"foo( bar, 1, :sym )" ) .unwrap(), next_expr, fun_call_expr( base_expr(BaseExprKind::Ident), vec![ base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Num), base_expr(BaseExprKind::Sym) ] ) ); test_parser!( Parser::try_from(r"foo()[0]").unwrap(), next_expr, index_expr( fun_call_expr(base_expr(BaseExprKind::Ident), vec![]), base_expr(BaseExprKind::Num), ) ); test_parser!( Parser::try_from(r"foo[0](bar)").unwrap(), next_expr, fun_call_expr( index_expr(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Num),), vec![base_expr(BaseExprKind::Ident)] ) ); } //////////////////////////////////////////////////////////////////////////////// // Stmt testing //////////////////////////////////////////////////////////////////////////////// fn assign_stmt(lhs: Expr, rhs: Expr) -> Stmt { Stmt::Assign(AssignStmt { lhs, rhs, span: Default::default(), }) } #[test] #[should_panic] fn test_stray_right_brace_body() { let mut parser = Parser::try_from( r" } ", ) .unwrap(); parser.next_body().unwrap(); } #[test] fn test_block_body() { test_parser!( Parser::try_from( r" a = 1 b = :sym foo() " ) .unwrap(), next_block_body, vec![ assign_stmt(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Num),), assign_stmt(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Sym),), Stmt::Expr(fun_call_expr(base_expr(BaseExprKind::Ident), vec![],)) ] ); } #[test] fn test_assign_stmt() { test_parser!( Parser::try_from( r" a = 1 b = :sym " ) .unwrap(), next_stmt, Some(assign_stmt( base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Num), )), next_stmt, Some(assign_stmt( base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Sym), )) ); } #[test] fn test_expr_stmt() { test_parser!( Parser::try_from( r" a 'b' :sym 1 " ) .unwrap(), next_stmt, Some(Stmt::Expr(base_expr(BaseExprKind::Ident),)), next_stmt, Some(Stmt::Expr(base_expr(BaseExprKind::Str),)), next_stmt, Some(Stmt::Expr(base_expr(BaseExprKind::Sym),)), next_stmt, Some(Stmt::Expr(base_expr(BaseExprKind::Num),)) ); test_parser!( Parser::try_from( r" (a + 1 * 3)" ) .unwrap(), next_stmt, Some(Stmt::Expr(bin_expr( base_expr(BaseExprKind::Ident), BinOp::Plus, bin_expr( base_expr(BaseExprKind::Num), BinOp::Times, base_expr(BaseExprKind::Num) ) ))) ); } }