use crate::{error::{ErrorKind, KabelError}, lexer::{Token, TokenType}};
pub struct Parser {
input: Vec<Token>,
text: String,
//start: usize,
current: usize,
token: Token,
pub errors: Vec<KabelError>,
}
impl Parser {
pub fn new(text: String, input: Vec<Token>) -> 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<AST, KabelError> {
let term = self.term()?;
Ok(term)
}
pub fn term(&mut self) -> Result<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<Token, KabelError> {
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<Token, KabelError> {
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<AST>),
Binary(Box<AST>, BinOp, Box<AST>),
Group(Box<AST>),
Ident(String),
Num(f32),
Str(String),
}
#[derive(Debug, Clone, Copy)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
}