use crate::{
error::{ErrorKind, KabelError},
lexer::{Token, TokenType}, lit,
};
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),
}
}
AST {
ast_type: ASTType::Program(program),
start: 0,
end: 0,
line: 0,
column: 0,
}
}
pub fn expression(&mut self) -> Result<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<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.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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<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>),
Decl(Box<AST>, Box<AST>),
Binary(Box<AST>, BinOp, Box<AST>),
Unary(UnOp, Box<AST>),
Group(Box<AST>),
Lit(Lit),
Call(Box<AST>, Vec<AST>),
Member(Box<AST>, Box<AST>),
}
#[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,
}