From a591f4cbb05376ae7fc930bb1cd92e2285b0664d Mon Sep 17 00:00:00 2001 From: Claude Pache Date: Sat, 29 Jul 2017 23:06:56 +0200 Subject: [PATCH] new spec text New spec text without Nil. Closes #20. Closes #15 . --- .gitignore | 3 + package.json | 19 ++ spec.html | 611 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 633 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 spec.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5f4bdf --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +out/ +out-old/ diff --git a/package.json b/package.json new file mode 100644 index 0000000..ac950a4 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "private": true, + "name": "proposal-optional-chaining", + "version": "1.0.0", + "description": "Optional chaining proposal for ECMAScript", + "scripts": { + "clean": "rm -rf out", + "build": "npm run clean && mkdir out && ecmarkup --verbose spec.html out/index.html --css out/ecmarkup.css --js out/ecmarkup.js", + "watch": "npm run clean && mkdir out && ecmarkup --watch --verbose spec.html out/index.html --css out/ecmarkup.css --js out/ecmarkup.js", + "update-pages": "node node_modules/ecmarkup/bin/ecmarkup.js spec.html _index.html --css _ecmarkup.css --js _ecmarkup.js --verbose && git checkout gh-pages && rm -f index.html ecmarkup.css ecmarkup.js && mv _index.html index.html && mv _ecmarkup.css ecmarkup.css && mv _ecmarkup.js ecmarkup.js && git add index.html ecmarkup.js ecmarkup.css && git commit -m \"update pages\" && git checkout master" + }, + "repository": "tc39/proposal-optional-chaining", + "author": "Claude Pache", + "license": "CC0", + "homepage": "https://tc39.github.io/proposal-optional-chaining/", + "dependencies": { + "ecmarkup": "^3.11.5" + } +} diff --git a/spec.html b/spec.html new file mode 100644 index 0000000..5319382 --- /dev/null +++ b/spec.html @@ -0,0 +1,611 @@ + + + + + + + +
+  title: Optional Chaining
+  status: proposal
+  stage: 1
+  location: https://claudepache.github.io/es-nil
+  copyright: false
+  contributors: Claude Pache, ECMA International
+
+ + +

Scope

+

This is the spec text of the Optional Chaining proposal in ECMAScript.

+ +

For the syntax, we use the `?.` token, with a lookahead at the level of the lexical grammar that allows to discriminate between `a?.b` (optional chaining) and `a?.3:0` (conditional operator, whose meaning cannot be changed due to backward compatibility constraints).

+ +

An early version of this proposal used a Nil reference to express short-circuiting. This one is based on syntax only.

+ +

Normative additions are marked like this. In order to avoid distraction, we don’t mark mere editorial amendments.

+ +

List of significant editorial modifications:

+ + +
+ + + +

(11) ECMAScript Language: Lexical Grammar

+ + + + +

(11.7) Punctuators

+

Syntax

