diff --git a/plang2/src/main.rs b/plang2/src/main.rs index 9265cb1..8ecccc3 100644 --- a/plang2/src/main.rs +++ b/plang2/src/main.rs @@ -4,7 +4,7 @@ use plang2_lib::*; fn main() { let code = r#" - (-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30 + a = 54 * sqrt(9); "#; let mut lexer = Lexer::new(code); diff --git a/plang2_lib/src/ast.rs b/plang2_lib/src/ast.rs index 5e55fa0..ba5462e 100644 --- a/plang2_lib/src/ast.rs +++ b/plang2_lib/src/ast.rs @@ -31,4 +31,11 @@ pub enum Expr { FnCall(FnCall), BinOp(BinOpType, Box, Box), UnOp(UnOpType, Box), -} \ No newline at end of file +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Statement { + Expr(Expr), + LetBinding(String, Expr), + Assignment(String, Expr), +} diff --git a/plang2_lib/src/parser.rs b/plang2_lib/src/parser.rs index b11cdda..dc4d2e4 100644 --- a/plang2_lib/src/parser.rs +++ b/plang2_lib/src/parser.rs @@ -1,6 +1,6 @@ use crate::{ - ast::{BinOpType, Expr, FnCall, UnOpType}, - token::{Group, Op, Token, TokenStream}, + ast::{BinOpType, Expr, FnCall, Statement, UnOpType}, + token::{Group, Keyword, Op, Token, TokenStream}, }; #[derive(Debug)] @@ -13,15 +13,22 @@ pub struct Parser { } /* -GRAMMAR +# GRAMMAR +## expressions -expr_literal = Literal -expr_fn_call = FnCall -expr_varibale = Variable +ident = IDENT +expr_literal = LITERAL +expr_fn_call = ident "(" expr_add? ( "," expr_add )* ")" +expr_varibale = ident expr_value = expr_literal | expr_fn_call | expr_variable expr_term = "-" expr_term | "(" expr_add ")" | expr_literal expr_mul = expr_term (("*"|"/") expr_term)* expr_add = expr_mul (("+"|"-") expr_mul)* + +## statements +stmt_let = "let" ident "=" expr_add +stmt_assign = ident "=" expr_add +stmt = ( stmt_let | stmt_assign | expr_add ) ";" */ impl Parser { @@ -41,8 +48,62 @@ impl Parser { self.tokens.advance() } - pub fn parse(&mut self) -> PRes { - self.parse_expr_add() + pub fn parse(&mut self) -> PRes { + self.parse_statement() + } + + pub fn parse_statement(&mut self) -> PRes { + let stmt = match self.curr() { + Some(Token::Keyword(Keyword::Let)) => self.parse_stmt_let(), + Some(Token::Ident(_)) if matches!(self.peek(), Some(Token::Op(Op::Assign))) => { + self.parse_stmt_assign() + } + _ => self.parse_expr_add().map(|expr| Statement::Expr(expr)), + }; + + if !matches!(self.advance(), Some(Token::Semicolon)) { + panic!("Expected ';' while parsing statement"); + } + + stmt + } + + pub fn parse_stmt_let(&mut self) -> PRes { + if !matches!(self.advance(), Some(Token::Keyword(Keyword::Let))) { + panic!("Unexpected token while parsing let statement. Expected 'let'"); + } + + let var_name = match self.advance() { + Some(Token::Ident(ident)) => ident.clone(), + _ => panic!("Unexpected token while parsing let statement. Expected ident"), + }; + + if !matches!(self.advance(), Some(Token::Op(Op::Assign))) { + panic!("Unexpected token while parsing let statement. Expected '='"); + } + + let rhs = self.parse_expr_add()?; + + let let_binding = Statement::LetBinding(var_name, rhs); + + Ok(let_binding) + } + + pub fn parse_stmt_assign(&mut self) -> PRes { + let var_name = match self.advance() { + Some(Token::Ident(ident)) => ident.clone(), + _ => panic!("Unexpected token while parsing assignment statement. Expected ident"), + }; + + if !matches!(self.advance(), Some(Token::Op(Op::Assign))) { + panic!("Unexpected token while parsing let assignment. Expected '='"); + } + + let rhs = self.parse_expr_add()?; + + let let_binding = Statement::Assignment(var_name, rhs); + + Ok(let_binding) } pub fn parse_expr_add(&mut self) -> PRes { @@ -94,7 +155,7 @@ impl Parser { self.advance(); let a = self.parse_expr_add()?; if !matches!(self.advance(), Some(Token::Close(Group::Paren))) { - panic!("Missing closing parentheses"); + panic!("Missing closing parentheses while parsing term"); } a } @@ -114,7 +175,7 @@ impl Parser { self.parse_expr_fn_call() } Some(Token::Ident(_)) => self.parse_expr_varibale(), - _ => panic!("Expected value (literal, variable or function call)"), + _ => panic!("Expected value (literal, variable or function call) while parsing value"), } } @@ -181,34 +242,34 @@ mod tests { // (-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30 let input_toks = vec![ - Token::Open(Group::Paren), // ( - Token::Op(Op::Sub), // - - Token::Open(Group::Paren), // ( - Token::Op(Op::Sub), // - - Token::Literal(Literal::Int64(5)), // 5 - Token::Op(Op::Add), // + - Token::Literal(Literal::Int64(2)), // 2 - Token::Close(Group::Paren), // ) - Token::Op(Op::Mul), // * - Token::Op(Op::Sub), // - - Token::Open(Group::Paren), // ( - Token::Literal(Literal::Int64(2)), // 2 - Token::Op(Op::Mul), // * - Token::Op(Op::Sub), // - - Token::Ident(fn_name.clone()), // sqrt - Token::Open(Group::Paren), // ( - Token::Literal(Literal::Int64(9)), // 9 - Token::Close(Group::Paren), // ) - Token::Close(Group::Paren), // ) - Token::Op(Op::Add), // + - Token::Op(Op::Sub), // - - Token::Open(Group::Paren), // ( - Token::Ident(var_name.clone()), // a - Token::Op(Op::Sub), // - - Token::Literal(Literal::Int64(6)), // 6 - Token::Close(Group::Paren), // ) - Token::Close(Group::Paren), // ) - Token::Op(Op::Mod), // % + Token::Open(Group::Paren), // ( + Token::Op(Op::Sub), // - + Token::Open(Group::Paren), // ( + Token::Op(Op::Sub), // - + Token::Literal(Literal::Int64(5)), // 5 + Token::Op(Op::Add), // + + Token::Literal(Literal::Int64(2)), // 2 + Token::Close(Group::Paren), // ) + Token::Op(Op::Mul), // * + Token::Op(Op::Sub), // - + Token::Open(Group::Paren), // ( + Token::Literal(Literal::Int64(2)), // 2 + Token::Op(Op::Mul), // * + Token::Op(Op::Sub), // - + Token::Ident(fn_name.clone()), // sqrt + Token::Open(Group::Paren), // ( + Token::Literal(Literal::Int64(9)), // 9 + Token::Close(Group::Paren), // ) + Token::Close(Group::Paren), // ) + Token::Op(Op::Add), // + + Token::Op(Op::Sub), // - + Token::Open(Group::Paren), // ( + Token::Ident(var_name.clone()), // a + Token::Op(Op::Sub), // - + Token::Literal(Literal::Int64(6)), // 6 + Token::Close(Group::Paren), // ) + Token::Close(Group::Paren), // ) + Token::Op(Op::Mod), // % Token::Literal(Literal::Int64(30)), // 30 ];