@@ -3919,8 +3919,14 @@ ParseNodePtr Parser::ParsePostfixOperators(
3919
3919
{
3920
3920
AutoMarkInParsingArgs autoMarkInParsingArgs(this);
3921
3921
3922
+ bool isNullPropagating = tkOptChain == this->GetScanner()->m_tkPrevious;
3922
3923
if (fInNew)
3923
3924
{
3925
+ if (isNullPropagating)
3926
+ {
3927
+ Error(ERRInvalidOptChainInNew);
3928
+ }
3929
+
3924
3930
ParseNodePtr pnodeArgs = ParseArgList<buildAST>(&callOfConstants, &spreadArgCount, &count);
3925
3931
if (buildAST)
3926
3932
{
@@ -3973,6 +3979,11 @@ ParseNodePtr Parser::ParsePostfixOperators(
3973
3979
// Detect super()
3974
3980
if (this->NodeIsSuperName(pnode))
3975
3981
{
3982
+ if (isNullPropagating)
3983
+ {
3984
+ Error(ERRInvalidOptChainInSuper);
3985
+ }
3986
+
3976
3987
pnode = CreateSuperCallNode(pnode->AsParseNodeSpecialName(), pnodeArgs);
3977
3988
Assert(pnode);
3978
3989
@@ -4007,6 +4018,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
4007
4018
pnode->AsParseNodeCall()->isApplyCall = false;
4008
4019
pnode->AsParseNodeCall()->isEvalCall = fCallIsEval;
4009
4020
pnode->AsParseNodeCall()->hasDestructuring = m_hasDestructuringPattern;
4021
+ pnode->AsParseNodeCall()->isNullPropagating = isNullPropagating;
4010
4022
Assert(!m_hasDestructuringPattern || count > 0);
4011
4023
pnode->AsParseNodeCall()->argCount = count;
4012
4024
pnode->ichLim = this->GetScanner()->IchLimTok();
@@ -4042,7 +4054,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
4042
4054
}
4043
4055
if (pfCanAssign)
4044
4056
{
4045
- *pfCanAssign = fCanAssignToCallResult &&
4057
+ *pfCanAssign = !isNullPropagating && fCanAssignToCallResult &&
4046
4058
(m_sourceContextInfo ?
4047
4059
!PHASE_ON_RAW(Js::EarlyErrorOnAssignToCallPhase, m_sourceContextInfo->sourceContextId, GetCurrentFunctionNode()->functionId) :
4048
4060
!PHASE_ON1(Js::EarlyErrorOnAssignToCallPhase));
@@ -4055,6 +4067,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
4055
4067
}
4056
4068
case tkLBrack:
4057
4069
{
4070
+ bool isNullPropagating = tkOptChain == this->GetScanner()->m_tkPrevious;
4071
+
4058
4072
this->GetScanner()->Scan();
4059
4073
IdentToken tok;
4060
4074
ParseNodePtr pnodeExpr = ParseExpr<buildAST>(0, FALSE, TRUE, FALSE, nullptr, nullptr, nullptr, &tok);
@@ -4063,12 +4077,17 @@ ParseNodePtr Parser::ParsePostfixOperators(
4063
4077
AnalysisAssert(pnodeExpr);
4064
4078
if (pnode && pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper)
4065
4079
{
4080
+ if (isNullPropagating)
4081
+ {
4082
+ Error(ERRInvalidOptChainInSuper);
4083
+ }
4084
+
4066
4085
pnode = CreateSuperReferenceNode(knopIndex, pnode->AsParseNodeSpecialName(), pnodeExpr);
4067
4086
pnode->AsParseNodeSuperReference()->pnodeThis = ReferenceSpecialName(wellKnownPropertyPids._this, pnode->ichMin, pnode->ichLim, true);
4068
4087
}
4069
4088
else
4070
4089
{
4071
- pnode = CreateBinNode(knopIndex, pnode, pnodeExpr);
4090
+ pnode = CreateBinNode(knopIndex, pnode, pnodeExpr, isNullPropagating );
4072
4091
}
4073
4092
4074
4093
AnalysisAssert(pnode);
@@ -4082,7 +4101,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
4082
4101
ChkCurTok(tkRBrack, ERRnoRbrack);
4083
4102
if (pfCanAssign)
4084
4103
{
4085
- *pfCanAssign = TRUE;
4104
+ // optional assignment not permitted
4105
+ *pfCanAssign = !isNullPropagating;
4086
4106
}
4087
4107
if (pfIsDotOrIndex)
4088
4108
{
@@ -4178,8 +4198,13 @@ ParseNodePtr Parser::ParsePostfixOperators(
4178
4198
this->GetScanner()->Scan();
4179
4199
if (!m_token.IsIdentifier())
4180
4200
{
4181
- //allow reserved words in ES5 mode
4182
- if (!(m_token.IsReservedWord()))
4201
+ if (isNullPropagating && (tkLParen == m_token.tk || tkLBrack == m_token.tk))
4202
+ {
4203
+ // Continue to parse function or index (loop)
4204
+ // Check previous token to check for null-propagation
4205
+ continue;
4206
+ }
4207
+ else if (!(m_token.IsReservedWord())) //allow reserved words in ES5 mode
4183
4208
{
4184
4209
IdentifierExpectedError(m_token);
4185
4210
}
@@ -4206,6 +4231,11 @@ ParseNodePtr Parser::ParsePostfixOperators(
4206
4231
}
4207
4232
if (pnode && pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper)
4208
4233
{
4234
+ if (isNullPropagating)
4235
+ {
4236
+ Error(ERRInvalidOptChainInSuper);
4237
+ }
4238
+
4209
4239
pnode = CreateSuperReferenceNode(opCode, pnode->AsParseNodeSpecialName(), name);
4210
4240
pnode->AsParseNodeSuperReference()->pnodeThis = ReferenceSpecialName(wellKnownPropertyPids._this, pnode->ichMin, pnode->ichLim, true);
4211
4241
}
@@ -4222,7 +4252,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
4222
4252
4223
4253
if (pfCanAssign)
4224
4254
{
4225
- *pfCanAssign = TRUE;
4255
+ // optional assignment not permitted
4256
+ *pfCanAssign = !isNullPropagating;
4226
4257
}
4227
4258
if (pfIsDotOrIndex)
4228
4259
{
0 commit comments