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#[derive(Clone, Debug, PrettyPrintSExpr)]
7pub struct SetPattern {
8 pub open_bracket_pipe: Token,
9 pub elements: Vec<Pattern>,
10 pub rest: Option<RestPattern>,
11 pub close_bracket_pipe: Token,
12}
13
14impl SetPattern {
15 pub(crate) fn parse(parser: &mut Parser) -> SyntaxResult<Self> {
16 let open_bracket_pipe = parser.expect(OBrackPipe).unwrap();
17 Self::parse_elements(parser, open_bracket_pipe, vec![])
18 }
19
20 pub(crate) fn parse_elements(
21 parser: &mut Parser,
22 open_bracket_pipe: Token,
23 mut elements: Vec<Pattern>,
24 ) -> SyntaxResult<Self> {
25 let rest = loop {
26 if parser.check(CBrackPipe).is_ok() {
27 break None;
28 };
29 if let Ok(spread) = parser.expect(OpDotDot) {
30 if let Ok(dot) = parser.expect(OpDot) {
31 parser.error(ErrorKind::TripleDot { dot: dot.span }.at(spread.span));
32 }
33 break Some(RestPattern::parse(parser, spread)?);
34 }
35 elements.push(Pattern::parse(parser)?);
36 if parser.check(CBrackPipe).is_ok() {
37 break None;
38 };
39 parser.expect(OpComma).map_err(|token| {
40 parser.expected(token, "expected `,` between set pattern elements")
41 })?;
42 };
43
44 if let Some(rest) = rest {
45 return Self::parse_rest(parser, open_bracket_pipe, elements, rest);
46 }
47 let close_bracket_pipe = parser
48 .expect(CBrackPipe)
49 .map_err(|token| parser.expected(token, "expected `|]` to end set pattern"))?;
50
51 Ok(Self {
52 open_bracket_pipe,
53 elements,
54 rest,
55 close_bracket_pipe,
56 })
57 }
58
59 pub(crate) fn parse_rest(
60 parser: &mut Parser,
61 open_bracket_pipe: Token,
62 elements: Vec<Pattern>,
63 rest: RestPattern,
64 ) -> SyntaxResult<Self> {
65 // We'll consume this trailing comma anyway as if it was going to work,
66 // and report an appropriate error. One of few attempts at smart error
67 // handling in this parser so far!
68 if let Ok(comma) = parser.expect(OpComma) {
69 let Ok(close_bracket_pipe) = parser.expect(CBrackPipe) else {
70 let error =
71 SyntaxError::new(comma.span, "a rest (`..`) element must end a set pattern");
72 parser.error(error.clone());
73 return Err(error);
74 };
75 parser.error(SyntaxError::new(
76 comma.span,
77 "no trailing comma is permitted after the rest (`..`) element in a set pattern",
78 ));
79 return Ok(Self {
80 open_bracket_pipe,
81 elements,
82 rest: Some(rest),
83 close_bracket_pipe,
84 });
85 }
86 let close_bracket_pipe = parser
87 .expect(CBrackPipe)
88 .map_err(|token| parser.expected(token, "expected `|]` to close set pattern"))?;
89 Ok(Self {
90 open_bracket_pipe,
91 elements,
92 rest: Some(rest),
93 close_bracket_pipe,
94 })
95 }
96
97 pub(crate) fn parse_from_expression(
98 parser: &mut Parser,
99 open_bracket_pipe: Token,
100 elements: Vec<SetElement>,
101 (spread, next): (Option<Token>, Pattern),
102 ) -> SyntaxResult<Self> {
103 let (mut elements, rest) = elements
104 .into_iter()
105 .try_fold(
106 (vec![], None::<Pattern>),
107 |(mut elements, mut spread), element| {
108 match element {
109 SetElement::Element(element) if spread.is_none() => {
110 elements.push(element.try_into()?)
111 }
112 SetElement::Element(element) => {
113 return Err(SyntaxError::new(
114 element.span(),
115 "no elements may follow the rest element of a set pattern, you might have meant this to be an expression",
116 ));
117 }
118 SetElement::Spread(_, element) if spread.is_none() => {
119 spread = Some(element.try_into()?);
120 }
121 SetElement::Spread(token, element) => {
122 return Err(SyntaxError::new(
123 token.span.union(element.span()),
124 "a set pattern may contain only one rest element, you might have meant this to be an expression",
125 ));
126 }
127 }
128 Ok((elements, spread))
129 })
130 .inspect_err(|error| {
131 parser.error(error.clone());
132 })?;
133 match rest {
134 None if spread.is_none() => {
135 elements.push(next);
136 Self::parse_elements(parser, open_bracket_pipe, elements)
137 }
138 None => Self::parse_rest(
139 parser,
140 open_bracket_pipe,
141 elements,
142 RestPattern::new(spread.unwrap(), next),
143 ),
144 Some(..) if spread.is_none() => Err(SyntaxError::new(
145 next.span().union(spread.unwrap().span()),
146 "no elements may follow the rest element of a set pattern, you might have meant this to be an expression",
147 )),
148 Some(rest) => Err(SyntaxError::new(
149 rest.span().union(spread.unwrap().span()),
150 "a set pattern may contain only one rest element, you might have meant this to be an expression",
151 )),
152 }
153 }
154}
155
156impl Spanned for SetPattern {
157 fn span(&self) -> Span {
158 self.open_bracket_pipe
159 .span
160 .union(self.close_bracket_pipe.span)
161 }
162}
163
164impl TryFrom<SetLiteral> for SetPattern {
165 type Error = SyntaxError;
166
167 fn try_from(value: SetLiteral) -> Result<Self, Self::Error> {
168 let mut head = vec![];
169 let mut rest = None;
170
171 for element in value.elements {
172 match element {
173 SetElement::Element(val) if rest.is_none() => head.push(val.try_into()?),
174 SetElement::Spread(token, val) if rest.is_none() => {
175 rest = Some(RestPattern::try_from((token, val))?)
176 }
177 SetElement::Element(val) | SetElement::Spread(_, val) => {
178 return Err(SyntaxError::new(
179 val.span(),
180 "no elements may follow the rest (`..`) element in a set pattern",
181 ));
182 }
183 }
184 }
185
186 Ok(Self {
187 open_bracket_pipe: value.open_bracket_pipe,
188 elements: head,
189 rest,
190 close_bracket_pipe: value.close_bracket_pipe,
191 })
192 }
193}