@@ -295,11 +295,8 @@ private function isListTerminator(int $parseContext) {
295295 case ParseContext::SourceElements:
296296 return false ;
297297
298- case ParseContext::InterfaceMembers:
299- case ParseContext::ClassMembers:
298+ case ParseContext::ClasslikeMembers:
300299 case ParseContext::BlockStatements:
301- case ParseContext::TraitMembers:
302- case ParseContext::EnumMembers:
303300 return $ tokenKind === TokenKind::CloseBraceToken;
304301 case ParseContext::SwitchStatementElements:
305302 return $ tokenKind === TokenKind::CloseBraceToken || $ tokenKind === TokenKind::EndSwitchKeyword;
@@ -345,17 +342,8 @@ private function isValidListElement($context, Token $token) {
345342 case ParseContext::DeclareStatementElements:
346343 return $ this ->isStatementStart ($ token );
347344
348- case ParseContext::ClassMembers:
349- return $ this ->isClassMemberDeclarationStart ($ token );
350-
351- case ParseContext::TraitMembers:
352- return $ this ->isTraitMemberDeclarationStart ($ token );
353-
354- case ParseContext::EnumMembers:
355- return $ this ->isEnumMemberDeclarationStart ($ token );
356-
357- case ParseContext::InterfaceMembers:
358- return $ this ->isInterfaceMemberDeclarationStart ($ token );
345+ case ParseContext::ClasslikeMembers:
346+ return $ this ->isClasslikeMemberDeclarationStart ($ token );
359347
360348 case ParseContext::SwitchStatementElements:
361349 return
@@ -376,17 +364,8 @@ private function getParseListElementFn($context) {
376364 case ParseContext::ForeachStatementElements:
377365 case ParseContext::DeclareStatementElements:
378366 return $ this ->parseStatementFn ();
379- case ParseContext::ClassMembers:
380- return $ this ->parseClassElementFn ();
381-
382- case ParseContext::TraitMembers:
383- return $ this ->parseTraitElementFn ();
384-
385- case ParseContext::InterfaceMembers:
386- return $ this ->parseInterfaceElementFn ();
387-
388- case ParseContext::EnumMembers:
389- return $ this ->parseEnumElementFn ();
367+ case ParseContext::ClasslikeMembers:
368+ return $ this ->parseClasslikeElementFn ();
390369
391370 case ParseContext::SwitchStatementElements:
392371 return $ this ->parseCaseOrDefaultStatement ();
@@ -636,15 +615,19 @@ private function parseStatementFn() {
636615 };
637616 }
638617
639- private function parseClassElementFn () {
618+ private function parseClasslikeElementFn () {
640619 return function ($ parentNode ) {
641620 $ modifiers = $ this ->parseModifiers ();
642621
643622 $ token = $ this ->getCurrentToken ();
623+ // Note that parsing the wrong type of class element in a classlike is a compile-time error, not a parse error.
644624 switch ($ token ->kind ) {
645625 case TokenKind::ConstKeyword:
646626 return $ this ->parseClassConstDeclaration ($ parentNode , $ modifiers );
647627
628+ case TokenKind::CaseKeyword:
629+ return $ this ->parseEnumCaseDeclaration ($ parentNode );
630+
648631 case TokenKind::FunctionKeyword:
649632 return $ this ->parseMethodDeclaration ($ parentNode , $ modifiers );
650633
@@ -688,14 +671,14 @@ private function parseClassDeclaration($parentNode) : Node {
688671 $ classNode ->name ->kind = TokenKind::Name;
689672 $ classNode ->classBaseClause = $ this ->parseClassBaseClause ($ classNode );
690673 $ classNode ->classInterfaceClause = $ this ->parseClassInterfaceClause ($ classNode );
691- $ classNode ->classMembers = $ this ->parseClassMembers ($ classNode );
674+ $ classNode ->classMembers = $ this ->parseClasslikeMembers ($ classNode );
692675 return $ classNode ;
693676 }
694677
695- private function parseClassMembers ($ parentNode ) : ClassMembersNode {
678+ private function parseClasslikeMembers ($ parentNode ) : ClassMembersNode {
696679 $ classMembers = new ClassMembersNode ();
697680 $ classMembers ->openBrace = $ this ->eat1 (TokenKind::OpenBraceToken);
698- $ classMembers ->classMemberDeclarations = $ this ->parseList ($ classMembers , ParseContext::ClassMembers );
681+ $ classMembers ->classMemberDeclarations = $ this ->parseList ($ classMembers , ParseContext::ClasslikeMembers );
699682 $ classMembers ->closeBrace = $ this ->eat1 (TokenKind::CloseBraceToken);
700683 $ classMembers ->parent = $ parentNode ;
701684 return $ classMembers ;
@@ -741,18 +724,9 @@ private function parseAttributeExpression($parentNode) {
741724 */
742725 private function parseAttributeStatement ($ parentNode ) {
743726 $ attributeGroups = $ this ->parseAttributeGroups (null );
744- if ($ parentNode instanceof ClassMembersNode) {
727+ if ($ parentNode instanceof ClassMembersNode || $ parentNode instanceof TraitMembers || $ parentNode instanceof EnumMembers || $ parentNode instanceof InterfaceMembers ) {
745728 // Create a class element or a MissingMemberDeclaration
746- $ statement = $ this ->parseClassElementFn ()($ parentNode );
747- } elseif ($ parentNode instanceof TraitMembers) {
748- // Create a trait element or a MissingMemberDeclaration
749- $ statement = $ this ->parseTraitElementFn ()($ parentNode );
750- } elseif ($ parentNode instanceof EnumMembers) {
751- // Create a enum element or a MissingMemberDeclaration
752- $ statement = $ this ->parseEnumElementFn ()($ parentNode );
753- } elseif ($ parentNode instanceof InterfaceMembers) {
754- // Create an interface element or a MissingMemberDeclaration
755- $ statement = $ this ->parseInterfaceElementFn ()($ parentNode );
729+ $ statement = $ this ->parseClasslikeElementFn ()($ parentNode );
756730 } else {
757731 // Classlikes, anonymous functions, global functions, and arrow functions can have attributes. Global constants cannot.
758732 if (in_array ($ this ->token ->kind , [TokenKind::ClassKeyword, TokenKind::TraitKeyword, TokenKind::InterfaceKeyword, TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::FunctionKeyword, TokenKind::FnKeyword, TokenKind::EnumKeyword], true ) ||
@@ -1045,7 +1019,7 @@ private function parseCompoundStatement($parentNode) {
10451019 return $ compoundStatement ;
10461020 }
10471021
1048- private function isClassMemberDeclarationStart (Token $ token ) {
1022+ private function isClasslikeMemberDeclarationStart (Token $ token ) {
10491023 switch ($ token ->kind ) {
10501024 // const-modifier
10511025 case TokenKind::ConstKeyword:
@@ -1073,6 +1047,9 @@ private function isClassMemberDeclarationStart(Token $token) {
10731047
10741048 // attributes
10751049 case TokenKind::AttributeToken:
1050+
1051+ // enum
1052+ case TokenKind::CaseKeyword:
10761053 return true ;
10771054
10781055 }
@@ -1417,7 +1394,7 @@ private function parseStringLiteralExpression2($parentNode): StringLiteral {
14171394 case TokenKind::DollarOpenBraceToken:
14181395 case TokenKind::OpenBraceDollarToken:
14191396 $ expression ->children [] = $ this ->eat (TokenKind::DollarOpenBraceToken, TokenKind::OpenBraceDollarToken);
1420- /**
1397+ /**
14211398 * @phpstan-ignore-next-line "Strict comparison using
14221399 * === between 403|404 and 408 will always evaluate to
14231400 * false" is wrong because those tokens were eaten above
@@ -3286,7 +3263,7 @@ private function parseObjectCreationExpression($parentNode) {
32863263 $ objectCreationExpression ->classInterfaceClause = $ this ->parseClassInterfaceClause ($ objectCreationExpression );
32873264
32883265 if ($ this ->getCurrentToken ()->kind === TokenKind::OpenBraceToken) {
3289- $ objectCreationExpression ->classMembers = $ this ->parseClassMembers ($ objectCreationExpression );
3266+ $ objectCreationExpression ->classMembers = $ this ->parseClasslikeMembers ($ objectCreationExpression );
32903267 }
32913268
32923269 return $ objectCreationExpression ;
@@ -3474,63 +3451,12 @@ private function parseInterfaceDeclaration($parentNode): InterfaceDeclaration {
34743451 private function parseInterfaceMembers ($ parentNode ) : InterfaceMembers {
34753452 $ interfaceMembers = new InterfaceMembers ();
34763453 $ interfaceMembers ->openBrace = $ this ->eat1 (TokenKind::OpenBraceToken);
3477- $ interfaceMembers ->interfaceMemberDeclarations = $ this ->parseList ($ interfaceMembers , ParseContext::InterfaceMembers );
3454+ $ interfaceMembers ->interfaceMemberDeclarations = $ this ->parseList ($ interfaceMembers , ParseContext::ClasslikeMembers );
34783455 $ interfaceMembers ->closeBrace = $ this ->eat1 (TokenKind::CloseBraceToken);
34793456 $ interfaceMembers ->parent = $ parentNode ;
34803457 return $ interfaceMembers ;
34813458 }
34823459
3483- private function isInterfaceMemberDeclarationStart (Token $ token ) {
3484- switch ($ token ->kind ) {
3485- // visibility-modifier
3486- case TokenKind::PublicKeyword:
3487- case TokenKind::ProtectedKeyword:
3488- case TokenKind::PrivateKeyword:
3489-
3490- // static-modifier
3491- case TokenKind::StaticKeyword:
3492-
3493- // readonly-modifier
3494- case TokenKind::ReadonlyKeyword:
3495-
3496- // class-modifier
3497- case TokenKind::AbstractKeyword:
3498- case TokenKind::FinalKeyword:
3499-
3500- case TokenKind::ConstKeyword:
3501-
3502- case TokenKind::FunctionKeyword:
3503-
3504- case TokenKind::AttributeToken:
3505- return true ;
3506- }
3507- return false ;
3508- }
3509-
3510- private function parseInterfaceElementFn () {
3511- return function ($ parentNode ) {
3512- $ modifiers = $ this ->parseModifiers ();
3513-
3514- $ token = $ this ->getCurrentToken ();
3515- switch ($ token ->kind ) {
3516- case TokenKind::ConstKeyword:
3517- return $ this ->parseClassConstDeclaration ($ parentNode , $ modifiers );
3518-
3519- case TokenKind::FunctionKeyword:
3520- return $ this ->parseMethodDeclaration ($ parentNode , $ modifiers );
3521-
3522- case TokenKind::AttributeToken:
3523- return $ this ->parseAttributeStatement ($ parentNode );
3524-
3525- default :
3526- $ missingInterfaceMemberDeclaration = new MissingMemberDeclaration ();
3527- $ missingInterfaceMemberDeclaration ->parent = $ parentNode ;
3528- $ missingInterfaceMemberDeclaration ->modifiers = $ modifiers ;
3529- return $ missingInterfaceMemberDeclaration ;
3530- }
3531- };
3532- }
3533-
35343460 private function parseInterfaceBaseClause ($ parentNode ) {
35353461 $ interfaceBaseClause = new InterfaceBaseClause ();
35363462 $ interfaceBaseClause ->parent = $ parentNode ;
@@ -3657,75 +3583,13 @@ private function parseTraitMembers($parentNode) {
36573583
36583584 $ traitMembers ->openBrace = $ this ->eat1 (TokenKind::OpenBraceToken);
36593585
3660- $ traitMembers ->traitMemberDeclarations = $ this ->parseList ($ traitMembers , ParseContext::TraitMembers );
3586+ $ traitMembers ->traitMemberDeclarations = $ this ->parseList ($ traitMembers , ParseContext::ClasslikeMembers );
36613587
36623588 $ traitMembers ->closeBrace = $ this ->eat1 (TokenKind::CloseBraceToken);
36633589
36643590 return $ traitMembers ;
36653591 }
36663592
3667- private function isTraitMemberDeclarationStart ($ token ) {
3668- switch ($ token ->kind ) {
3669- // property-declaration
3670- case TokenKind::VariableName:
3671-
3672- // modifiers
3673- case TokenKind::PublicKeyword:
3674- case TokenKind::ProtectedKeyword:
3675- case TokenKind::PrivateKeyword:
3676- case TokenKind::VarKeyword:
3677- case TokenKind::StaticKeyword:
3678- case TokenKind::AbstractKeyword:
3679- case TokenKind::FinalKeyword:
3680- case TokenKind::ReadonlyKeyword:
3681- case TokenKind::ConstKeyword:
3682-
3683- // method-declaration
3684- case TokenKind::FunctionKeyword:
3685-
3686- // trait-use-clauses
3687- case TokenKind::UseKeyword:
3688-
3689- // attributes
3690- case TokenKind::AttributeToken:
3691- return true ;
3692- }
3693- return false ;
3694- }
3695-
3696- private function parseTraitElementFn () {
3697- return function ($ parentNode ) {
3698- $ modifiers = $ this ->parseModifiers ();
3699-
3700- $ token = $ this ->getCurrentToken ();
3701- switch ($ token ->kind ) {
3702- case TokenKind::ConstKeyword:
3703- return $ this ->parseClassConstDeclaration ($ parentNode , $ modifiers );
3704-
3705- case TokenKind::FunctionKeyword:
3706- return $ this ->parseMethodDeclaration ($ parentNode , $ modifiers );
3707-
3708- case TokenKind::QuestionToken:
3709- return $ this ->parseRemainingPropertyDeclarationOrMissingMemberDeclaration (
3710- $ parentNode ,
3711- $ modifiers ,
3712- $ this ->eat1 (TokenKind::QuestionToken)
3713- );
3714- case TokenKind::VariableName:
3715- return $ this ->parsePropertyDeclaration ($ parentNode , $ modifiers );
3716-
3717- case TokenKind::UseKeyword:
3718- return $ this ->parseTraitUseClause ($ parentNode );
3719-
3720- case TokenKind::AttributeToken:
3721- return $ this ->parseAttributeStatement ($ parentNode );
3722-
3723- default :
3724- return $ this ->parseRemainingPropertyDeclarationOrMissingMemberDeclaration ($ parentNode , $ modifiers );
3725- }
3726- };
3727- }
3728-
37293593 private function parseEnumDeclaration ($ parentNode ) {
37303594 $ enumDeclaration = new EnumDeclaration ();
37313595 $ enumDeclaration ->parent = $ parentNode ;
@@ -3765,78 +3629,13 @@ private function parseEnumMembers($parentNode) {
37653629
37663630 $ enumMembers ->openBrace = $ this ->eat1 (TokenKind::OpenBraceToken);
37673631
3768- $ enumMembers ->enumMemberDeclarations = $ this ->parseList ($ enumMembers , ParseContext::EnumMembers );
3632+ $ enumMembers ->enumMemberDeclarations = $ this ->parseList ($ enumMembers , ParseContext::ClasslikeMembers );
37693633
37703634 $ enumMembers ->closeBrace = $ this ->eat1 (TokenKind::CloseBraceToken);
37713635
37723636 return $ enumMembers ;
37733637 }
37743638
3775- private function isEnumMemberDeclarationStart ($ token ) {
3776- switch ($ token ->kind ) {
3777- // modifiers
3778- case TokenKind::PublicKeyword:
3779- case TokenKind::ProtectedKeyword:
3780- case TokenKind::PrivateKeyword:
3781- case TokenKind::StaticKeyword:
3782- case TokenKind::AbstractKeyword:
3783- case TokenKind::FinalKeyword:
3784-
3785- // method-declaration
3786- case TokenKind::FunctionKeyword:
3787-
3788- // trait-use-clauses (enums can use traits)
3789- case TokenKind::UseKeyword:
3790-
3791- // cases and constants
3792- case TokenKind::CaseKeyword:
3793- case TokenKind::ConstKeyword:
3794-
3795- // attributes
3796- case TokenKind::AttributeToken:
3797- return true ;
3798- }
3799- return false ;
3800- }
3801-
3802- private function parseEnumElementFn () {
3803- return function ($ parentNode ) {
3804- $ modifiers = $ this ->parseModifiers ();
3805-
3806- $ token = $ this ->getCurrentToken ();
3807- switch ($ token ->kind ) {
3808- // TODO: CaseKeyword
3809- case TokenKind::CaseKeyword:
3810- return $ this ->parseEnumCaseDeclaration ($ parentNode );
3811-
3812- case TokenKind::ConstKeyword:
3813- return $ this ->parseClassConstDeclaration ($ parentNode , $ modifiers );
3814-
3815- case TokenKind::FunctionKeyword:
3816- return $ this ->parseMethodDeclaration ($ parentNode , $ modifiers );
3817-
3818- case TokenKind::QuestionToken:
3819- return $ this ->parseRemainingPropertyDeclarationOrMissingMemberDeclaration (
3820- $ parentNode ,
3821- $ modifiers ,
3822- $ this ->eat1 (TokenKind::QuestionToken)
3823- );
3824- case TokenKind::VariableName:
3825- return $ this ->parsePropertyDeclaration ($ parentNode , $ modifiers );
3826-
3827- case TokenKind::UseKeyword:
3828- return $ this ->parseTraitUseClause ($ parentNode );
3829-
3830- case TokenKind::AttributeToken:
3831- return $ this ->parseAttributeStatement ($ parentNode );
3832-
3833- default :
3834- return $ this ->parseRemainingPropertyDeclarationOrMissingMemberDeclaration ($ parentNode , $ modifiers );
3835- }
3836- };
3837- }
3838-
3839-
38403639 /**
38413640 * @param Node $parentNode
38423641 * @param Token[] $modifiers
0 commit comments