use std::error::Error;
use crate::scanner::{Scanner, Token, TokenType};
use crate::ast::{ASTNode, NodeType};
pub struct PrecedenceParser {
scanner: Scanner,
current_token: Option<Token>,
}
impl PrecedenceParser {
pub fn new(scanner: Scanner) -> Result<Self, Box<dyn Error>> {
let mut parser = PrecedenceParser {
scanner,
current_token: None,
};
parser.current_token = parser.scanner.scan()?;
Ok(parser)
}
fn advance(&mut self) -> Result<(), Box<dyn Error>> {
self.current_token = self.scanner.scan()?;
Ok(())
}
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()),
}
}
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()),
}
}
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()),
}
}
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)
}
pub fn parse(&mut self) -> Result<Box<ASTNode>, Box<dyn Error>> {
self.expression(0)
}
}