parser+lexer: support match expressions

Closes #16.
This commit is contained in:
Ryan Chandler 2022-08-04 00:21:10 +01:00
parent 1a7aae97d9
commit b254e59bde
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
6 changed files with 64 additions and 3 deletions

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

@ -0,0 +1,7 @@
<?php
match ($expr) {
'foo' => 'bar',
'baz', 'car', 'bob' => 'foop',
default => null,
};

View File

@ -709,6 +709,7 @@ impl Lexer {
#[allow(dead_code)]
fn identifier_to_keyword(ident: &str) -> Option<TokenKind> {
Some(match ident {
"match" => TokenKind::Match,
"abstract" => TokenKind::Abstract,
"array" => TokenKind::Array,
"as" => TokenKind::As,
@ -718,6 +719,7 @@ fn identifier_to_keyword(ident: &str) -> Option<TokenKind> {
"continue" => TokenKind::Continue,
"const" => TokenKind::Const,
"declare" => TokenKind::Declare,
"default" => TokenKind::Default,
"echo" => TokenKind::Echo,
"else" => TokenKind::Else,
"elseif" => TokenKind::ElseIf,

View File

@ -96,6 +96,7 @@ pub enum TokenKind {
LeftShift,
LessThan,
LessThanEquals,
Match,
Minus,
Namespace,
NamespaceSeparator,
@ -226,6 +227,7 @@ impl Display for TokenKind {
Self::LeftShift => "<<",
Self::LessThan => "<",
Self::LessThanEquals => "<=",
Self::Match => "match",
Self::Minus => "-",
Self::Namespace => "namespace",
Self::NamespaceSeparator => "\\",

View File

@ -354,7 +354,17 @@ pub enum Expression {
},
Clone {
target: Box<Self>
}
},
Match {
condition: Box<Self>,
arms: Vec<MatchArm>,
},
}
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct MatchArm {
pub conditions: Option<Vec<Expression>>,
pub body: Expression,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize)]

View File

@ -1,5 +1,5 @@
mod ast;
mod parser;
pub use ast::{Statement, Expression, Program, Block, Param, Identifier, Type, InfixOp};
pub use ast::{Statement, Expression, Program, Block, Param, Identifier, Type, InfixOp, MatchArm};
pub use parser::{Parser, ParseError};

View File

@ -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, ElseIf, UseKind, MagicConst}, Identifier, Type};
use crate::{Program, Statement, Block, Expression, ast::{ArrayItem, Use, MethodFlag, ClassFlag, ElseIf, UseKind, MagicConst}, Identifier, Type, MatchArm};
type ParseResult<T> = Result<T, ParseError>;
@ -789,6 +789,46 @@ impl Parser {
e
},
TokenKind::Match => {
self.next();
self.lparen()?;
let condition = Box::new(self.expression(0)?);
self.rparen()?;
self.lbrace()?;
let mut arms = Vec::new();
while self.current.kind != TokenKind::RightBrace {
let mut conditions = Vec::new();
while self.current.kind != TokenKind::DoubleArrow {
if self.current.kind == TokenKind::Default {
self.next();
break;
}
conditions.push(self.expression(0)?);
self.optional_comma()?;
}
expect!(self, TokenKind::DoubleArrow, "expected =>");
let body = self.expression(0)?;
self.optional_comma()?;
arms.push(MatchArm {
conditions: if conditions.is_empty() { None } else { Some(conditions) },
body,
})
}
self.rbrace()?;
Expression::Match { condition, arms }
},
TokenKind::Array => {
let mut items = vec![];