Merge pull request #64 from ryangjchandler/feature/readonly-classes

This commit is contained in:
Ryan Chandler 2022-09-13 12:03:19 +01:00 committed by GitHub
commit 736964de7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 3 deletions

View File

@ -836,6 +836,7 @@ impl Lexer {
#[allow(dead_code)]
fn identifier_to_keyword(ident: &[u8]) -> Option<TokenKind> {
Some(match ident {
b"readonly" => TokenKind::Readonly,
b"global" => TokenKind::Global,
b"match" => TokenKind::Match,
b"abstract" => TokenKind::Abstract,
@ -949,7 +950,7 @@ mod tests {
#[test]
fn keywords() {
assert_tokens("<?php function if else elseif echo return class extends implements public protected private static null NULL true TRUE false FALSE use const namespace interface new foreach instanceof", &[
assert_tokens("<?php function if else elseif echo return class extends implements public protected private static null NULL true TRUE false FALSE use const namespace interface new foreach instanceof readonly", &[
open!(),
TokenKind::Function,
TokenKind::If,
@ -977,6 +978,7 @@ mod tests {
TokenKind::New,
TokenKind::Foreach,
TokenKind::Instanceof,
TokenKind::Readonly,
]);
}

View File

@ -11,6 +11,7 @@ pub enum OpenTagKind {
#[derive(Debug, PartialEq, Clone)]
pub enum TokenKind {
Readonly,
Global,
Abstract,
Ampersand,
@ -169,6 +170,7 @@ impl Default for Token {
impl Display for TokenKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::Readonly => "readonly",
Self::AsteriskEqual => "*=",
Self::ObjectCast => "(object)",
Self::Abstract => "abstract",

View File

@ -118,6 +118,7 @@ impl From<TokenKind> for MethodFlag {
pub enum ClassFlag {
Final,
Abstract,
Readonly,
}
impl From<TokenKind> for ClassFlag {
@ -125,6 +126,7 @@ impl From<TokenKind> for ClassFlag {
match k {
TokenKind::Final => Self::Final,
TokenKind::Abstract => Self::Abstract,
TokenKind::Readonly => Self::Readonly,
_ => unreachable!("token {:?} can't be converted into class flag.", k),
}
}

View File

@ -416,6 +416,26 @@ impl Parser {
_ => unreachable!(),
}
}
TokenKind::Readonly if self.peek.kind == TokenKind::Class => {
self.next();
match self.class()? {
Statement::Class {
name,
extends,
implements,
body,
..
} => Statement::Class {
name,
extends,
implements,
body,
flag: Some(ClassFlag::Readonly),
},
_ => unreachable!(),
}
}
TokenKind::Trait => {
self.next();
@ -2193,8 +2213,8 @@ mod tests {
use super::Parser;
use crate::{
ast::{
Arg, ArrayItem, Case, Constant, DeclareItem, ElseIf, IncludeKind, InfixOp, MethodFlag,
PropertyFlag,
Arg, ArrayItem, Case, ClassFlag, Constant, DeclareItem, ElseIf, IncludeKind, InfixOp,
MethodFlag, PropertyFlag,
},
Catch, Expression, Identifier, Param, Statement, Type,
};
@ -3515,6 +3535,20 @@ mod tests {
)
}
#[test]
fn readonly_classes() {
assert_ast(
"<?php readonly class Foo {}",
&[Statement::Class {
name: "Foo".as_bytes().into(),
extends: None,
implements: vec![],
body: vec![],
flag: Some(ClassFlag::Readonly),
}],
);
}
fn assert_ast(source: &str, expected: &[Statement]) {
let mut lexer = Lexer::new(None);
let tokens = lexer.tokenize(source).unwrap();