Actually just three programming languages in a trenchcoat
at main 220 lines 8.0 kB view raw
1use super::{record_literal::RecordPatternElement, *}; 2use crate::{Parser, Spanned}; 3use source_span::Span; 4use trilogy_scanner::{Token, TokenType::*}; 5 6#[derive(Clone, Debug)] 7pub struct RecordPattern { 8 pub open_brace_pipe: Token, 9 pub elements: Vec<(Pattern, Pattern)>, 10 pub rest: Option<RestPattern>, 11 pub close_brace_pipe: Token, 12 pub span: Span, 13} 14 15impl RecordPattern { 16 pub(crate) fn parse(parser: &mut Parser) -> SyntaxResult<Self> { 17 let open_brace_pipe = parser.expect(OBracePipe).unwrap(); 18 Self::parse_elements(parser, open_brace_pipe, vec![]) 19 } 20 21 pub(crate) fn parse_elements( 22 parser: &mut Parser, 23 open_brace_pipe: Token, 24 mut elements: Vec<(Pattern, Pattern)>, 25 ) -> SyntaxResult<Self> { 26 let rest = loop { 27 if parser.check(CBracePipe).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 let key = Pattern::parse(parser)?; 37 parser.expect(OpFatArrow).map_err(|token| { 38 parser.expected( 39 token, 40 "expected `=>` to separate key and value of record element pattern", 41 ) 42 })?; 43 let value = Pattern::parse(parser)?; 44 elements.push((key, value)); 45 if parser.check(CBracePipe).is_ok() { 46 break None; 47 }; 48 parser.expect(OpComma).map_err(|token| { 49 parser.expected(token, "expected `,` between record pattern elements") 50 })?; 51 }; 52 53 if let Some(rest) = rest { 54 return Self::parse_rest(parser, open_brace_pipe, elements, rest); 55 } 56 57 let close_brace_pipe = parser 58 .expect(CBracePipe) 59 .map_err(|token| parser.expected(token, "expected `|}` to end record pattern"))?; 60 61 Ok(Self { 62 span: open_brace_pipe.span.union(close_brace_pipe.span), 63 open_brace_pipe, 64 elements, 65 rest, 66 close_brace_pipe, 67 }) 68 } 69 70 pub(crate) fn parse_rest( 71 parser: &mut Parser, 72 open_brace_pipe: Token, 73 elements: Vec<(Pattern, Pattern)>, 74 rest: RestPattern, 75 ) -> SyntaxResult<Self> { 76 // We'll consume this trailing comma anyway as if it was going to work, 77 // and report an appropriate error. One of few attempts at smart error 78 // handling in this parser so far! 79 if let Ok(comma) = parser.expect(OpComma) { 80 let Ok(end) = parser.expect(CBracePipe) else { 81 let error = SyntaxError::new( 82 comma.span, 83 "a rest (`..`) element must end a record pattern", 84 ); 85 parser.error(error.clone()); 86 return Err(error); 87 }; 88 parser.error(SyntaxError::new( 89 comma.span, 90 "no trailing comma is permitted after the rest (`..`) element in a record pattern", 91 )); 92 return Ok(Self { 93 span: open_brace_pipe.span.union(end.span), 94 open_brace_pipe, 95 elements, 96 rest: Some(rest), 97 close_brace_pipe: end, 98 }); 99 } 100 101 let end = parser 102 .expect(CBracePipe) 103 .map_err(|token| parser.expected(token, "expected `|}` to end record pattern"))?; 104 105 Ok(Self { 106 span: open_brace_pipe.span.union(end.span), 107 open_brace_pipe, 108 elements, 109 rest: Some(rest), 110 close_brace_pipe: end, 111 }) 112 } 113 114 pub(super) fn parse_from_expression( 115 parser: &mut Parser, 116 open_brace_pipe: Token, 117 elements: Vec<RecordElement>, 118 head_element: RecordPatternElement, 119 ) -> SyntaxResult<Self> { 120 let (mut elements, rest) = elements 121 .into_iter() 122 .try_fold((vec![], None::<Pattern>), |(mut elements, mut rest), element| { 123 match element { 124 RecordElement::Element{ key, value, .. } if rest.is_none() => { 125 elements.push((key.try_into()?, value.try_into()?)); 126 }, 127 RecordElement::Element{ key, value, .. } => { 128 return Err(SyntaxError::new( 129 key.span().union(value.span()), 130 "no elements may follow the rest element of a record pattern, you might have meant this to be an expression", 131 )); 132 }, 133 RecordElement::Spread{ value, .. } if rest.is_none() => { 134 rest = Some(value.try_into()?); 135 }, 136 RecordElement::Spread{ span, ..} => { 137 return Err(SyntaxError::new( 138 span, 139 "a record pattern may contain only one rest element, you might have meant this to be an expression", 140 )); 141 }, 142 } 143 Ok((elements, rest)) 144 }) 145 .inspect_err(|error| { 146 parser.error(error.clone()); 147 })?; 148 match (rest, head_element) { 149 (None, RecordPatternElement::Element { key, value, .. }) => { 150 elements.push((key, value)); 151 Self::parse_elements(parser, open_brace_pipe, elements) 152 } 153 (None, RecordPatternElement::Spread { spread, value, .. }) => Self::parse_rest( 154 parser, 155 open_brace_pipe, 156 elements, 157 RestPattern::new(spread, value), 158 ), 159 (Some(..), element @ RecordPatternElement::Element { .. }) => Err(SyntaxError::new( 160 element.span(), 161 "no elements may follow the rest element in a record pattern, you might have meant this to be an expression", 162 )), 163 (Some(..), element @ RecordPatternElement::Spread { .. }) => Err(SyntaxError::new( 164 element.span(), 165 "a record pattern may contain only one rest element, you might have meant this to be an expression", 166 )), 167 } 168 } 169 170 pub fn start_token(&self) -> &Token { 171 &self.open_brace_pipe 172 } 173 174 pub fn end_token(&self) -> &Token { 175 &self.close_brace_pipe 176 } 177} 178 179impl Spanned for RecordPattern { 180 fn span(&self) -> Span { 181 self.span 182 } 183} 184 185impl TryFrom<RecordLiteral> for RecordPattern { 186 type Error = SyntaxError; 187 188 fn try_from(value: RecordLiteral) -> Result<Self, Self::Error> { 189 let mut head = vec![]; 190 let mut rest = None; 191 192 for element in value.elements { 193 match element { 194 RecordElement::Element { key, value, .. } if rest.is_none() => { 195 head.push((key.try_into()?, value.try_into()?)) 196 } 197 RecordElement::Spread { spread, value, .. } if rest.is_none() => { 198 rest = Some(RestPattern::try_from((spread, value))?) 199 } 200 RecordElement::Element { .. } | RecordElement::Spread { .. } => { 201 return Err(SyntaxError::new( 202 element.span(), 203 "no elements may follow the rest (`..`) element in a set pattern", 204 )); 205 } 206 } 207 } 208 209 Ok(Self { 210 span: value 211 .open_brace_pipe 212 .span 213 .union(value.close_brace_pipe.span), 214 open_brace_pipe: value.open_brace_pipe, 215 elements: head, 216 rest, 217 close_brace_pipe: value.close_brace_pipe, 218 }) 219 } 220}