Add function expression parsing
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -26,17 +26,19 @@ pub enum Expr {
|
|||||||
Un(Box<UnExpr>),
|
Un(Box<UnExpr>),
|
||||||
FunCall(Box<FunCallExpr>),
|
FunCall(Box<FunCallExpr>),
|
||||||
Index(Box<IndexExpr>),
|
Index(Box<IndexExpr>),
|
||||||
|
Fun(Box<FunExpr>),
|
||||||
Base(BaseExpr),
|
Base(BaseExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spanned for Expr {
|
impl Spanned for Expr {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
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(),
|
Expr::FunCall(f) => f.span(),
|
||||||
Expr::Index(i) => i.span(),
|
Expr::Index(i) => i.span(),
|
||||||
|
Expr::Fun(f) => f.span(),
|
||||||
|
Expr::Base(b) => b.span(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,6 +122,21 @@ impl Spanned for IndexExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Clone, PartialEq, Eq)]
|
||||||
|
#[derivative(Debug)]
|
||||||
|
pub struct FunExpr {
|
||||||
|
pub params: Vec<String>,
|
||||||
|
pub expr: Expr,
|
||||||
|
#[derivative(Debug = "ignore")]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Spanned for FunExpr {
|
||||||
|
fn span(&self) -> Span {
|
||||||
|
self.span
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum BaseExprKind {
|
pub enum BaseExprKind {
|
||||||
Ident,
|
Ident,
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ impl<'t> Lexer<'t> {
|
|||||||
self.chars().next().is_none()
|
self.chars().next().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn text(&self) -> &'t str {
|
||||||
|
&self.text
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Character advancement
|
// Character advancement
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -253,13 +253,20 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
TokenKind::LParen => {
|
TokenKind::LParen => {
|
||||||
let prev_skip = self.set_skip_newlines(true)?;
|
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()?;
|
let first = self.next_expr()?;
|
||||||
if let Some(_) = self.match_token_kind(TokenKind::Comma)? {
|
if let Some(_) = self.match_token_kind(TokenKind::Comma)? {
|
||||||
let mut list = self.next_expr_list(TokenKind::RParen)?;
|
let mut list = self.next_expr_list(TokenKind::RParen)?;
|
||||||
|
|
||||||
self.set_skip_newlines(prev_skip)?;
|
self.set_skip_newlines(prev_skip)?;
|
||||||
let end_token = self.expect_token_kind(TokenKind::RParen, "end of tuple")?;
|
let end_token = self.expect_token_kind(TokenKind::RParen, "end of tuple")?;
|
||||||
|
|
||||||
let span = token.span().union(end_token.span());
|
let span = token.span().union(end_token.span());
|
||||||
list.insert(0, first);
|
list.insert(0, first);
|
||||||
Expr::Base(
|
Expr::Base(
|
||||||
@@ -275,6 +282,7 @@ impl<'t> Parser<'t> {
|
|||||||
first
|
first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -306,6 +314,51 @@ impl<'t> Parser<'t> {
|
|||||||
let span = expr.span().union(end_token.span());
|
let span = expr.span().union(end_token.span());
|
||||||
let index_expr = Expr::Index(IndexExpr { expr, index, span }.into());
|
let index_expr = Expr::Index(IndexExpr { expr, index, span }.into());
|
||||||
self.next_suffix_expr(index_expr)
|
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 {
|
} else {
|
||||||
Ok(expr)
|
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]
|
#[test]
|
||||||
fn test_base_expr() {
|
fn test_base_expr() {
|
||||||
test_parser!(
|
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]
|
#[test]
|
||||||
fn test_bin_expr() {
|
fn test_bin_expr() {
|
||||||
test_parser!(
|
test_parser!(
|
||||||
|
|||||||
Reference in New Issue
Block a user