From 022a158dfe7f7ad41c59170c6200519e05c3ff0d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 24 Jul 2019 15:33:24 -0700 Subject: [PATCH] Normative: Add Optional Chaining --- spec.html | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 201 insertions(+), 12 deletions(-) diff --git a/spec.html b/spec.html index 4717216dbf2..b2048090734 100644 --- a/spec.html +++ b/spec.html @@ -10999,7 +10999,11 @@

Syntax

Punctuators

Syntax

- Punctuator :: one of + OptionalChainingPunctuator :: + `?.` [lookahead <! DecimalDigit] + OtherPunctuator + + OtherPunctuator :: one of `{` `(` `)` `[` `]` `.` `...` `;` `,` `<` `>` `<=` `>=` @@ -11014,6 +11018,10 @@

Syntax

`=` `+=` `-=` `*=` `%=` `**=` `<<=` `>>=` `>>>=` `&=` `|=` `^=` `=>` + Punctuator :: + OptionalChainingPunctuator + OtherPunctuator + DivPunctuator :: `/` `/=` @@ -13364,9 +13372,25 @@

Syntax

ArgumentList[?Yield, ?Await] `,` AssignmentExpression[+In, ?Yield, ?Await] ArgumentList[?Yield, ?Await] `,` `...` AssignmentExpression[+In, ?Yield, ?Await] + OptionalExpression[Yield, Await] : + MemberExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] + CallExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] + OptionalExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] + + OptionalChain[Yield, Await] : + `?.` `[` Expression[+In, ?Yield, ?Await] `]` + `?.` IdentifierName + `?.` Arguments[?Yield, ?Await] + `?.` TemplateLiteral[?Yield, ?Await, +Tagged] + OptionalChain[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` + OptionalChain[?Yield, ?Await] `.` IdentifierName + OptionalChain[?Yield, ?Await] Arguments[?Yield, ?Await] + OptionalChain[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] + LeftHandSideExpression[Yield, Await] : NewExpression[?Yield, ?Await] CallExpression[?Yield, ?Await] + OptionalExpression[?Yield, ?Await]

Supplemental Syntax

When processing an instance of the production CallExpression : CoverCallExpressionAndAsyncArrowHead the interpretation of |CoverCallExpressionAndAsyncArrowHead| is refined using the following grammar:

@@ -13378,6 +13402,33 @@

Supplemental Syntax

Static Semantics

+ +

Static Semantics: Early Errors

+ + OptionalChain[Yield, Await] : + `?.` TemplateLiteral[?Yield, ?Await, +Tagged] + OptionalChain[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] + +
    +
  • + It is a Syntax Error if any code matches this production. +
  • +
+ +

This production exists in order to prevent automatic semicolon insertion rules () to be applied to the following code:

+

+            a?.b
+            `c`
+          
+

so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code without optional chaining operator:

+

+            a.b
+            `c`
+          
+

which is a valid statement and where automatic semicolon insertion does not apply.

+
+
+

Static Semantics: CoveredCallExpression

@@ -13413,6 +13464,19 @@

Static Semantics: Contains

1. If _symbol_ is an |Identifier| and StringValue of _symbol_ is the same value as the StringValue of |IdentifierName|, return *true*. 1. Return *false*. + OptionalChain : `?.` IdentifierName + + 1. If _symbol_ is a |ReservedWord|, return *false*. + 1. If _symbol_ is an |Identifier| and StringValue of _symbol_ is the same value as the StringValue of |IdentifierName|, return *true*. + 1. Return *false*. + + OptionalChain : OptionalChain `.` IdentifierName + + 1. If |OptionalChain| Contains _symbol_ is *true*, return *true*. + 1. If _symbol_ is a |ReservedWord|, return *false*. + 1. If _symbol_ is an |Identifier| and StringValue of _symbol_ is the same value as the StringValue of |IdentifierName|, return *true*. + 1. Return *false*. +
@@ -13432,6 +13496,7 @@

Static Semantics: IsFunctionDefinition

LeftHandSideExpression : CallExpression + OptionalExpression 1. Return *false*. @@ -13460,6 +13525,7 @@

Static Semantics: IsDestructuring

LeftHandSideExpression : CallExpression + OptionalExpression 1. Return *false*. @@ -13483,6 +13549,7 @@

Static Semantics: IsIdentifierRef

LeftHandSideExpression : CallExpression + OptionalExpression 1. Return *false*. @@ -13522,6 +13589,9 @@

Static Semantics: AssignmentTargetType

NewTarget : `new` `.` `target` + + LeftHandSideExpression : + OptionalExpression 1. Return ~invalid~. @@ -13569,29 +13639,52 @@

Runtime Semantics: Evaluation

1. Let _baseReference_ be the result of evaluating |MemberExpression|. 1. Let _baseValue_ be ? GetValue(_baseReference_). - 1. Let _propertyNameReference_ be the result of evaluating |Expression|. - 1. Let _propertyNameValue_ be ? GetValue(_propertyNameReference_). - 1. Let _bv_ be ? RequireObjectCoercible(_baseValue_). - 1. Let _propertyKey_ be ? ToPropertyKey(_propertyNameValue_). 1. If the code matched by this |MemberExpression| is strict mode code, let _strict_ be *true*; else let _strict_ be *false*. - 1. Return a value of type Reference whose base value component is _bv_, whose referenced name component is _propertyKey_, and whose strict reference flag is _strict_. + 1. Return ? EvaluateDynamicPropertyAccess(_baseValue_, |Expression|, _strict_). MemberExpression : MemberExpression `.` IdentifierName 1. Let _baseReference_ be the result of evaluating |MemberExpression|. 1. Let _baseValue_ be ? GetValue(_baseReference_). - 1. Let _bv_ be ? RequireObjectCoercible(_baseValue_). - 1. Let _propertyNameString_ be StringValue of |IdentifierName|. 1. If the code matched by this |MemberExpression| is strict mode code, let _strict_ be *true*; else let _strict_ be *false*. - 1. Return a value of type Reference whose base value component is _bv_, whose referenced name component is _propertyNameString_, and whose strict reference flag is _strict_. + 1. Return ? EvaluateStaticPropertyAccess(_baseValue_, |IdentifierName|, _strict_); CallExpression : CallExpression `[` Expression `]` -

Is evaluated in exactly the same manner as MemberExpression : MemberExpression `[` Expression `]` except that the contained |CallExpression| is evaluated in step 1.

+ + 1. Let _baseReference_ be the result of evaluating |CallExpression|. + 1. Let _baseValue_ be ? GetValue(_baseReference_). + 1. If the code matched by this |CallExpression| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateDynamicPropertyAccess(_baseValue_, |Expression|, _strict_). + CallExpression : CallExpression `.` IdentifierName -

Is evaluated in exactly the same manner as MemberExpression : MemberExpression `.` IdentifierName except that the contained |CallExpression| is evaluated in step 1.

+ + 1. Let _baseReference_ be the result of evaluating |CallExpression|. + 1. Let _baseValue_ be ? GetValue(_baseReference_). + 1. If the code matched by this |CallExpression| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateStaticPropertyAccess(_baseValue_, |IdentifierName|, _strict_); +
+ +

Runtime Semantics: EvaluateDynamicPropertyAccess(_baseValue_, _expression_, _strict_ )

+

The abstract operation EvaluateDynamicPropertyAccess takes as arguments a value _baseValue_, a Parse Node _expression_, and a Boolean argument _strict_. It performs the following steps:

+ + 1. Let _propertyNameReference_ be the result of evaluating _expression_. + 1. Let _propertyNameValue_ be ? GetValue(_propertyNameReference_). + 1. Let _bv_ be ? RequireObjectCoercible(_baseValue_). + 1. Let _propertyKey_ be ? ToPropertyKey(_propertyNameValue_). + 1. Return a value of type Reference whose base value component is _bv_, whose referenced name component is _propertyKey_, and whose strict reference flag is _strict_. +
+ +

Runtime Semantics: EvaluateStaticPropertyAccess(_baseValue_, _identifierName_, _strict_ )

+

The abstract operation EvaluateStaticPropertyAccess takes as arguments a value _baseValue_, a Parse Node _identifierName_, and a Boolean argument _strict_. It performs the following steps:

+ + 1. Let _bv_ be ? RequireObjectCoercible(_baseValue_). + 1. Let _propertyNameString_ be StringValue of _identifierName_. + 1. Return a value of type Reference whose base value component is _bv_, whose referenced name component is _propertyNameString_, and whose strict reference flag is _strict_. +
+

The `new` Operator

@@ -13636,7 +13729,7 @@

Runtime Semantics: Evaluation

1. Let _arguments_ be the |Arguments| of _expr_. 1. Let _ref_ be the result of evaluating _memberExpr_. 1. Let _func_ be ? GetValue(_ref_). - 1. If Type(_ref_) is Reference and IsPropertyReference(_ref_) is *false* and GetReferencedName(_ref_) is *"eval"*, then + 1. If Type(_ref_) is Reference, IsPropertyReference(_ref_) is *false*, and GetReferencedName(_ref_) is *"eval"*, then 1. If SameValue(_func_, %eval%) is *true*, then 1. Let _argList_ be ? ArgumentListEvaluation of _arguments_. 1. If _argList_ has no elements, return *undefined*. @@ -13799,6 +13892,74 @@

Runtime Semantics: ArgumentListEvaluation

+ +

Optional Chains

+ An optional chain is a chain of one or more property accesses and function calls, the first of which begins with the token `?.`. + +

Runtime Semantics: Evaluation

+ + OptionalExpression : + MemberExpression OptionalChain + CallExpression OptionalChain + OptionalExpression OptionalChain + + + 1. Let _baseExpression_ be the first child of this production (i.e., this |MemberExpression|, |CallExpression|, or |OptionalExpression|). + 1. Let _baseReference_ be ? _baseExpression_.Evaluation(). + 1. Let _baseValue_ be ? GetValue(_baseReference_). + 1. If _baseValue_ is *undefined* or *null*, then + 1. Return *undefined*. + 1. Let _optionalChain_ be this |OptionalChain|. + 1. Return ? _optionalChain_.ChainEvaluation(_baseValue_, _baseReference_). + +
+ +

Runtime Semantics: ChainEvaluation

+

With parameters _baseValue_ and _baseReference_.

+ OptionalChain : `?.` `[` Expression `]` + + 1. If the code matched by this production is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateDynamicPropertyAccess(_baseValue_, |Expression|, _strict_). + + OptionalChain : `?.` IdentifierName + + 1. If the code matched by this production is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateStaticPropertyAccess(_baseValue_, |IdentifierName|, _strict_). + + OptionalChain : `?.` Arguments + + 1. Let _thisChain_ be this production. + 1. Let _tailCall_ be IsInTailPosition(_thisChain_). + 1. Return ? EvaluateCall(_baseValue_, _baseReference_, |Arguments|, _tailCall_). + + OptionalChain : OptionalChain `[` Expression `]` + + 1. Let _optionalChain_ be this |OptionalChain|. + 1. Let _newReference_ be ? _optionalChain_.ChainEvaluation(_baseValue_, _baseReference_). + 1. Let _newValue_ be ? GetValue(_newReference_). + 1. If the code matched by this production is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateDynamicPropertyAccess(_newValue_, |Expression|, _strict_). + + OptionalChain : OptionalChain `.` IdentifierName + + 1. Let _optionalChain_ be this |OptionalChain|. + 1. Let _newReference_ be ? _optionalChain_.ChainEvaluation(_baseValue_, _baseReference_). + 1. Let _newValue_ be ? GetValue(_newReference_). + 1. If the code matched by this production is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateStaticPropertyAccess(_newValue_, |IdentifierName|, _strict_). + + OptionalChain : OptionalChain Arguments + + 1. Let _optionalChain_ be this |OptionalChain|. + 1. Let _newReference_ be ? _optionalChain_.ChainEvaluation(_baseValue_, _baseReference_). + 1. Let _newValue_ be ? GetValue(_newReference_). + 1. Let _thisChain_ be this production. + 1. Let _tailCall_ be IsInTailPosition(_thisChain_). + 1. Return ? EvaluateCall(_newValue_, _newReference_, |Arguments|, _tailCall_). + +
+
+

Import Calls

@@ -21733,6 +21894,34 @@

Expression Rules

1. If this |CallExpression| is _call_, return *true*. 1. Return *false*. + + OptionalExpression : + MemberExpression OptionalChain + CallExpression OptionalChain + OptionalExpression OptionalChain + + + 1. Return HasCallInTailPosition of |OptionalChain| with argument _call_. + + + OptionalChain : + `?.` `[` Expression `]` + `?.` IdentifierName + OptionalChain `[` Expression `]` + OptionalChain `.` IdentifierName + + + 1. Return *false*. + + + OptionalChain : + `?.` Arguments + OptionalChain Arguments + + + 1. If this |OptionalChain| is _call_, return *true*. + 1. Return *false*. + MemberExpression : MemberExpression TemplateLiteral