From ba3ae0ee069866b119646ca0bfc771ef377ebc5c Mon Sep 17 00:00:00 2001 From: Domantas Date: Tue, 26 Jul 2022 14:39:22 +0200 Subject: [PATCH 1/2] parser: support else if statements --- phpast/samples/if.php | 4 ++++ trunk_parser/src/ast.rs | 7 +++++++ trunk_parser/src/parser/mod.rs | 35 +++++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/phpast/samples/if.php b/phpast/samples/if.php index 7c55694..bdee8d8 100644 --- a/phpast/samples/if.php +++ b/phpast/samples/if.php @@ -2,6 +2,10 @@ if($foo) { return $foo; +} elseif($foo) { + return $foo; +} elseif($foo) { + return $foo; } else { return $foo; } \ No newline at end of file diff --git a/trunk_parser/src/ast.rs b/trunk_parser/src/ast.rs index 765cc1b..4ad0a5a 100644 --- a/trunk_parser/src/ast.rs +++ b/trunk_parser/src/ast.rs @@ -176,6 +176,7 @@ pub enum Statement { If { condition: Expression, then: Block, + else_ifs: Vec, r#else: Option }, Return { @@ -271,4 +272,10 @@ impl From for InfixOp { _ => unreachable!() } } +} + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct ElseIf { + pub condition: Expression, + pub body: Block, } \ No newline at end of file diff --git a/trunk_parser/src/parser/mod.rs b/trunk_parser/src/parser/mod.rs index ed5984b..e89b7ee 100644 --- a/trunk_parser/src/parser/mod.rs +++ b/trunk_parser/src/parser/mod.rs @@ -1,6 +1,6 @@ use std::{vec::IntoIter, fmt::{Display}}; use trunk_lexer::{Token, TokenKind, Span}; -use crate::{Program, Statement, Block, Expression, ast::{ArrayItem, Use, MethodFlag, ClassFlag}, Identifier, Type, Param}; +use crate::{Program, Statement, Block, Expression, ast::{ArrayItem, Use, MethodFlag, ClassFlag, ElseIf}, Identifier, Type, Param}; type ParseResult = Result; @@ -354,8 +354,34 @@ impl Parser { expect!(self, TokenKind::RightBrace, "expected }"); } + let mut else_ifs: Vec = Vec::new(); + loop { + if self.current.kind == TokenKind::ElseIf { + self.next(); + + expect!(self, TokenKind::LeftParen, "expected ("); + + let condition = self.expression(0)?; + + expect!(self, TokenKind::RightParen, "expected )"); + + expect!(self, TokenKind::LeftBrace, "expected {"); + + let mut body = Block::new(); + while ! self.is_eof() && self.current.kind != TokenKind::RightBrace { + body.push(self.statement()?); + } + + expect!(self, TokenKind::RightBrace, "expected }"); + + else_ifs.push(ElseIf { condition, body }); + } else { + break; + } + } + if self.current.kind != TokenKind::Else { - return Ok(Statement::If { condition, then, r#else: None }); + return Ok(Statement::If { condition, then, else_ifs, r#else: None }); } expect!(self, TokenKind::Else, "expected else"); @@ -369,7 +395,7 @@ impl Parser { expect!(self, TokenKind::RightBrace, "expected }"); - Statement::If { condition, then, r#else: Some(r#else) } + Statement::If { condition, then, else_ifs, r#else: Some(r#else) } }, TokenKind::Class => self.class()?, TokenKind::Echo => { @@ -1209,6 +1235,7 @@ mod tests { then: vec![ Statement::Return { value: Some(Expression::Variable("n".into())) } ], + else_ifs: vec![], r#else: None }, Statement::Return { @@ -1248,6 +1275,7 @@ mod tests { then: vec![ Statement::Return { value: Some(Expression::Variable("foo".into())) } ], + else_ifs: vec![], r#else: None }, ]); @@ -1261,6 +1289,7 @@ mod tests { then: vec![ Statement::Return { value: Some(Expression::Variable("foo".into())) } ], + else_ifs: vec![], r#else: Some(vec![ Statement::Return { value: Some(Expression::Variable("foo".into())) } ]) From 72ff4cdcc244421102fa57bf4c574ffdf72ae69d Mon Sep 17 00:00:00 2001 From: Domantas Date: Tue, 26 Jul 2022 14:44:06 +0200 Subject: [PATCH 2/2] parser: add elseif test --- trunk_parser/src/parser/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/trunk_parser/src/parser/mod.rs b/trunk_parser/src/parser/mod.rs index e89b7ee..b27b80d 100644 --- a/trunk_parser/src/parser/mod.rs +++ b/trunk_parser/src/parser/mod.rs @@ -1031,7 +1031,7 @@ impl Display for ParseError { #[cfg(test)] mod tests { use trunk_lexer::Lexer; - use crate::{Statement, Param, Expression, ast::{InfixOp}, Type, Identifier}; + use crate::{Statement, Param, Expression, ast::{InfixOp, ElseIf}, Type, Identifier}; use super::Parser; macro_rules! function { @@ -1297,6 +1297,29 @@ mod tests { ]); } + #[test] + fn if_elseif_else_statement() { + assert_ast("