@@ 59,6 59,14 @@ impl Lexer {
self.output.push(token!(self, TokenType::RightParen));
self.start = self.current;
}
+ b'{' => {
+ self.output.push(token!(self, TokenType::LeftBrace));
+ self.start = self.current;
+ }
+ b'}' => {
+ self.output.push(token!(self, TokenType::RightBrace));
+ self.start = self.current;
+ }
b'.' => {
self.output.push(token!(self, TokenType::Period));
self.start = self.current;
@@ 67,6 75,10 @@ impl Lexer {
self.output.push(token!(self, TokenType::Comma));
self.start = self.current;
}
+ b';' => {
+ self.output.push(token!(self, TokenType::Semicolon));
+ self.start = self.current;
+ }
b'|' => {
if self.peek() == b'|' {
self.read_char();
@@ 151,6 163,7 @@ impl Lexer {
self.line += 1;
self.line_start = self.current;
self.column = 0;
+ self.start = self.current;
}
b' ' | b'\r' | b'\t' => {
self.start = self.current;
@@ 234,8 247,11 @@ pub enum TokenType {
Minus,
LeftParen,
RightParen,
+ LeftBrace,
+ RightBrace,
Period,
Comma,
+ Semicolon,
Equal,
EqualEqual,
Bang,
@@ 1,6 1,7 @@
use crate::{
error::{ErrorKind, KabelError},
- lexer::{Token, TokenType}, lit,
+ lexer::{Token, TokenType},
+ lit,
};
pub struct Parser {
@@ 30,7 31,7 @@ impl Parser {
if self.current >= self.input.len() {
break;
}
- match self.expression() {
+ match self.statement() {
Ok(ast) => program.push(ast),
Err(e) => self.errors.push(e),
}
@@ 44,6 45,171 @@ impl Parser {
}
}
+ pub fn statement(&mut self) -> Result<AST, KabelError> {
+ 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<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(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<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(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<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(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<AST, KabelError> {
if let TokenType::Ident(name) = self.peek()?.token_type {
if name == "var" {
@@ 62,7 228,10 @@ impl Parser {
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())),
+ ast_type: ASTType::Decl(
+ Box::new(lit!(Ident, name, ident)),
+ Box::new(expr.clone()),
+ ),
start: var.start,
end: expr.end,
line: var.line,
@@ 105,7 274,11 @@ impl Parser {
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())),
+ 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,
@@ 434,7 607,10 @@ impl Parser {
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())),
+ ast_type: ASTType::Member(
+ Box::new(expr.clone()),
+ Box::new(call.clone()),
+ ),
start: expr.start,
end: call.end,
line: expr.line,
@@ 447,7 623,10 @@ impl Parser {
}
}
expr = AST {
- ast_type: ASTType::Member(Box::new(expr.clone()), Box::new(lit!(Ident, child_str, child))),
+ ast_type: ASTType::Member(
+ Box::new(expr.clone()),
+ Box::new(lit!(Ident, child_str, child)),
+ ),
start: expr.start,
end: child.end,
line: expr.line,
@@ 573,6 752,9 @@ pub struct AST {
pub enum ASTType {
Program(Vec<AST>),
+ If(Box<AST>, Box<AST>, Option<Box<AST>>),
+ Block(Vec<AST>),
+
Decl(Box<AST>, Box<AST>),
Binary(Box<AST>, BinOp, Box<AST>),
Unary(UnOp, Box<AST>),