@@ -1015,6 +1015,9 @@ private function parseStringLiteralExpression2($parentNode) {
10151015 case TokenKind::HeredocEnd:
10161016 $ expression ->endQuote = $ this ->eat ($ startQuoteKind , TokenKind::HeredocEnd);
10171017 return $ expression ;
1018+ case TokenKind::VariableName:
1019+ $ expression ->children [] = $ this ->parseTemplateStringExpression ($ expression );
1020+ continue ;
10181021 default :
10191022 $ expression ->children [] = $ this ->getCurrentToken ();
10201023 $ this ->advanceToken ();
@@ -1025,6 +1028,71 @@ private function parseStringLiteralExpression2($parentNode) {
10251028 return $ expression ;
10261029 }
10271030
1031+ /**
1032+ * Double-quoted and heredoc strings support a basic set of expression types, described in http://php.net/manual/en/language.types.string.php#language.types.string.parsing
1033+ * Supported: $x, $x->p, $x[0], $x[$y]
1034+ * Not supported: $x->p1->p2, $x[0][1], etc.
1035+ * Since there is a relatively small finite set of allowed forms, I implement it here rather than trying to reuse the general expression parsing code.
1036+ */
1037+ private function parseTemplateStringExpression ($ parentNode ) {
1038+ $ token = $ this ->getCurrentToken ();
1039+ if ($ token ->kind === TokenKind::VariableName) {
1040+ $ var = $ this ->parseSimpleVariable ($ parentNode );
1041+ $ token = $ this ->getCurrentToken ();
1042+ if ($ token ->kind === TokenKind::OpenBracketToken) {
1043+ return $ this ->parseTemplateStringSubscriptExpression ($ var );
1044+ } else if ($ token ->kind === TokenKind::ArrowToken) {
1045+ return $ this ->parseTemplateStringMemberAccessExpression ($ var );
1046+ } else {
1047+ return $ var ;
1048+ }
1049+ }
1050+
1051+ return null ;
1052+ }
1053+
1054+ private function parseTemplateStringSubscriptExpression ($ postfixExpression ) : SubscriptExpression {
1055+ $ subscriptExpression = new SubscriptExpression ();
1056+ $ subscriptExpression ->parent = $ postfixExpression ->parent ;
1057+ $ postfixExpression ->parent = $ subscriptExpression ;
1058+
1059+ $ subscriptExpression ->postfixExpression = $ postfixExpression ;
1060+ $ subscriptExpression ->openBracketOrBrace = $ this ->eat (TokenKind::OpenBracketToken); // Only [] syntax is supported, not {}
1061+ $ token = $ this ->getCurrentToken ();
1062+ if ($ token ->kind === TokenKind::VariableName) {
1063+ $ subscriptExpression ->accessExpression = $ this ->parseSimpleVariable ($ subscriptExpression );
1064+ } elseif ($ token ->kind === TokenKind::IntegerLiteralToken) {
1065+ $ subscriptExpression ->accessExpression = $ this ->parseNumericLiteralExpression ($ subscriptExpression );
1066+ } elseif ($ token ->kind === TokenKind::Name) {
1067+ $ subscriptExpression ->accessExpression = $ this ->parseTemplateStringSubscriptStringLiteral ($ subscriptExpression );
1068+ } else {
1069+ $ subscriptExpression ->accessExpression = new MissingToken (TokenKind::Expression, $ token ->fullStart );
1070+ }
1071+
1072+ $ subscriptExpression ->closeBracketOrBrace = $ this ->eat (TokenKind::CloseBracketToken);
1073+
1074+ return $ subscriptExpression ;
1075+ }
1076+
1077+ private function parseTemplateStringSubscriptStringLiteral ($ parentNode ) : StringLiteral {
1078+ $ expression = new StringLiteral ();
1079+ $ expression ->parent = $ parentNode ;
1080+ $ expression ->children = $ this ->eat (TokenKind::Name);
1081+ return $ expression ;
1082+ }
1083+
1084+ private function parseTemplateStringMemberAccessExpression ($ expression ) : MemberAccessExpression {
1085+ $ memberAccessExpression = new MemberAccessExpression ();
1086+ $ memberAccessExpression ->parent = $ expression ->parent ;
1087+ $ expression ->parent = $ memberAccessExpression ;
1088+
1089+ $ memberAccessExpression ->dereferencableExpression = $ expression ;
1090+ $ memberAccessExpression ->arrowToken = $ this ->eat (TokenKind::ArrowToken);
1091+ $ memberAccessExpression ->memberName = $ this ->eat (TokenKind::Name);
1092+
1093+ return $ memberAccessExpression ;
1094+ }
1095+
10281096 private function parseNumericLiteralExpression ($ parentNode ) {
10291097 $ numericLiteral = new NumericLiteral ();
10301098 $ numericLiteral ->parent = $ parentNode ;
0 commit comments