From 6922bff15844056844e1d738494ed7b70def1fef Mon Sep 17 00:00:00 2001 From: ghostlyzsh Date: Thu, 1 Aug 2024 13:58:56 -0500 Subject: [PATCH] call, member access, declaration, and assignment --- kabel/grammar.ebnf | 18 +++-- kabel/src/lexer.rs | 10 +++ kabel/src/macros.rs | 13 +++ kabel/src/parser.rs | 193 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 216 insertions(+), 18 deletions(-) diff --git a/kabel/grammar.ebnf b/kabel/grammar.ebnf index dcee8e1dadee005aa99e14ae96dc043da4a06618..8b8346bcc8dcb8ac4c62dc7ca8c2bd15bea5d313 100644 --- a/kabel/grammar.ebnf +++ b/kabel/grammar.ebnf @@ -2,19 +2,23 @@ program = { statement } ; statement = if | while | ( expression , ";" ) ; -while = "while" , expression , block ; +function = "function" , identifier , "(" , { identifier , "," , } ")" , block -if = "if" , expression , block ; +loop = "loop" , block ; + +while = "while" , "(" , expression , ")" , block ; + +if = "if" , "(" , expression , ")" , block [ , "else" , ( if | block ) ] ; block = "{" , { statement } , "}" ; +(* implemented *) expression = assignment | declaration ; declaration = "var" , identifier , "=" , expression ; -assignment = { identifier , "=" , } logical_or ; +assignment = ( identifier , "=" , assignment ) | logical_or; -(* implemented *) logical_or = logical_and { , "||" , logical_and } ; logical_and = equality { , "&&" , equality } ; @@ -29,7 +33,11 @@ factor = unary { , ( "*" | "/" ) , unary } ; unary = ( ( "!" | "-" ) , unary ) | primary ; -primary = identifier | number | string | group ; +primary = identifier | member | call | number | string | group ; + +member = identifier , "." , { ( identifier | call ) , "." ? } ; + +call = ( identifier , "(" , { expression, "," ? } , ")" ) ; group = "(" , expression , ")" ; diff --git a/kabel/src/lexer.rs b/kabel/src/lexer.rs index 4cdc4ee0528c33f6c408b47676f2eac4e2b1ed6b..d3c792556f4bb1e105fbc25a859d75e1743b76bb 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::Period)); + self.start = self.current; + } + b',' => { + self.output.push(token!(self, TokenType::Comma)); + self.start = self.current; + } b'|' => { if self.peek() == b'|' { self.read_char(); @@ -226,6 +234,8 @@ pub enum TokenType { Minus, LeftParen, RightParen, + Period, + Comma, Equal, EqualEqual, Bang, diff --git a/kabel/src/macros.rs b/kabel/src/macros.rs index 85a715ab8f99d00705c7241284311a8a056fc4fb..a408b6f43e15525445d6eae6f4670eed2ae5cf81 100644 --- a/kabel/src/macros.rs +++ b/kabel/src/macros.rs @@ -11,3 +11,16 @@ macro_rules! token { } }; } + +#[macro_export] +macro_rules! lit { + ($type:ident, $data:expr, $token:expr) => { + $crate::parser::AST { + ast_type: $crate::parser::ASTType::Lit($crate::parser::Lit::$type($data)), + start: $token.start, + end: $token.end, + line: $token.line, + column: $token.column, + } + } +} diff --git a/kabel/src/parser.rs b/kabel/src/parser.rs index e2d21fcf0a81dc06bc003bdfae5ab032ec89863f..975d4b6e9da3802e0a7ac32b51102a34162c82e8 100644 --- a/kabel/src/parser.rs +++ b/kabel/src/parser.rs @@ -1,6 +1,6 @@ use crate::{ error::{ErrorKind, KabelError}, - lexer::{Token, TokenType}, + lexer::{Token, TokenType}, lit, }; pub struct Parser { @@ -45,19 +45,92 @@ impl Parser { } pub fn expression(&mut self) -> Result { - let equality = self.logical_or()?; - Ok(equality) + 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 { + 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 { + 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 { let mut left = self.logical_and()?; - while self.current < self.input.len() - && self.peek()?.token_type == TokenType::OrOr { + 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())), + ast_type: ASTType::Binary( + Box::new(left.clone()), + BinOp::Or, + Box::new(right.clone()), + ), start: left.start, end: right.end, line: left.line, @@ -70,12 +143,15 @@ impl Parser { pub fn logical_and(&mut self) -> Result { let mut left = self.equality()?; - while self.current < self.input.len() - && self.peek()?.token_type == TokenType::AndAnd { + 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())), + ast_type: ASTType::Binary( + Box::new(left.clone()), + BinOp::And, + Box::new(right.clone()), + ), start: left.start, end: right.end, line: left.line, @@ -294,9 +370,17 @@ impl Parser { let token = self.read_token()?; match token.token_type { - TokenType::Ident(ident) => { + 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::Ident(ident), + ast_type: ASTType::Lit(Lit::Ident(ident.clone())), start: token.start, end: token.end, line: token.line, @@ -305,7 +389,7 @@ impl Parser { } TokenType::Num(num) => { return Ok(AST { - ast_type: ASTType::Num(num), + ast_type: ASTType::Lit(Lit::Num(num)), start: token.start, end: token.end, line: token.line, @@ -314,7 +398,7 @@ impl Parser { } TokenType::Str(string) => { return Ok(AST { - ast_type: ASTType::Str(string), + ast_type: ASTType::Lit(Lit::Str(string)), start: token.start, end: token.end, line: token.line, @@ -338,6 +422,80 @@ impl Parser { } } } + + pub fn member(&mut self, ident: Token) -> Result { + 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 { + 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 { let expr = self.expression()?; let right_paren = self.peek(); @@ -415,10 +573,18 @@ pub struct AST { pub enum ASTType { Program(Vec), + Decl(Box, Box), Binary(Box, BinOp, Box), Unary(UnOp, Box), Group(Box), + Lit(Lit), + Call(Box, Vec), + Member(Box, Box), +} + +#[derive(Debug, Clone)] +pub enum Lit { Ident(String), Num(f32), Str(String), @@ -438,6 +604,7 @@ pub enum BinOp { Le, Or, And, + Assign, } #[derive(Debug, Clone, Copy)]