parser: support enums

This commit is contained in:
Ryan Chandler 2022-08-05 23:18:29 +01:00
parent 63d3c4bffd
commit f488e584bd
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
3 changed files with 103 additions and 1 deletions

17
phpast/samples/enum.php Normal file
View File

@ -0,0 +1,17 @@
<?php
enum Foo {
case Bar;
}
enum Bar: string {
case Baz = 'car';
}
enum Baz: int {
case Caz = 'boo';
}
enum Foo implements Bob {
}

View File

@ -240,9 +240,25 @@ pub enum Statement {
catches: Vec<Catch>, catches: Vec<Catch>,
finally: Option<Block>, finally: Option<Block>,
}, },
Enum {
name: Identifier,
implements: Vec<Identifier>,
backed_type: Option<BackedEnumType>,
body: Block,
},
EnumCase {
name: Identifier,
value: Option<Expression>,
},
Noop, Noop,
} }
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum BackedEnumType {
String,
Int,
}
#[derive(Debug, Clone, PartialEq, Serialize)] #[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Case { pub struct Case {
pub condition: Option<Expression>, pub condition: Option<Expression>,

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, ElseIf, UseKind, MagicConst}, Identifier, Type, MatchArm, Catch, Case}; use crate::{Program, Statement, Block, Expression, ast::{ArrayItem, Use, MethodFlag, ClassFlag, ElseIf, UseKind, MagicConst, BackedEnumType}, Identifier, Type, MatchArm, Catch, Case};
type ParseResult<T> = Result<T, ParseError>; type ParseResult<T> = Result<T, ParseError>;
@ -342,6 +342,75 @@ impl Parser {
Statement::Interface { name: name.into(), extends, body } Statement::Interface { name: name.into(), extends, body }
}, },
TokenKind::Enum if matches!(self.peek.kind, TokenKind::Identifier(_)) => {
self.next();
let name = self.ident()?;
let mut is_backed = false;
let backed_type: Option<BackedEnumType> = if self.current.kind == TokenKind::Colon {
expect!(self, TokenKind::Colon, "expected :");
match self.current.kind.clone() {
TokenKind::Identifier(s) if s == String::from("string") || s == String::from("int") => {
self.next();
is_backed = true;
Some(match s.as_str() {
"string" => BackedEnumType::String,
"int" => BackedEnumType::Int,
_ => unreachable!()
})
},
_ => return Err(ParseError::UnexpectedToken(self.current.kind.to_string(), self.current.span))
}
} else {
None
};
let mut implements = Vec::new();
if self.current.kind == TokenKind::Implements {
self.next();
while self.current.kind != TokenKind::LeftBrace {
implements.push(self.full_name()?.into());
self.optional_comma()?;
}
}
self.lbrace()?;
let mut body = Block::new();
while self.current.kind != TokenKind::RightBrace {
match self.current.kind {
TokenKind::Case => {
self.next();
let name = self.ident()?;
let mut value = None;
if is_backed {
expect!(self, TokenKind::Equals, "expected =");
value = Some(self.expression(0)?);
}
self.semi()?;
body.push(Statement::EnumCase { name: name.into(), value })
},
_ => {
body.push(self.class_statement()?);
}
}
}
self.rbrace()?;
Statement::Enum { name: name.into(), backed_type, implements, body }
},
TokenKind::Use => { TokenKind::Use => {
self.next(); self.next();