in src/Parser.php [1315:1350]
private function parseStringLiteralExpression2($parentNode) {
// TODO validate input token
$expression = new StringLiteral();
$expression->parent = $parentNode;
$expression->startQuote = $this->eat(TokenKind::SingleQuoteToken, TokenKind::DoubleQuoteToken, TokenKind::HeredocStart, TokenKind::BacktickToken);
$expression->children = [];
while (true) {
switch ($this->getCurrentToken()->kind) {
case TokenKind::DollarOpenBraceToken:
case TokenKind::OpenBraceDollarToken:
$expression->children[] = $this->eat(TokenKind::DollarOpenBraceToken, TokenKind::OpenBraceDollarToken);
// TODO: Reject ${var->prop} and ${(var->prop)} without rejecting ${var+otherVar}
// Currently, this fails to reject ${var->prop} (because `var` has TokenKind::Name instead of StringVarname)
if ($this->getCurrentToken()->kind === TokenKind::StringVarname) {
$expression->children[] = $this->parseComplexDollarTemplateStringExpression($expression);
} else {
$expression->children[] = $this->parseExpression($expression);
}
$expression->children[] = $this->eat1(TokenKind::CloseBraceToken);
break;
case $startQuoteKind = $expression->startQuote->kind:
case TokenKind::EndOfFileToken:
case TokenKind::HeredocEnd:
$expression->endQuote = $this->eat($startQuoteKind, TokenKind::HeredocEnd);
return $expression;
case TokenKind::VariableName:
$expression->children[] = $this->parseTemplateStringExpression($expression);
break;
default:
$expression->children[] = $this->getCurrentToken();
$this->advanceToken();
break;
}
}
}