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