From 21616e272332dcf1b301302bf700f0d282d9e79f Mon Sep 17 00:00:00 2001 From: minish Date: Fri, 11 Jul 2025 03:02:03 -0400 Subject: [PATCH] if --- src/lexer.rs | 6 ++++++ src/parser.rs | 19 ++++++++++++++++--- src/parser/util.rs | 7 +++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index 480ed3d..5b3eb26 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -47,6 +47,8 @@ pub enum Token { Comma, Eol, + If, + Else, Return, Not, @@ -68,6 +70,7 @@ pub enum Token { pub enum Precedence { Min, Return, + If, Assign, Logical, Equality, @@ -86,6 +89,7 @@ impl Token { pub fn prefix_precedence(&self) -> Option { Some(match self { Token::Return => Precedence::Return, + Token::If => Precedence::If, Token::Minus | Token::Not => Precedence::NegateNot, _ => return None, }) @@ -192,6 +196,8 @@ where match word.as_str() { "return" => Token::Return, + "if" => Token::If, + "else" => Token::Else, "true" => Token::Literal(Literal::Boolean(true)), "false" => Token::Literal(Literal::Boolean(false)), "nil" => Token::Literal(Literal::Nil), diff --git a/src/parser.rs b/src/parser.rs index e39f9c5..bce2ed8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,6 +12,7 @@ pub enum Expr { // Runtime datatypes Block(Block), // Control flow + If(Box, Box, Option>), Return(Box), Call(Box, Vec), // Unary operations @@ -137,6 +138,19 @@ where Token::Minus => Expr::Negate(rhs), Token::Not => Expr::Not(rhs), Token::Return => Expr::Return(rhs), + Token::If => { + // parse the true case + let true_case = self.parse_expr(Precedence::Min, false)?; + // and maybe a false case + let false_case = matches!(self.try_peek(), Ok(Token::Else)) + .then(|| { + self.eat(); + self.parse_expr(Precedence::Min, false) + }) + .transpose()?; + // pack + Expr::If(rhs, true_case, false_case) + } _ => unreachable!(), }) } @@ -238,15 +252,14 @@ where match self.try_peek() { // end (block) Ok(Token::CurlyClose) if in_block => break, - // end (stream) lpwkey idk if this is a good way to check for error - // need to add error nodes anyway so whatever + // end (stream) Err(ParseError::UnexpectedEnd) if !in_block => break, // try to parse expr Ok(_) => exprs.push(*self.parse_expr(Precedence::Min, false)?), // invalid - Err(err) => return Err(err), + Err(_) => unreachable!(), } } Ok(Block { exprs }) diff --git a/src/parser/util.rs b/src/parser/util.rs index 25dd7a5..4b5ec9c 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -31,6 +31,13 @@ fn fmt_expr(e: Expr, depth: usize) -> String { result.push(')'); result } + Expr::If(c, t, f) => { + let mut result = format!("if ({}) ({})", fmt_expr(*c, depth), fmt_expr(*t, depth)); + if let Some(f) = f { + result.push_str(&format!(" else ({})", fmt_expr(*f, depth))); + } + result + } Expr::Return(l) => format!("return {}", fmt_expr(*l, depth)), Expr::Block(b) => { let mut result = String::new();