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), } break; } AST { ast_type: ASTType::Program(program), start: 0, end: 0, line: 0, column: 0, } } pub fn expression(&mut self) -> Result { let term = self.term()?; Ok(term) } 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.primary()?; 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.primary()?; 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 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), Group(Box), Ident(String), Num(f32), Str(String), } #[derive(Debug, Clone, Copy)] pub enum BinOp { Add, Sub, Mul, Div, }