rustcc 0.1.1

An little C Complier( now it's just WIP :) )
//! # RustCC Precedence Parser
//! A parser implementation that uses an operator precedence table
//! to handle operator precedence in arithmetic expressions.

use std::error::Error;
use crate::scanner::{Scanner, Token, TokenType};
use crate::ast::{ASTNode, NodeType};

/// A parser that uses an operator precedence table to parse arithmetic expressions.
/// This implementation is based on the "shunting yard" algorithm concept,
/// using a recursive descent approach with precedence levels.
pub struct PrecedenceParser {
    scanner: Scanner,
    current_token: Option<Token>,
}

impl PrecedenceParser {
    /// Creates a new precedence parser with the specified scanner.
    /// 
    /// # Arguments
    /// * `scanner` - The scanner to use for token input
    /// 
    /// # Returns
    /// * `Ok(PrecedenceParser)` - A new parser instance
    /// * `Err(Box<dyn Error>)` - If an error occurs while initializing the parser
    pub fn new(scanner: Scanner) -> Result<Self, Box<dyn Error>> {
        let mut parser = PrecedenceParser {
            scanner,
            current_token: None,
        };
        // Initialize with the first token
        parser.current_token = parser.scanner.scan()?;
        Ok(parser)
    }

    /// Advances to the next token in the input stream.
    /// 
    /// # Returns
    /// * `Ok(())` - If the next token was successfully read
    /// * `Err(Box<dyn Error>)` - If an error occurs while reading the next token
    fn advance(&mut self) -> Result<(), Box<dyn Error>> {
        self.current_token = self.scanner.scan()?;
        Ok(())
    }

    /// Returns the precedence of the current token.
    /// 
    /// # Returns
    /// * `i32` - The precedence value of the current token
    /// * `Err(Box<dyn Error>)` - If the current token is not a valid operator
    fn get_precedence(&self) -> Result<i32, Box<dyn Error>> {
        match &self.current_token {
            Some(token) => match token.token_type {
                TokenType::Plus | TokenType::Minus => Ok(10),
                TokenType::Star | TokenType::Slash => Ok(20),
                TokenType::IntLit => Ok(0),
            },
            None => Err("Unexpected end of input".into()),
        }
    }

    /// Converts a token type to an AST node type.
    /// 
    /// # Arguments
    /// * `token_type` - The token type to convert
    /// 
    /// # Returns
    /// * `NodeType` - The corresponding AST node type
    /// * `Err(Box<dyn Error>)` - If the token type is not a valid operator
    fn token_to_node_type(&self, token_type: TokenType) -> Result<NodeType, Box<dyn Error>> {
        match token_type {
            TokenType::Plus => Ok(NodeType::Add),
            TokenType::Minus => Ok(NodeType::Subtract),
            TokenType::Star => Ok(NodeType::Multiply),
            TokenType::Slash => Ok(NodeType::Divide),
            _ => Err(format!("Not an operator: {:?}", token_type).into()),
        }
    }

    /// Parses a primary factor (integer literal).
    /// 
    /// # Returns
    /// * `Ok(Box<ASTNode>)` - The parsed factor as an AST node
    /// * `Err(Box<dyn Error>)` - If a syntax error occurs
    fn primary(&mut self) -> Result<Box<ASTNode>, Box<dyn Error>> {
        match &self.current_token {
            Some(token) => match token.token_type {
                TokenType::IntLit => {
                    let value = token.int_value.unwrap_or(0);
                    let node = Box::new(ASTNode::new_int_lit(value));
                    self.advance()?;
                    Ok(node)
                },
                _ => Err(format!(
                    "Unexpected token: {:?} at line {}",
                    token, self.scanner.line()
                ).into()),
            },
            None => Err("Unexpected end of input".into()),
        }
    }

    /// Parses an expression using operator precedence.
    /// 
    /// # Arguments
    /// * `rbp` - The right binding power (precedence) of the current context
    /// 
    /// # Returns
    /// * `Ok(Box<ASTNode>)` - The parsed expression as an AST node
    /// * `Err(Box<dyn Error>)` - If a syntax error occurs
    pub fn expression(&mut self, rbp: i32) -> Result<Box<ASTNode>, Box<dyn Error>> {
        let mut left = self.primary()?;

        loop {
            let current_precedence = match self.get_precedence() {
                Ok(p) => p,
                Err(_) => break,
            };

            if current_precedence <= rbp {
                break;
            }

            let token_type = self.current_token.as_ref().unwrap().token_type;
            let op = self.token_to_node_type(token_type)?;
            self.advance()?;

            let right = self.expression(current_precedence)?;
            left = Box::new(ASTNode::new_binary_op(op, left, right));
        }

        Ok(left)
    }

    /// Parses the entire input and returns the root of the AST.
    /// 
    /// # Returns
    /// * `Ok(Box<ASTNode>)` - The root of the parsed AST
    /// * `Err(Box<dyn Error>)` - If a syntax error occurs
    pub fn parse(&mut self) -> Result<Box<ASTNode>, Box<dyn Error>> {
        self.expression(0)
    }
}