parser: support else statements

This commit is contained in:
Domantas 2022-07-26 12:48:37 +02:00
parent 61c76ad49a
commit be71eff76c
3 changed files with 44 additions and 8 deletions

7
phpast/samples/if.php Normal file
View File

@ -0,0 +1,7 @@
<?php
if($foo) {
return $foo;
} else {
return $foo;
}

View File

@ -170,6 +170,7 @@ pub enum Statement {
If {
condition: Expression,
then: Block,
r#else: Option<Block>
},
Return {
value: Option<Expression>,

View File

@ -354,7 +354,22 @@ impl Parser {
expect!(self, TokenKind::RightBrace, "expected }");
}
Statement::If { condition, then }
if self.current.kind != TokenKind::Else {
return Ok(Statement::If { condition, then, r#else: None });
}
expect!(self, TokenKind::Else, "expected else");
expect!(self, TokenKind::LeftBrace, "expected {");
let mut r#else = Block::new();
while ! self.is_eof() && self.current.kind != TokenKind::RightBrace {
r#else.push(self.statement()?);
}
expect!(self, TokenKind::RightBrace, "expected }");
Statement::If { condition, then, r#else: Some(r#else) }
},
TokenKind::Class => self.class()?,
TokenKind::Echo => {
@ -1117,6 +1132,7 @@ mod tests {
then: vec![
Statement::Return { value: Some(Expression::Variable("n".into())) }
],
r#else: None
},
Statement::Return {
value: Some(Expression::Infix(
@ -1149,16 +1165,28 @@ mod tests {
#[test]
fn one_liner_if_statement() {
assert_ast("\
<?php
if($name)
return $name;", &[
assert_ast("<?php if($foo) return $foo;", &[
Statement::If {
condition: Expression::Variable("name".into()),
condition: Expression::Variable("foo".into()),
then: vec![
Statement::Return { value: Some(Expression::Variable("name".into())) }
Statement::Return { value: Some(Expression::Variable("foo".into())) }
],
r#else: None
},
]);
}
#[test]
fn if_else_statement() {
assert_ast("<?php if($foo) { return $foo; } else { return $foo; }", &[
Statement::If {
condition: Expression::Variable("foo".into()),
then: vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) }
],
r#else: Some(vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) }
])
},
]);
}