Add function expression parsing
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -253,26 +253,34 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
TokenKind::LParen => {
|
||||
let prev_skip = self.set_skip_newlines(true)?;
|
||||
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")?;
|
||||
|
||||
if let Some(end_token) = self.match_token_kind(TokenKind::RParen)? {
|
||||
// empty tuple
|
||||
let span = token.span().union(end_token.span());
|
||||
list.insert(0, first);
|
||||
Expr::Base(
|
||||
BaseExpr {
|
||||
kind: BaseExprKind::Tuple(list),
|
||||
span,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
Expr::Base(BaseExpr {
|
||||
kind: BaseExprKind::Tuple(Default::default()),
|
||||
span,
|
||||
})
|
||||
} else {
|
||||
self.set_skip_newlines(prev_skip)?;
|
||||
self.expect_token_kind(TokenKind::RParen, "end of expression")?;
|
||||
first
|
||||
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!(),
|
||||
@@ -306,6 +314,51 @@ impl<'t> Parser<'t> {
|
||||
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<String>;
|
||||
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());
|
||||
// TODO : get params from tuple expr - it's a little funky to do it at this stage but I
|
||||
// think it will be fine
|
||||
Ok(Expr::Fun(FunExpr {
|
||||
params,
|
||||
expr: rhs,
|
||||
span,
|
||||
}.into()))
|
||||
} else {
|
||||
Ok(expr)
|
||||
}
|
||||
@@ -624,6 +677,17 @@ mod test {
|
||||
)
|
||||
}
|
||||
|
||||
fn fun_expr(params: Vec<String>, expr: Expr) -> Expr {
|
||||
Expr::Fun(
|
||||
FunExpr {
|
||||
params,
|
||||
expr,
|
||||
span: Default::default(),
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base_expr() {
|
||||
test_parser!(
|
||||
@@ -732,6 +796,66 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[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!(
|
||||
|
||||
Reference in New Issue
Block a user