Add function call expressions

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-05-06 17:39:31 -04:00
parent bd87e9dd30
commit 5c505e5ae5
2 changed files with 105 additions and 2 deletions

View File

@@ -22,9 +22,10 @@ impl Spanned for AssignStmt {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr { pub enum Expr {
Base(BaseExpr),
Bin(Box<BinExpr>), Bin(Box<BinExpr>),
Un(Box<UnExpr>), Un(Box<UnExpr>),
FunCall(Box<FunCallExpr>),
Base(BaseExpr),
} }
impl Spanned for Expr { impl Spanned for Expr {
@@ -33,6 +34,7 @@ impl Spanned for Expr {
Expr::Base(b) => b.span(), Expr::Base(b) => b.span(),
Expr::Bin(b) => b.span(), Expr::Bin(b) => b.span(),
Expr::Un(u) => u.span(), Expr::Un(u) => u.span(),
Expr::FunCall(f) => f.span(),
} }
} }
} }
@@ -86,6 +88,21 @@ impl Spanned for UnExpr {
} }
} }
#[derive(Derivative, Clone, PartialEq, Eq)]
#[derivative(Debug)]
pub struct FunCallExpr {
pub expr: Expr,
pub args: Vec<Expr>,
#[derivative(Debug = "ignore")]
pub span: Span,
}
impl Spanned for FunCallExpr {
fn span(&self) -> Span {
self.span
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum BaseExprKind { pub enum BaseExprKind {
Ident, Ident,

View File

@@ -276,8 +276,33 @@ impl<'t> Parser<'t> {
_ => unreachable!(), _ => 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<Expr> {
if self.match_token_kind(TokenKind::LParen)?.is_some() {
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 (left 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() {
todo!()
} else {
Ok(expr) Ok(expr)
} }
}
/// Gets a list of expressions separated by commas, stopping when EOF or specified end token is /// Gets a list of expressions separated by commas, stopping when EOF or specified end token is
/// reached. /// reached.
@@ -570,6 +595,14 @@ mod test {
}) })
} }
fn fun_call_expr(expr: Expr, args: Vec<Expr>) -> Expr {
Expr::FunCall(FunCallExpr {
expr,
args,
span: Default::default(),
}.into())
}
#[test] #[test]
fn test_base_expr() { fn test_base_expr() {
test_parser!( test_parser!(
@@ -894,6 +927,59 @@ mod test {
); );
} }
#[test]
fn test_fun_call_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)
]
)
);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Stmt testing // Stmt testing
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////