use crate::ast::AstNode;
use crate::errors::{Result, SecelError};
use crate::lexer::{Lexer, Token};
pub struct Parser {
lexer: Lexer,
trace: bool,
}
impl Parser {
pub fn new(input: &str) -> Self {
Self {
lexer: Lexer::new(input),
trace: false,
}
}
pub fn parse(&mut self) -> Result<AstNode> {
self.parse_statement()
}
fn parse_statement(&mut self) -> Result<AstNode> {
self.trace("statement");
self.parse_if_expression()
}
fn parse_if_expression(&mut self) -> Result<AstNode> {
self.trace("if-expression");
self.consume_token(Token::If)?;
self.consume_token(Token::LeftParen)?;
let comparison = self.parse_condition()?;
self.consume_token(Token::Semicolon)?;
let left_op = self.parse_expression()?;
self.consume_token(Token::Semicolon)?;
let right_op = self.parse_expression()?;
self.consume_token(Token::RightParen)?;
Ok(AstNode::If(Box::new(comparison), Box::new(left_op), Box::new(right_op)))
}
fn parse_condition(&mut self) -> Result<AstNode> {
self.trace("condition");
let mut left_node = self.parse_disjunction()?;
let position = self.lexer.get_position();
let mut consumed_or = false;
while self.consume_token(Token::Or).is_ok() {
consumed_or = true;
let right_node = self.parse_disjunction()?;
left_node = AstNode::Or(Box::new(left_node), Box::new(right_node));
}
if consumed_or {
return Ok(left_node);
}
self.lexer.set_position(position);
Ok(left_node)
}
fn parse_disjunction(&mut self) -> Result<AstNode> {
self.trace("disjunction");
let mut left_node = self.parse_conjunction()?;
let position = self.lexer.get_position();
let mut consumed_and = false;
while self.consume_token(Token::And).is_ok() {
consumed_and = true;
let right_node = self.parse_conjunction()?;
left_node = AstNode::And(Box::new(left_node), Box::new(right_node));
}
if consumed_and {
return Ok(left_node);
}
self.lexer.set_position(position);
Ok(left_node)
}
fn parse_conjunction(&mut self) -> Result<AstNode> {
self.trace("conjunction");
let position = self.lexer.get_position();
if let result @ Ok(_) = self.parse_comparison() {
return result;
}
self.lexer.set_position(position);
self.consume_token(Token::LeftParen)?;
let node = self.parse_condition()?;
self.consume_token(Token::RightParen)?;
Ok(node)
}
fn parse_comparison(&mut self) -> Result<AstNode> {
self.trace("comparison");
let left_op = self.parse_value()?;
let comparison_token = self.lexer.next_token();
let right_op = self.parse_value()?;
match comparison_token {
Token::Eq => Ok(AstNode::Eq(Box::new(left_op), Box::new(right_op))),
Token::Nq => Ok(AstNode::Nq(Box::new(left_op), Box::new(right_op))),
Token::Ge => Ok(AstNode::Ge(Box::new(left_op), Box::new(right_op))),
Token::Gt => Ok(AstNode::Gt(Box::new(left_op), Box::new(right_op))),
Token::Le => Ok(AstNode::Le(Box::new(left_op), Box::new(right_op))),
Token::Lt => Ok(AstNode::Lt(Box::new(left_op), Box::new(right_op))),
other => Err(SecelError::new(&format!("expected comparison token, but encountered {:?}", other))),
}
}
fn parse_expression(&mut self) -> Result<AstNode> {
self.trace("expression");
let position = self.lexer.get_position();
if let result @ Ok(_) = self.parse_value() {
return result;
}
self.lexer.set_position(position);
if let result @ Ok(_) = self.parse_if_expression() {
return result;
}
self.lexer.set_position(position);
Err(SecelError::new("expected 'value' or 'if expression`"))
}
fn parse_value(&mut self) -> Result<AstNode> {
self.trace("value");
let position = self.lexer.get_position();
match self.lexer.next_token() {
Token::Null => Ok(AstNode::Null),
Token::Number(n) => Ok(AstNode::Number(n)),
other => {
self.lexer.set_position(position);
Err(SecelError::new(&format!("expected null or number but encountered {:?}", other)))
}
}
}
fn consume_token(&mut self, expected: Token) -> Result<()> {
let position = self.lexer.get_position();
let token = self.lexer.next_token();
if token == expected {
Ok(())
} else {
self.lexer.set_position(position);
Err(SecelError::new(&format!("expected token '{:?}', actual token: '{:?}'", expected, token)))
}
}
fn trace(&self, name: &str) {
if self.trace {
print!("{:14}", name);
self.lexer.trace();
println!();
}
}
}