use crate::{ error::{ErrorKind, KabelError}, lexer::{Token, TokenType}, lit, }; 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.statement() { 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 statement(&mut self) -> Result { match self.peek()?.token_type { TokenType::Ident(ident) => { match ident.as_str() { "if" => self.if_statement(), _ => self.expression_statement() } } _ => self.expression_statement() } } pub fn if_statement(&mut self) -> Result { let if_ident = self.read_token()?; let left_paren = self.read_token()?; if let TokenType::LeftParen = left_paren.token_type { let condition = self.expression()?; let right_paren = self.read_token()?; if let TokenType::RightParen = right_paren.token_type { let block = self.block()?; if self.current < self.input.len() { let else_ident = self.read_token()?; if let TokenType::Ident(content) = else_ident.token_type { if content == "else" { if let TokenType::LeftBrace = self.peek()?.token_type { let else_block = self.block()?; return Ok(AST { ast_type: ASTType::If(Box::new(condition), Box::new(block.clone()), Some(Box::new(else_block.clone()))), start: if_ident.start, end: else_block.end, line: if_ident.line, column: if_ident.column, }); } let else_if_ident = self.peek()?; if let TokenType::Ident(content) = else_if_ident.token_type { if content == "if" { let else_if = self.if_statement()?; return Ok(AST { ast_type: ASTType::If(Box::new(condition), Box::new(block.clone()), Some(Box::new(else_if.clone()))), start: if_ident.start, end: else_if.end, line: if_ident.line, column: if_ident.column, }); } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected if found {}", self.text[else_if_ident.start..else_if_ident.end].to_string() ), else_if_ident.line, else_if_ident.column, self.text[else_if_ident.line_start..else_if_ident.end].to_string(), )); } } return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Unexpected token {}", self.text[else_ident.start..else_ident.end].to_string() ), else_ident.line, else_ident.column, self.text[else_ident.line_start..else_ident.end].to_string(), )); } else { self.current -= 1; } } } return Ok(AST { ast_type: ASTType::If(Box::new(condition), Box::new(block.clone()), None), start: if_ident.start, end: block.end, line: if_ident.line, column: if_ident.column, }); } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected ) found {}", self.text[right_paren.start..right_paren.end].to_string() ), right_paren.line, right_paren.column, self.text[right_paren.line_start..right_paren.end].to_string(), )); } } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected ( found {}", self.text[left_paren.start..left_paren.end].to_string() ), left_paren.line, left_paren.column, self.text[left_paren.line_start..left_paren.end].to_string(), )); } } pub fn block(&mut self) -> Result { let left_brace = self.read_token()?; if let TokenType::LeftBrace = left_brace.token_type { let mut stmts = Vec::new(); while self.peek()?.token_type != TokenType::RightBrace { stmts.push(self.statement()?); } let right_brace = self.read_token()?; return Ok(AST { ast_type: ASTType::Block(stmts), start: left_brace.start, end: right_brace.end, line: left_brace.line, column: left_brace.column, }); } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected {{ found {}", self.text[left_brace.start..left_brace.end].to_string() ), left_brace.line, left_brace.column, self.text[left_brace.line_start..left_brace.end].to_string(), )); } } pub fn expression_statement(&mut self) -> Result { let expression = self.expression()?; if self.current >= self.input.len() { let last = self.input.last().unwrap(); return Err(KabelError::new( ErrorKind::UnexpectedEof, "Unexpected end of file, expected ;".to_string(), expression.line, last.column, self.text[last.line_start..expression.end].to_string(), )); } let semicolon = self.read_token()?; if let TokenType::Semicolon = semicolon.token_type { return Ok(expression); } else { self.current -= 1; return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected ; found {}", self.text[semicolon.start..semicolon.end].to_string() ), semicolon.line, semicolon.column, self.text[semicolon.line_start..semicolon.end].to_string(), )); } } pub fn expression(&mut self) -> Result { if let TokenType::Ident(name) = self.peek()?.token_type { if name == "var" { return self.declaration(); } } let assignment = self.assignment()?; Ok(assignment) } pub fn declaration(&mut self) -> Result { let var = self.read_token()?; let ident = self.read_token()?; if let TokenType::Ident(name) = ident.token_type { let equal = self.read_token()?; if let TokenType::Equal = equal.token_type { let expr = self.expression()?; return Ok(AST { ast_type: ASTType::Decl( Box::new(lit!(Ident, name, ident)), Box::new(expr.clone()), ), start: var.start, end: expr.end, line: var.line, column: var.column, }); } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected equals, found {}", self.text[equal.start..equal.end].to_string() ), equal.line, equal.column, self.text[equal.line_start..equal.end].to_string(), )); } } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Expected identifier, found {}", self.text[ident.start..ident.end].to_string() ), ident.line, ident.column, self.text[ident.line_start..ident.end].to_string(), )); } } pub fn assignment(&mut self) -> Result { if let TokenType::Ident(name) = self.peek()?.token_type { let ident = self.read_token()?; if self.current >= self.input.len() { self.current -= 1; return self.logical_or(); } if self.peek()?.token_type == TokenType::Equal { self.read_token()?; let expr = self.assignment()?; return Ok(AST { ast_type: ASTType::Binary( Box::new(lit!(Ident, name, ident)), BinOp::Assign, Box::new(expr.clone()), ), start: ident.start, end: expr.end, line: ident.line, column: ident.column, }); } self.current -= 1; return self.logical_or(); } return self.logical_or(); } pub fn logical_or(&mut self) -> Result { let mut left = self.logical_and()?; while self.current < self.input.len() && self.peek()?.token_type == TokenType::OrOr { self.read_token()?; let right = self.logical_and()?; left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::Or, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } Ok(left) } pub fn logical_and(&mut self) -> Result { let mut left = self.equality()?; while self.current < self.input.len() && self.peek()?.token_type == TokenType::AndAnd { self.read_token()?; let right = self.equality()?; left = AST { ast_type: ASTType::Binary( Box::new(left.clone()), BinOp::And, Box::new(right.clone()), ), start: left.start, end: right.end, line: left.line, column: left.column, }; } Ok(left) } 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(ref ident) => { if self.current < self.input.len() { if let TokenType::LeftParen = self.peek()?.token_type { return self.call(token); } if let TokenType::Period = self.peek()?.token_type { return self.member(token); } } return Ok(AST { ast_type: ASTType::Lit(Lit::Ident(ident.clone())), start: token.start, end: token.end, line: token.line, column: token.column, }); } TokenType::Num(num) => { return Ok(AST { ast_type: ASTType::Lit(Lit::Num(num)), start: token.start, end: token.end, line: token.line, column: token.column, }); } TokenType::Str(string) => { return Ok(AST { ast_type: ASTType::Lit(Lit::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 member(&mut self, ident: Token) -> Result { if let TokenType::Ident(first) = ident.token_type { let mut expr: AST = lit!(Ident, first, ident); while self.peek()?.token_type == TokenType::Period { self.read_token()?; let child = self.read_token()?; if let TokenType::Ident(child_str) = child.clone().token_type { if self.current < self.input.len() { if let TokenType::LeftParen = self.peek()?.token_type { let call = self.call(child)?; expr = AST { ast_type: ASTType::Member( Box::new(expr.clone()), Box::new(call.clone()), ), start: expr.start, end: call.end, line: expr.line, column: expr.column, }; if self.current >= self.input.len() { break; } continue; } } expr = AST { ast_type: ASTType::Member( Box::new(expr.clone()), Box::new(lit!(Ident, child_str, child)), ), start: expr.start, end: child.end, line: expr.line, column: expr.column, }; } else { return Err(KabelError::new( ErrorKind::UnexpectedToken, format!( "Unexpected token {}", self.text[child.start..child.end].to_string() ), child.line, child.column, self.text[child.line_start..child.end].to_string(), )); } if self.current >= self.input.len() { break; } } return Ok(expr); } panic!("Bad member logic"); } pub fn call(&mut self, ident: Token) -> Result { self.read_token()?; let mut expressions = Vec::new(); while self.peek()?.token_type != TokenType::RightParen { expressions.push(self.expression()?); if let TokenType::Comma = self.peek()?.token_type { self.read_token()?; } } let right_paren = self.read_token()?; if let TokenType::Ident(name) = ident.token_type { return Ok(AST { ast_type: ASTType::Call(Box::new(lit!(Ident, name, ident)), expressions), start: ident.start, end: right_paren.end, line: ident.start, column: ident.column, }); } panic!("Call logic broke"); } 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), If(Box, Box, Option>), Block(Vec), Decl(Box, Box), Binary(Box, BinOp, Box), Unary(UnOp, Box), Group(Box), Lit(Lit), Call(Box, Vec), Member(Box, Box), } #[derive(Debug, Clone)] pub enum Lit { Ident(String), Num(f32), Str(String), } #[derive(Debug, Clone, Copy)] pub enum BinOp { Add, Sub, Mul, Div, Eq, Ne, Gr, Ge, Ls, Le, Or, And, Assign, } #[derive(Debug, Clone, Copy)] pub enum UnOp { Not, Neg, }