2020-05-02 18:42:01 -04:00
|
|
|
use crate::syn::{ast::*, error::*, lexer::Lexer, op::*, span::*, token::*};
|
2020-05-06 16:57:28 -04:00
|
|
|
use lazy_static::lazy_static;
|
2020-04-27 20:17:16 -04:00
|
|
|
use std::{convert::TryFrom, mem};
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
lazy_static! {
|
|
|
|
|
static ref BASE_EXPR_START: Vec<TokenKind> = vec![
|
|
|
|
|
TokenKind::Ident,
|
|
|
|
|
TokenKind::Num,
|
|
|
|
|
TokenKind::Str,
|
|
|
|
|
TokenKind::Sym,
|
|
|
|
|
TokenKind::LParen,
|
|
|
|
|
TokenKind::LBracket,
|
|
|
|
|
TokenKind::LBrace,
|
|
|
|
|
TokenKind::ObjBrace,
|
|
|
|
|
];
|
|
|
|
|
static ref UN_EXPR_START: Vec<TokenKind> =
|
|
|
|
|
vec![TokenKind::Plus, TokenKind::Minus, TokenKind::Bang];
|
|
|
|
|
static ref EXPR_START: Vec<TokenKind> = {
|
|
|
|
|
let mut start = BASE_EXPR_START.clone();
|
|
|
|
|
start.extend(UN_EXPR_START.iter());
|
|
|
|
|
start
|
|
|
|
|
};
|
|
|
|
|
static ref EOL: Vec<TokenKind> = vec![TokenKind::Eol, TokenKind::Newline];
|
|
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
|
|
|
|
|
pub struct Parser<'t> {
|
|
|
|
|
lexer: Lexer<'t>,
|
|
|
|
|
curr_token: Option<Token>,
|
2020-05-02 18:42:01 -04:00
|
|
|
skip_newlines: bool,
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'t> Parser<'t> {
|
|
|
|
|
pub fn new(lexer: Lexer<'t>) -> Result<Self> {
|
|
|
|
|
let mut parser = Parser {
|
|
|
|
|
lexer,
|
|
|
|
|
curr_token: None,
|
2020-05-02 18:42:01 -04:00
|
|
|
skip_newlines: false,
|
2020-04-27 20:17:16 -04:00
|
|
|
};
|
|
|
|
|
parser.adv_token()?;
|
|
|
|
|
Ok(parser)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_eof(&self) -> bool {
|
|
|
|
|
self.lexer.is_eof()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn pos(&self) -> Pos {
|
|
|
|
|
self.span().start
|
|
|
|
|
}
|
2020-05-05 16:38:07 -04:00
|
|
|
|
|
|
|
|
pub fn set_skip_newlines(&mut self, skip: bool) -> Result<bool> {
|
|
|
|
|
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(())
|
|
|
|
|
}
|
2020-05-02 18:42:01 -04:00
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
|
2020-05-05 17:21:12 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Statement parsing
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
impl<'t> Parser<'t> {
|
2020-05-08 16:19:01 -04:00
|
|
|
/// Gets the remaining list of statements in this file, expecting EOF at the end.
|
|
|
|
|
pub fn next_body(&mut self) -> Result<Vec<Stmt>> {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
pub fn next_stmt(&mut self) -> Result<Option<Stmt>> {
|
|
|
|
|
// 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());
|
2020-05-06 17:14:55 -04:00
|
|
|
Ok(Some(Stmt::Assign(AssignStmt {
|
|
|
|
|
lhs: expr,
|
|
|
|
|
rhs,
|
|
|
|
|
span,
|
|
|
|
|
})))
|
2020-05-06 16:57:28 -04:00
|
|
|
} else {
|
|
|
|
|
self.expect_eol_or_eof("end-of-line after expression")?;
|
|
|
|
|
Ok(Some(Stmt::Expr(expr)))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 17:14:55 -04:00
|
|
|
/// Parses a list of statements until it reaches a right curly brace.
|
2020-05-08 16:19:01 -04:00
|
|
|
fn next_block_body(&mut self) -> Result<Vec<Stmt>> {
|
2020-05-06 16:57:28 -04:00
|
|
|
let mut body = Vec::new();
|
|
|
|
|
|
2020-05-08 16:19:01 -04:00
|
|
|
// end of body token
|
2020-05-06 16:57:28 -04:00
|
|
|
if self.is_token_kind(TokenKind::RBrace) {
|
2020-05-08 16:19:01 -04:00
|
|
|
self.expect_eol_or_eof("end-of-line after assignment")?;
|
2020-05-06 16:57:28 -04:00
|
|
|
return Ok(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while let Some(stmt) = self.next_stmt()? {
|
|
|
|
|
body.push(stmt);
|
2020-05-08 16:19:01 -04:00
|
|
|
|
|
|
|
|
// end of body token
|
2020-05-06 16:57:28 -04:00
|
|
|
if self.is_token_kind(TokenKind::RBrace) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(body)
|
|
|
|
|
}
|
2020-05-05 17:21:12 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2020-05-05 16:52:46 -04:00
|
|
|
// Expression parsing
|
2020-05-02 18:42:01 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2020-04-27 20:17:16 -04:00
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
macro_rules! bin_expr {
|
|
|
|
|
($name:ident, $op_tokens:expr, $next:ident) => {
|
|
|
|
|
fn $name(&mut self) -> Result<Expr> {
|
|
|
|
|
let lhs = self.$next()?;
|
2020-05-06 16:57:28 -04:00
|
|
|
if let Some(token) = self.match_any_token_kind($op_tokens)? {
|
2020-05-02 18:42:01 -04:00
|
|
|
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> {
|
2020-04-27 20:17:16 -04:00
|
|
|
pub fn next_expr(&mut self) -> Result<Expr> {
|
2020-05-05 16:38:07 -04:00
|
|
|
self.next_bin_cmp_expr()
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-05 16:38:07 -04:00
|
|
|
// == < > <= >=
|
|
|
|
|
bin_expr!(
|
|
|
|
|
next_bin_cmp_expr,
|
|
|
|
|
&[
|
|
|
|
|
TokenKind::EqEq,
|
|
|
|
|
TokenKind::Lt,
|
|
|
|
|
TokenKind::Gt,
|
|
|
|
|
TokenKind::LtEq,
|
|
|
|
|
TokenKind::GtEq
|
|
|
|
|
],
|
|
|
|
|
next_bin_add_expr
|
|
|
|
|
);
|
|
|
|
|
// + -
|
2020-05-02 18:42:01 -04:00
|
|
|
bin_expr!(
|
|
|
|
|
next_bin_add_expr,
|
|
|
|
|
&[TokenKind::Plus, TokenKind::Minus],
|
|
|
|
|
next_bin_mul_expr
|
|
|
|
|
);
|
2020-05-05 16:38:07 -04:00
|
|
|
// * /
|
2020-05-02 18:42:01 -04:00
|
|
|
bin_expr!(
|
|
|
|
|
next_bin_mul_expr,
|
|
|
|
|
&[TokenKind::FSlash, TokenKind::Splat],
|
2020-05-06 18:02:13 -04:00
|
|
|
next_dot_expr
|
|
|
|
|
);
|
|
|
|
|
// .
|
2020-05-06 18:04:07 -04:00
|
|
|
bin_expr!(next_dot_expr, &[TokenKind::Dot], next_un_expr);
|
2020-04-27 20:17:16 -04:00
|
|
|
|
|
|
|
|
fn next_un_expr(&mut self) -> Result<Expr> {
|
2020-05-06 16:57:28 -04:00
|
|
|
if let Some(un_op) = self.match_any_token_kind(&UN_EXPR_START)? {
|
2020-05-02 18:42:01 -04:00
|
|
|
let start = un_op.span();
|
|
|
|
|
let expr = self.next_un_expr()?;
|
|
|
|
|
let end = expr.span();
|
2020-05-05 16:38:07 -04:00
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
Ok(UnExpr {
|
|
|
|
|
op: un_op.kind().into(),
|
|
|
|
|
expr,
|
|
|
|
|
span: start.union(end),
|
|
|
|
|
}
|
|
|
|
|
.into())
|
|
|
|
|
} else {
|
|
|
|
|
self.next_base_expr()
|
|
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn next_base_expr(&mut self) -> Result<Expr> {
|
2020-05-06 17:14:55 -04:00
|
|
|
let token = self.expect_any_token_kind(&BASE_EXPR_START, "base expression")?;
|
2020-04-27 20:17:16 -04:00
|
|
|
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(),
|
2020-05-02 18:42:01 -04:00
|
|
|
TokenKind::LBracket => {
|
2020-05-05 16:38:07 -04:00
|
|
|
let prev_skip = self.set_skip_newlines(true)?;
|
2020-05-02 18:42:01 -04:00
|
|
|
let expr_list = self.next_expr_list(TokenKind::RBracket)?;
|
2020-05-05 16:38:07 -04:00
|
|
|
self.set_skip_newlines(prev_skip)?;
|
2020-05-02 18:42:01 -04:00
|
|
|
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()
|
|
|
|
|
}
|
2020-05-06 17:14:55 -04:00
|
|
|
TokenKind::LBrace => {
|
2020-05-08 16:19:01 -04:00
|
|
|
// 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)?;
|
2020-05-06 17:14:55 -04:00
|
|
|
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,
|
|
|
|
|
})
|
|
|
|
|
}
|
2020-05-05 17:21:12 -04:00
|
|
|
TokenKind::ObjBrace => {
|
|
|
|
|
let prev_skip = self.set_skip_newlines(true)?;
|
|
|
|
|
let object = self.next_obj_list()?;
|
2020-05-06 16:57:28 -04:00
|
|
|
self.set_skip_newlines(prev_skip)?;
|
2020-05-05 17:22:39 -04:00
|
|
|
let end_token =
|
|
|
|
|
self.expect_token_kind(TokenKind::RBrace, "end of object (right curly brace)")?;
|
2020-05-05 17:21:12 -04:00
|
|
|
let span = token.span().union(end_token.span());
|
|
|
|
|
Expr::Base(BaseExpr {
|
|
|
|
|
kind: BaseExprKind::Object(object),
|
|
|
|
|
span,
|
|
|
|
|
})
|
|
|
|
|
}
|
2020-05-02 18:42:01 -04:00
|
|
|
TokenKind::LParen => {
|
2020-05-05 16:38:07 -04:00
|
|
|
let prev_skip = self.set_skip_newlines(true)?;
|
2020-05-07 17:43:39 -04:00
|
|
|
if let Some(end_token) = self.match_token_kind(TokenKind::RParen)? {
|
|
|
|
|
// empty tuple
|
2020-05-05 17:21:12 -04:00
|
|
|
let span = token.span().union(end_token.span());
|
2020-05-07 17:43:39 -04:00
|
|
|
Expr::Base(BaseExpr {
|
|
|
|
|
kind: BaseExprKind::Tuple(Default::default()),
|
|
|
|
|
span,
|
|
|
|
|
})
|
2020-05-02 18:42:01 -04:00
|
|
|
} else {
|
2020-05-07 17:43:39 -04:00
|
|
|
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)?;
|
2020-05-08 16:19:01 -04:00
|
|
|
let end_token =
|
|
|
|
|
self.expect_token_kind(TokenKind::RParen, "end of tuple")?;
|
2020-05-07 17:43:39 -04:00
|
|
|
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
|
|
|
|
|
}
|
2020-05-02 18:42:01 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
_ => unreachable!(),
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-06 17:39:31 -04:00
|
|
|
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<Expr> {
|
|
|
|
|
if self.match_token_kind(TokenKind::LParen)?.is_some() {
|
2020-05-06 17:55:25 -04:00
|
|
|
// function call
|
2020-05-06 17:39:31 -04:00
|
|
|
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 =
|
2020-05-06 17:55:25 -04:00
|
|
|
self.expect_token_kind(TokenKind::RParen, "end of function call (right paren)")?;
|
2020-05-06 17:39:31 -04:00
|
|
|
let span = expr.span().union(end_token.span());
|
2020-05-06 18:04:07 -04:00
|
|
|
let fun_call = Expr::FunCall(FunCallExpr { expr, args, span }.into());
|
2020-05-06 17:39:31 -04:00
|
|
|
self.next_suffix_expr(fun_call)
|
|
|
|
|
} else if self.match_token_kind(TokenKind::LBracket)?.is_some() {
|
2020-05-06 17:55:25 -04:00
|
|
|
// indexing
|
|
|
|
|
let prev_skip = self.set_skip_newlines(true)?;
|
|
|
|
|
let index = self.next_expr()?;
|
|
|
|
|
self.set_skip_newlines(prev_skip)?;
|
2020-05-06 18:04:07 -04:00
|
|
|
let end_token = self.expect_token_kind(
|
|
|
|
|
TokenKind::RBracket,
|
|
|
|
|
"end of index expression (right square bracket)",
|
|
|
|
|
)?;
|
2020-05-06 17:55:25 -04:00
|
|
|
let span = expr.span().union(end_token.span());
|
2020-05-06 18:04:07 -04:00
|
|
|
let index_expr = Expr::Index(IndexExpr { expr, index, span }.into());
|
2020-05-06 17:55:25 -04:00
|
|
|
self.next_suffix_expr(index_expr)
|
2020-05-07 17:43:39 -04:00
|
|
|
} 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<String>;
|
|
|
|
|
match expr {
|
2020-05-08 16:19:01 -04:00
|
|
|
Expr::Base(BaseExpr {
|
|
|
|
|
kind: BaseExprKind::Tuple(ref tuple),
|
|
|
|
|
..
|
|
|
|
|
}) => {
|
2020-05-07 17:43:39 -04:00
|
|
|
// Multi-parameter case
|
|
|
|
|
params = Vec::with_capacity(tuple.len());
|
|
|
|
|
for param_expr in tuple.iter() {
|
2020-05-08 16:19:01 -04:00
|
|
|
if let Expr::Base(BaseExpr {
|
|
|
|
|
kind: BaseExprKind::Ident,
|
|
|
|
|
span,
|
|
|
|
|
}) = ¶m_expr
|
|
|
|
|
{
|
2020-05-07 17:43:39 -04:00
|
|
|
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,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-08 16:19:01 -04:00
|
|
|
Expr::Base(BaseExpr {
|
|
|
|
|
kind: BaseExprKind::Ident,
|
|
|
|
|
span,
|
|
|
|
|
}) => {
|
2020-05-07 17:43:39 -04:00
|
|
|
// 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());
|
2020-05-08 16:19:01 -04:00
|
|
|
Ok(Expr::Fun(
|
|
|
|
|
FunExpr {
|
|
|
|
|
params,
|
|
|
|
|
expr: rhs,
|
|
|
|
|
span,
|
|
|
|
|
}
|
|
|
|
|
.into(),
|
|
|
|
|
))
|
2020-05-06 17:39:31 -04:00
|
|
|
} else {
|
|
|
|
|
Ok(expr)
|
|
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
/// 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<Vec<Expr>> {
|
2020-04-27 20:17:16 -04:00
|
|
|
let mut list_items = Vec::new();
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
while !self.is_token_kind(stop_before) {
|
|
|
|
|
list_items.push(self.next_expr()?);
|
2020-04-27 20:17:16 -04:00
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
// match a comma, otherwise exit the loop
|
|
|
|
|
if self.match_token_kind(TokenKind::Comma)?.is_none() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(list_items)
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-05 17:21:12 -04:00
|
|
|
/// 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<Vec<(Expr, Expr)>> {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 20:17:16 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Token matching functions
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
fn adv_token(&mut self) -> Result<Option<Token>> {
|
2020-05-05 16:38:07 -04:00
|
|
|
let mut next_token = self.lexer.next_token()?;
|
|
|
|
|
|
|
|
|
|
if self.is_skip_newlines() {
|
2020-05-05 17:21:12 -04:00
|
|
|
while next_token
|
|
|
|
|
.map(|t| t.kind() == TokenKind::Newline)
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
2020-05-05 16:38:07 -04:00
|
|
|
next_token = self.lexer.next_token()?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self.is_token_kind(TokenKind::Newline) {
|
|
|
|
|
self.curr_token = next_token;
|
2020-05-05 17:21:12 -04:00
|
|
|
while next_token
|
|
|
|
|
.map(|t| t.kind() == TokenKind::Newline)
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
2020-05-05 16:38:07 -04:00
|
|
|
next_token = self.lexer.next_token()?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 20:17:16 -04:00
|
|
|
Ok(mem::replace(&mut self.curr_token, next_token))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn match_token_where<P>(&mut self, pred: P) -> Result<Option<Token>>
|
2020-05-02 18:42:01 -04:00
|
|
|
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<Option<Token>> {
|
|
|
|
|
if self.is_token_kind(kind) {
|
|
|
|
|
self.adv_token()
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
fn match_any_token_kind(&mut self, kinds: &[TokenKind]) -> Result<Option<Token>> {
|
|
|
|
|
if self.is_any_token_kind(kinds) {
|
|
|
|
|
self.adv_token()
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
fn is_token_match<P>(&self, pred: P) -> bool
|
2020-04-27 20:17:16 -04:00
|
|
|
where
|
|
|
|
|
P: Fn(Token) -> bool,
|
|
|
|
|
{
|
|
|
|
|
match self.curr_token {
|
2020-05-02 18:42:01 -04:00
|
|
|
Some(token) => (pred)(token),
|
|
|
|
|
None => false,
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
fn is_token_kind(&self, kind: TokenKind) -> bool {
|
|
|
|
|
self.is_token_match(|t| t.kind() == kind)
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
fn is_any_token_kind(&self, kinds: &[TokenKind]) -> bool {
|
|
|
|
|
self.is_token_match(|t| kinds.contains(&t.kind()))
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 20:17:16 -04:00
|
|
|
fn expect_token_where<P>(&mut self, pred: P, expected: impl ToString) -> Result<Token>
|
|
|
|
|
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(),
|
|
|
|
|
})
|
|
|
|
|
}
|
2020-05-02 18:42:01 -04:00
|
|
|
|
|
|
|
|
fn expect_token_kind(&mut self, kind: TokenKind, expected: impl ToString) -> Result<Token> {
|
|
|
|
|
self.expect_token_where(|t| t.kind() == kind, expected)
|
|
|
|
|
}
|
2020-05-06 16:57:28 -04:00
|
|
|
|
2020-05-06 17:14:55 -04:00
|
|
|
fn expect_any_token_kind(
|
|
|
|
|
&mut self,
|
|
|
|
|
kinds: &[TokenKind],
|
|
|
|
|
expected: impl ToString,
|
|
|
|
|
) -> Result<Token> {
|
2020-05-06 16:57:28 -04:00
|
|
|
self.expect_token_where(|t| kinds.contains(&t.kind()), expected)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn expect_eol_or_eof(&mut self, expected: impl ToString) -> Result<Option<Token>> {
|
|
|
|
|
if self.curr_token.is_none() {
|
|
|
|
|
Ok(None)
|
|
|
|
|
} else {
|
|
|
|
|
self.expect_any_token_kind(&EOL, expected).map(Some)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<Lexer<'t>> for Parser<'t> {
|
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
|
|
fn try_from(lexer: Lexer<'t>) -> Result<Self> {
|
|
|
|
|
Parser::new(lexer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'t> TryFrom<&'t str> for Parser<'t> {
|
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
|
|
fn try_from(text: &'t str) -> Result<Self> {
|
|
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
macro_rules! test_parser {
|
2020-05-05 16:38:07 -04:00
|
|
|
($parser:expr, $($tail:tt)+) => {{
|
|
|
|
|
let mut parser = $parser;
|
2020-05-02 18:42:01 -04:00
|
|
|
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)*);
|
|
|
|
|
}};
|
|
|
|
|
|
2020-05-05 16:38:07 -04:00
|
|
|
(@TAIL, $parser:expr) => {
|
|
|
|
|
assert!($parser.is_eof());
|
|
|
|
|
};
|
|
|
|
|
(@TAIL, $parser:expr,) => {
|
|
|
|
|
assert!($parser.is_eof());
|
|
|
|
|
};
|
2020-05-02 18:42:01 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Expr testing
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
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(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 17:39:31 -04:00
|
|
|
fn fun_call_expr(expr: Expr, args: Vec<Expr>) -> Expr {
|
2020-05-06 18:04:07 -04:00
|
|
|
Expr::FunCall(
|
|
|
|
|
FunCallExpr {
|
|
|
|
|
expr,
|
|
|
|
|
args,
|
|
|
|
|
span: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
.into(),
|
|
|
|
|
)
|
2020-05-06 17:39:31 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-06 17:55:25 -04:00
|
|
|
fn index_expr(expr: Expr, index: Expr) -> Expr {
|
2020-05-06 18:04:07 -04:00
|
|
|
Expr::Index(
|
|
|
|
|
IndexExpr {
|
|
|
|
|
expr,
|
|
|
|
|
index,
|
|
|
|
|
span: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
.into(),
|
|
|
|
|
)
|
2020-05-06 17:55:25 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-07 17:43:39 -04:00
|
|
|
fn fun_expr(params: Vec<String>, expr: Expr) -> Expr {
|
|
|
|
|
Expr::Fun(
|
|
|
|
|
FunExpr {
|
|
|
|
|
params,
|
|
|
|
|
expr,
|
|
|
|
|
span: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
.into(),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 20:17:16 -04:00
|
|
|
#[test]
|
|
|
|
|
fn test_base_expr() {
|
2020-05-02 18:42:01 -04:00
|
|
|
test_parser!(
|
2020-05-05 16:38:07 -04:00
|
|
|
Parser::try_from("1 x 'value' :sym").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
// 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)
|
|
|
|
|
);
|
2020-05-05 16:38:07 -04:00
|
|
|
}
|
2020-05-02 18:42:01 -04:00
|
|
|
|
2020-05-05 16:38:07 -04:00
|
|
|
#[test]
|
|
|
|
|
fn test_list_expr() {
|
2020-05-02 18:42:01 -04:00
|
|
|
test_parser!(
|
2020-05-05 16:38:07 -04:00
|
|
|
Parser::try_from("[1, x, 'value', :sym]").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
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!(
|
2020-05-05 16:38:07 -04:00
|
|
|
Parser::try_from("[1, x, 'value', :sym,]").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
next_expr,
|
|
|
|
|
base_expr(BaseExprKind::List(vec![
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
base_expr(BaseExprKind::Str),
|
|
|
|
|
base_expr(BaseExprKind::Sym),
|
|
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2020-05-05 16:38:07 -04:00
|
|
|
fn test_tuple_expr() {
|
2020-05-02 18:42:01 -04:00
|
|
|
test_parser!(
|
2020-05-05 16:38:07 -04:00
|
|
|
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,
|
2020-05-05 17:21:12 -04:00
|
|
|
base_expr(BaseExprKind::Tuple(vec![base_expr(BaseExprKind::Sym),]))
|
2020-05-05 16:38:07 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("(:sym)").unwrap(),
|
|
|
|
|
next_expr,
|
|
|
|
|
base_expr(BaseExprKind::Sym)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 17:14:55 -04:00
|
|
|
#[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))
|
|
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-05 17:21:12 -04:00
|
|
|
#[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![
|
2020-05-05 17:22:39 -04:00
|
|
|
(base_expr(BaseExprKind::Sym), base_expr(BaseExprKind::Ident)),
|
|
|
|
|
(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Str)),
|
|
|
|
|
(base_expr(BaseExprKind::Str), base_expr(BaseExprKind::Num)),
|
2020-05-05 17:21:12 -04:00
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-07 17:43:39 -04:00
|
|
|
#[test]
|
|
|
|
|
fn test_fun_expr() {
|
|
|
|
|
test_parser!(
|
2020-05-08 16:19:01 -04:00
|
|
|
Parser::try_from(r#"() -> ()"#).unwrap(),
|
2020-05-07 17:43:39 -04:00
|
|
|
next_expr,
|
2020-05-08 16:19:01 -04:00
|
|
|
fun_expr(vec![], base_expr(BaseExprKind::Tuple(vec![])))
|
2020-05-07 17:43:39 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
2020-05-08 16:19:01 -04:00
|
|
|
Parser::try_from(r#"() -> 1"#).unwrap(),
|
2020-05-07 17:43:39 -04:00
|
|
|
next_expr,
|
2020-05-08 16:19:01 -04:00
|
|
|
fun_expr(vec![], base_expr(BaseExprKind::Num),)
|
2020-05-07 17:43:39 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
2020-05-08 16:19:01 -04:00
|
|
|
Parser::try_from(r#"(a) -> 1"#).unwrap(),
|
2020-05-07 17:43:39 -04:00
|
|
|
next_expr,
|
2020-05-08 16:19:01 -04:00
|
|
|
fun_expr(vec![String::from("a"),], base_expr(BaseExprKind::Num),)
|
2020-05-07 17:43:39 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
2020-05-08 16:19:01 -04:00
|
|
|
Parser::try_from(r#"(a, b) -> a + b"#).unwrap(),
|
2020-05-07 17:43:39 -04:00
|
|
|
next_expr,
|
|
|
|
|
fun_expr(
|
2020-05-08 16:19:01 -04:00
|
|
|
vec![String::from("a"), String::from("b"),],
|
2020-05-07 17:43:39 -04:00
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
BinOp::Plus,
|
|
|
|
|
base_expr(BaseExprKind::Ident)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-05 16:38:07 -04:00
|
|
|
#[test]
|
|
|
|
|
fn test_bin_expr() {
|
|
|
|
|
test_parser!(
|
2020-05-05 16:52:46 -04:00
|
|
|
Parser::try_from("x + 2").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
next_expr,
|
|
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
BinOp::Plus,
|
|
|
|
|
base_expr(BaseExprKind::Num)
|
2020-05-05 16:52:46 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("1 + 2 * 3 - 4 / 5").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
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)
|
|
|
|
|
)
|
|
|
|
|
)
|
2020-05-05 16:52:46 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("1+2*3-4/5").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
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)
|
|
|
|
|
)
|
|
|
|
|
)
|
2020-05-05 16:52:46 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("1 - -1 * 8").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
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)
|
|
|
|
|
)
|
2020-05-05 16:52:46 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("1--1*8").unwrap(),
|
2020-05-02 18:42:01 -04:00
|
|
|
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)
|
2020-04-27 20:17:16 -04:00
|
|
|
)
|
2020-05-05 16:52:46 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("1 + 1 == 2").unwrap(),
|
2020-05-05 16:38:07 -04:00
|
|
|
next_expr,
|
|
|
|
|
bin_expr(
|
|
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
BinOp::Plus,
|
|
|
|
|
base_expr(BaseExprKind::Num)
|
|
|
|
|
),
|
|
|
|
|
BinOp::EqEq,
|
|
|
|
|
base_expr(BaseExprKind::Num)
|
2020-05-05 16:52:46 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from("3 >= 1 + 2").unwrap(),
|
2020-05-05 16:38:07 -04:00
|
|
|
next_expr,
|
|
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
BinOp::GtEq,
|
|
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
BinOp::Plus,
|
|
|
|
|
base_expr(BaseExprKind::Num)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
2020-05-06 18:02:13 -04:00
|
|
|
|
|
|
|
|
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,
|
2020-05-06 18:04:07 -04:00
|
|
|
fun_call_expr(
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
vec![base_expr(BaseExprKind::Ident)]
|
|
|
|
|
),
|
2020-05-06 18:02:13 -04:00
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
2020-05-05 16:38:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_multiline_exprs() {
|
|
|
|
|
test_parser!(
|
2020-05-05 17:21:12 -04:00
|
|
|
Parser::try_from(
|
|
|
|
|
r"[
|
2020-05-05 16:38:07 -04:00
|
|
|
1,
|
|
|
|
|
x,
|
|
|
|
|
['value', :value],
|
|
|
|
|
:sym
|
2020-05-05 17:21:12 -04:00
|
|
|
]"
|
|
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-05 16:38:07 -04:00
|
|
|
next_expr,
|
|
|
|
|
base_expr(BaseExprKind::List(vec![
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
base_expr(BaseExprKind::List(vec![
|
2020-05-05 17:21:12 -04:00
|
|
|
base_expr(BaseExprKind::Str),
|
|
|
|
|
base_expr(BaseExprKind::Sym),
|
2020-05-05 16:38:07 -04:00
|
|
|
])),
|
|
|
|
|
base_expr(BaseExprKind::Sym),
|
|
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
2020-05-05 17:21:12 -04:00
|
|
|
Parser::try_from(
|
|
|
|
|
r"(
|
2020-05-05 16:38:07 -04:00
|
|
|
1,
|
|
|
|
|
x,
|
|
|
|
|
[
|
2020-05-05 16:52:46 -04:00
|
|
|
:key,
|
2020-05-05 16:38:07 -04:00
|
|
|
'value',
|
|
|
|
|
],
|
|
|
|
|
:sym
|
2020-05-05 17:21:12 -04:00
|
|
|
)"
|
|
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-05 16:38:07 -04:00
|
|
|
next_expr,
|
|
|
|
|
base_expr(BaseExprKind::Tuple(vec![
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
base_expr(BaseExprKind::List(vec![
|
2020-05-05 17:21:12 -04:00
|
|
|
base_expr(BaseExprKind::Sym),
|
|
|
|
|
base_expr(BaseExprKind::Str),
|
2020-05-05 16:38:07 -04:00
|
|
|
])),
|
|
|
|
|
base_expr(BaseExprKind::Sym),
|
|
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
2020-05-05 17:21:12 -04:00
|
|
|
Parser::try_from(
|
|
|
|
|
r"(
|
2020-05-05 16:38:07 -04:00
|
|
|
+ 1
|
|
|
|
|
+ 2
|
|
|
|
|
+ 3
|
|
|
|
|
+ 4
|
2020-05-05 17:21:12 -04:00
|
|
|
)"
|
|
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-05 16:38:07 -04:00
|
|
|
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)
|
|
|
|
|
)
|
|
|
|
|
)
|
2020-04-27 20:17:16 -04:00
|
|
|
)
|
2020-05-02 18:42:01 -04:00
|
|
|
);
|
|
|
|
|
|
2020-05-05 16:38:07 -04:00
|
|
|
test_parser!(
|
2020-05-05 17:21:12 -04:00
|
|
|
Parser::try_from(
|
|
|
|
|
r"(
|
2020-05-05 16:38:07 -04:00
|
|
|
+ 1
|
|
|
|
|
+ 2
|
|
|
|
|
+ 3
|
|
|
|
|
+ 4
|
|
|
|
|
,
|
2020-05-05 17:21:12 -04:00
|
|
|
)"
|
|
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-05 16:38:07 -04:00
|
|
|
next_expr,
|
2020-05-05 17:21:12 -04:00
|
|
|
base_expr(BaseExprKind::Tuple(vec![bin_expr(
|
|
|
|
|
un_expr(UnOp::Plus, base_expr(BaseExprKind::Num)),
|
|
|
|
|
BinOp::Plus,
|
2020-05-05 16:38:07 -04:00
|
|
|
bin_expr(
|
2020-05-05 17:21:12 -04:00
|
|
|
base_expr(BaseExprKind::Num),
|
2020-05-05 16:38:07 -04:00
|
|
|
BinOp::Plus,
|
|
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
BinOp::Plus,
|
2020-05-05 17:21:12 -04:00
|
|
|
base_expr(BaseExprKind::Num)
|
2020-05-05 16:38:07 -04:00
|
|
|
)
|
|
|
|
|
)
|
2020-05-05 17:21:12 -04:00
|
|
|
)]))
|
2020-05-05 16:38:07 -04:00
|
|
|
);
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|
2020-05-06 17:14:55 -04:00
|
|
|
|
2020-05-06 17:39:31 -04:00
|
|
|
#[test]
|
2020-05-06 17:55:25 -04:00
|
|
|
fn test_suffix_expr() {
|
2020-05-06 17:39:31 -04:00
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from(r"foo()").unwrap(),
|
|
|
|
|
next_expr,
|
2020-05-06 18:04:07 -04:00
|
|
|
fun_call_expr(base_expr(BaseExprKind::Ident), vec![])
|
2020-05-06 17:39:31 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from(r"foo(bar)").unwrap(),
|
|
|
|
|
next_expr,
|
|
|
|
|
fun_call_expr(
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
2020-05-06 18:04:07 -04:00
|
|
|
vec![base_expr(BaseExprKind::Ident)]
|
2020-05-06 17:39:31 -04:00
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
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!(
|
2020-05-06 18:04:07 -04:00
|
|
|
Parser::try_from(
|
|
|
|
|
r"foo(
|
2020-05-06 17:39:31 -04:00
|
|
|
bar,
|
|
|
|
|
1,
|
|
|
|
|
:sym
|
2020-05-06 18:04:07 -04:00
|
|
|
)"
|
|
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-06 17:39:31 -04:00
|
|
|
next_expr,
|
|
|
|
|
fun_call_expr(
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
vec![
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
base_expr(BaseExprKind::Sym)
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
);
|
2020-05-06 17:55:25 -04:00
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from(r"foo()[0]").unwrap(),
|
|
|
|
|
next_expr,
|
|
|
|
|
index_expr(
|
2020-05-06 18:04:07 -04:00
|
|
|
fun_call_expr(base_expr(BaseExprKind::Ident), vec![]),
|
2020-05-06 17:55:25 -04:00
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from(r"foo[0](bar)").unwrap(),
|
|
|
|
|
next_expr,
|
|
|
|
|
fun_call_expr(
|
2020-05-06 18:04:07 -04:00
|
|
|
index_expr(base_expr(BaseExprKind::Ident), base_expr(BaseExprKind::Num),),
|
|
|
|
|
vec![base_expr(BaseExprKind::Ident)]
|
2020-05-06 17:55:25 -04:00
|
|
|
)
|
|
|
|
|
);
|
2020-05-06 17:39:31 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Stmt testing
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
fn assign_stmt(lhs: Expr, rhs: Expr) -> Stmt {
|
2020-05-06 17:14:55 -04:00
|
|
|
Stmt::Assign(AssignStmt {
|
|
|
|
|
lhs,
|
|
|
|
|
rhs,
|
|
|
|
|
span: Default::default(),
|
|
|
|
|
})
|
2020-05-06 16:57:28 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-08 16:19:01 -04:00
|
|
|
#[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![],))
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 16:57:28 -04:00
|
|
|
#[test]
|
|
|
|
|
fn test_assign_stmt() {
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from(
|
|
|
|
|
r"
|
|
|
|
|
a = 1
|
|
|
|
|
|
|
|
|
|
b = :sym
|
|
|
|
|
"
|
2020-05-06 17:14:55 -04:00
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-06 16:57:28 -04:00
|
|
|
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
|
|
|
|
|
"
|
2020-05-06 17:14:55 -04:00
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-06 16:57:28 -04:00
|
|
|
next_stmt,
|
2020-05-06 17:14:55 -04:00
|
|
|
Some(Stmt::Expr(base_expr(BaseExprKind::Ident),)),
|
2020-05-06 16:57:28 -04:00
|
|
|
next_stmt,
|
2020-05-06 17:14:55 -04:00
|
|
|
Some(Stmt::Expr(base_expr(BaseExprKind::Str),)),
|
2020-05-06 16:57:28 -04:00
|
|
|
next_stmt,
|
2020-05-06 17:14:55 -04:00
|
|
|
Some(Stmt::Expr(base_expr(BaseExprKind::Sym),)),
|
2020-05-06 16:57:28 -04:00
|
|
|
next_stmt,
|
2020-05-06 17:14:55 -04:00
|
|
|
Some(Stmt::Expr(base_expr(BaseExprKind::Num),))
|
2020-05-06 16:57:28 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
test_parser!(
|
|
|
|
|
Parser::try_from(
|
|
|
|
|
r"
|
|
|
|
|
(a
|
|
|
|
|
+
|
|
|
|
|
1
|
|
|
|
|
*
|
|
|
|
|
3)"
|
2020-05-06 17:14:55 -04:00
|
|
|
)
|
|
|
|
|
.unwrap(),
|
2020-05-06 16:57:28 -04:00
|
|
|
next_stmt,
|
2020-05-06 17:14:55 -04:00
|
|
|
Some(Stmt::Expr(bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Ident),
|
|
|
|
|
BinOp::Plus,
|
|
|
|
|
bin_expr(
|
|
|
|
|
base_expr(BaseExprKind::Num),
|
|
|
|
|
BinOp::Times,
|
|
|
|
|
base_expr(BaseExprKind::Num)
|
|
|
|
|
)
|
|
|
|
|
)))
|
2020-05-06 16:57:28 -04:00
|
|
|
);
|
|
|
|
|
}
|
2020-04-27 20:17:16 -04:00
|
|
|
}
|