use crate::{
error::{ErrorKind, KabelError},
lexer::{Token, TokenType},
lit, unexpected_token,
};
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.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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST , KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<AST, KabelError> {
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<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(unexpected_token!(self, "Expected = found {}", equal));
}
} else {
return Err(unexpected_token!(
self,
"Expected identifier found {}",
ident
));
}
}
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,
});
}
}
self.subscript()
}
pub fn subscript(&mut self) -> Result<AST, KabelError> {
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<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 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<AST, KabelError> {
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<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(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<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>),
// statements
Function(Box<AST>, Vec<AST>, Box<AST>), // name, args, block
Return(Option<Box<AST>>), // expression
Loop(Box<AST>), // block
While(Box<AST>, Box<AST>), // condition, block
For(Box<Option<AST>>, Box<Option<AST>>, Box<Option<AST>>, Box<AST>), // expr1, expr2, expr3, block
Break,
Continue,
If(Box<AST>, Box<AST>, Option<Box<AST>>), // condition, block, else/else if
Block(Vec<AST>), // statements
// expressions
Decl(Box<AST>, Box<AST>), // identifier, expression
Subscript(Box<AST>, Box<AST>),
Binary(Box<AST>, BinOp, Box<AST>),
Unary(UnOp, Box<AST>),
// primary
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),
Array(Vec<AST>),
}
#[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,
}