use crate::{ error::{ErrorKind, KabelError}, lexer::{Token, TokenType}, lit, unexpected_token, }; 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() { "function" => self.function_statement(), "return" => self.return_statement(), "loop" => self.loop_statement(), "while" => self.while_statement(), "for" => self.for_statement(), "break" => self.break_statement(), "continue" => self.continue_statement(), "if" => self.if_statement(), _ => self.expression_statement(), }, _ => self.expression_statement(), } } pub fn function_statement(&mut self) -> Result { let function_ident = self.read_token()?; let ident = self.read_token()?; if let TokenType::Ident(name) = ident.token_type { let left_paren = self.read_token()?; if let TokenType::LeftParen = left_paren.token_type { 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::RightParen = right_paren.token_type { let block = self.block()?; return Ok(AST { ast_type: ASTType::Function( Box::new(lit!(Ident, name, ident)), expressions, Box::new(block.clone()), ), start: function_ident.start, end: block.end, line: function_ident.line, column: function_ident.column, }); } else { return Err(unexpected_token!(self, "Expected ) found {}", right_paren)); } } else { return Err(unexpected_token!(self, "Expected ( found {}", left_paren)); } } else { return Err(unexpected_token!( self, "Expected identifier found {}", ident )); } } pub fn return_statement(&mut self) -> Result { let return_ident = self.read_token()?; if let TokenType::Semicolon = self.peek()?.token_type { let semicolon = self.read_token()?; return Ok(AST { ast_type: ASTType::Return(None), start: return_ident.start, end: semicolon.end, line: return_ident.line, column: return_ident.column, }); } let expression = self.expression()?; let semicolon = self.read_token()?; if let TokenType::Semicolon = semicolon.token_type { Ok(AST { ast_type: ASTType::Return(Some(Box::new(expression))), start: return_ident.start, end: semicolon.end, line: return_ident.line, column: return_ident.column, }) } else { return Err(unexpected_token!(self, "Expected ; found {}", semicolon)); } } pub fn loop_statement(&mut self) -> Result { let loop_ident = self.read_token()?; let block = self.block()?; Ok(AST { ast_type: ASTType::Loop(Box::new(block.clone())), start: loop_ident.start, end: block.end, line: loop_ident.line, column: loop_ident.column, }) } pub fn while_statement(&mut self) -> Result { let while_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()?; return Ok(AST { ast_type: ASTType::While(Box::new(condition), Box::new(block.clone())), start: while_ident.start, end: block.end, line: while_ident.line, column: while_ident.column, }); } else { return Err(unexpected_token!(self, "Expected ) found {}", right_paren)); } } else { return Err(unexpected_token!(self, "Expected ( found {}", left_paren)); } } pub fn for_statement(&mut self) -> Result { let for_ident = self.read_token()?; let left_paren = self.read_token()?; if let TokenType::LeftParen = left_paren.token_type { let expression1; if let TokenType::Semicolon = self.peek()?.token_type { expression1 = None; } else { expression1 = Some(self.expression()?); } let semicolon = self.read_token()?; if let TokenType::Semicolon = semicolon.token_type { let expression2; if let TokenType::Semicolon = self.peek()?.token_type { expression2 = None; } else { expression2 = Some(self.expression()?); } let semicolon = self.read_token()?; if let TokenType::Semicolon = semicolon.token_type { let expression3; if let TokenType::RightParen = self.peek()?.token_type { expression3 = None; } else { expression3 = Some(self.expression()?); } let right_paren = self.read_token()?; if let TokenType::RightParen = right_paren.token_type { let block = self.block()?; return Ok(AST { ast_type: ASTType::For(Box::new(expression1), Box::new(expression2), Box::new(expression3), Box::new(block.clone())), start: for_ident.start, end: block.end, line: for_ident.line, column: for_ident.column, }); } else { return Err(unexpected_token!(self, "Expected ) found {}", right_paren)); } } else { return Err(unexpected_token!(self, "Expected ; found {}", semicolon)); } } else { return Err(unexpected_token!(self, "Expected ; found {}", semicolon)); } } else { return Err(unexpected_token!(self, "Expected ( found {}", left_paren)); } } pub fn break_statement(&mut self) -> Result { let break_ident = self.read_token()?; let semicolon = self.read_token()?; if let TokenType::Semicolon = semicolon.token_type { Ok(AST { ast_type: ASTType::Break, start: break_ident.start, end: semicolon.end, line: break_ident.line, column: break_ident.column, }) } else { Err(unexpected_token!(self, "Expected ; found {}", semicolon)) } } pub fn continue_statement(&mut self) -> Result { let continue_ident = self.read_token()?; let semicolon = self.read_token()?; if let TokenType::Semicolon = semicolon.token_type { Ok(AST { ast_type: ASTType::Continue, start: continue_ident.start, end: semicolon.end, line: continue_ident.line, column: continue_ident.column, }) } else { Err(unexpected_token!(self, "Expected ; found {}", semicolon)) } } 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(unexpected_token!( self, "Expected if found {}", else_if_ident )); } } return Err(unexpected_token!(self, "Unexpected token {}", else_ident)); } 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(unexpected_token!(self, "Expected ) found {}", right_paren)); } } else { return Err(unexpected_token!(self, "Expected ( found {}", left_paren)); } } 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(unexpected_token!(self, "Expected {{ found {}", left_brace)); } } 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(unexpected_token!(self, "Expected ; found {}", semicolon)); } } 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(unexpected_token!(self, "Expected = found {}", equal)); } } else { return Err(unexpected_token!( self, "Expected identifier found {}", ident )); } } 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, }); } } self.subscript() } pub fn subscript(&mut self) -> Result { let mut primary = self.primary()?; while self.current < self.input.len() && self.peek()?.token_type == TokenType::LeftSquare { self.read_token()?; let expr = self.expression()?; let right_brace = self.read_token()?; if let TokenType::RightSquare = right_brace.token_type { primary = AST { ast_type: ASTType::Subscript(Box::new(primary.clone()), Box::new(expr)), start: primary.start, end: right_brace.end, line: primary.line, column: primary.column, }; } else { return Err(unexpected_token!(self, "Expected ] found {}", right_brace)); } } Ok(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 self.group(token); } TokenType::LeftSquare => { return self.array(token); } _ => { return Err(unexpected_token!(self, "Unexpected token {}", token)); } } } pub fn array(&mut self, left_square: Token) -> Result { let mut expressions = Vec::new(); while self.peek()?.token_type != TokenType::RightSquare { expressions.push(self.expression()?); if let TokenType::Comma = self.peek()?.token_type { self.read_token()?; } } let right_square = self.read_token()?; Ok(AST { ast_type: ASTType::Lit(Lit::Array(expressions)), start: left_square.start, end: right_square.end, line: left_square.line, column: left_square.column, }) } 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(unexpected_token!(self, "Unexpected token {}", child)); } 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), // statements Function(Box, Vec, Box), // name, args, block Return(Option>), // expression Loop(Box), // block While(Box, Box), // condition, block For(Box>, Box>, Box>, Box), // expr1, expr2, expr3, block Break, Continue, If(Box, Box, Option>), // condition, block, else/else if Block(Vec), // statements // expressions Decl(Box, Box), // identifier, expression Subscript(Box, Box), Binary(Box, BinOp, Box), Unary(UnOp, Box), // primary Group(Box), Lit(Lit), Call(Box, Vec), Member(Box, Box), } #[derive(Debug, Clone)] pub enum Lit { Ident(String), Num(f32), Str(String), Array(Vec), } #[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, }