diff --git a/src/parser.rs b/src/parser.rs index f6970de..ea2bbed 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4,6 +4,7 @@ use crate::{ tokens::{Token, TokenType}, }; +/// The parser contains the input tokens and the current input position. #[derive(Debug)] pub struct Parser { tokens: Vec, @@ -11,10 +12,13 @@ pub struct Parser { } impl Parser { + /// Initialize the parser. pub fn new(tokens: Vec) -> Self { Self { tokens, current: 0 } } + /// Parse the tokens into an AST and return it, or return nothing if a + /// parser error occurs. pub fn parse(mut self, err_hdl: &mut ErrorHandler) -> Option { match self.parse_expression() { Ok(expr) => Some(expr), @@ -25,10 +29,23 @@ impl Parser { } } + /* ------------------------ * + * RECURSIVE DESCENT PARSER * + * ------------------------ */ + + /// Parse the following rule: + /// ``` + /// expression := equality + /// ``` fn parse_expression(&mut self) -> Result { self.parse_equality() } + /// Parse the following rule: + /// ``` + /// equality := comparison "==" comparison + /// equality := comparison "!=" comparison + /// ``` fn parse_equality(&mut self) -> Result { let mut expr = self.parse_comparison()?; while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) { @@ -42,6 +59,11 @@ impl Parser { Ok(expr) } + /// Parse the following rule: + /// ``` + /// comparison := term comparison_operator term + /// comparison_operator := "<" | "<=" | ">" | ">=" + /// ``` fn parse_comparison(&mut self) -> Result { let mut expr = self.parse_term()?; while let Some(operator) = self.expect(&[ @@ -60,6 +82,11 @@ impl Parser { Ok(expr) } + /// Parse the following rule: + /// ``` + /// term := factor "+" factor + /// term := factor "-" factor + /// ``` fn parse_term(&mut self) -> Result { let mut expr = self.parse_factor()?; while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) { @@ -73,6 +100,11 @@ impl Parser { Ok(expr) } + /// Parse the following rule: + /// ``` + /// factor := unary "*" unary + /// factor := unary "/" unary + /// ``` fn parse_factor(&mut self) -> Result { let mut expr = self.parse_unary()?; while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) { @@ -86,6 +118,12 @@ impl Parser { Ok(expr) } + /// Parse the following rule: + /// ``` + /// unary := "-" unary + /// unary := "!" unary + /// unary := primary + /// ``` fn parse_unary(&mut self) -> Result { if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) { Ok(ast::ExprNode::Unary { @@ -97,6 +135,11 @@ impl Parser { } } + /// Parse the following rule: + /// ``` + /// primary := "(" expression ")" + /// primary := FALSE | TRUE | NIL | STRING | NUMBER + /// ``` fn parse_primary(&mut self) -> Result { if self.expect(&[TokenType::LeftParen]).is_some() { let expr = self.parse_expression()?; @@ -118,6 +161,12 @@ impl Parser { } } + /* -------------- * + * HELPER METHODS * + * -------------- */ + + /// Expect a token of some types. If a matching token is found, the read + /// pointer is moved and a clone of the token is returned. fn expect(&mut self, accepts: &[TokenType]) -> Option { for tt in accepts { if self.check(tt) { @@ -127,6 +176,8 @@ impl Parser { None } + /// Consume a token of a given type. If no matching token is found, a + /// parse error is returned instead. Otherwise the read pointer is moved. fn consume(&mut self, token_type: &TokenType, error: &str) -> Result<&Token, ParserError> { if self.check(token_type) { Ok(self.advance()) @@ -135,6 +186,8 @@ impl Parser { } } + /// Check for a token of some type. Returns `false` if the end of the input + /// has been reached. The read pointer isn't affected. fn check(&self, token_type: &TokenType) -> bool { if self.is_at_end() { false @@ -143,6 +196,9 @@ impl Parser { } } + /// Move the read pointer forward if the end hasn't been reached. In all + /// cases, return the previous element (so either the element that was + /// current before the pointer moved, or the last, non-`EOF` token). fn advance(&mut self) -> &Token { if !self.is_at_end() { self.current += 1 @@ -150,14 +206,18 @@ impl Parser { self.previous() } + /// Check whether the end of token stream has been reached by checking + /// for the `EOF` token. fn is_at_end(&self) -> bool { self.peek().token_type == TokenType::EOF } + /// Return a reference to the current token in the stream. fn peek(&self) -> &Token { &self.tokens[self.current] } + /// Return a reference to the previous token in the stream. fn previous(&self) -> &Token { &self.tokens[self.current - 1] }