aiken_lang/parser/expr/
assignment.rs1use crate::{
2 ast::{self, Span},
3 expr::UntypedExpr,
4 parser::{annotation, error::ParseError, pattern, token::Token},
5};
6use chumsky::prelude::*;
7
8pub fn let_(
9 r: Recursive<'_, Token, UntypedExpr, ParseError>,
10) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
11 just(Token::Let)
12 .ignore_then(assignment_patterns())
13 .then(choice((just(Token::Equal), just(Token::LArrow))))
14 .then(r.clone())
15 .validate(move |((patterns, kind), value), span, emit| {
16 if matches!(value, UntypedExpr::Assignment { .. }) {
17 emit(ParseError::invalid_assignment_right_hand_side(span))
18 }
19
20 let patterns = patterns
21 .try_into()
22 .expect("We use at_least(1) so this should never be empty");
23
24 UntypedExpr::Assignment {
25 location: span,
26 value: Box::new(value),
27 patterns,
28 kind: ast::AssignmentKind::Let {
29 backpassing: kind == Token::LArrow,
30 },
31 }
32 })
33}
34
35fn assignment_patterns() -> impl Parser<Token, Vec<ast::AssignmentPattern>, Error = ParseError> {
36 assignment_pattern()
37 .separated_by(just(Token::Comma))
38 .allow_trailing()
39 .at_least(1)
40}
41
42pub fn assignment_pattern() -> impl Parser<Token, ast::AssignmentPattern, Error = ParseError> {
43 pattern()
44 .then(just(Token::Colon).ignore_then(annotation()).or_not())
45 .map_with_span(|(pattern, annotation), span| ast::AssignmentPattern {
46 pattern,
47 annotation,
48 location: span,
49 })
50}
51
52pub fn expect(
53 r: Recursive<'_, Token, UntypedExpr, ParseError>,
54) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
55 just(Token::Expect)
56 .ignore_then(
57 assignment_patterns()
58 .then(choice((just(Token::Equal), just(Token::LArrow))))
59 .or_not(),
60 )
61 .then(r.clone())
62 .validate(move |(opt_pattern, value), span, emit| {
63 if matches!(value, UntypedExpr::Assignment { .. }) {
64 emit(ParseError::invalid_assignment_right_hand_side(span))
65 }
66
67 let (patterns, kind) = opt_pattern.unwrap_or_else(|| {
68 let filler_true = ast::AssignmentPattern::new(
69 ast::UntypedPattern::true_(span),
70 None,
71 Span::empty(),
72 );
73
74 (vec![filler_true], Token::Equal)
75 });
76
77 let patterns = patterns
78 .try_into()
79 .expect("We use at_least(1) so this should never be empty");
80
81 UntypedExpr::Assignment {
82 location: span,
83 patterns,
84 value: Box::new(value),
85 kind: ast::AssignmentKind::Expect {
86 backpassing: kind == Token::LArrow,
87 },
88 }
89 })
90}
91
92#[cfg(test)]
93mod tests {
94 use crate::assert_expr;
95
96 #[test]
97 fn let_bindings() {
98 assert_expr!("let thing = [ 1, 2, a ]");
99 }
100
101 #[test]
102 fn expect() {
103 assert_expr!("expect Some(x) = something.field");
104 }
105
106 #[test]
107 fn expect_bool_sugar() {
108 assert_expr!("expect something.field == wow");
109 }
110
111 #[test]
112 fn expect_trace_if_false() {
113 assert_expr!("expect foo?");
114 }
115
116 #[test]
117 fn expect_unfinished_let() {
118 assert_expr!(
119 "
120 let a =
121 // foo
122 let b = 42
123 "
124 );
125 }
126
127 #[test]
128 fn expect_let_in_let() {
129 assert_expr!("let a = { let b = 42 }");
130 }
131
132 #[test]
133 fn expect_let_in_let_return() {
134 assert_expr!(
135 "
136 let a = {
137 let b = 42
138 b
139 }
140 "
141 );
142 }
143
144 #[test]
145 fn expect_let_in_let_parens() {
146 assert_expr!("let a = ( let b = 42 )");
147 }
148
149 #[test]
150 fn expect_expect_let() {
151 assert_expr!("expect { let a = 42 } = foo");
152 }
153}