From 334dc99752fc5f0b4a030379f859900f8323fdfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Sun, 8 Jan 2023 11:31:02 +0100
Subject: [PATCH] Parser - Some refactoring of code that handles identifiers

---
 src/parser.rs | 50 +++++++++++++++++++++-----------------------------
 1 file changed, 21 insertions(+), 29 deletions(-)

diff --git a/src/parser.rs b/src/parser.rs
index d3e9b7f..c75c363 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -200,10 +200,7 @@ impl Parser {
     /// var_declaration := "var" IDENTIFIER "=" expression ";"
     /// ```
     fn parse_var_declaration(&mut self) -> SloxResult<StmtNode> {
-        let name = match self.peek().token_type {
-            TokenType::Identifier(_) => self.advance().clone(),
-            _ => return self.error("expected variable name"),
-        };
+        let name = self.consume_identifier("expected variable name")?;
         let initializer: Option<ExprNode> = match self.expect(&[TokenType::Equal]) {
             Some(_) => Some(self.parse_expression()?),
             None => None,
@@ -220,12 +217,7 @@ impl Parser {
     /// class := IDENTIFIER "{" function* "}"
     /// ```
     fn parse_class(&mut self) -> SloxResult<StmtNode> {
-        // Read the name
-        let name = match self.peek().token_type {
-            TokenType::Identifier(_) => self.advance().clone(),
-            _ => return self.error("class name expected"),
-        };
-        // Read the body
+        let name = self.consume_identifier("expected class name")?;
         self.consume(&TokenType::LeftBrace, "'{' expected")?;
         let mut methods = Vec::new();
         while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
@@ -245,11 +237,7 @@ impl Parser {
     /// ```
     /// The `kind` parameter is used to generate error messages.
     fn parse_function(&mut self, kind: FunctionKind) -> SloxResult<StmtNode> {
-        // Read the name
-        let name = match self.peek().token_type {
-            TokenType::Identifier(_) => self.advance().clone(),
-            _ => return self.error_mv(format!("expected {} name", kind.name())),
-        };
+        let name = self.consume_identifier(&format!("expected {} name", kind.name()))?;
         let (params, block) = self.parse_function_info(kind)?;
         Ok(StmtNode::FunDecl(FunDecl {
             name,
@@ -284,15 +272,12 @@ impl Parser {
                         kind.max_params()
                     ));
                 }
-                if let TokenType::Identifier(name) = &self.peek().token_type {
-                    if names.contains(name) {
-                        return self.error_mv(format!("duplicate {} parameter", kind.name()));
-                    }
-                    names.insert(name.to_owned());
-                    params.push(self.advance().clone());
-                } else {
-                    return self.error("parameter name expected");
+                let name = self.consume_identifier("parameter name expected")?;
+                if names.contains(&name.lexeme) {
+                    return self.error_mv(format!("duplicate {} parameter", kind.name()));
                 }
+                names.insert(name.lexeme);
+                params.push(self.advance().clone());
                 if self.expect(&[TokenType::Comma]).is_none() {
                     break;
                 }
@@ -357,11 +342,7 @@ impl Parser {
     /// labelled_loop := "@" IDENTIFIER for_statement
     /// ```
     fn parse_labelled_loop(&mut self) -> SloxResult<StmtNode> {
-        let name_token = match self.peek().token_type {
-            TokenType::Identifier(_) => self.advance().clone(),
-            _ => return self.error("identifier expected after '@'"),
-        };
-
+        let name_token = self.consume_identifier("identifier expected after '@'")?;
         if self.expect(&[TokenType::While]).is_some() {
             self.parse_while_statement(Some(name_token))
         } else if self.expect(&[TokenType::For]).is_some() {
@@ -478,7 +459,7 @@ impl Parser {
             ));
         }
 
-        let loop_name = if let TokenType::Identifier(_) = self.peek().token_type {
+        let loop_name = if self.peek().is_identifier() {
             let name_token = self.advance().clone();
             if !self.find_named_loop(&name_token.lexeme) {
                 self.expect(&[TokenType::Semicolon]);
@@ -817,6 +798,17 @@ impl Parser {
         self.previous()
     }
 
+    /// Advance if the current token is an identifier, returning a clone of
+    /// the token. If it isn't, an error with the specified message is
+    /// returned instead.
+    fn consume_identifier(&mut self, message: &str) -> SloxResult<Token> {
+        if self.peek().is_identifier() {
+            Ok(self.advance().clone())
+        } else {
+            self.error(message)
+        }
+    }
+
     /// Check whether the end of token stream has been reached by checking
     /// for the `EOF` token.
     fn is_at_end(&self) -> bool {