From 055da4d220ea92bcbbb6ef162c2937e9dc1adec9 Mon Sep 17 00:00:00 2001 From: Gavin Crawford <94875769+gavincrawford@users.noreply.github.com> Date: Mon, 20 Jul 2026 21:51:36 -0600 Subject: [PATCH] refactor: Minify duplicated Token-to-char conversion with helper --- src/parser.rs | 51 +++++++++++++++++---------------------------------- src/token.rs | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 80ede2b..8d73a9e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -429,7 +429,12 @@ impl<'a> Parser<'a> { } fn parse_left_delimited(&mut self) -> Result { - let left = self.read_delimiter("left")?; + // Peek left and convert it back to it's character representation + let left = self + .peek() + .and_then(|tok| tok.as_char()) + .ok_or(ParseError::ExpectedDelimiter { side: "left" })?; + let inner_start = self.pos; let mut depth = 0usize; let mut match_idx = None; @@ -459,21 +464,17 @@ impl<'a> Parser<'a> { return Err(ParseError::Internal("mismatched delimiter scan".into())); } - let Some((right_token, _)) = self.tokens.get(match_idx + 1) else { - return Err(ParseError::ExpectedDelimiter { side: "right" }); - }; - let right = match right_token { - Token::LParen | Token::Escape("(") => '(', - Token::LBracket | Token::Escape("[") => '[', - Token::LBrace | Token::Escape("{") => '{', - Token::RParen | Token::Escape(")") => ')', - Token::RBracket | Token::Escape("]") => ']', - Token::RBrace | Token::Escape("}") => '}', - Token::Pipe | Token::Escape("|") => '|', - _ => { - return Err(ParseError::ExpectedDelimiter { side: "right" }); - } - }; + // Convert the token after the matched index back into it's character representation + let right = self + .tokens + .get(match_idx + 1) + .and_then(|(t, _)| t.as_char()) + .ok_or(ParseError::ExpectedDelimiter { side: "right" })?; + + // Expect left and right delimiters to match + // TODO: this should probably get it's own strongly-typed error variant. it's not really + // unreachable code, and this branch could reasonably be called in production, resulting in + // a hard panic. let expected_right = match left { '(' => ')', '[' => ']', @@ -494,24 +495,6 @@ impl<'a> Parser<'a> { }) } - fn read_delimiter(&mut self, side: &'static str) -> Result { - let delim = match self.peek() { - Some(Token::LParen) | Some(Token::Escape("(")) => '(', - Some(Token::LBracket) | Some(Token::Escape("[")) => '[', - Some(Token::LBrace) | Some(Token::Escape("{")) => '{', - Some(Token::Pipe) | Some(Token::Escape("|")) => '|', - Some(Token::RParen) | Some(Token::Escape(")")) => ')', - Some(Token::RBracket) | Some(Token::Escape("]")) => ']', - Some(Token::RBrace) | Some(Token::Escape("}")) => '}', - _ => { - return Err(ParseError::ExpectedDelimiter { side }); - } - }; - - self.advance(); - Ok(delim) - } - fn parse_delimited_arg(&mut self, close: Token) -> Result { self.advance(); let inner_start = self.pos; diff --git a/src/token.rs b/src/token.rs index 1b7ccfb..904ec79 100644 --- a/src/token.rs +++ b/src/token.rs @@ -73,6 +73,21 @@ pub enum Token<'a> { Whitespace, } +impl<'a> Token<'a> { + pub fn as_char(&self) -> Option { + match self { + Token::LParen | Token::Escape("(") => Some('('), + Token::RParen | Token::Escape(")") => Some(')'), + Token::LBracket | Token::Escape("[") => Some('['), + Token::RBracket | Token::Escape("]") => Some(']'), + Token::LBrace | Token::Escape("{") => Some('{'), + Token::RBrace | Token::Escape("}") => Some('}'), + Token::Pipe | Token::Escape("|") => Some('|'), + _ => None, + } + } +} + pub fn tokenize(input: &str) -> Result>, ParseError> { Token::lexer(input) .spanned()