use crate::{ error::{ErrorKind, KabelError}, lexer::{Token, TokenType}, }; pub struct Parser { input: Vec, text: String, //start: usize, current: usize, token: Token, pub errors: Vec, } impl Parser { pub fn new(text: String, input: Vec) -> Self { Self { input: input.clone(), text, //start: 0, current: 0, token: input[0].clone(), errors: Vec::new(), } } pub fn program(&mut self) -> AST { let mut program = Vec::new(); loop { if self.current >= self.input.len() { break; } match self.expression() { Ok(ast) => program.push(ast), Err(e) => self.errors.push(e), } } AST { ast_type: ASTType::Program(program), start: 0, end: 0, line: 0, column: 0, } } pub fn expression(&mut self) -> Result { let equality = self.equality()?; Ok(equality) } pub fn equality(&mut self) -> Result { let mut left = self.comparison()?; while self.current < self.input.len() && (self.peek()?.token_type == TokenType::EqualEqual || self.peek()?.token_type == TokenType::BangEqual) { let binop = self.read_token()?; let right = self.comparison()?; if binop.token_type == TokenType::EqualEqual { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Eq, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } else { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Ne, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } } Ok(left) } pub fn comparison(&mut self) -> Result { let mut left = self.term()?; while self.current < self.input.len() && (self.peek()?.token_type == TokenType::Less || self.peek()?.token_type == TokenType::LessEqual || self.peek()?.token_type == TokenType::Greater || self.peek()?.token_type == TokenType::GreaterEqual) { let binop = self.read_token()?; let right = self.term()?; if binop.token_type == TokenType::Less { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Ls, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } else if binop.token_type == TokenType::LessEqual { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Le, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } else if binop.token_type == TokenType::Greater { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Gr, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } else { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Ge, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } } Ok(left) } pub fn term(&mut self) -> Result { let mut left = self.factor()?; while self.current < self.input.len() && (self.peek()?.token_type == TokenType::Plus || self.peek()?.token_type == TokenType::Minus) { let binop = self.read_token()?; let right = self.factor()?; if binop.token_type == TokenType::Plus { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Add, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } else { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Sub, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } } Ok(left) } pub fn factor(&mut self) -> Result { let mut left = self.unary()?; while self.current < self.input.len() && (self.peek()?.token_type == TokenType::Star || self.peek()?.token_type == TokenType::Slash) { let binop = self.read_token()?; let right = self.unary()?; if binop.token_type == TokenType::Star { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Mul, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } else { left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Div, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } } Ok(left) } pub fn unary(&mut self) -> Result { if let TokenType::Bang | TokenType::Minus = self.peek()?.token_type { let token = self.read_token()?; let unary = self.unary()?; if token.token_type == TokenType::Bang { return Ok(AST { ast_type: ASTType::Unary(UnOp::Not, Box::new(unary.clone())), start: token.start, end: unary.end, line: token.line, column: token.column, }); } else { return Ok(AST { ast_type: ASTType::Unary(UnOp::Neg, Box::new(unary.clone())), start: token.start, end: unary.end, line: token.line, column: token.column, }); } } Ok(self.primary()?) } pub fn primary(&mut self) -> Result { let token = self.read_token()?; match token.token_type { TokenType::Ident(ident) => { return Ok(AST { ast_type: ASTType::Ident(ident), start: token.start, end: token.end, line: token.line, column: token.column, }); } TokenType::Num(num) => { return Ok(AST { ast_type: ASTType::Num(num), start: token.start, end: token.end, line: token.line, column: token.column, }); } TokenType::Str(string) => { return Ok(AST { ast_type: ASTType::Str(string), start: token.start, end: token.end, line: token.line, column: token.column, }); } TokenType::LeftParen => { return Ok(self.group(token)?); } _ => { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Unexpected token {}", self.text[token.start..token.end].to_string() ), token.line, token.column, self.text[token.line_start..token.end].to_string(), )); } } } pub fn group(&mut self, left_paren: Token) -> Result { let expr = self.expression()?; let right_paren = self.peek(); if let Ok(right_paren) = right_paren { if right_paren.token_type != TokenType::RightParen { return Err(KabelError::new( ErrorKind::MissingDelimiter, "Missing right parenthesis".to_string(), right_paren.line, right_paren.column, self.text[left_paren.start..right_paren.end].to_string(), )); } self.read_token()?; return Ok(AST { ast_type: ASTType::Group(Box::new(expr.clone())), start: left_paren.start, end: right_paren.end, line: left_paren.line, column: left_paren.column, }); } if let Err(e) = right_paren { return Err(KabelError::new( ErrorKind::MissingDelimiter, "Missing right parenthesis".to_string(), e.line, e.column, self.text[left_paren.line_start..expr.end].to_string(), )); } unreachable!(); } pub fn read_token(&mut self) -> Result { if self.current >= self.input.len() { let last_token = self.input[self.input.len() - 1].clone(); return Err(KabelError::new( ErrorKind::UnexpectedEof, "Unexpected end of file".to_string(), last_token.line, last_token.column, self.text[last_token.line_start..last_token.end].to_string(), )); } self.token = self.input[self.current].clone(); self.current += 1; return Ok(self.token.clone()); } pub fn peek(&mut self) -> Result { if self.current >= self.input.len() { let last_token = self.input[self.input.len() - 1].clone(); return Err(KabelError::new( ErrorKind::UnexpectedEof, "Unexpected end of file".to_string(), last_token.line, last_token.column, self.text[last_token.line_start..last_token.end].to_string(), )); } return Ok(self.input[self.current].clone()); } } #[derive(Debug, Clone)] pub struct AST { pub ast_type: ASTType, pub start: usize, pub end: usize, pub line: usize, pub column: usize, } #[derive(Debug, Clone)] pub enum ASTType { Program(Vec), Binary(Box, BinOp, Box), Unary(UnOp, Box), Group(Box), Ident(String), Num(f32), Str(String), } #[derive(Debug, Clone, Copy)] pub enum BinOp { Add, Sub, Mul, Div, Eq, Ne, Gr, Ge, Ls, Le, } #[derive(Debug, Clone, Copy)] pub enum UnOp { Not, Neg, }