aiken_lang/parser/expr/
anonymous_function.rs1use crate::{
2 ast,
3 expr::{FnStyle, UntypedExpr},
4 parser::{annotation, error::ParseError, pattern, token::Token},
5};
6use chumsky::prelude::*;
7
8pub fn parser(
9 sequence: Recursive<'_, Token, UntypedExpr, ParseError>,
10) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
11 just(Token::Fn)
12 .ignore_then(
13 params()
14 .separated_by(just(Token::Comma))
15 .allow_trailing()
16 .delimited_by(just(Token::LeftParen), just(Token::RightParen)),
17 )
18 .then(just(Token::RArrow).ignore_then(annotation()).or_not())
19 .then(sequence.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)))
20 .map_with_span(
21 |((arguments, return_annotation), body), span| UntypedExpr::Fn {
22 arguments,
23 body: Box::new(body),
24 location: span,
25 fn_style: FnStyle::Plain,
26 return_annotation,
27 },
28 )
29}
30
31pub fn params() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
32 choice((
34 select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
35 ast::ArgBy::ByName(ast::ArgName::Discarded {
36 label: name.clone(),
37 name,
38 location: span,
39 })
40 }),
41 select! {Token::Name {name} => name}.map_with_span(|name, span| {
42 ast::ArgBy::ByName(ast::ArgName::Named {
43 label: name.clone(),
44 name,
45 location: span,
46 })
47 }),
48 pattern().map(ast::ArgBy::ByPattern),
49 ))
50 .then(just(Token::Colon).ignore_then(annotation()).or_not())
51 .map_with_span(|(by, annotation), span| ast::UntypedArg {
52 is_validator_param: false,
53 location: span,
54 annotation,
55 doc: None,
56 by,
57 })
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::assert_expr;
63
64 #[test]
65 fn anonymous_function_basic() {
66 assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#);
67 }
68
69 #[test]
70 fn anonymous_function_by_pattern_no_annotation() {
71 assert_expr!(r#"fn (Foo { my_field }) { my_field * 2 }"#);
72 }
73
74 #[test]
75 fn anonymous_function_by_pattern_with_annotation() {
76 assert_expr!(r#"fn (Foo { my_field } : Foo) { my_field * 2 }"#);
77 }
78
79 #[test]
80 fn anonymous_function_by_pattern_with_alias() {
81 assert_expr!(r#"fn (Foo { my_field, .. } as x) { my_field * my_other_field }"#);
82 }
83}