use std::error::Error;
use crate::scanner::{Scanner, Token, TokenType};
use crate::ast::{ASTNode, NodeType};
pub struct Parser {
scanner: Scanner,
current_token: Option<Token>,
}
impl Parser {
pub fn new(scanner: Scanner) -> Result<Self, Box<dyn Error>> {
let mut parser = Parser {
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 factor(&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())
}
}
fn term(&mut self) -> Result<Box<ASTNode>, Box<dyn Error>> {
let mut left = self.factor()?;
while let Some(token) = &self.current_token {
let op_type = match token.token_type {
TokenType::Star => Some(NodeType::Multiply),
TokenType::Slash => Some(NodeType::Divide),
_ => None,
};
if let Some(op) = op_type {
self.advance()?;
let right = self.factor()?;
left = Box::new(ASTNode::new_binary_op(op, left, right));
} else {
break;
}
}
Ok(left)
}
pub fn expr(&mut self) -> Result<Box<ASTNode>, Box<dyn Error>> {
let mut left = self.term()?;
while let Some(token) = &self.current_token {
let op_type = match token.token_type {
TokenType::Plus => Some(NodeType::Add),
TokenType::Minus => Some(NodeType::Subtract),
_ => None,
};
if let Some(op) = op_type {
self.advance()?;
let right = self.term()?;
left = Box::new(ASTNode::new_binary_op(op, left, right));
} else {
break;
}
}
Ok(left)
}
pub fn parse(&mut self) -> Result<Box<ASTNode>, Box<dyn Error>> {
self.expr()
}
}