From 7b6fc89fb7e0f2efe300a93a58be4098fec89e21 Mon Sep 17 00:00:00 2001 From: Daniel M Date: Wed, 2 Feb 2022 16:19:46 +0100 Subject: [PATCH] Implement if --- src/interpreter.rs | 18 +++++++++---- src/lexer.rs | 8 ++++++ src/parser.rs | 66 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 2587939..694752c 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, fmt::Display}; -use crate::{parser::{Expression, BinOpType, UnOpType, Ast, Statement, parse}, lexer::lex}; +use crate::{parser::{Expression, BinOpType, UnOpType, Ast, Statement, parse, If}, lexer::lex}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Value { @@ -40,16 +40,16 @@ impl Interpreter { self.resolve_expr(expr); } - Statement::Loop(lop) => { + Statement::Loop(looop) => { // loop runs as long condition != 0 loop { - if matches!(self.resolve_expr(lop.condition.clone()), Value::I64(0)) { + if matches!(self.resolve_expr(looop.condition.clone()), Value::I64(0)) { break; } - self.run(lop.body.clone()); + self.run(looop.body.clone()); - if let Some(adv) = &lop.advancement { + if let Some(adv) = &looop.advancement { self.resolve_expr(adv.clone()); } } @@ -59,6 +59,14 @@ impl Interpreter { let result = self.resolve_expr(expr); println!("{}", result); } + + Statement::If(If {condition, body_true, body_false}) => { + if matches!(self.resolve_expr(condition.clone()), Value::I64(0)) { + self.run(body_false.clone()); + } else { + self.run(body_true.clone()); + } + } } } diff --git a/src/lexer.rs b/src/lexer.rs index f5fb1b4..a746dfb 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -16,6 +16,12 @@ pub enum Token { /// Print keyword (print) Print, + /// If keyword (if) + If, + + /// Else keyword (else) + Else, + /// Left Parenthesis ('(') LParen, @@ -204,6 +210,8 @@ impl<'a> Lexer<'a> { let token = match ident.as_str() { "loop" => Token::Loop, "print" => Token::Print, + "if" => Token::If, + "else" => Token::Else, _ => Token::Ident(ident), }; diff --git a/src/parser.rs b/src/parser.rs index 244e564..dbb42a6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -92,13 +92,24 @@ pub struct Loop { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Statement { - Expr(Expression), - Loop(Loop), - Print(Expression), +pub struct If { + /// The condition + pub condition: Expression, + /// The body that is executed when condition is true + pub body_true: Ast, + /// The if body that is executed when the condition is false + pub body_false: Ast, } #[derive(Debug, PartialEq, Eq, Clone)] +pub enum Statement { + Expr(Expression), + Loop(Loop), + If(If), + Print(Expression), +} + +#[derive(Debug, PartialEq, Eq, Clone, Default)] pub struct Ast { pub prog: Vec } @@ -124,7 +135,6 @@ impl> Parser { } Token::EoF => break, Token::RBraces => { - self.next(); break; } @@ -156,6 +166,8 @@ impl> Parser { Statement::Print(expr) } + Token::If => Statement::If(self.parse_if()), + // If it is not a loop, try to lex as an expression _ => { let stmt = Statement::Expr(self.parse_expr()); @@ -170,11 +182,41 @@ impl> Parser { } } - // loop i < 1_000; i = i +1 { - // if i % 3 == 0 | i % 5 == 0 { - // sum = sum + i; - // } - // } + fn parse_if(&mut self) -> If { + if !matches!(self.next(), Token::If) { + panic!("Error lexing if: Expected if token"); + } + + let condition = self.parse_expr(); + + if !matches!(self.next(), Token::LBraces) { + panic!("Error lexing if: Expected '{{'") + } + + let body_true = self.parse(); + + if !matches!(self.next(), Token::RBraces) { + panic!("Error lexing if: Expected '}}'") + } + + let mut body_false = Ast::default(); + + if matches!(self.peek(), Token::Else) { + self.next(); + + if !matches!(self.next(), Token::LBraces) { + panic!("Error lexing if: Expected '{{'") + } + + body_false = self.parse(); + + if !matches!(self.next(), Token::RBraces) { + panic!("Error lexing if: Expected '}}'") + } + } + + If { condition, body_true, body_false } + } fn parse_loop(&mut self) -> Loop { if !matches!(self.next(), Token::Loop) { @@ -204,6 +246,10 @@ impl> Parser { _ => panic!("Error lexing loop: Expected ';' or '{{'") } + if !matches!(self.next(), Token::RBraces) { + panic!("Error lexing loop: Expected '}}'") + } + Loop { condition, advancement, body } }