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 literal expression.
7///
8/// ```trilogy
9/// [..prefix, 1, 2, 3, ..suffix]
10/// ```
11#[derive(Clone, Debug, PrettyPrintSExpr)]
12pub struct ArrayLiteral {
13 pub open_bracket: Token,
14 pub elements: Punctuated<ArrayElement>,
15 pub close_bracket: Token,
16}
17
18impl ArrayLiteral {
19 pub(crate) fn new_empty(open_bracket: Token, close_bracket: Token) -> Self {
20 Self {
21 open_bracket,
22 elements: Punctuated::default(),
23 close_bracket,
24 }
25 }
26
27 pub(crate) fn parse_rest(
28 parser: &mut Parser,
29 open_bracket: Token,
30 first: ArrayElement,
31 ) -> SyntaxResult<Result<Self, ArrayPattern>> {
32 let mut elements = Punctuated::init(first);
33 if let Ok(close_bracket) = parser.expect(CBrack) {
34 return Ok(Ok(Self {
35 open_bracket,
36 elements,
37 close_bracket,
38 }));
39 }
40
41 let close_bracket = loop {
42 let comma = parser.expect(OpComma).map_err(|token| {
43 parser.expected(
44 token,
45 "expected `]` to end or `,` to continue array literal",
46 )
47 })?;
48 if let Ok(end) = parser.expect(CBrack) {
49 elements.finish(comma);
50 break end;
51 };
52 match ArrayElement::parse(parser)? {
53 Ok(element) => elements.follow(comma, element),
54 Err(next) => {
55 return Ok(Err(ArrayPattern::parse_from_expression(
56 parser,
57 open_bracket,
58 elements,
59 next,
60 )?));
61 }
62 }
63 if let Ok(token) = parser.check(KwFor) {
64 let error = SyntaxError::new(
65 token.span,
66 "only one element may precede the `for` keyword in a comprehension",
67 );
68 parser.error(error.clone());
69 return Err(error);
70 }
71 if let Ok(close_bracket) = parser.expect(CBrack) {
72 break close_bracket;
73 };
74 };
75 Ok(Ok(Self {
76 open_bracket,
77 elements,
78 close_bracket,
79 }))
80 }
81}
82
83impl Spanned for ArrayLiteral {
84 fn span(&self) -> Span {
85 self.open_bracket.span.union(self.close_bracket.span)
86 }
87}
88
89#[derive(Clone, Debug, Spanned, PrettyPrintSExpr)]
90pub enum ArrayElement {
91 Element(Expression),
92 Spread(Token, Expression),
93}
94
95impl ArrayElement {
96 pub(crate) fn parse(
97 parser: &mut Parser,
98 ) -> SyntaxResult<Result<Self, (Option<Token>, Pattern)>> {
99 let spread = parser.expect(OpDotDot).ok();
100 if let Some(spread) = &spread
101 && let Ok(dot) = parser.expect(OpDot)
102 {
103 parser.error(ErrorKind::TripleDot { dot: dot.span }.at(spread.span));
104 }
105 let expression = Expression::parse_parameter_list(parser)?;
106 match expression {
107 Ok(expression) => match spread {
108 None => Ok(Ok(Self::Element(expression))),
109 Some(spread) => Ok(Ok(Self::Spread(spread, expression))),
110 },
111 Err(pattern) => Ok(Err((spread, pattern))),
112 }
113 }
114}
115
116#[cfg(test)]
117mod test {
118 use super::*;
119
120 test_parse!(arraylit_empty: "[]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [] _))");
121 test_parse!(arraylit_one: "[1]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [_] _))");
122 test_parse!(arraylit_one_tc: "[1, ]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [_] _))");
123 test_parse!(arraylit_many: "[1, 2, 3]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [_ _ _] _))");
124 test_parse!(arraylit_many_tc: "[1, 2, 3, ]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [_ _ _] _))");
125 test_parse!(arraylit_nested: "[[1, 2], [3, 4], [5, 6]]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [_ _ _] _))");
126 test_parse!(arraylit_no_comma: "[f 2]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [(_ (Expression::Application _))] _))");
127 test_parse!(arraylit_spread: "[..a, b]" => Expression::parse => "(Expression::Array (ArrayLiteral _ [(ArrayElement::Spread _ _) (ArrayElement::Element _)] _))");
128
129 test_parse_error!(arraylit_empty_tc: "[,]" => Expression::parse);
130 test_parse_error!(arraylit_missing_item: "[1,,]" => Expression::parse);
131 test_parse_error!(arraylit_missing_end: "[1,2," => Expression::parse);
132 test_parse_error!(arraylit_incomplete: "[1, 2" => Expression::parse => "expected `]` to end or `,` to continue array literal");
133 test_parse_error!(arraylit_mismatched: "[1, 2)" => Expression::parse => "expected `]` to end or `,` to continue array literal");
134}