Merge branch 'main' of github.com:ryangjchandler/trunk

This commit is contained in:
Ryan Chandler 2022-07-26 14:23:18 +01:00
commit e52dd5db95
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
3 changed files with 67 additions and 4 deletions

View File

@ -2,6 +2,10 @@
if($foo) { if($foo) {
return $foo; return $foo;
} elseif($foo) {
return $foo;
} elseif($foo) {
return $foo;
} else { } else {
return $foo; return $foo;
} }

View File

@ -176,6 +176,7 @@ pub enum Statement {
If { If {
condition: Expression, condition: Expression,
then: Block, then: Block,
else_ifs: Vec<ElseIf>,
r#else: Option<Block> r#else: Option<Block>
}, },
Return { Return {
@ -271,4 +272,10 @@ impl From<TokenKind> for InfixOp {
_ => unreachable!() _ => unreachable!()
} }
} }
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ElseIf {
pub condition: Expression,
pub body: Block,
} }

View File

@ -1,6 +1,6 @@
use std::{vec::IntoIter, fmt::{Display}}; use std::{vec::IntoIter, fmt::{Display}};
use trunk_lexer::{Token, TokenKind, Span}; 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<T> = Result<T, ParseError>; type ParseResult<T> = Result<T, ParseError>;
@ -354,8 +354,34 @@ impl Parser {
expect!(self, TokenKind::RightBrace, "expected }"); expect!(self, TokenKind::RightBrace, "expected }");
} }
let mut else_ifs: Vec<ElseIf> = 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 { 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"); expect!(self, TokenKind::Else, "expected else");
@ -369,7 +395,7 @@ impl Parser {
expect!(self, TokenKind::RightBrace, "expected }"); 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::Class => self.class()?,
TokenKind::Echo => { TokenKind::Echo => {
@ -1005,7 +1031,7 @@ impl Display for ParseError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use trunk_lexer::Lexer; 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; use super::Parser;
macro_rules! function { macro_rules! function {
@ -1209,6 +1235,7 @@ mod tests {
then: vec![ then: vec![
Statement::Return { value: Some(Expression::Variable("n".into())) } Statement::Return { value: Some(Expression::Variable("n".into())) }
], ],
else_ifs: vec![],
r#else: None r#else: None
}, },
Statement::Return { Statement::Return {
@ -1248,6 +1275,7 @@ mod tests {
then: vec![ then: vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) } Statement::Return { value: Some(Expression::Variable("foo".into())) }
], ],
else_ifs: vec![],
r#else: None r#else: None
}, },
]); ]);
@ -1261,6 +1289,30 @@ mod tests {
then: vec![ then: vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) } Statement::Return { value: Some(Expression::Variable("foo".into())) }
], ],
else_ifs: vec![],
r#else: Some(vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) }
])
},
]);
}
#[test]
fn if_elseif_else_statement() {
assert_ast("<?php if($foo) { return $foo; } elseif($foo) { return $foo; } else { return $foo; }", &[
Statement::If {
condition: Expression::Variable("foo".into()),
then: vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) }
],
else_ifs: vec![
ElseIf {
condition: Expression::Variable("foo".into()),
body: vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) }
]
}
],
r#else: Some(vec![ r#else: Some(vec![
Statement::Return { value: Some(Expression::Variable("foo".into())) } Statement::Return { value: Some(Expression::Variable("foo".into())) }
]) ])