+ + + OptionalChainingPunctuator :: + `?.` [lookahead <! DecimalDigit + + + OtherPunctuator :: one of + `{` `(` `)` `[` `]` + `.` `...` `;` `,` + `<` `>` `<=` `>=` + `==` `!=` `===` `!==` + `+` `-` `*` `%` `**` + `++` `--` + `<<` `>>` `>>>` + `&` `|` `^` + `!` `~` + `&&` `||` + `?` `:` + `=` `+=` `-=` `*=` `%=` `**=` `<<=` `>>=` `>>>=` `&=` `|=` `^=` + `=>` + + Punctuator :: + OptionalChainingPunctuator + OtherPunctuator + + DivPunctuator :: + `/` + `/=` + + RightBracePunctuator :: + `}` + +
+ +
+ + + +

(12) ECMAScript Language: Expressions

+ + + + +

(12.3) Left-Hand-Side Expressions

+

Syntax

+ + MemberExpression[Yield, Await] : + PrimaryExpression[?Yield, ?Await] + MemberExpression[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` + MemberExpression[?Yield, ?Await] `.` IdentifierName + MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await] + SuperProperty[?Yield, ?Await] + MetaProperty + `new` MemberExpression[?Yield, ?Await] Arguments[?Yield, ?Await] + + SuperProperty[Yield, Await] : + `super` `[` Expression[+In, ?Yield, ?Await] `]` + `super` `.` IdentifierName + + MetaProperty : + NewTarget + + NewTarget : + `new` `.` `target` + + NewExpression[Yield, Await] : + MemberExpression[?Yield, ?Await] + `new` NewExpression[?Yield, ?Await] + + CallExpression[Yield, Await] : + CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] #callcover + SuperCall[?Yield, ?Await] + CallExpression[?Yield, ?Await] Arguments[?Yield, ?Await] + CallExpression[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` + CallExpression[?Yield, ?Await] `.` IdentifierName + CallExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await] + + SuperCall[Yield, Await] : + `super` Arguments[?Yield, ?Await] + + Arguments[Yield, Await] : + `(` `)` + `(` ArgumentList[?Yield, ?Await] `)` + `(` ArgumentList[?Yield, ?Await] `,` `)` + + ArgumentList[Yield, Await] : + AssignmentExpression[+In, ?Yield, ?Await] + `...` AssignmentExpression[+In, ?Yield, ?Await] + ArgumentList[?Yield, ?Await] `,` AssignmentExpression[+In, ?Yield, ?Await] + ArgumentList[?Yield, ?Await] `,` `...` AssignmentExpression[+In, ?Yield, ?Await] + + + OptionalChainingExpression[Yield, Await] : + MemberExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] + CallExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] + OptionalChainingExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] + + OptionalChain[Yield, Await] : + OptionalChainingPunctuator `[` Expression[+In, ?Yield, ?Await] `]` + OptionalChainingPunctuator `.` IdentifierName + OptionalChainingPunctuator Arguments[?Yield, ?Await] + OptionalChain[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` + OptionalChain[?Yield, ?Await] `.` IdentifierName + OptionalChain[?Yield, ?Await] Arguments[?Yield, ?Await] + + + LeftHandSideExpression[Yield, Await] : + NewExpression[?Yield, ?Await] + CallExpression[?Yield, ?Await] + OptionalChainingExpression[?Yield, ?Await] + +

Supplemental Syntax

+

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

+ + CallMemberExpression[Yield, Await] : + MemberExpression[?Yield, ?Await] Arguments[?Yield, ?Await] + + + + +

(12.3.1) Static Semantics

+ + +

Static Semantics: CoveredCallExpression

+ + CallExpression : CoverCallExpressionAndAsyncArrowHead + + + 1. Return the result of parsing the lexical token stream matched by |CoverCallExpressionAndAsyncArrowHead| using |CallMemberExpression| as the goal symbol with its [Yield] and [Await] parameters set to the values used when parsing |CoverCallExpressionAndAsyncArrowHead|. + +
+ + + +

Static Semantics: Contains

+

With parameter _symbol_.

+ + MemberExpression : MemberExpression `.` IdentifierName + + 1. If |MemberExpression| 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*. + + SuperProperty : `super` `.` IdentifierName + + 1. If _symbol_ is the |ReservedWord| `super`, 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*. + + CallExpression : CallExpression `.` IdentifierName + + 1. If |CallExpression| 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*. + + + OptionalChain : OptionalChainingPunctuator 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*. + + +
+ + + +

Static Semantics: IsFunctionDefinition

+ + + MemberExpression : + MemberExpression `[` Expression `]` + MemberExpression `.` IdentifierName + MemberExpression TemplateLiteral + SuperProperty + MetaProperty + `new` MemberExpression Arguments + + NewExpression : + `new` NewExpression + + LeftHandSideExpression : + CallExpression + OptionalChainingExpression + + + 1. Return *false*. + +
+ + + +

Static Semantics: IsDestructuring

+ + MemberExpression : PrimaryExpression + + 1. If |PrimaryExpression| is either an |ObjectLiteral| or an |ArrayLiteral|, return *true*. + 1. Return *false*. + + + MemberExpression : + MemberExpression `[` Expression `]` + MemberExpression `.` IdentifierName + MemberExpression TemplateLiteral + SuperProperty + MetaProperty + `new` MemberExpression Arguments + + NewExpression : + `new` NewExpression + + LeftHandSideExpression : + CallExpression + OptionalChainingExpression + + + 1. Return *false*. + +
+ + + +

Static Semantics: IsIdentifierRef

+ + + MemberExpression : + MemberExpression `[` Expression `]` + MemberExpression `.` IdentifierName + MemberExpression TemplateLiteral + SuperProperty + MetaProperty + `new` MemberExpression Arguments + + NewExpression : + `new` NewExpression + + LeftHandSideExpression : + CallExpression + OptionalChainingExpression + + + 1. Return *false*. + +
+ + + +

Static Semantics: IsValidSimpleAssignmentTarget

+ + + CallExpression : + CallExpression `[` Expression `]` + CallExpression `.` IdentifierName + + MemberExpression : + MemberExpression `[` Expression `]` + MemberExpression `.` IdentifierName + SuperProperty + + + 1. Return *true*. + + + CallExpression : + CoverCallExpressionAndAsyncArrowHead + SuperCall + CallExpression Arguments + CallExpression TemplateLiteral + + NewExpression : + `new` NewExpression + + MemberExpression : + MemberExpression TemplateLiteral + `new` MemberExpression Arguments + + NewTarget : + `new` `.` `target` + + + LeftHandSideExpression : + OptionalChainingExpression + + + + 1. Return *false*. + +
+
+ + + +

(12.3.2) Property Accessors

+ +

Properties are accessed by name, using either the dot notation:

+
+ |MemberExpression| `.` |IdentifierName| +
+ |CallExpression| `.` |IdentifierName| +
+

or the bracket notation:

+
+ |MemberExpression| `[` |Expression| `]` +
+ |CallExpression| `[` |Expression| `]` +
+

The dot notation is explained by the following syntactic conversion:

+
+ |MemberExpression| `.` |IdentifierName| +
+

is identical in its behaviour to

+
+ |MemberExpression| `[` <identifier-name-string> `]` +
+

and similarly

+
+ |CallExpression| `.` |IdentifierName| +
+

is identical in its behaviour to

+
+ |CallExpression| `[` <identifier-name-string> `]` +
+

where <identifier-name-string> is the result of evaluating StringValue of |IdentifierName|.

+
+ + + +

Runtime Semantics: Evaluation

+ MemberExpression : MemberExpression `[` Expression `]` + + 1. Let _baseReference_ be the result of evaluating |MemberExpression|. + 1. Let _baseValue_ be ? GetValue(_baseReference_). + 1. If the code matched by this |MemberExpression| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 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. If the code matched by this |MemberExpression| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateStaticPropertyAccess(_baseValue_, |IdentifierName|, _strict_); + + CallExpression : CallExpression `[` Expression `]` + + 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 + + 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_. +
+ +
+ + + +

(12.3.3) The `new` Operator

+ +

(not modified)

+
+ + + +

(12.3.4) Function Calls

+ + + +

Runtime Semantics: Evaluation

+ CallExpression : CoverCallExpressionAndAsyncArrowHead + + 1. Let _expr_ be CoveredCallExpression of |CoverCallExpressionAndAsyncArrowHead|. + 1. Let _memberExpr_ be the |MemberExpression| of _expr_. + 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, 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. ReturnIfAbrupt(_argList_). + 1. If _argList_ has no elements, return *undefined*. + 1. Let _evalText_ be the first element of _argList_. + 1. If the source code matching this |CallExpression| is strict mode code, let _strictCaller_ be *true*. Otherwise let _strictCaller_ be *false*. + 1. Let _evalRealm_ be the current Realm Record. + 1. Perform ? HostEnsureCanCompileStrings(_evalRealm_, _evalRealm_). + 1. Return ? PerformEval(_evalText_, _evalRealm_, _strictCaller_, *true*). + 1. Let _thisCall_ be this |CallExpression|. + 1. Let _tailCall_ be IsInTailPosition(_thisCall_). + 1. Return ? EvaluateCall(_func_, _ref_, _arguments_, _tailCall_). + +

A |CallExpression| evaluation that executes step 6.a.vii is a direct eval.

+ CallExpression : CallExpression Arguments + + 1. Let _ref_ be the result of evaluating |CallExpression|. + 1. Let _func_ be ? GetValue(_ref_). + 1. Let _thisCall_ be this |CallExpression|. + 1. Let _tailCall_ be IsInTailPosition(_thisCall_). + 1. Return ? EvaluateCall(_func_, _ref_, |Arguments|, _tailCall_). + +
+ + + +

Runtime Semantics: EvaluateCall(_func_, _ref_, _arguments_, _tailPosition_ )

+

The abstract operation EvaluateCall takes as arguments a value _func_, a value _ref_, a Parse Node _arguments_, and a Boolean argument _tailPosition_. It performs the following steps:

+ + 1. If Type(_ref_) is Reference, then + 1. If IsPropertyReference(_ref_) is *true*, then + 1. Let _thisValue_ be GetThisValue(_ref_). + 1. Else the base of _ref_ is an Environment Record, + 1. Let _refEnv_ be GetBase(_ref_). + 1. Let _thisValue_ be _refEnv_.WithBaseObject(). + 1. Else Type(_ref_) is not Reference, + 1. Let _thisValue_ be *undefined*. + 1. Let _argList_ be ArgumentListEvaluation of _arguments_. + 1. ReturnIfAbrupt(_argList_). + 1. If Type(_func_) is not Object, throw a *TypeError* exception. + 1. If IsCallable(_func_) is *false*, throw a *TypeError* exception. + 1. If _tailPosition_ is *true*, perform PrepareForTailCall(). + 1. Let _result_ be Call(_func_, _thisValue_, _argList_). + 1. Assert: If _tailPosition_ is *true*, the above call will not return here, but instead evaluation will continue as if the following return has already occurred. + 1. Assert: If _result_ is not an abrupt completion, then Type(_result_) is an ECMAScript language type. + 1. Return _result_. + +
+
+ + + +

(12.3.5) The `super` Keyword

+ +

(not modified)

+
+ + + +

(12.3.6) Argument Lists

+ +

(not modified)

+
+ + + +

(12.3.7) Tagged Templates

+

(not modified)

+
+ + + +

Optional Chains

+ An optional chain is a chain of property accesses and function calls introduced by a |OptionalChainingPunctuator|. + + +

Runtime Semantics: Evaluation

+ + OptionalChainingExpression : + MemberExpression OptionalChain + CallExpression OptionalChain + OptionalChainingExpression OptionalChain + + + 1. Let _baseExpression_ be the first child of this production (i.e., this |MemberExpression|, |CallExpression|, or |OptionalChainingExpression|). + 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 : OptionalChainingPunctuator `[` Expression `]` + + 1. If the code matched by this |OptionalChain| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateDynamicPropertyAccess(_baseValue_, |Expression|, _strict_). + + OptionalChain : OptionalChainingPunctuator IdentifierName + + 1. If the code matched by this |OptionalChain| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateStaticPropertyAccess(_baseValue_, |IdentifierName|, _strict_). + + OptionalChain : OptionalChainingPunctuator Arguments + + 1. If the code matched by this |OptionalChain| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateCall(_baseValue_, _baseReference_, |Arguments|, _strict_). + + 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 |OptionalChain| 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 |OptionalChain| 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. If the code matched by this |OptionalChain| is strict mode code, let _strict_ be *true*, else let _strict_ be *false*. + 1. Return ? EvaluateCall(_newValue_, _newReference_, |Arguments|, _strict_). + +
+
+
+ + + +

(12.3.8) Meta Properties

+ +

(not modified)

+
+
+ +
+ + +