Actually just three programming languages in a trenchcoat
at main 230 lines 8.8 kB view raw
1use super::*; 2use crate::{Parser, Spanned}; 3use source_span::Span; 4use trilogy_scanner::{Token, TokenType::*}; 5 6/// An array pattern. 7/// 8/// ```trilogy 9/// [1, 2, 3, ..rest, 5, 6, 7] 10/// ``` 11#[derive(Clone, Debug)] 12pub struct ArrayPattern { 13 pub open_bracket: Token, 14 /// The head elements, which come before the optional `rest` element. Will be all elements if `rest` is `None`. 15 pub head: Vec<Pattern>, 16 /// A single optional spread elements, containing the rest of the elements. 17 pub rest: Option<RestPattern>, 18 /// The tail elements, which follow the spread. Will be empty if `rest` is `None`. 19 pub tail: Vec<Pattern>, 20 pub close_bracket: Token, 21} 22 23impl ArrayPattern { 24 pub(crate) fn parse_elements( 25 parser: &mut Parser, 26 open_bracket: Token, 27 mut head: Vec<Pattern>, 28 ) -> SyntaxResult<Self> { 29 let rest = loop { 30 if parser.check(CBrack).is_ok() { 31 break None; 32 }; 33 if let Ok(spread) = parser.expect(OpDotDot) { 34 if let Ok(dot) = parser.expect(OpDot) { 35 parser.error(ErrorKind::TripleDot { dot: dot.span }.at(spread.span)); 36 } 37 break Some(RestPattern::parse(parser, spread)?); 38 } 39 head.push(Pattern::parse(parser)?); 40 if parser.check(CBrack).is_ok() { 41 break None; 42 }; 43 parser.expect(OpComma).map_err(|token| { 44 parser.expected( 45 token, 46 "expected `]` to end or `,` to continue array pattern", 47 ) 48 })?; 49 }; 50 51 if let Some(rest) = rest { 52 return Self::parse_rest(parser, open_bracket, head, rest, vec![]); 53 } 54 55 let close_bracket = parser 56 .expect(CBrack) 57 .map_err(|token| parser.expected(token, "expected `]` to end array pattern"))?; 58 59 Ok(Self { 60 open_bracket, 61 head, 62 rest: None, 63 tail: vec![], 64 close_bracket, 65 }) 66 } 67 68 pub(crate) fn parse_rest( 69 parser: &mut Parser, 70 start: Token, 71 head: Vec<Pattern>, 72 rest: RestPattern, 73 mut tail: Vec<Pattern>, 74 ) -> SyntaxResult<Self> { 75 // at this point, either we: 76 // * saw the `]`, so there will be no rest; or 77 // * parsed a rest pattern, so there must be a comma next before allowing 78 // more elements, or there is no comma so we must be at end of array. 79 if parser.expect(OpComma).is_ok() { 80 loop { 81 if parser.check(CBrack).is_ok() { 82 break; 83 }; 84 if let Ok(token) = parser.expect(OpDotDot) { 85 // Avoid an error cascade here by parsing the rest pattern as a regular 86 // pattern, discarding the "restness". 87 parser.error(SyntaxError::new( 88 token.span, 89 "array patterns may contain at most one rest (`..`) segment", 90 )); 91 } 92 tail.push(Pattern::parse(parser)?); 93 if parser.check(CBrack).is_ok() { 94 break; 95 }; 96 parser.expect(OpComma).map_err(|token| { 97 parser.expected( 98 token, 99 "expected `]` to end or `,` to continue array pattern", 100 ) 101 })?; 102 } 103 } 104 105 let end = parser 106 .expect(CBrack) 107 .map_err(|token| parser.expected(token, "expected `]` to end array pattern"))?; 108 109 Ok(Self { 110 open_bracket: start, 111 head, 112 rest: Some(rest), 113 tail, 114 close_bracket: end, 115 }) 116 } 117 118 pub(crate) fn parse(parser: &mut Parser) -> SyntaxResult<Self> { 119 let start = parser 120 .expect(OBrack) 121 .expect("Caller should have found this"); 122 Self::parse_elements(parser, start, vec![]) 123 } 124 125 pub(crate) fn parse_from_expression( 126 parser: &mut Parser, 127 start: Token, 128 elements: Punctuated<ArrayElement>, 129 (spread, next): (Option<Token>, Pattern), 130 ) -> SyntaxResult<Self> { 131 let (head, rest, tail) = elements.into_iter().try_fold( 132 (vec![], None, vec![]), 133 |(mut head, mut spread, mut tail), element| { 134 match element { 135 ArrayElement::Element(expr) if spread.is_none() => { 136 head.push(expr.try_into()?); 137 } 138 ArrayElement::Element(expr) => tail.push(expr.try_into()?), 139 ArrayElement::Spread(sp, expr) if spread.is_none() => { 140 spread = Some(RestPattern::try_from((sp, expr))?); 141 } 142 ArrayElement::Spread(token, element) => return Err(SyntaxError::new( 143 token.span.union(element.span()), 144 "an array pattern may contain only one rest element, or you might have meant this to be an array expression", 145 )), 146 } 147 Ok((head, spread, tail)) 148 }, 149 ).inspect_err(|error| { 150 parser.error(error.clone()); 151 })?; 152 match (spread, rest) { 153 (None, None) => Self::parse_elements(parser, start, head), 154 (None, Some(rest)) => Self::parse_rest(parser, start, head, rest, tail), 155 (Some(token), None) => { 156 Self::parse_rest(parser, start, head, RestPattern::new(token, next), tail) 157 } 158 (Some(token), Some(..)) => { 159 let error = SyntaxError::new( 160 token.span.union(next.span()), 161 "an array pattern may only contain a single spread element, or you might have meant this to be an array expression", 162 ); 163 parser.error(error.clone()); 164 Err(error) 165 } 166 } 167 } 168} 169 170impl TryFrom<ArrayLiteral> for ArrayPattern { 171 type Error = SyntaxError; 172 173 fn try_from(value: ArrayLiteral) -> Result<Self, Self::Error> { 174 let mut head = vec![]; 175 let mut tail = vec![]; 176 let mut rest = None; 177 178 for element in value.elements { 179 match element { 180 ArrayElement::Element(val) if rest.is_none() => head.push(val.try_into()?), 181 ArrayElement::Element(val) => tail.push(val.try_into()?), 182 ArrayElement::Spread(spread, val) if rest.is_none() => { 183 rest = Some(RestPattern::try_from((spread, val))?) 184 } 185 ArrayElement::Spread(.., val) => { 186 return Err(SyntaxError::new( 187 val.span(), 188 "an array pattern may contain only a single spread element", 189 )); 190 } 191 } 192 } 193 194 Ok(Self { 195 open_bracket: value.open_bracket, 196 head, 197 rest, 198 tail, 199 close_bracket: value.close_bracket, 200 }) 201 } 202} 203 204impl Spanned for ArrayPattern { 205 fn span(&self) -> Span { 206 self.open_bracket.span.union(self.close_bracket.span) 207 } 208} 209 210#[cfg(test)] 211mod test { 212 use super::*; 213 214 test_parse!(arraypat_empty: "[]" => Pattern::parse => Pattern::Array(..)); 215 test_parse!(arraypat_one: "[1]" => Pattern::parse => Pattern::Array(..)); 216 test_parse!(arraypat_one_tc: "[1, ]" => Pattern::parse => Pattern::Array(..)); 217 test_parse!(arraypat_many: "[1, 2, 3]" => Pattern::parse => Pattern::Array(..)); 218 test_parse!(arraypat_many_tc: "[1, 2, 3, ]" => Pattern::parse => Pattern::Array(..)); 219 test_parse!(arraypat_spread_middle: "[1, 2, ..a, 4, 5]" => Pattern::parse => Pattern::Array(..)); 220 test_parse!(arraypat_spread_end: "[1, 2, ..a]" => Pattern::parse => Pattern::Array(..)); 221 test_parse!(arraypat_spread_start: "[..a, 1, 2]" => Pattern::parse => Pattern::Array(..)); 222 223 test_parse_error!(arraypat_spread_multi: "[..a, 1, ..b]" => Pattern::parse => "array patterns may contain at most one rest (`..`) segment"); 224 test_parse_error!(arraypat_expression: "[f 2]" => Pattern::parse); 225 test_parse_error!(arraypat_empty_tc: "[,]" => Pattern::parse); 226 test_parse_error!(arraypat_missing_item: "[1,,]" => Pattern::parse); 227 test_parse_error!(arraypat_missing_end: "[1,2," => Pattern::parse); 228 test_parse_error!(arraypat_incomplete: "[1, 2" => Pattern::parse => "expected `]` to end or `,` to continue array pattern"); 229 test_parse_error!(arraypat_mismatched: "[1, 2)" => Pattern::parse => "expected `]` to end or `,` to continue array pattern"); 230}