diff --git a/src/parser.rs b/src/parser.rs index 45c4c80..0453177 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -414,50 +414,58 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { /// Parse an expression, e.g. `1 + 2` fn parse_expression(&mut self) -> CompilationResult<'src, Expression<'src>> { if self.accepted_keyword(Keyword::If)? { - let lhs = self.parse_expression()?; - - let inverted = self.accepted(BangEquals)?; - - if !inverted { - self.expect(EqualsEquals)?; - } - - let rhs = self.parse_expression()?; - - self.expect(BraceL)?; - - let then = self.parse_expression()?; - - self.expect(BraceR)?; - - self.expect_keyword(Keyword::Else)?; - - self.expect(BraceL)?; - - let otherwise = self.parse_expression()?; - - self.expect(BraceR)?; - - return Ok(Expression::Conditional { - lhs: Box::new(lhs), - rhs: Box::new(rhs), - then: Box::new(then), - otherwise: Box::new(otherwise), - inverted, - }); - } - - let value = self.parse_value()?; - - if self.accepted(Plus)? { - let lhs = Box::new(value); - let rhs = Box::new(self.parse_expression()?); - Ok(Expression::Concatination { lhs, rhs }) + self.parse_conditional() } else { - Ok(value) + let value = self.parse_value()?; + + if self.accepted(Plus)? { + let lhs = Box::new(value); + let rhs = Box::new(self.parse_expression()?); + Ok(Expression::Concatination { lhs, rhs }) + } else { + Ok(value) + } } } + /// Parse a conditional, e.g. `if a == b { "foo" } else { "bar" }` + fn parse_conditional(&mut self) -> CompilationResult<'src, Expression<'src>> { + let lhs = self.parse_expression()?; + + let inverted = self.accepted(BangEquals)?; + + if !inverted { + self.expect(EqualsEquals)?; + } + + let rhs = self.parse_expression()?; + + self.expect(BraceL)?; + + let then = self.parse_expression()?; + + self.expect(BraceR)?; + + self.expect_keyword(Keyword::Else)?; + + let otherwise = if self.accepted_keyword(Keyword::If)? { + self.parse_conditional()? + } else { + self.expect(BraceL)?; + let otherwise = self.parse_expression()?; + self.expect(BraceR)?; + otherwise + }; + + Ok(Expression::Conditional { + lhs: Box::new(lhs), + rhs: Box::new(rhs), + then: Box::new(then), + otherwise: Box::new(otherwise), + inverted, + }) + } + /// Parse a value, e.g. `(bar)` fn parse_value(&mut self) -> CompilationResult<'src, Expression<'src>> { if self.next_is(StringToken) { diff --git a/tests/conditional.rs b/tests/conditional.rs index f1b2e22..dc346e7 100644 --- a/tests/conditional.rs +++ b/tests/conditional.rs @@ -156,3 +156,15 @@ test! { echo {{ a }} ", } + +test! { + name: if_else, + justfile: " + x := if '0' == '1' { 'a' } else if '0' == '0' { 'b' } else { 'c' } + + foo: + echo {{ x }} + ", + stdout: "b\n", + stderr: "echo b\n", +}