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