Skip to content

Commit 47190b0

Browse files
Parse call
1 parent 64c73e4 commit 47190b0

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

lib/Parser/Parse.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3919,8 +3919,14 @@ ParseNodePtr Parser::ParsePostfixOperators(
39193919
{
39203920
AutoMarkInParsingArgs autoMarkInParsingArgs(this);
39213921

3922+
bool isNullPropagating = tkOptChain == this->GetScanner()->m_tkPrevious;
39223923
if (fInNew)
39233924
{
3925+
if (isNullPropagating)
3926+
{
3927+
Error(ERRInvalidOptChainInNew);
3928+
}
3929+
39243930
ParseNodePtr pnodeArgs = ParseArgList<buildAST>(&callOfConstants, &spreadArgCount, &count);
39253931
if (buildAST)
39263932
{
@@ -3973,6 +3979,11 @@ ParseNodePtr Parser::ParsePostfixOperators(
39733979
// Detect super()
39743980
if (this->NodeIsSuperName(pnode))
39753981
{
3982+
if (isNullPropagating)
3983+
{
3984+
Error(ERRInvalidOptChainInSuper);
3985+
}
3986+
39763987
pnode = CreateSuperCallNode(pnode->AsParseNodeSpecialName(), pnodeArgs);
39773988
Assert(pnode);
39783989

@@ -4007,6 +4018,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
40074018
pnode->AsParseNodeCall()->isApplyCall = false;
40084019
pnode->AsParseNodeCall()->isEvalCall = fCallIsEval;
40094020
pnode->AsParseNodeCall()->hasDestructuring = m_hasDestructuringPattern;
4021+
pnode->AsParseNodeCall()->isNullPropagating = isNullPropagating;
40104022
Assert(!m_hasDestructuringPattern || count > 0);
40114023
pnode->AsParseNodeCall()->argCount = count;
40124024
pnode->ichLim = this->GetScanner()->IchLimTok();
@@ -4042,7 +4054,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
40424054
}
40434055
if (pfCanAssign)
40444056
{
4045-
*pfCanAssign = fCanAssignToCallResult &&
4057+
*pfCanAssign = !isNullPropagating && fCanAssignToCallResult &&
40464058
(m_sourceContextInfo ?
40474059
!PHASE_ON_RAW(Js::EarlyErrorOnAssignToCallPhase, m_sourceContextInfo->sourceContextId, GetCurrentFunctionNode()->functionId) :
40484060
!PHASE_ON1(Js::EarlyErrorOnAssignToCallPhase));
@@ -4055,6 +4067,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
40554067
}
40564068
case tkLBrack:
40574069
{
4070+
bool isNullPropagating = tkOptChain == this->GetScanner()->m_tkPrevious;
4071+
40584072
this->GetScanner()->Scan();
40594073
IdentToken tok;
40604074
ParseNodePtr pnodeExpr = ParseExpr<buildAST>(0, FALSE, TRUE, FALSE, nullptr, nullptr, nullptr, &tok);
@@ -4063,12 +4077,17 @@ ParseNodePtr Parser::ParsePostfixOperators(
40634077
AnalysisAssert(pnodeExpr);
40644078
if (pnode && pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper)
40654079
{
4080+
if (isNullPropagating)
4081+
{
4082+
Error(ERRInvalidOptChainInSuper);
4083+
}
4084+
40664085
pnode = CreateSuperReferenceNode(knopIndex, pnode->AsParseNodeSpecialName(), pnodeExpr);
40674086
pnode->AsParseNodeSuperReference()->pnodeThis = ReferenceSpecialName(wellKnownPropertyPids._this, pnode->ichMin, pnode->ichLim, true);
40684087
}
40694088
else
40704089
{
4071-
pnode = CreateBinNode(knopIndex, pnode, pnodeExpr);
4090+
pnode = CreateBinNode(knopIndex, pnode, pnodeExpr, isNullPropagating);
40724091
}
40734092

40744093
AnalysisAssert(pnode);
@@ -4082,7 +4101,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
40824101
ChkCurTok(tkRBrack, ERRnoRbrack);
40834102
if (pfCanAssign)
40844103
{
4085-
*pfCanAssign = TRUE;
4104+
// optional assignment not permitted
4105+
*pfCanAssign = !isNullPropagating;
40864106
}
40874107
if (pfIsDotOrIndex)
40884108
{
@@ -4178,8 +4198,13 @@ ParseNodePtr Parser::ParsePostfixOperators(
41784198
this->GetScanner()->Scan();
41794199
if (!m_token.IsIdentifier())
41804200
{
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
41834208
{
41844209
IdentifierExpectedError(m_token);
41854210
}
@@ -4206,6 +4231,11 @@ ParseNodePtr Parser::ParsePostfixOperators(
42064231
}
42074232
if (pnode && pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper)
42084233
{
4234+
if (isNullPropagating)
4235+
{
4236+
Error(ERRInvalidOptChainInSuper);
4237+
}
4238+
42094239
pnode = CreateSuperReferenceNode(opCode, pnode->AsParseNodeSpecialName(), name);
42104240
pnode->AsParseNodeSuperReference()->pnodeThis = ReferenceSpecialName(wellKnownPropertyPids._this, pnode->ichMin, pnode->ichLim, true);
42114241
}
@@ -4222,7 +4252,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
42224252

42234253
if (pfCanAssign)
42244254
{
4225-
*pfCanAssign = TRUE;
4255+
// optional assignment not permitted
4256+
*pfCanAssign = !isNullPropagating;
42264257
}
42274258
if (pfIsDotOrIndex)
42284259
{

lib/Parser/perrors.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ LSC_ERROR_MSG(1102, ERRInvalidAsgTarget, "Invalid left-hand side in assignment."
120120
LSC_ERROR_MSG(1103, ERRMissingFrom, "Expected 'from' after import or export clause.")
121121

122122
// 1104 ERRsyntaxEOF
123-
// 1105-1199 available for future use
123+
124+
LSC_ERROR_MSG(1105, ERRInvalidOptChainInNew, "Invalid optional chain in new expression.")
125+
LSC_ERROR_MSG(1106, ERRInvalidOptChainInSuper, "Invalid optional chain in call to 'super'.")
126+
// 1107-1199 available for future use
124127

125128
// Generic errors intended to be re-usable
126129
LSC_ERROR_MSG(1200, ERRKeywordAfter, "Unexpected keyword '%s' after '%s'")

lib/Parser/ptree.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#include "ParserPch.h"
@@ -496,6 +497,7 @@ ParseNodeCall::ParseNodeCall(OpCode nop, charcount_t ichMin, charcount_t ichLim,
496497
this->isEvalCall = false;
497498
this->isSuperCall = false;
498499
this->hasDestructuring = false;
500+
this->isNullPropagating = false;
499501
}
500502

501503
ParseNodeStmt::ParseNodeStmt(OpCode nop, charcount_t ichMin, charcount_t ichLim)

lib/Parser/ptree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#pragma once
@@ -792,6 +793,7 @@ class ParseNodeCall : public ParseNode
792793
BYTE isEvalCall : 1;
793794
BYTE isSuperCall : 1;
794795
BYTE hasDestructuring : 1;
796+
bool isNullPropagating;
795797

796798
DISABLE_SELF_CAST(ParseNodeCall);
797799
};

0 commit comments

Comments
 (0)