Parser - Comments
This commit is contained in:
parent
fc345f2ffb
commit
1e122c77a5
1 changed files with 60 additions and 0 deletions
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
tokens::{Token, TokenType},
|
tokens::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The parser contains the input tokens and the current input position.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
|
@ -11,10 +12,13 @@ pub struct Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
|
/// Initialize the parser.
|
||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
Self { tokens, current: 0 }
|
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<ast::ExprNode> {
|
pub fn parse(mut self, err_hdl: &mut ErrorHandler) -> Option<ast::ExprNode> {
|
||||||
match self.parse_expression() {
|
match self.parse_expression() {
|
||||||
Ok(expr) => Some(expr),
|
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<ast::ExprNode, ParserError> {
|
fn parse_expression(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
self.parse_equality()
|
self.parse_equality()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// equality := comparison "==" comparison
|
||||||
|
/// equality := comparison "!=" comparison
|
||||||
|
/// ```
|
||||||
fn parse_equality(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_equality(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
let mut expr = self.parse_comparison()?;
|
let mut expr = self.parse_comparison()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) {
|
while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) {
|
||||||
|
@ -42,6 +59,11 @@ impl Parser {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// comparison := term comparison_operator term
|
||||||
|
/// comparison_operator := "<" | "<=" | ">" | ">="
|
||||||
|
/// ```
|
||||||
fn parse_comparison(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_comparison(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
let mut expr = self.parse_term()?;
|
let mut expr = self.parse_term()?;
|
||||||
while let Some(operator) = self.expect(&[
|
while let Some(operator) = self.expect(&[
|
||||||
|
@ -60,6 +82,11 @@ impl Parser {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// term := factor "+" factor
|
||||||
|
/// term := factor "-" factor
|
||||||
|
/// ```
|
||||||
fn parse_term(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_term(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
let mut expr = self.parse_factor()?;
|
let mut expr = self.parse_factor()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) {
|
while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) {
|
||||||
|
@ -73,6 +100,11 @@ impl Parser {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// factor := unary "*" unary
|
||||||
|
/// factor := unary "/" unary
|
||||||
|
/// ```
|
||||||
fn parse_factor(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_factor(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
let mut expr = self.parse_unary()?;
|
let mut expr = self.parse_unary()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) {
|
while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) {
|
||||||
|
@ -86,6 +118,12 @@ impl Parser {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// unary := "-" unary
|
||||||
|
/// unary := "!" unary
|
||||||
|
/// unary := primary
|
||||||
|
/// ```
|
||||||
fn parse_unary(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_unary(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) {
|
if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) {
|
||||||
Ok(ast::ExprNode::Unary {
|
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<ast::ExprNode, ParserError> {
|
fn parse_primary(&mut self) -> Result<ast::ExprNode, ParserError> {
|
||||||
if self.expect(&[TokenType::LeftParen]).is_some() {
|
if self.expect(&[TokenType::LeftParen]).is_some() {
|
||||||
let expr = self.parse_expression()?;
|
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<Token> {
|
fn expect(&mut self, accepts: &[TokenType]) -> Option<Token> {
|
||||||
for tt in accepts {
|
for tt in accepts {
|
||||||
if self.check(tt) {
|
if self.check(tt) {
|
||||||
|
@ -127,6 +176,8 @@ impl Parser {
|
||||||
None
|
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> {
|
fn consume(&mut self, token_type: &TokenType, error: &str) -> Result<&Token, ParserError> {
|
||||||
if self.check(token_type) {
|
if self.check(token_type) {
|
||||||
Ok(self.advance())
|
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 {
|
fn check(&self, token_type: &TokenType) -> bool {
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
false
|
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 {
|
fn advance(&mut self) -> &Token {
|
||||||
if !self.is_at_end() {
|
if !self.is_at_end() {
|
||||||
self.current += 1
|
self.current += 1
|
||||||
|
@ -150,14 +206,18 @@ impl Parser {
|
||||||
self.previous()
|
self.previous()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether the end of token stream has been reached by checking
|
||||||
|
/// for the `EOF` token.
|
||||||
fn is_at_end(&self) -> bool {
|
fn is_at_end(&self) -> bool {
|
||||||
self.peek().token_type == TokenType::EOF
|
self.peek().token_type == TokenType::EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a reference to the current token in the stream.
|
||||||
fn peek(&self) -> &Token {
|
fn peek(&self) -> &Token {
|
||||||
&self.tokens[self.current]
|
&self.tokens[self.current]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a reference to the previous token in the stream.
|
||||||
fn previous(&self) -> &Token {
|
fn previous(&self) -> &Token {
|
||||||
&self.tokens[self.current - 1]
|
&self.tokens[self.current - 1]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue