diff --git a/src/ast.rs b/src/ast.rs index 83dc148..8018c18 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -82,6 +82,8 @@ pub enum Expression { I64(i64), /// String literal String(Rc), + + FunCall(String, Vec), /// Variable Var(String), /// Binary operation. Consists of type, left hand side and right hand side @@ -116,6 +118,7 @@ pub enum Statement { Loop(Loop), If(If), Print(Expression), + FunDecl(Vec<(String, Expression)>), } #[derive(Debug, PartialEq, Eq, Clone, Default)] diff --git a/src/interpreter.rs b/src/interpreter.rs index ddee443..70c56e3 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -68,6 +68,7 @@ impl Interpreter { self.run(body_true); } } + Statement::FunDecl(_) => todo!(), } } @@ -80,6 +81,7 @@ impl Interpreter { Expression::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, lhs, rhs), Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand), Expression::Var(name) => self.resolve_var(name), + Expression::FunCall(_, _) => todo!(), } } diff --git a/src/lexer.rs b/src/lexer.rs index 73ee243..1937d42 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -106,6 +106,7 @@ impl<'a> Lexer<'a> { '{' => tokens.push(Token::LBraces), '}' => tokens.push(Token::RBraces), '!' => tokens.push(Token::LNot), + ',' => tokens.push(Token::Comma), // Lex numbers ch @ '0'..='9' => { @@ -189,6 +190,7 @@ impl<'a> Lexer<'a> { "print" => Token::Print, "if" => Token::If, "else" => Token::Else, + "fun" => Token::Fun, // If it doesn't match a keyword, it is a normal identifier _ => Token::Ident(ident), diff --git a/src/parser.rs b/src/parser.rs index e63e04f..ff60fe4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use std::iter::Peekable; -use crate::token::Token; use crate::ast::*; +use crate::token::Token; struct Parser> { tokens: Peekable, @@ -28,14 +28,11 @@ impl> Parser { } // By default try to lex a statement - _ => { - prog.push(self.parse_stmt()) - } + _ => prog.push(self.parse_stmt()), } } Ast { prog } - } fn parse_stmt(&mut self) -> Statement { @@ -98,13 +95,17 @@ impl> Parser { } body_false = self.parse(); - + if !matches!(self.next(), Token::RBraces) { panic!("Error lexing if: Expected '}}'") } } - If { condition, body_true, body_false } + If { + condition, + body_true, + body_false, + } } fn parse_loop(&mut self) -> Loop { @@ -130,17 +131,20 @@ impl> Parser { } body = self.parse(); - }, + } - _ => panic!("Error lexing loop: Expected ';' or '{{'") + _ => panic!("Error lexing loop: Expected ';' or '{{'"), } if !matches!(self.next(), Token::RBraces) { panic!("Error lexing loop: Expected '}}'") } - Loop { condition, advancement, body } - + Loop { + condition, + advancement, + body, + } } fn parse_expr(&mut self) -> Expression { @@ -185,6 +189,8 @@ impl> Parser { // Literal String Token::String(text) => Expression::String(text.into()), + Token::Ident(name) if matches!(self.peek(), Token::LParen) => self.parse_funcall(name), + Token::Ident(name) => Expression::Var(name), // Parentheses grouping @@ -210,7 +216,7 @@ impl> Parser { let operand = self.parse_primary(); Expression::UnOp(UnOpType::BNot, operand.into()) } - + // Unary logical not Token::LNot => { let operand = self.parse_primary(); @@ -221,6 +227,24 @@ impl> Parser { } } + fn parse_funcall(&mut self, name: String) -> Expression { + let mut args = Vec::new(); + + // Consume ( + self.next(); + + while self.peek() != &Token::RParen { + args.push(self.parse_expr()); + + if self.peek() == &Token::Comma { + self.next(); + } + } + self.next(); + + Expression::FunCall(name, args) + } + /// Get the next Token without removing it fn peek(&mut self) -> &Token { self.tokens.peek().unwrap_or(&Token::EoF) @@ -265,8 +289,11 @@ impl BinOpType { #[cfg(test)] mod tests { - use super::{parse, Expression, BinOpType}; - use crate::{token::Token, parser::{Statement, Ast}}; + use super::{parse, BinOpType, Expression}; + use crate::{ + parser::{Ast, Statement}, + token::Token, + }; #[test] fn test_parser() { @@ -288,13 +315,20 @@ mod tests { Expression::BinOp( BinOpType::Add, Expression::I64(1).into(), - Expression::BinOp(BinOpType::Mul, Expression::I64(2).into(), Expression::I64(3).into()).into(), + Expression::BinOp( + BinOpType::Mul, + Expression::I64(2).into(), + Expression::I64(3).into(), + ) + .into(), ) .into(), Expression::I64(4).into(), )); - let expected = Ast { prog: vec![expected] }; + let expected = Ast { + prog: vec![expected], + }; let actual = parse(tokens); assert_eq!(expected, actual); diff --git a/src/token.rs b/src/token.rs index 19f3d3e..7796033 100644 --- a/src/token.rs +++ b/src/token.rs @@ -23,6 +23,10 @@ pub enum Token { /// Else keyword (else) Else, + Fun, + + Comma, + /// Left Parenthesis ('(') LParen,