@@ -144,8 +144,9 @@ public function __construct() {
144144 [TokenKind::ArrayKeyword, TokenKind::CallableKeyword, TokenKind::BoolReservedWord,
145145 TokenKind::FloatReservedWord, TokenKind::IntReservedWord, TokenKind::StringReservedWord,
146146 TokenKind::ObjectReservedWord, TokenKind::NullReservedWord, TokenKind::FalseReservedWord,
147+ TokenKind::TrueReservedWord,
147148 TokenKind::IterableReservedWord, TokenKind::MixedReservedWord]; // TODO update spec
148- $ this ->returnTypeDeclarationTokens = \array_merge ([TokenKind::VoidReservedWord, TokenKind::NullReservedWord, TokenKind::FalseReservedWord, TokenKind::StaticKeyword], $ this ->parameterTypeDeclarationTokens );
149+ $ this ->returnTypeDeclarationTokens = \array_merge ([TokenKind::VoidReservedWord, TokenKind::NullReservedWord, TokenKind::FalseReservedWord, TokenKind::TrueReservedWord, TokenKind:: StaticKeyword], $ this ->parameterTypeDeclarationTokens );
149150 }
150151
151152 /**
@@ -557,10 +558,8 @@ private function parseStatementFn() {
557558 // class-declaration
558559 case TokenKind::FinalKeyword:
559560 case TokenKind::AbstractKeyword:
560- if (!$ this ->lookahead (TokenKind::ClassKeyword)) {
561- $ this ->advanceToken ();
562- return new SkippedToken ($ token );
563- }
561+ case TokenKind::ReadonlyKeyword:
562+ // fallthrough
564563 case TokenKind::ClassKeyword:
565564 return $ this ->parseClassDeclaration ($ parentNode );
566565
@@ -657,10 +656,20 @@ private function parseClassElementFn() {
657656 };
658657 }
659658
659+ /** @return Token[] */
660+ private function parseClassModifiers (): array {
661+ $ modifiers = [];
662+ while ($ token = $ this ->eatOptional (TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::ReadonlyKeyword)) {
663+ $ modifiers [] = $ token ;
664+ }
665+ return $ modifiers ;
666+ }
667+
660668 private function parseClassDeclaration ($ parentNode ) : Node {
661669 $ classNode = new ClassDeclaration (); // TODO verify not nested
662670 $ classNode ->parent = $ parentNode ;
663- $ classNode ->abstractOrFinalModifier = $ this ->eatOptional (TokenKind::AbstractKeyword, TokenKind::FinalKeyword);
671+ $ classNode ->abstractOrFinalModifier = $ this ->eatOptional (TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::ReadonlyKeyword);
672+ $ classNode ->modifiers = $ this ->parseClassModifiers ();
664673 $ classNode ->classKeyword = $ this ->eat1 (TokenKind::ClassKeyword);
665674 $ classNode ->name = $ this ->eat ($ this ->nameOrReservedWordTokens ); // TODO should be any
666675 $ classNode ->name ->kind = TokenKind::Name;
@@ -1036,6 +1045,7 @@ private function isStatementStart(Token $token) {
10361045 case TokenKind::ClassKeyword:
10371046 case TokenKind::AbstractKeyword:
10381047 case TokenKind::FinalKeyword:
1048+ case TokenKind::ReadonlyKeyword:
10391049
10401050 // interface-declaration
10411051 case TokenKind::InterfaceKeyword:
@@ -3531,6 +3541,7 @@ private function isTraitMemberDeclarationStart($token) {
35313541 case TokenKind::AbstractKeyword:
35323542 case TokenKind::FinalKeyword:
35333543 case TokenKind::ReadonlyKeyword:
3544+ case TokenKind::ConstKeyword:
35343545
35353546 // method-declaration
35363547 case TokenKind::FunctionKeyword:
@@ -3551,6 +3562,9 @@ private function parseTraitElementFn() {
35513562
35523563 $ token = $ this ->getCurrentToken ();
35533564 switch ($ token ->kind ) {
3565+ case TokenKind::ConstKeyword:
3566+ return $ this ->parseClassConstDeclaration ($ parentNode , $ modifiers );
3567+
35543568 case TokenKind::FunctionKeyword:
35553569 return $ this ->parseMethodDeclaration ($ parentNode , $ modifiers );
35563570
0 commit comments