Actually just three programming languages in a trenchcoat
1use super::*;
2use crate::{Parser, Spanned};
3use source_span::Span;
4use trilogy_scanner::{Token, TokenType::*};
5
6/// An array comprehension expression.
7///
8/// ```trilogy
9/// [x for query(x)]
10/// ```
11#[derive(Clone, Debug)]
12pub struct ArrayComprehension {
13 pub open_bracket: Token,
14 pub expression: Expression,
15 pub r#for: Token,
16 pub query: Query,
17 pub close_bracket: Token,
18 pub span: Span,
19}
20
21impl Spanned for ArrayComprehension {
22 fn span(&self) -> Span {
23 self.span
24 }
25}
26
27impl ArrayComprehension {
28 pub(crate) fn parse_rest(
29 parser: &mut Parser,
30 open_bracket: Token,
31 expression: Expression,
32 ) -> SyntaxResult<Self> {
33 let r#for = parser
34 .expect(KwFor)
35 .map_err(|token| parser.expected(token, "expected `for` in array comprehension"))?;
36 let query = Query::parse(parser)?;
37 let close_bracket = parser
38 .expect(CBrack)
39 .map_err(|token| parser.expected(token, "expected `]` to end array comprehension"))?;
40 let span = open_bracket.span.union(close_bracket.span);
41 Ok(Self {
42 open_bracket,
43 expression,
44 r#for,
45 query,
46 close_bracket,
47 span,
48 })
49 }
50}
51
52#[cfg(test)]
53mod test {
54 use super::*;
55
56 test_parse!(arraycomp_simple: "[x for x in array]" => Expression::parse => Expression::ArrayComprehension(ArrayComprehension { .. }));
57 test_parse!(arraycomp_complex: "[x:y for lookup(x) and another(y)]" => Expression::parse => Expression::ArrayComprehension(ArrayComprehension { .. }));
58 test_parse!(array_comp_seq: "[{x; y} for lookup(x, y)]" => Expression::parse => Expression::ArrayComprehension(ArrayComprehension { .. }));
59
60 test_parse_error!(arraycomp_no_commas: "[x, y for lookup(x, y)]" => Expression::parse => "only one element may precede the `for` keyword in a comprehension");
61 test_parse_error!(arraycomp_no_end: "[x for x in array" => Expression::parse => "expected `]` to end array comprehension");
62 test_parse_error!(arraycomp_no_expression: "[for y]" => Expression::parse);
63
64 test_parse_error!(arraycomp_invalid_query: "[x for y]" => Expression::parse);
65 test_parse_error!(arraycomp_invalid_expr: "[() for x in y]" => Expression::parse);
66}