From d593bc7063de0d9edc1353c7718050598966602e Mon Sep 17 00:00:00 2001 From: ghostlyzsh Date: Thu, 1 Aug 2024 19:26:00 -0500 Subject: [PATCH] if statement --- kabel/grammar.ebnf | 2 +- kabel/src/lexer.rs | 16 ++++ kabel/src/macros.rs | 2 +- kabel/src/parser.rs | 194 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 206 insertions(+), 8 deletions(-) diff --git a/kabel/grammar.ebnf b/kabel/grammar.ebnf index 8b8346bcc8dcb8ac4c62dc7ca8c2bd15bea5d313..99d3143806298470108356e22d6aafe18dc9c31b 100644 --- a/kabel/grammar.ebnf +++ b/kabel/grammar.ebnf @@ -8,11 +8,11 @@ loop = "loop" , block ; while = "while" , "(" , expression , ")" , block ; +(* implemented *) if = "if" , "(" , expression , ")" , block [ , "else" , ( if | block ) ] ; block = "{" , { statement } , "}" ; -(* implemented *) expression = assignment | declaration ; declaration = "var" , identifier , "=" , expression ; diff --git a/kabel/src/lexer.rs b/kabel/src/lexer.rs index d3c792556f4bb1e105fbc25a859d75e1743b76bb..56973153c5b8f5e7254020acc36390e4cc7382e3 100644 --- a/kabel/src/lexer.rs +++ b/kabel/src/lexer.rs @@ -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, diff --git a/kabel/src/macros.rs b/kabel/src/macros.rs index a408b6f43e15525445d6eae6f4670eed2ae5cf81..35012ac73aa5112f59dbd272bd02d3aac781070d 100644 --- a/kabel/src/macros.rs +++ b/kabel/src/macros.rs @@ -22,5 +22,5 @@ macro_rules! lit { line: $token.line, column: $token.column, } - } + }; } diff --git a/kabel/src/parser.rs b/kabel/src/parser.rs index 975d4b6e9da3802e0a7ac32b51102a34162c82e8..07e7c8d7e42097f6c75bbe18c9ffecd926ce4926 100644 --- a/kabel/src/parser.rs +++ b/kabel/src/parser.rs @@ -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 { + 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 { + 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 { + 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 { + 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 { 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), + If(Box, Box, Option>), + Block(Vec), + Decl(Box, Box), Binary(Box, BinOp, Box), Unary(UnOp, Box),