167 lines
3.9 KiB
Rust
167 lines
3.9 KiB
Rust
use super::astnode;
|
|
use super::astnode::{ASTNode, BinaryExpr};
|
|
use crate::lexer::{token, token::TokenType};
|
|
use std::iter;
|
|
use std::result::Result as StdResult;
|
|
|
|
type Result<T> = StdResult<T, ASTParsingError>;
|
|
|
|
#[derive(Debug)]
|
|
pub enum ASTParsingError {
|
|
UnmatchedBrace,
|
|
}
|
|
|
|
impl std::fmt::Display for ASTParsingError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match *self {
|
|
Self::UnmatchedBrace => write!(f, "Unmatched brace"),
|
|
}
|
|
}
|
|
}
|
|
impl std::error::Error for ASTParsingError {}
|
|
|
|
pub struct Parser<'a, T: Iterator<Item = token::Token<'a>>> {
|
|
token_iter: iter::Peekable<T>,
|
|
}
|
|
|
|
impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
|
|
pub fn new(iter: T) -> Parser<'a, T> {
|
|
Parser {
|
|
token_iter: iter.peekable(),
|
|
}
|
|
}
|
|
pub fn scan_expressions(&mut self) -> StdResult<Vec<ASTNode>, Vec<ASTParsingError>> {
|
|
let mut tokens = Vec::new();
|
|
let mut errors = Vec::new();
|
|
|
|
while self.token_iter.peek().is_some() {
|
|
match self.expression() {
|
|
Ok(token) => {
|
|
if errors.is_empty() {
|
|
tokens.push(token)
|
|
}
|
|
}
|
|
Err(e) => errors.push(e),
|
|
}
|
|
}
|
|
if errors.is_empty() {
|
|
Ok(tokens)
|
|
} else {
|
|
Err(errors)
|
|
}
|
|
}
|
|
|
|
fn expression(&mut self) -> Result<ASTNode> {
|
|
self.equality()
|
|
}
|
|
|
|
fn equality(&mut self) -> Result<ASTNode> {
|
|
let mut node = self.comparison()?;
|
|
while let Some(o) = self
|
|
.token_iter
|
|
.next_if(|t| matches!(t.token_type, TokenType::EqualEqual | TokenType::BangEqual))
|
|
{
|
|
node = BinaryExpr::new(
|
|
Box::new(node),
|
|
o.token_type.try_into().unwrap(),
|
|
Box::new(self.comparison()?),
|
|
)
|
|
.into();
|
|
}
|
|
Ok(node)
|
|
}
|
|
|
|
fn comparison(&mut self) -> Result<ASTNode> {
|
|
let mut node = self.term()?;
|
|
|
|
while let Some(o) = self.token_iter.next_if(|t| {
|
|
matches!(
|
|
t.token_type,
|
|
TokenType::Greater
|
|
| TokenType::GreaterEqual
|
|
| TokenType::Less | TokenType::LessEqual
|
|
)
|
|
}) {
|
|
node = BinaryExpr::new(
|
|
Box::new(node),
|
|
o.token_type.try_into().unwrap(),
|
|
Box::new(self.comparison()?),
|
|
)
|
|
.into();
|
|
}
|
|
Ok(node)
|
|
}
|
|
|
|
fn term(&mut self) -> Result<ASTNode> {
|
|
let mut node = self.factor()?;
|
|
|
|
while let Some(o) = self
|
|
.token_iter
|
|
.next_if(|t| matches!(t.token_type, TokenType::Minus | TokenType::Plus))
|
|
{
|
|
node = BinaryExpr::new(
|
|
Box::new(node),
|
|
o.token_type.try_into().unwrap(),
|
|
Box::new(self.comparison()?),
|
|
)
|
|
.into()
|
|
}
|
|
Ok(node)
|
|
}
|
|
|
|
fn factor(&mut self) -> Result<ASTNode> {
|
|
let mut node = self.unary()?;
|
|
|
|
while let Some(o) = self
|
|
.token_iter
|
|
.next_if(|t| matches!(t.token_type, TokenType::Star | TokenType::Slash))
|
|
{
|
|
node = BinaryExpr::new(
|
|
Box::new(node),
|
|
o.token_type.try_into().unwrap(),
|
|
Box::new(self.comparison()?),
|
|
)
|
|
.into();
|
|
}
|
|
Ok(node)
|
|
}
|
|
|
|
fn unary(&mut self) -> Result<ASTNode> {
|
|
if let Some(op) = self
|
|
.token_iter
|
|
.next_if(|t| matches!(t.token_type, TokenType::Bang | TokenType::Minus))
|
|
{
|
|
let right = Box::new(self.unary()?);
|
|
Ok(ASTNode::UnaryExpr(astnode::UnaryExpr::new(
|
|
op.token_type.try_into().unwrap(),
|
|
right,
|
|
)))
|
|
} else {
|
|
self.primary()
|
|
}
|
|
}
|
|
|
|
fn primary(&mut self) -> Result<ASTNode> {
|
|
let node = match self.token_iter.next().map(|it| it.token_type) {
|
|
Some(TokenType::False) => ASTNode::Literal(astnode::Literal::Bool(false)),
|
|
Some(TokenType::True) => ASTNode::Literal(astnode::Literal::Bool(true)),
|
|
Some(TokenType::Int(i)) => ASTNode::Literal(astnode::Literal::Int(i)),
|
|
Some(TokenType::String(i)) => ASTNode::Literal(astnode::Literal::String(i)),
|
|
Some(TokenType::Float(f)) => ASTNode::Literal(astnode::Literal::Float(f)),
|
|
Some(TokenType::LeftParen) => {
|
|
let expr = self.expression()?;
|
|
let group = astnode::GroupingExpr::new(Box::new(expr));
|
|
match self
|
|
.token_iter
|
|
.next_if(|v| matches!(v.token_type, TokenType::RightParen))
|
|
{
|
|
Some(_) => return Ok(group.into()),
|
|
None => return Err(ASTParsingError::UnmatchedBrace),
|
|
}
|
|
}
|
|
Some(a) => panic!("{:#?}", a),
|
|
None => todo!(),
|
|
};
|
|
Ok(node)
|
|
}
|
|
}
|