mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 16:58:38 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
f3c7008077
333 changed files with 15703 additions and 5992 deletions
|
|
@ -361,6 +361,8 @@ int main(int argc, char* argv[], char* envp[])
|
|||
return 255;
|
||||
}
|
||||
|
||||
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
|
||||
|
||||
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
|
||||
XRE_EnableSameExecutableForContentProc();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1042,11 +1042,6 @@
|
|||
if (this.mCurrentBrowser == newBrowser && !aForceUpdate)
|
||||
return;
|
||||
|
||||
if (!aForceUpdate) {
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
|
||||
.beginTabSwitch();
|
||||
}
|
||||
|
||||
var oldTab = this.mCurrentTab;
|
||||
|
||||
// Preview mode should not reset the owner
|
||||
|
|
@ -1757,8 +1752,6 @@
|
|||
|
||||
if (animate) {
|
||||
requestAnimationFrame(function () {
|
||||
this.tabContainer._handleTabTelemetryStart(t, aURI);
|
||||
|
||||
// kick the animation off
|
||||
t.setAttribute("fadein", "true");
|
||||
|
||||
|
|
@ -1959,8 +1952,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
this.tabContainer._handleTabTelemetryStart(aTab);
|
||||
|
||||
this._blurTab(aTab);
|
||||
aTab.style.maxWidth = ""; // ensure that fade-out transition happens
|
||||
aTab.removeAttribute("fadein");
|
||||
|
|
@ -3628,7 +3619,6 @@
|
|||
window.addEventListener("resize", this, false);
|
||||
window.addEventListener("load", this, false);
|
||||
|
||||
this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled", false);
|
||||
this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
|
||||
]]>
|
||||
</constructor>
|
||||
|
|
@ -4327,85 +4317,6 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_handleTabTelemetryStart">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aURI"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// Animation-smoothness telemetry/logging
|
||||
if (this._tabAnimationLoggingEnabled) {
|
||||
if (aURI == "about:newtab" && (aTab._tPos == 1 || aTab._tPos == 2)) {
|
||||
// Indicate newtab page animation where other tabs are unaffected
|
||||
// (for which case, the 2nd or 3rd tabs are good representatives, even if not absolute)
|
||||
aTab._recordingTabOpenPlain = true;
|
||||
}
|
||||
aTab._recordingHandle = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.startFrameTimeRecording();
|
||||
}
|
||||
|
||||
// Overall animation duration
|
||||
aTab._animStartTime = Date.now();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_handleTabTelemetryEnd">
|
||||
<parameter name="aTab"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!aTab._animStartTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
aTab._animStartTime = 0;
|
||||
|
||||
// Handle tab animation smoothness telemetry/logging of frame intervals and paint times
|
||||
if (!("_recordingHandle" in aTab)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let paints = {};
|
||||
let intervals = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.stopFrameTimeRecording(aTab._recordingHandle, paints);
|
||||
delete aTab._recordingHandle;
|
||||
paints = paints.value; // The result array itself.
|
||||
let frameCount = intervals.length;
|
||||
|
||||
if (this._tabAnimationLoggingEnabled) {
|
||||
let msg = "Tab " + (aTab.closing ? "close" : "open") + " (Frame-interval / paint-processing):\n";
|
||||
for (let i = 0; i < frameCount; i++) {
|
||||
msg += Math.round(intervals[i]) + " / " + Math.round(paints[i]) + "\n";
|
||||
}
|
||||
Services.console.logStringMessage(msg);
|
||||
}
|
||||
|
||||
// For telemetry, the first frame interval is not useful since it may represent an interval
|
||||
// to a relatively old frame (prior to recording start). So we'll ignore it for the average.
|
||||
// But if we recorded only 1 frame (very rare), then the first paint duration is a good
|
||||
// representative of the first frame interval for our cause (indicates very bad animation).
|
||||
// First paint duration is always useful for us.
|
||||
if (frameCount > 0) {
|
||||
let averageInterval = 0;
|
||||
let averagePaint = paints[0];
|
||||
for (let i = 1; i < frameCount; i++) {
|
||||
averageInterval += intervals[i];
|
||||
averagePaint += paints[i];
|
||||
};
|
||||
averagePaint /= frameCount;
|
||||
averageInterval = (frameCount == 1)
|
||||
? averagePaint
|
||||
: averageInterval / (frameCount - 1);
|
||||
|
||||
if (aTab._recordingTabOpenPlain) {
|
||||
delete aTab._recordingTabOpenPlain;
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<!-- Deprecated stuff, implemented for backwards compatibility. -->
|
||||
<property name="mTabstripClosebutton" readonly="true"
|
||||
onget="return document.getElementById('tabs-closebutton');"/>
|
||||
|
|
@ -4422,8 +4333,6 @@
|
|||
|
||||
var tab = event.target;
|
||||
|
||||
this._handleTabTelemetryEnd(tab);
|
||||
|
||||
if (tab.getAttribute("fadein") == "true") {
|
||||
if (tab._fullyOpen)
|
||||
this.adjustTabstrip();
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
28.10.5a1
|
||||
28.10.6a1
|
||||
|
|
@ -195,7 +195,6 @@ this.AutoCompletePopup = {
|
|||
this.openedPopup.hidePopup();
|
||||
} catch(e) {
|
||||
Cu.reportError(e);
|
||||
console.log("Debug: ", this.openedPopup);
|
||||
}
|
||||
}
|
||||
AutoCompleteTreeView.clearResults();
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@
|
|||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
4.8.4
|
||||
4.8.5
|
||||
|
|
@ -178,6 +178,22 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
|
|||
}
|
||||
|
||||
let completionPart = inputValue.substring(beginning.startPos);
|
||||
|
||||
// Strip optional chaining characters from completion part, which we check
|
||||
// by looking if it has ?. and if there are no digits (marker for ternary).
|
||||
let optionalChainRegex = /\?\./g;
|
||||
let optionalElemAccessRegex = /\?\.\[/g;
|
||||
let digitRegex = /\?\.\d/;
|
||||
// Handle optional element access
|
||||
if (optionalElemAccessRegex.test(completionPart)) {
|
||||
completionPart = completionPart.replace(optionalElemAccessRegex, "[");
|
||||
}
|
||||
// Handle optional chaining characters
|
||||
if (optionalChainRegex.test(completionPart) &&
|
||||
!digitRegex.test(completionPart)) {
|
||||
completionPart = completionPart.replace(optionalChainRegex, ".");
|
||||
}
|
||||
|
||||
let lastDot = completionPart.lastIndexOf(".");
|
||||
|
||||
// Don't complete on just an empty string.
|
||||
|
|
|
|||
|
|
@ -145,6 +145,38 @@ function runChecks(dbgObject, dbgEnv) {
|
|||
do_print("Test that suggestions are not given if there is an hyphen in the chain.");
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "testHyphenated['prop-A'].");
|
||||
do_check_null(results);
|
||||
|
||||
do_print("Test that expression with optional chaining operator are completed");
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "testObject?.prop");
|
||||
test_has_result(results, "propA");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "testObject?.propA[0]?.propB?.to");
|
||||
test_has_result(results, "toString");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "testObject?.propA?.[0]?.propB?.to");
|
||||
test_has_result(results, "toString");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "[1,2,3]?.");
|
||||
test_has_result(results, "indexOf");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "'foo'?.");
|
||||
test_has_result(results, "charAt");
|
||||
|
||||
// Check this doesn't throw since `propC` is not defined.
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "testObject?.propC?.this?.does?.not?.exist?.d");
|
||||
|
||||
// Test more ternary
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "true ? t");
|
||||
test_has_result(results, "testObject");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "true ?? t");
|
||||
test_has_result(results, "testObject");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "true ? /* comment */ t");
|
||||
test_has_result(results, "testObject");
|
||||
|
||||
results = JSPropertyProvider(dbgObject, dbgEnv, "true?<t");
|
||||
test_has_no_results(results);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -69,9 +69,12 @@ public:
|
|||
}
|
||||
|
||||
DOMHighResTimeStamp FetchStart() const {
|
||||
return mTiming
|
||||
if (mTiming) {
|
||||
return mTiming->TimingAllowed()
|
||||
? mTiming->FetchStartHighRes()
|
||||
: 0;
|
||||
: StartTime();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp RedirectStart() const {
|
||||
|
|
|
|||
|
|
@ -576,10 +576,11 @@ class NodeBuilder
|
|||
MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
|
||||
MutableHandleValue dst);
|
||||
MutableHandleValue dst, bool isOptional = false);
|
||||
|
||||
MOZ_MUST_USE bool memberExpression(bool computed, HandleValue expr, HandleValue member,
|
||||
TokenPos* pos, MutableHandleValue dst);
|
||||
TokenPos* pos, MutableHandleValue dst,
|
||||
bool isOptional = false);
|
||||
|
||||
MOZ_MUST_USE bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
|
||||
|
||||
|
|
@ -593,6 +594,11 @@ class NodeBuilder
|
|||
|
||||
MOZ_MUST_USE bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool optionalExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool deleteOptionalExpression(HandleValue expr, TokenPos* pos,
|
||||
MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
|
||||
|
|
@ -1121,7 +1127,7 @@ NodeBuilder::sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleVa
|
|||
|
||||
bool
|
||||
NodeBuilder::callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
|
||||
MutableHandleValue dst)
|
||||
MutableHandleValue dst, bool isOptional)
|
||||
{
|
||||
RootedValue array(cx);
|
||||
if (!newArray(args, &array))
|
||||
|
|
@ -1131,9 +1137,12 @@ NodeBuilder::callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
|
|||
if (!cb.isNull())
|
||||
return callback(cb, callee, array, pos, dst);
|
||||
|
||||
return newNode(AST_CALL_EXPR, pos,
|
||||
"callee", callee,
|
||||
"arguments", array,
|
||||
return newNode(isOptional ? AST_OPT_CALL_EXPR : AST_CALL_EXPR,
|
||||
pos,
|
||||
"callee",
|
||||
callee,
|
||||
"arguments",
|
||||
array,
|
||||
dst);
|
||||
}
|
||||
|
||||
|
|
@ -1157,7 +1166,7 @@ NodeBuilder::newExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
|
|||
|
||||
bool
|
||||
NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos* pos,
|
||||
MutableHandleValue dst)
|
||||
MutableHandleValue dst, bool isOptional)
|
||||
{
|
||||
RootedValue computedVal(cx, BooleanValue(computed));
|
||||
|
||||
|
|
@ -1165,10 +1174,14 @@ NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue membe
|
|||
if (!cb.isNull())
|
||||
return callback(cb, computedVal, expr, member, pos, dst);
|
||||
|
||||
return newNode(AST_MEMBER_EXPR, pos,
|
||||
"object", expr,
|
||||
"property", member,
|
||||
"computed", computedVal,
|
||||
return newNode(isOptional ? AST_OPT_MEMBER_EXPR : AST_MEMBER_EXPR,
|
||||
pos,
|
||||
"object",
|
||||
expr,
|
||||
"property",
|
||||
member,
|
||||
"computed",
|
||||
computedVal,
|
||||
dst);
|
||||
}
|
||||
|
||||
|
|
@ -1231,6 +1244,22 @@ NodeBuilder::spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValu
|
|||
dst);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::optionalExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst)
|
||||
{
|
||||
return newNode(AST_OPTIONAL_EXPR, pos,
|
||||
"expression", expr,
|
||||
dst);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::deleteOptionalExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst)
|
||||
{
|
||||
return newNode(AST_DELETE_OPTIONAL_EXPR, pos,
|
||||
"expression", expr,
|
||||
dst);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos* pos,
|
||||
MutableHandleValue dst)
|
||||
|
|
@ -2950,9 +2979,22 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
case PNK_GENEXP:
|
||||
return generatorExpression(pn->generatorExpr(), dst);
|
||||
|
||||
case PNK_DELETEOPTCHAIN: {
|
||||
RootedValue expr(cx);
|
||||
return expression(pn->pn_kid, &expr) &&
|
||||
builder.deleteOptionalExpression(expr, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_OPTCHAIN: {
|
||||
RootedValue expr(cx);
|
||||
return expression(pn->pn_kid, &expr) &&
|
||||
builder.optionalExpression(expr, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_NEW:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALL:
|
||||
case PNK_OPTCALL:
|
||||
case PNK_SUPERCALL:
|
||||
{
|
||||
ParseNode* next = pn->pn_head;
|
||||
|
|
@ -2984,13 +3026,15 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
if (pn->getKind() == PNK_TAGGED_TEMPLATE)
|
||||
return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
|
||||
|
||||
bool isOptional = pn->isKind(PNK_OPTCALL);
|
||||
|
||||
// SUPERCALL is Call(super, args)
|
||||
return pn->isKind(PNK_NEW)
|
||||
? builder.newExpression(callee, args, &pn->pn_pos, dst)
|
||||
|
||||
: builder.callExpression(callee, args, &pn->pn_pos, dst);
|
||||
: builder.callExpression(callee, args, &pn->pn_pos, dst, isOptional);
|
||||
}
|
||||
|
||||
case PNK_OPTDOT:
|
||||
case PNK_DOT:
|
||||
{
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
|
||||
|
|
@ -2999,7 +3043,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
RootedValue propname(cx);
|
||||
RootedAtom pnAtom(cx, pn->pn_atom);
|
||||
|
||||
if (pn->as<PropertyAccess>().isSuper()) {
|
||||
bool isSuper = pn->is<PropertyAccess>() &&
|
||||
pn->as<PropertyAccess>().isSuper();
|
||||
|
||||
if (isSuper) {
|
||||
if (!builder.super(&pn->pn_expr->pn_pos, &expr))
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -3007,10 +3054,14 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isOptional = pn->isKind(PNK_OPTDOT);
|
||||
|
||||
return identifier(pnAtom, nullptr, &propname) &&
|
||||
builder.memberExpression(false, expr, propname, &pn->pn_pos, dst);
|
||||
builder.memberExpression(false, expr, propname, &pn->pn_pos,
|
||||
dst, isOptional);
|
||||
}
|
||||
|
||||
case PNK_OPTELEM:
|
||||
case PNK_ELEM:
|
||||
{
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
|
||||
|
|
@ -3018,7 +3069,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
|
||||
RootedValue left(cx), right(cx);
|
||||
|
||||
if (pn->as<PropertyByValue>().isSuper()) {
|
||||
bool isSuper = pn->is<PropertyByValue>() &&
|
||||
pn->as<PropertyByValue>().isSuper();
|
||||
|
||||
if (isSuper) {
|
||||
if (!builder.super(&pn->pn_left->pn_pos, &left))
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -3026,8 +3080,11 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isOptional = pn->isKind(PNK_OPTELEM);
|
||||
|
||||
return expression(pn->pn_right, &right) &&
|
||||
builder.memberExpression(true, left, right, &pn->pn_pos, dst);
|
||||
builder.memberExpression(true, left, right, &pn->pn_pos, dst,
|
||||
isOptional);
|
||||
}
|
||||
|
||||
case PNK_CALLSITEOBJ:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,6 +19,8 @@
|
|||
#include "frontend/SourceNotes.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
||||
class OptionalEmitter;
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
|
|
@ -456,6 +458,11 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue,
|
||||
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
|
||||
|
||||
// Emit code for the optional tree rooted at pn.
|
||||
MOZ_MUST_USE bool emitOptionalTree(ParseNode* pn,
|
||||
OptionalEmitter& oe,
|
||||
ValueUsage valueUsage = ValueUsage::WantValue);
|
||||
|
||||
// Emit code for the tree rooted at pn with its own TDZ cache.
|
||||
MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
|
||||
ValueUsage valueUsage = ValueUsage::WantValue);
|
||||
|
|
@ -731,6 +738,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
|
||||
MOZ_MUST_USE bool emitAsyncIterator();
|
||||
|
||||
// XXX currently used only by OptionalEmitter, research still required
|
||||
// to identify when this was introduced in m-c.
|
||||
MOZ_MUST_USE bool emitPushNotUndefinedOrNull();
|
||||
|
||||
// Pops iterator from the top of the stack. Pushes the result of |.next()|
|
||||
// onto the stack.
|
||||
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
|
||||
|
|
@ -776,6 +787,32 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitDeleteElement(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitDeleteExpression(ParseNode* pn);
|
||||
|
||||
// Optional methods which emit Optional Jump Target
|
||||
MOZ_MUST_USE bool emitOptionalChain(ParseNode* optionalChain,
|
||||
ValueUsage valueUsage);
|
||||
MOZ_MUST_USE bool emitCalleeAndThisForOptionalChain(ParseNode* optionalChain,
|
||||
ParseNode* callNode,
|
||||
bool isCall);
|
||||
MOZ_MUST_USE bool emitDeleteOptionalChain(ParseNode* deleteNode);
|
||||
|
||||
// Optional methods which emit a shortCircuit jump. They need to be called by
|
||||
// a method which emits an Optional Jump Target, see below.
|
||||
MOZ_MUST_USE bool emitOptionalDotExpression(PropertyAccessBase* prop,
|
||||
OptionalEmitter& oe,
|
||||
ParseNode* calleeNode,
|
||||
bool isCall);
|
||||
MOZ_MUST_USE bool emitOptionalElemExpression(PropertyByValueBase* elem,
|
||||
OptionalEmitter& oe,
|
||||
ParseNode* calleeNode,
|
||||
bool isCall);
|
||||
MOZ_MUST_USE bool emitOptionalCall(ParseNode* callNode,
|
||||
OptionalEmitter& oe,
|
||||
ValueUsage valueUsage);
|
||||
MOZ_MUST_USE bool emitDeletePropertyInOptChain(PropertyAccessBase* propExpr,
|
||||
OptionalEmitter& oe);
|
||||
MOZ_MUST_USE bool emitDeleteElementInOptChain(PropertyByValueBase* elemExpr,
|
||||
OptionalEmitter& oe);
|
||||
|
||||
// |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
|
||||
MOZ_MUST_USE bool emitTypeof(ParseNode* node, JSOp op);
|
||||
|
||||
|
|
@ -794,7 +831,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result);
|
||||
MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
|
||||
|
||||
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
|
||||
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn,
|
||||
ValueUsage valueUsage = ValueUsage::WantValue);
|
||||
MOZ_MUST_USE bool emitCalleeAndThis(ParseNode* callNode,
|
||||
ParseNode* calleeNode,
|
||||
bool isCall);
|
||||
MOZ_MUST_USE bool emitOptionalCalleeAndThis(ParseNode* callNode,
|
||||
ParseNode* calleeNode,
|
||||
bool isCall,
|
||||
OptionalEmitter& oe);
|
||||
MOZ_MUST_USE bool emitCallOrNewThis(ParseNode* callNode,
|
||||
bool isCall);
|
||||
MOZ_MUST_USE bool emitCallOrNewArgumentsAndEnd(ParseNode* callNode,
|
||||
ParseNode* calleeNode,
|
||||
bool isCall,
|
||||
ValueUsage valueUsage);
|
||||
|
||||
MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
|||
case PNK_DELETEPROP:
|
||||
case PNK_DELETEELEM:
|
||||
case PNK_DELETEEXPR:
|
||||
case PNK_DELETEOPTCHAIN:
|
||||
case PNK_POS:
|
||||
case PNK_NEG:
|
||||
case PNK_PREINCREMENT:
|
||||
|
|
@ -368,6 +369,10 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
|||
case PNK_DOT:
|
||||
case PNK_ELEM:
|
||||
case PNK_CALL:
|
||||
case PNK_OPTCHAIN:
|
||||
case PNK_OPTDOT:
|
||||
case PNK_OPTELEM:
|
||||
case PNK_OPTCALL:
|
||||
case PNK_NAME:
|
||||
case PNK_TEMPLATE_STRING:
|
||||
case PNK_TEMPLATE_STRING_LIST:
|
||||
|
|
@ -1304,7 +1309,7 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>&
|
|||
{
|
||||
ParseNode* node = *nodePtr;
|
||||
|
||||
MOZ_ASSERT(node->isKind(PNK_ELEM));
|
||||
MOZ_ASSERT(node->isKind(PNK_ELEM) || node->isKind(PNK_OPTELEM));
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
|
||||
ParseNode*& expr = node->pn_left;
|
||||
|
|
@ -1348,9 +1353,15 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>&
|
|||
|
||||
// Optimization 3: We have expr["foo"] where foo is not an index. Convert
|
||||
// to a property access (like expr.foo) that optimizes better downstream.
|
||||
ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end);
|
||||
if (!dottedAccess)
|
||||
ParseNode* dottedAccess;
|
||||
if (node->isKind(PNK_OPTELEM)) {
|
||||
dottedAccess = parser.handler.newOptionalPropertyAccess(expr, name, node->pn_pos.end);
|
||||
} else {
|
||||
dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end);
|
||||
}
|
||||
if (!dottedAccess) {
|
||||
return false;
|
||||
}
|
||||
dottedAccess->setInParens(node->isInParens());
|
||||
ReplaceNode(nodePtr, dottedAccess);
|
||||
|
||||
|
|
@ -1522,7 +1533,9 @@ static bool
|
|||
FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
|
||||
bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_SUPERCALL) ||
|
||||
MOZ_ASSERT(node->isKind(PNK_CALL) ||
|
||||
node->isKind(PNK_OPTCALL) ||
|
||||
node->isKind(PNK_SUPERCALL) ||
|
||||
node->isKind(PNK_TAGGED_TEMPLATE));
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
|
||||
|
|
@ -1599,13 +1612,13 @@ static bool
|
|||
FoldDottedProperty(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
|
||||
bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_DOT));
|
||||
MOZ_ASSERT(node->isKind(PNK_DOT) || node->isKind(PNK_OPTDOT));
|
||||
MOZ_ASSERT(node->isArity(PN_NAME));
|
||||
|
||||
// Iterate through a long chain of dotted property accesses to find the
|
||||
// most-nested non-dotted property node, then fold that.
|
||||
ParseNode** nested = &node->pn_expr;
|
||||
while ((*nested)->isKind(PNK_DOT)) {
|
||||
while ((*nested)->isKind(PNK_DOT) || (*nested)->isKind(PNK_OPTDOT)) {
|
||||
MOZ_ASSERT((*nested)->isArity(PN_NAME));
|
||||
nested = &(*nested)->pn_expr;
|
||||
}
|
||||
|
|
@ -1632,6 +1645,9 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
ParseNode* pn = *pnp;
|
||||
#ifdef DEBUG
|
||||
ParseNodeKind kind = pn->getKind();
|
||||
#endif
|
||||
|
||||
switch (pn->getKind()) {
|
||||
case PNK_NOP:
|
||||
|
|
@ -1713,6 +1729,8 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
|
||||
|
||||
case PNK_DELETEOPTCHAIN:
|
||||
case PNK_OPTCHAIN:
|
||||
case PNK_SEMI:
|
||||
case PNK_THIS:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
|
|
@ -1806,6 +1824,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
case PNK_CLASS:
|
||||
return FoldClass(cx, pn, parser, inGenexpLambda);
|
||||
|
||||
case PNK_OPTELEM:
|
||||
case PNK_ELEM:
|
||||
return FoldElement(cx, pnp, parser, inGenexpLambda);
|
||||
|
||||
|
|
@ -1813,6 +1832,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
return FoldAdd(cx, pnp, parser, inGenexpLambda);
|
||||
|
||||
case PNK_CALL:
|
||||
case PNK_OPTCALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
return FoldCall(cx, pn, parser, inGenexpLambda);
|
||||
|
|
@ -1896,6 +1916,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
MOZ_ASSERT(pn->isArity(PN_NAME));
|
||||
return Fold(cx, &pn->pn_expr, parser, inGenexpLambda);
|
||||
|
||||
case PNK_OPTDOT:
|
||||
case PNK_DOT:
|
||||
return FoldDottedProperty(cx, pn, parser, inGenexpLambda);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ class FullParseHandler
|
|||
return node->isKind(PNK_DOT) || node->isKind(PNK_ELEM);
|
||||
}
|
||||
|
||||
bool isOptionalPropertyAccess(ParseNode* node) {
|
||||
return node->isKind(PNK_OPTDOT) || node->isKind(PNK_OPTELEM);
|
||||
}
|
||||
|
||||
bool isFunctionCall(ParseNode* node) {
|
||||
// Note: super() is a special form, *not* a function call.
|
||||
return node->isKind(PNK_CALL);
|
||||
|
|
@ -213,6 +217,18 @@ class FullParseHandler
|
|||
if (expr->isKind(PNK_ELEM))
|
||||
return newUnary(PNK_DELETEELEM, JSOP_NOP, begin, expr);
|
||||
|
||||
if (expr->isKind(PNK_OPTCHAIN)) {
|
||||
ParseNode* kid = expr->pn_kid;
|
||||
// Handle property deletion explicitly. OptionalCall is handled
|
||||
// via DeleteExpr.
|
||||
if (kid->isKind(PNK_DOT) ||
|
||||
kid->isKind(PNK_OPTDOT) ||
|
||||
kid->isKind(PNK_ELEM) ||
|
||||
kid->isKind(PNK_OPTELEM)) {
|
||||
return newUnary(PNK_DELETEOPTCHAIN, JSOP_NOP, begin, kid);
|
||||
}
|
||||
}
|
||||
|
||||
return newUnary(PNK_DELETEEXPR, JSOP_NOP, begin, expr);
|
||||
}
|
||||
|
||||
|
|
@ -319,6 +335,10 @@ class FullParseHandler
|
|||
return newList(PNK_CALL, JSOP_CALL);
|
||||
}
|
||||
|
||||
ParseNode* newOptionalCall() {
|
||||
return newList(PNK_OPTCALL, JSOP_CALL);
|
||||
}
|
||||
|
||||
ParseNode* newTaggedTemplate() {
|
||||
return newList(PNK_TAGGED_TEMPLATE, JSOP_CALL);
|
||||
}
|
||||
|
|
@ -459,6 +479,11 @@ class FullParseHandler
|
|||
return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
|
||||
}
|
||||
|
||||
ParseNode* newOptionalChain(uint32_t begin, ParseNode* value) {
|
||||
TokenPos pos(begin, value->pn_pos.end);
|
||||
return new_<UnaryNode>(PNK_OPTCHAIN, JSOP_NOP, pos, value);
|
||||
}
|
||||
|
||||
// Statements
|
||||
|
||||
ParseNode* newStatementList(const TokenPos& pos) {
|
||||
|
|
@ -678,6 +703,14 @@ class FullParseHandler
|
|||
return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
|
||||
}
|
||||
|
||||
ParseNode* newOptionalPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) {
|
||||
return new_<OptionalPropertyAccess>(pn, name, pn->pn_pos.begin, end);
|
||||
}
|
||||
|
||||
ParseNode* newOptionalPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) {
|
||||
return new_<OptionalPropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
|
||||
}
|
||||
|
||||
inline MOZ_MUST_USE bool addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope,
|
||||
ParseNode* catchName, ParseNode* catchGuard,
|
||||
ParseNode* catchBody);
|
||||
|
|
@ -920,7 +953,9 @@ class FullParseHandler
|
|||
return pn->isKind(PNK_CALL);
|
||||
}
|
||||
PropertyName* maybeDottedProperty(ParseNode* pn) {
|
||||
return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name() : nullptr;
|
||||
return pn->is<PropertyAccessBase>() ?
|
||||
&pn->as<PropertyAccessBase>().name() :
|
||||
nullptr;
|
||||
}
|
||||
JSAtom* isStringExprStatement(ParseNode* pn, TokenPos* pos) {
|
||||
if (JSAtom* atom = pn->isStringExprStatement()) {
|
||||
|
|
|
|||
|
|
@ -228,6 +228,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
|||
return PushUnaryNodeChild(pn, stack);
|
||||
|
||||
// Nodes with a single nullable child.
|
||||
case PNK_OPTCHAIN:
|
||||
case PNK_DELETEOPTCHAIN:
|
||||
case PNK_THIS:
|
||||
case PNK_SEMI: {
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
|
|
@ -253,6 +255,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
|||
case PNK_MODASSIGN:
|
||||
case PNK_POWASSIGN:
|
||||
// ...and a few others.
|
||||
case PNK_OPTELEM:
|
||||
case PNK_ELEM:
|
||||
case PNK_IMPORT_SPEC:
|
||||
case PNK_EXPORT_SPEC:
|
||||
|
|
@ -449,6 +452,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
|||
case PNK_POW:
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_OPTCALL:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_GENEXP:
|
||||
|
|
@ -483,6 +487,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
|||
}
|
||||
|
||||
case PNK_LABEL:
|
||||
case PNK_OPTDOT:
|
||||
case PNK_DOT:
|
||||
case PNK_NAME:
|
||||
return PushNameNodeChildren(pn, stack);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ class ObjectBox;
|
|||
F(POSTDECREMENT) \
|
||||
F(DOT) \
|
||||
F(ELEM) \
|
||||
F(OPTDOT) \
|
||||
F(OPTCHAIN) \
|
||||
F(OPTELEM) \
|
||||
F(OPTCALL) \
|
||||
F(ARRAY) \
|
||||
F(ELISION) \
|
||||
F(STATEMENTLIST) \
|
||||
|
|
@ -76,6 +80,7 @@ class ObjectBox;
|
|||
F(DELETEPROP) \
|
||||
F(DELETEELEM) \
|
||||
F(DELETEEXPR) \
|
||||
F(DELETEOPTCHAIN) \
|
||||
F(TRY) \
|
||||
F(CATCH) \
|
||||
F(CATCHLIST) \
|
||||
|
|
@ -371,6 +376,29 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* for a more-specific PNK_DELETE* unless constant
|
||||
* folding (or a similar parse tree manipulation) has
|
||||
* occurred
|
||||
* PNK_DELETEOPTCHAIN unary pn_kid: MEMBER expr that's evaluated, then the
|
||||
* overall delete evaluates to true; If constant
|
||||
* folding occurs, PNK_ELEM may become PNK_DOT.
|
||||
* PNK_OPTELEM does not get folded into PNK_OPTDOT.
|
||||
* PNK_OPTCHAIN unary pn_kid: expression that is evaluated as a chain.
|
||||
* Contains one or more optional nodes. Its first node
|
||||
* is always an optional node, such as PNK_OPTELEM,
|
||||
* PNK_OPTDOT, or PNK_OPTCALL. This will shortcircuit
|
||||
* and return 'undefined' without evaluating the rest
|
||||
* of the expression if any of the optional nodes it
|
||||
* contains are nullish. An optional chain can also
|
||||
* contain nodes such as PNK_DOT, PNK_ELEM, PNK_NAME,
|
||||
* PNK_CALL, etc. These are evaluated normally.
|
||||
* PNK_OPTDOT name pn_expr: MEMBER expr to left of .
|
||||
* short circuits back to PNK_OPTCHAIN if nullish.
|
||||
* pn_atom: name to right of .
|
||||
* PNK_OPTELEM binary pn_left: MEMBER expr to left of [
|
||||
* short circuits back to PNK_OPTCHAIN if nullish.
|
||||
* pn_right: expr between [ and ]
|
||||
* PNK_OPTCALL list pn_head: list of call, arg1, arg2, ... argN
|
||||
* pn_count: 1 + N (where N is number of args)
|
||||
* call is a MEMBER expr naming a callable object,
|
||||
* short circuits back to PNK_OPTCHAIN if nullish.
|
||||
* PNK_DOT name pn_expr: MEMBER expr to left of .
|
||||
* pn_atom: name to right of .
|
||||
* PNK_ELEM binary pn_left: MEMBER expr to left of [
|
||||
|
|
@ -1182,11 +1210,12 @@ class RegExpLiteral : public NullaryNode
|
|||
}
|
||||
};
|
||||
|
||||
class PropertyAccess : public ParseNode
|
||||
class PropertyAccessBase : public ParseNode
|
||||
{
|
||||
public:
|
||||
PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, uint32_t end)
|
||||
: ParseNode(PNK_DOT, JSOP_NOP, PN_NAME, TokenPos(begin, end))
|
||||
PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, PropertyName* name,
|
||||
uint32_t begin, uint32_t end)
|
||||
: ParseNode(kind, JSOP_NOP, PN_NAME, TokenPos(begin, end))
|
||||
{
|
||||
MOZ_ASSERT(lhs != nullptr);
|
||||
MOZ_ASSERT(name != nullptr);
|
||||
|
|
@ -1195,7 +1224,8 @@ class PropertyAccess : public ParseNode
|
|||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(PNK_DOT);
|
||||
bool match = node.isKind(PNK_DOT) ||
|
||||
node.isKind(PNK_OPTDOT);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
|
||||
return match;
|
||||
}
|
||||
|
|
@ -1207,6 +1237,24 @@ class PropertyAccess : public ParseNode
|
|||
PropertyName& name() const {
|
||||
return *pn_u.name.atom->asPropertyName();
|
||||
}
|
||||
};
|
||||
|
||||
class PropertyAccess : public PropertyAccessBase
|
||||
{
|
||||
public:
|
||||
PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin,
|
||||
uint32_t end)
|
||||
: PropertyAccessBase(PNK_DOT, lhs, name, begin, end)
|
||||
{
|
||||
MOZ_ASSERT(lhs != nullptr);
|
||||
MOZ_ASSERT(name != nullptr);
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(PNK_DOT);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
|
||||
return match;
|
||||
}
|
||||
|
||||
bool isSuper() const {
|
||||
// PNK_SUPERBASE cannot result from any expression syntax.
|
||||
|
|
@ -1214,16 +1262,49 @@ class PropertyAccess : public ParseNode
|
|||
}
|
||||
};
|
||||
|
||||
class PropertyByValue : public ParseNode
|
||||
class OptionalPropertyAccess : public PropertyAccessBase
|
||||
{
|
||||
public:
|
||||
PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin, uint32_t end)
|
||||
: ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end))
|
||||
OptionalPropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin,
|
||||
uint32_t end)
|
||||
: PropertyAccessBase(PNK_OPTDOT, lhs, name, begin, end)
|
||||
{
|
||||
MOZ_ASSERT(lhs != nullptr);
|
||||
MOZ_ASSERT(name != nullptr);
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(PNK_OPTDOT);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_NAME));
|
||||
return match;
|
||||
}
|
||||
};
|
||||
|
||||
class PropertyByValueBase : public ParseNode
|
||||
{
|
||||
public:
|
||||
PropertyByValueBase(ParseNodeKind kind, ParseNode* lhs, ParseNode* propExpr,
|
||||
uint32_t begin, uint32_t end)
|
||||
: ParseNode(kind, JSOP_NOP, PN_BINARY, TokenPos(begin, end))
|
||||
{
|
||||
pn_u.binary.left = lhs;
|
||||
pn_u.binary.right = propExpr;
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(PNK_ELEM) ||
|
||||
node.isKind(PNK_OPTELEM);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
|
||||
return match;
|
||||
}
|
||||
};
|
||||
|
||||
class PropertyByValue : public PropertyByValueBase {
|
||||
public:
|
||||
PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin,
|
||||
uint32_t end)
|
||||
: PropertyByValueBase(PNK_ELEM, lhs, propExpr, begin, end) {}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(PNK_ELEM);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
|
||||
|
|
@ -1235,6 +1316,19 @@ class PropertyByValue : public ParseNode
|
|||
}
|
||||
};
|
||||
|
||||
class OptionalPropertyByValue : public PropertyByValueBase {
|
||||
public:
|
||||
OptionalPropertyByValue(ParseNode* lhs, ParseNode* propExpr,
|
||||
uint32_t begin, uint32_t end)
|
||||
: PropertyByValueBase(PNK_OPTELEM, lhs, propExpr, begin, end) {}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(PNK_OPTELEM);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
|
||||
return match;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A CallSiteNode represents the implicit call site object argument in a TaggedTemplate.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7156,7 +7156,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
if (hasHeritage) {
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
classHeritage = memberExpr(yieldHandling, TripledotProhibited, tt);
|
||||
classHeritage = optionalExpr(yieldHandling, TripledotProhibited, tt);
|
||||
if (!classHeritage)
|
||||
return null();
|
||||
}
|
||||
|
|
@ -8363,6 +8363,108 @@ Parser<ParseHandler>::unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kin
|
|||
return handler.newUnary(kind, op, begin, kid);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::optionalExpr(
|
||||
YieldHandling yieldHandling, TripledotHandling tripledotHandling,
|
||||
TokenKind tt, bool allowCallSyntax /* = true */,
|
||||
PossibleError* possibleError /* = nullptr */,
|
||||
InvokedPrediction invoked /* = PredictUninvoked */)
|
||||
{
|
||||
JS_CHECK_RECURSION(context, return null());
|
||||
|
||||
uint32_t begin = pos().begin;
|
||||
|
||||
Node lhs = memberExpr(yieldHandling, tripledotHandling, tt,
|
||||
/* allowCallSyntax = */ true, possibleError, invoked);
|
||||
|
||||
if (!lhs) {
|
||||
return null();
|
||||
}
|
||||
|
||||
// Note: TokenStream::None is equivalent to TokenStream::SlashIsDiv
|
||||
// in current Mozilla code, see bug 1539821.
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::None)) {
|
||||
return null();
|
||||
}
|
||||
|
||||
if (tt != TOK_OPTCHAIN) {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (!tokenStream.getToken(&tt)) {
|
||||
return null();
|
||||
}
|
||||
|
||||
if (tt == TOK_EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
Node nextMember;
|
||||
if (tt == TOK_OPTCHAIN) {
|
||||
if (!tokenStream.getToken(&tt)) {
|
||||
return null();
|
||||
}
|
||||
if (TokenKindIsPossibleIdentifierName(tt)) {
|
||||
nextMember = memberPropertyAccess(lhs, OptionalKind::Optional);
|
||||
if (!nextMember) {
|
||||
return null();
|
||||
}
|
||||
} else if (tt == TOK_LB) {
|
||||
nextMember = memberElemAccess(lhs, yieldHandling,
|
||||
OptionalKind::Optional);
|
||||
if (!nextMember) {
|
||||
return null();
|
||||
}
|
||||
} else if (tt == TOK_LP) {
|
||||
nextMember = memberCall(tt, lhs, yieldHandling, possibleError,
|
||||
OptionalKind::Optional);
|
||||
if (!nextMember) {
|
||||
return null();
|
||||
}
|
||||
} else {
|
||||
error(JSMSG_NAME_AFTER_DOT);
|
||||
return null();
|
||||
}
|
||||
} else if (tt == TOK_DOT) {
|
||||
if (!tokenStream.getToken(&tt)) {
|
||||
return null();
|
||||
}
|
||||
if (TokenKindIsPossibleIdentifierName(tt)) {
|
||||
nextMember = memberPropertyAccess(lhs);
|
||||
if (!nextMember) {
|
||||
return null();
|
||||
}
|
||||
} else {
|
||||
error(JSMSG_NAME_AFTER_DOT);
|
||||
return null();
|
||||
}
|
||||
} else if (tt == TOK_LB) {
|
||||
nextMember = memberElemAccess(lhs, yieldHandling);
|
||||
if (!nextMember) {
|
||||
return null();
|
||||
}
|
||||
} else if (allowCallSyntax && tt == TOK_LP) {
|
||||
nextMember = memberCall(tt, lhs, yieldHandling, possibleError);
|
||||
if (!nextMember) {
|
||||
return null();
|
||||
}
|
||||
} else if (tt == TOK_TEMPLATE_HEAD || tt == TOK_NO_SUBS_TEMPLATE) {
|
||||
error(JSMSG_BAD_OPTIONAL_TEMPLATE);
|
||||
return null();
|
||||
} else {
|
||||
tokenStream.ungetToken();
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(nextMember);
|
||||
lhs = nextMember;
|
||||
}
|
||||
|
||||
return handler.newOptionalChain(begin, lhs);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
|
||||
|
|
@ -8414,7 +8516,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
|
|||
return null();
|
||||
|
||||
uint32_t operandOffset = pos().begin;
|
||||
Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2);
|
||||
Node operand = optionalExpr(yieldHandling, TripledotProhibited, tt2);
|
||||
if (!operand || !checkIncDecOperand(operand, operandOffset))
|
||||
return null();
|
||||
|
||||
|
|
@ -8456,8 +8558,9 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
|
|||
MOZ_FALLTHROUGH;
|
||||
|
||||
default: {
|
||||
Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
|
||||
possibleError, invoked);
|
||||
Node expr = optionalExpr(yieldHandling, tripledotHandling, tt,
|
||||
/* allowCallSyntax = */ true,
|
||||
possibleError, invoked);
|
||||
if (!expr)
|
||||
return null();
|
||||
|
||||
|
|
@ -8906,6 +9009,18 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
|
||||
handler.addList(lhs, ctorExpr);
|
||||
|
||||
// If we have encountered an optional chain, in the form of `new
|
||||
// ClassName?.()` then we need to throw, as this is disallowed
|
||||
// by the spec.
|
||||
bool optionalToken;
|
||||
if (!tokenStream.matchToken(&optionalToken, TOK_OPTCHAIN)) {
|
||||
return null();
|
||||
}
|
||||
if (optionalToken) {
|
||||
errorAt(newBegin, JSMSG_BAD_NEW_OPTIONAL);
|
||||
return null();
|
||||
}
|
||||
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TOK_LP))
|
||||
return null();
|
||||
|
|
@ -8943,12 +9058,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (TokenKindIsPossibleIdentifierName(tt)) {
|
||||
PropertyName* field = tokenStream.currentName();
|
||||
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
|
||||
error(JSMSG_BAD_SUPERPROP, "property");
|
||||
return null();
|
||||
}
|
||||
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
|
||||
nextMember = memberPropertyAccess(lhs);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
} else {
|
||||
|
|
@ -8956,17 +9066,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
return null();
|
||||
}
|
||||
} else if (tt == TOK_LB) {
|
||||
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!propExpr)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
|
||||
|
||||
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
|
||||
error(JSMSG_BAD_SUPERPROP, "member");
|
||||
return null();
|
||||
}
|
||||
nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
|
||||
nextMember = memberElemAccess(lhs, yieldHandling);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
} else if ((allowCallSyntax && tt == TOK_LP) ||
|
||||
|
|
@ -9002,82 +9102,17 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
|
|||
if (!thisName)
|
||||
return null();
|
||||
|
||||
// XXX This was refactored out into memberSuperCall as part of
|
||||
// bug 1566143, but was not used elsewhere aside from here, so
|
||||
// I opted not to move this into a separate function. However,
|
||||
// I'm unsure if this will be needed eventually in the future.
|
||||
nextMember = handler.newSetThis(thisName, nextMember);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
} else {
|
||||
if (options().selfHostingMode && handler.isPropertyAccess(lhs)) {
|
||||
error(JSMSG_SELFHOSTED_METHOD_CALL);
|
||||
return null();
|
||||
}
|
||||
|
||||
nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
|
||||
nextMember = memberCall(tt, lhs, yieldHandling, possibleError);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
|
||||
JSOp op = JSOP_CALL;
|
||||
bool maybeAsyncArrow = false;
|
||||
if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
|
||||
// Use the JSOP_FUN{APPLY,CALL} optimizations given the
|
||||
// right syntax.
|
||||
if (prop == context->names().apply) {
|
||||
op = JSOP_FUNAPPLY;
|
||||
if (pc->isFunctionBox()) {
|
||||
pc->functionBox()->usesApply = true;
|
||||
}
|
||||
} else if (prop == context->names().call) {
|
||||
op = JSOP_FUNCALL;
|
||||
}
|
||||
} else if (tt == TOK_LP) {
|
||||
if (handler.isAsyncKeyword(lhs, context)) {
|
||||
// |async (| can be the start of an async arrow
|
||||
// function, so we need to defer reporting possible
|
||||
// errors from destructuring syntax. To give better
|
||||
// error messages, we only allow the AsyncArrowHead
|
||||
// part of the CoverCallExpressionAndAsyncArrowHead
|
||||
// syntax when the initial name is "async".
|
||||
maybeAsyncArrow = true;
|
||||
} else if (handler.isEvalAnyParentheses(lhs, context)) {
|
||||
// Select the right EVAL op and flag pc as having a
|
||||
// direct eval.
|
||||
op = pc->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
|
||||
pc->sc()->setBindingsAccessedDynamically();
|
||||
pc->sc()->setHasDirectEval();
|
||||
|
||||
// In non-strict mode code, direct calls to eval can
|
||||
// add variables to the call object.
|
||||
if (pc->isFunctionBox() && !pc->sc()->strict())
|
||||
pc->functionBox()->setHasExtensibleScope();
|
||||
|
||||
// If we're in a method, mark the method as requiring
|
||||
// support for 'super', since direct eval code can use
|
||||
// it. (If we're not in a method, that's fine, so
|
||||
// ignore the return value.)
|
||||
checkAndMarkSuperScope();
|
||||
}
|
||||
}
|
||||
|
||||
handler.setBeginPosition(nextMember, lhs);
|
||||
handler.addList(nextMember, lhs);
|
||||
|
||||
if (tt == TOK_LP) {
|
||||
bool isSpread = false;
|
||||
PossibleError* asyncPossibleError = maybeAsyncArrow ? possibleError : nullptr;
|
||||
if (!argumentList(yieldHandling, nextMember, &isSpread, asyncPossibleError))
|
||||
return null();
|
||||
if (isSpread) {
|
||||
if (op == JSOP_EVAL)
|
||||
op = JSOP_SPREADEVAL;
|
||||
else if (op == JSOP_STRICTEVAL)
|
||||
op = JSOP_STRICTSPREADEVAL;
|
||||
else
|
||||
op = JSOP_SPREADCALL;
|
||||
}
|
||||
} else {
|
||||
if (!taggedTemplate(yieldHandling, nextMember, tt))
|
||||
return null();
|
||||
}
|
||||
handler.setOp(nextMember, op);
|
||||
}
|
||||
} else {
|
||||
tokenStream.ungetToken();
|
||||
|
|
@ -9111,6 +9146,158 @@ Parser<ParseHandler>::newName(PropertyName* name, TokenPos pos)
|
|||
return handler.newName(name, pos, context);
|
||||
}
|
||||
|
||||
template <class ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::memberPropertyAccess(
|
||||
Node lhs, OptionalKind optionalKind /* = OptionalKind::NonOptional */)
|
||||
{
|
||||
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tokenStream.currentToken().type));
|
||||
PropertyName* field = tokenStream.currentName();
|
||||
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
|
||||
error(JSMSG_BAD_SUPERPROP, "property");
|
||||
return null();
|
||||
}
|
||||
if (optionalKind == OptionalKind::Optional) {
|
||||
MOZ_ASSERT(!handler.isSuperBase(lhs));
|
||||
return handler.newOptionalPropertyAccess(lhs, field, pos().end);
|
||||
}
|
||||
return handler.newPropertyAccess(lhs, field, pos().end);
|
||||
}
|
||||
|
||||
template <class ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::memberElemAccess(
|
||||
Node lhs, YieldHandling yieldHandling,
|
||||
OptionalKind optionalKind /* = OptionalKind::NonOptional */)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.currentToken().type == TOK_LB);
|
||||
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!propExpr) {
|
||||
return null();
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
|
||||
|
||||
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
|
||||
error(JSMSG_BAD_SUPERPROP, "member");
|
||||
return null();
|
||||
}
|
||||
|
||||
if (optionalKind == OptionalKind::Optional) {
|
||||
MOZ_ASSERT(!handler.isSuperBase(lhs));
|
||||
return handler.newOptionalPropertyByValue(lhs, propExpr, pos().end);
|
||||
}
|
||||
return handler.newPropertyByValue(lhs, propExpr, pos().end);
|
||||
}
|
||||
|
||||
template <class ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::memberCall(
|
||||
TokenKind tt, Node lhs, YieldHandling yieldHandling,
|
||||
PossibleError* possibleError /* = nullptr */,
|
||||
OptionalKind optionalKind /* = OptionalKind::NonOptional */)
|
||||
{
|
||||
if (options().selfHostingMode && (handler.isPropertyAccess(lhs) ||
|
||||
handler.isOptionalPropertyAccess(lhs))) {
|
||||
error(JSMSG_SELFHOSTED_METHOD_CALL);
|
||||
return null();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(tt == TOK_LP ||
|
||||
tt == TOK_TEMPLATE_HEAD ||
|
||||
tt == TOK_NO_SUBS_TEMPLATE,
|
||||
"Unexpected token kind for member call");
|
||||
|
||||
Node nextMember;
|
||||
if (tt == TOK_LP) {
|
||||
if (optionalKind == OptionalKind::Optional) {
|
||||
nextMember = handler.newOptionalCall();
|
||||
} else {
|
||||
nextMember = handler.newCall();
|
||||
}
|
||||
} else {
|
||||
nextMember = handler.newTaggedTemplate();
|
||||
}
|
||||
|
||||
JSOp op = JSOP_CALL;
|
||||
bool maybeAsyncArrow = false;
|
||||
if (PropertyName* prop = handler.maybeDottedProperty(lhs)) {
|
||||
// Use the JSOP_FUN{APPLY,CALL} optimizations given the
|
||||
// right syntax.
|
||||
if (prop == context->names().apply) {
|
||||
op = JSOP_FUNAPPLY;
|
||||
if (pc->isFunctionBox()) {
|
||||
pc->functionBox()->usesApply = true;
|
||||
}
|
||||
} else if (prop == context->names().call) {
|
||||
op = JSOP_FUNCALL;
|
||||
}
|
||||
} else if (tt == TOK_LP && optionalKind == OptionalKind::NonOptional) {
|
||||
if (handler.isAsyncKeyword(lhs, context)) {
|
||||
// |async (| can be the start of an async arrow
|
||||
// function, so we need to defer reporting possible
|
||||
// errors from destructuring syntax. To give better
|
||||
// error messages, we only allow the AsyncArrowHead
|
||||
// part of the CoverCallExpressionAndAsyncArrowHead
|
||||
// syntax when the initial name is "async".
|
||||
maybeAsyncArrow = true;
|
||||
} else if (handler.isEvalAnyParentheses(lhs, context)) {
|
||||
// Select the right EVAL op and flag pc as having a
|
||||
// direct eval.
|
||||
op = pc->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
|
||||
pc->sc()->setBindingsAccessedDynamically();
|
||||
pc->sc()->setHasDirectEval();
|
||||
|
||||
// In non-strict mode code, direct calls to eval can
|
||||
// add variables to the call object.
|
||||
if (pc->isFunctionBox() && !pc->sc()->strict()) {
|
||||
pc->functionBox()->setHasExtensibleScope();
|
||||
}
|
||||
|
||||
// If we're in a method, mark the method as requiring
|
||||
// support for 'super', since direct eval code can use
|
||||
// it. (If we're not in a method, that's fine, so
|
||||
// ignore the return value.)
|
||||
checkAndMarkSuperScope();
|
||||
}
|
||||
}
|
||||
|
||||
handler.setBeginPosition(nextMember, lhs);
|
||||
handler.addList(nextMember, lhs);
|
||||
|
||||
if (tt == TOK_LP) {
|
||||
bool isSpread = false;
|
||||
PossibleError* asyncPossibleError = maybeAsyncArrow ?
|
||||
possibleError :
|
||||
nullptr;
|
||||
|
||||
if (!argumentList(yieldHandling, nextMember, &isSpread, asyncPossibleError)) {
|
||||
return null();
|
||||
}
|
||||
|
||||
if (isSpread) {
|
||||
if (op == JSOP_EVAL) {
|
||||
op = JSOP_SPREADEVAL;
|
||||
} else if (op == JSOP_STRICTEVAL) {
|
||||
op = JSOP_STRICTSPREADEVAL;
|
||||
} else {
|
||||
op = JSOP_SPREADCALL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!taggedTemplate(yieldHandling, nextMember, tt)) {
|
||||
return null();
|
||||
}
|
||||
if (optionalKind == OptionalKind::Optional) {
|
||||
error(JSMSG_BAD_OPTIONAL_TEMPLATE);
|
||||
return null();
|
||||
}
|
||||
}
|
||||
handler.setOp(nextMember, op);
|
||||
|
||||
return nextMember;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::checkLabelOrIdentifierReference(HandlePropertyName ident,
|
||||
|
|
|
|||
|
|
@ -1321,6 +1321,11 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
Node unaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
|
||||
PossibleError* possibleError = nullptr,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node optionalExpr(YieldHandling yieldHandling,
|
||||
TripledotHandling tripledotHandling, TokenKind tt,
|
||||
bool allowCallSyntax = true,
|
||||
PossibleError* possibleError = nullptr,
|
||||
InvokedPrediction invoked = PredictUninvoked);
|
||||
Node memberExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
|
||||
TokenKind tt, bool allowCallSyntax = true,
|
||||
PossibleError* possibleError = nullptr,
|
||||
|
|
@ -1532,6 +1537,18 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
|
||||
|
||||
bool asmJS(Node list);
|
||||
|
||||
enum class OptionalKind {
|
||||
NonOptional = 0,
|
||||
Optional,
|
||||
};
|
||||
Node memberPropertyAccess(
|
||||
Node lhs, OptionalKind optionalKind = OptionalKind::NonOptional);
|
||||
Node memberElemAccess(Node lhs, YieldHandling yieldHandling,
|
||||
OptionalKind optionalKind = OptionalKind::NonOptional);
|
||||
Node memberCall(TokenKind tt, Node lhs, YieldHandling yieldHandling,
|
||||
PossibleError* possibleError,
|
||||
OptionalKind optionalKind = OptionalKind::NonOptional);
|
||||
};
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ namespace js {
|
|||
M(SRC_BREAK, "break", 0) /* JSOP_GOTO is a break. */ \
|
||||
M(SRC_BREAK2LABEL, "break2label", 0) /* JSOP_GOTO for 'break label'. */ \
|
||||
M(SRC_SWITCHBREAK, "switchbreak", 0) /* JSOP_GOTO is a break in a switch. */ \
|
||||
M(SRC_OPTCHAIN, "optchain", 0) /* JSOP_GOTO for optional chains. */ \
|
||||
M(SRC_TABLESWITCH, "tableswitch", 1) /* JSOP_TABLESWITCH; offset points to end of switch. */ \
|
||||
M(SRC_CONDSWITCH, "condswitch", 2) /* JSOP_CONDSWITCH; 1st offset points to end of switch, \
|
||||
2nd points to first JSOP_CASE. */ \
|
||||
|
|
@ -63,7 +64,6 @@ namespace js {
|
|||
M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \
|
||||
M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \
|
||||
M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \
|
||||
M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \
|
||||
M(SRC_XDELTA, "xdelta", 0) /* 24-31 are for extended delta notes. */
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ class SyntaxParseHandler
|
|||
// in code not actually executed (or at least not executed enough to be
|
||||
// noticed).
|
||||
NodeFunctionCall,
|
||||
NodeOptionalFunctionCall,
|
||||
|
||||
// Nodes representing *parenthesized* IsValidSimpleAssignmentTarget
|
||||
// nodes. We can't simply treat all such parenthesized nodes
|
||||
|
|
@ -78,7 +79,9 @@ class SyntaxParseHandler
|
|||
NodeParenthesizedName,
|
||||
|
||||
NodeDottedProperty,
|
||||
NodeOptionalDottedProperty,
|
||||
NodeElement,
|
||||
NodeOptionalElement,
|
||||
|
||||
// Destructuring target patterns can't be parenthesized: |([a]) = [3];|
|
||||
// must be a syntax error. (We can't use NodeGeneric instead of these
|
||||
|
|
@ -146,6 +149,10 @@ class SyntaxParseHandler
|
|||
return node == NodeDottedProperty || node == NodeElement;
|
||||
}
|
||||
|
||||
bool isOptionalPropertyAccess(Node node) {
|
||||
return node == NodeOptionalDottedProperty || node == NodeOptionalElement;
|
||||
}
|
||||
|
||||
bool isFunctionCall(Node node) {
|
||||
// Note: super() is a special form, *not* a function call.
|
||||
return node == NodeFunctionCall;
|
||||
|
|
@ -283,6 +290,7 @@ class SyntaxParseHandler
|
|||
void addArrayElement(Node literal, Node element) { }
|
||||
|
||||
Node newCall() { return NodeFunctionCall; }
|
||||
Node newOptionalCall() { return NodeOptionalFunctionCall; }
|
||||
Node newTaggedTemplate() { return NodeGeneric; }
|
||||
|
||||
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
|
||||
|
|
@ -303,6 +311,7 @@ class SyntaxParseHandler
|
|||
Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
Node newOptionalChain(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
|
||||
// Statements
|
||||
|
||||
|
|
@ -353,8 +362,15 @@ class SyntaxParseHandler
|
|||
return NodeDottedProperty;
|
||||
}
|
||||
|
||||
Node newOptionalPropertyAccess(Node pn, PropertyName* name, uint32_t end) {
|
||||
lastAtom = name;
|
||||
return NodeOptionalDottedProperty;
|
||||
}
|
||||
|
||||
Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeElement; }
|
||||
|
||||
Node newOptionalPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeOptionalElement; }
|
||||
|
||||
MOZ_MUST_USE bool addCatchBlock(Node catchList, Node letBlock, Node catchName,
|
||||
Node catchGuard, Node catchBody) { return true; }
|
||||
|
||||
|
|
@ -471,7 +487,8 @@ class SyntaxParseHandler
|
|||
list == NodeUnparenthesizedCommaExpr ||
|
||||
list == NodeVarDeclaration ||
|
||||
list == NodeLexicalDeclaration ||
|
||||
list == NodeFunctionCall);
|
||||
list == NodeFunctionCall ||
|
||||
list == NodeOptionalFunctionCall);
|
||||
}
|
||||
|
||||
Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs, JSOp op) {
|
||||
|
|
@ -590,7 +607,7 @@ class SyntaxParseHandler
|
|||
// |this|. It's not really eligible for the funapply/funcall
|
||||
// optimizations as they're currently implemented (assuming a single
|
||||
// value is used for both retrieval and |this|).
|
||||
if (node != NodeDottedProperty)
|
||||
if (node != NodeDottedProperty && node != NodeOptionalDottedProperty)
|
||||
return nullptr;
|
||||
return lastAtom->asPropertyName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
macro(DEC, "'--'") /* decrement */ \
|
||||
macro(DOT, "'.'") /* member operator */ \
|
||||
macro(TRIPLEDOT, "'...'") /* rest arguments and spread operator */ \
|
||||
macro(OPTCHAIN, "'?.'") \
|
||||
macro(LB, "'['") \
|
||||
macro(RB, "']'") \
|
||||
macro(LC, "'{'") \
|
||||
|
|
|
|||
|
|
@ -1285,7 +1285,7 @@ static const uint8_t firstCharKinds[] = {
|
|||
/* 30+ */ _______, _______, Space, _______, String, _______, Ident, _______, _______, String,
|
||||
/* 40+ */ TOK_LP, TOK_RP, _______, _______, T_COMMA,_______, _______, _______,BasePrefix, Dec,
|
||||
/* 50+ */ Dec, Dec, Dec, Dec, Dec, Dec, Dec, Dec, T_COLON,TOK_SEMI,
|
||||
/* 60+ */ _______, _______, _______,TOK_HOOK, _______, Ident, Ident, Ident, Ident, Ident,
|
||||
/* 60+ */ _______, _______, _______, _______, _______, Ident, Ident, Ident, Ident, Ident,
|
||||
/* 70+ */ Ident, Ident, Ident, Ident, Ident, Ident, Ident, Ident, Ident, Ident,
|
||||
/* 80+ */ Ident, Ident, Ident, Ident, Ident, Ident, Ident, Ident, Ident, Ident,
|
||||
/* 90+ */ Ident, TOK_LB, _______, TOK_RB, _______, Ident, Templat, Ident, Ident, Ident,
|
||||
|
|
@ -1796,6 +1796,25 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
|||
tp->type = matchChar('=') ? TOK_BITANDASSIGN : TOK_BITAND;
|
||||
goto out;
|
||||
|
||||
case '?':
|
||||
if (matchChar('.')) {
|
||||
c = getCharIgnoreEOL();
|
||||
if (JS7_ISDEC(c)) {
|
||||
// if the code unit is followed by a number, for example it has
|
||||
// the following form `<...> ?.5 <..> then it should be treated
|
||||
// as a ternary rather than as an optional chain
|
||||
tp->type = TOK_HOOK;
|
||||
ungetCharIgnoreEOL(c);
|
||||
ungetChar('.');
|
||||
} else {
|
||||
ungetCharIgnoreEOL(c);
|
||||
tp->type = TOK_OPTCHAIN;
|
||||
}
|
||||
} else {
|
||||
tp->type = TOK_HOOK;
|
||||
}
|
||||
goto out;
|
||||
|
||||
case '!':
|
||||
if (matchChar('='))
|
||||
tp->type = matchChar('=') ? TOK_STRICTNE : TOK_NE;
|
||||
|
|
|
|||
5
js/src/jit-test/tests/basic/bug1644839-2.js
Normal file
5
js/src/jit-test/tests/basic/bug1644839-2.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// |jit-test| skip-if: !('oomTest' in this)
|
||||
var code = `
|
||||
(\`\${key}: \${(args[1]?.toString)?.()}\`)
|
||||
`;
|
||||
oomTest(function() { return parseModule(code); });
|
||||
5
js/src/jit-test/tests/basic/bug1644839.js
Normal file
5
js/src/jit-test/tests/basic/bug1644839.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// |jit-test| skip-if: !('oomTest' in this)
|
||||
var code = `
|
||||
(\`\${key}: \${args[1]?.toString()}\`)
|
||||
`;
|
||||
oomTest(function() { return parseModule(code); });
|
||||
34
js/src/jit-test/tests/optional-chain/call-ignore-rval.js
Normal file
34
js/src/jit-test/tests/optional-chain/call-ignore-rval.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Tests for JSOp::CallIgnoresRv in optional chains.
|
||||
|
||||
// Note:: IgnoresReturnValueNative is supported for Array.prototype.splice.
|
||||
|
||||
// Test for optional call.
|
||||
function testOptionalCall() {
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var x = [1, 2, 3];
|
||||
x.splice?.(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) { testOptionalCall(); }
|
||||
|
||||
// Test for optional prop directly followed by call.
|
||||
function testOptionalProp() {
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var x = [1, 2, 3];
|
||||
x?.splice(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) { testOptionalProp(); }
|
||||
|
||||
// Test for call in optional chain expression.
|
||||
function testOptionalChain() {
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var x = [1, 2, 3];
|
||||
var o = {x};
|
||||
o?.x.splice(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) { testOptionalChain(); }
|
||||
60
js/src/jit-test/tests/optional-chain/fun-call-or-apply.js
Normal file
60
js/src/jit-test/tests/optional-chain/fun-call-or-apply.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Tests for JSOp::FunCall and JSOp::FunApply in optional calls.
|
||||
|
||||
function f1() {
|
||||
return 0;
|
||||
}
|
||||
function f2(a) {
|
||||
return a * 2;
|
||||
}
|
||||
|
||||
function funCall(fn) {
|
||||
// Without arguments.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.call(), 0);
|
||||
}
|
||||
|
||||
// Only this-arg.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.call(null), 0);
|
||||
}
|
||||
|
||||
// With one arg.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.call(null, 1), 0);
|
||||
assertEq(f2?.call(null, 5), 10);
|
||||
}
|
||||
|
||||
// With multiple args.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.call(null, 1, 2, 3), 0);
|
||||
assertEq(f2?.call(null, 4, 5, 6), 8);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) { funCall(); }
|
||||
|
||||
function funApply(fn) {
|
||||
// Without arguments.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.apply(), 0);
|
||||
}
|
||||
|
||||
// Only this-arg.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.apply(null), 0);
|
||||
}
|
||||
|
||||
// With one arg.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.apply(null, [1]), 0);
|
||||
assertEq(f2?.apply(null, [5]), 10);
|
||||
}
|
||||
|
||||
// With multiple args.
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
assertEq(f1?.apply(null, [1, 2, 3]), 0);
|
||||
assertEq(f2?.apply(null, [4, 5, 6]), 8);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i) { funApply(); }
|
||||
|
|
@ -1649,6 +1649,12 @@ IonBuilder::snoopControlFlow(JSOp op)
|
|||
// while (cond) { }
|
||||
return whileOrForInLoop(sn);
|
||||
|
||||
case SRC_OPTCHAIN:
|
||||
// XXX Instead of aborting early, breaking at this point works.
|
||||
// However, I'm not sure if we still need to further process
|
||||
// optional chains under IonBuilder.
|
||||
break;
|
||||
|
||||
default:
|
||||
// Hard assert for now - make an error later.
|
||||
MOZ_CRASH("unknown goto case");
|
||||
|
|
|
|||
|
|
@ -354,6 +354,8 @@ MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of
|
|||
MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration")
|
||||
MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration")
|
||||
MSG_DEF(JSMSG_BAD_NEWTARGET, 0, JSEXN_SYNTAXERR, "new.target only allowed within functions")
|
||||
MSG_DEF(JSMSG_BAD_NEW_OPTIONAL, 0, JSEXN_SYNTAXERR, "new keyword cannot be used with an optional chain")
|
||||
MSG_DEF(JSMSG_BAD_OPTIONAL_TEMPLATE, 0, JSEXN_SYNTAXERR, "tagged template cannot be used with optional chain")
|
||||
MSG_DEF(JSMSG_ESCAPED_KEYWORD, 0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes")
|
||||
|
||||
// asm.js
|
||||
|
|
|
|||
|
|
@ -27,10 +27,14 @@ ASTDEF(AST_LOGICAL_EXPR, "LogicalExpression", "logicalExpr
|
|||
ASTDEF(AST_UPDATE_EXPR, "UpdateExpression", "updateExpression")
|
||||
ASTDEF(AST_NEW_EXPR, "NewExpression", "newExpression")
|
||||
ASTDEF(AST_CALL_EXPR, "CallExpression", "callExpression")
|
||||
ASTDEF(AST_OPT_CALL_EXPR, "OptionalCallExpression", "optionalCallExpression")
|
||||
ASTDEF(AST_MEMBER_EXPR, "MemberExpression", "memberExpression")
|
||||
ASTDEF(AST_OPT_MEMBER_EXPR, "OptionalMemberExpression", "optionalMemberExpression")
|
||||
ASTDEF(AST_FUNC_EXPR, "FunctionExpression", "functionExpression")
|
||||
ASTDEF(AST_ARROW_EXPR, "ArrowFunctionExpression", "arrowFunctionExpression")
|
||||
ASTDEF(AST_ARRAY_EXPR, "ArrayExpression", "arrayExpression")
|
||||
ASTDEF(AST_DELETE_OPTIONAL_EXPR, "DeleteOptionalExpression", "deleteOptionalExpression")
|
||||
ASTDEF(AST_OPTIONAL_EXPR, "OptionalExpression", "optionalExpression")
|
||||
ASTDEF(AST_SPREAD_EXPR, "SpreadExpression", "spreadExpression")
|
||||
ASTDEF(AST_OBJECT_EXPR, "ObjectExpression", "objectExpression")
|
||||
ASTDEF(AST_THIS_EXPR, "ThisExpression", "thisExpression")
|
||||
|
|
|
|||
|
|
@ -699,6 +699,30 @@ IsEqualityOp(JSOp op)
|
|||
return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsSpreadOp(JSOp op)
|
||||
{
|
||||
return JOF_OPTYPE(op) == JOF_BYTE;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsNewOp(JSOp op)
|
||||
{
|
||||
return op == JSOP_NEW ||
|
||||
op == JSOP_SPREADNEW ||
|
||||
op == JSOP_SUPERCALL ||
|
||||
op == JSOP_SPREADSUPERCALL;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsEvalOp(JSOp op)
|
||||
{
|
||||
return op == JSOP_EVAL ||
|
||||
op == JSOP_STRICTEVAL ||
|
||||
op == JSOP_SPREADEVAL ||
|
||||
op == JSOP_STRICTSPREADEVAL;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsCheckStrictOp(JSOp op)
|
||||
{
|
||||
|
|
|
|||
0
js/src/tests/non262/expressions/browser.js
Normal file
0
js/src/tests/non262/expressions/browser.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// Optional expression can be part of a class heritage expression.
|
||||
|
||||
var a = {b: null};
|
||||
|
||||
class C extends a?.b {}
|
||||
|
||||
assertEq(Object.getPrototypeOf(C.prototype), null);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// Verify bytecode emitter accepts all valid optional chain first expressions.
|
||||
|
||||
const expressions = [
|
||||
// https://tc39.es/ecma262/#sec-primary-expression
|
||||
"this",
|
||||
"ident",
|
||||
"null",
|
||||
"true",
|
||||
"false",
|
||||
"123",
|
||||
"123n",
|
||||
"'str'",
|
||||
"[]",
|
||||
"{}",
|
||||
"function(){}",
|
||||
"class{}",
|
||||
"function*(){}",
|
||||
"async function(){}",
|
||||
"async function*(){}",
|
||||
"/a/",
|
||||
"`str`",
|
||||
"(a + b)",
|
||||
|
||||
// https://tc39.es/ecma262/#sec-left-hand-side-expressions
|
||||
"a[b]",
|
||||
"a.b",
|
||||
"a``",
|
||||
"super[a]",
|
||||
"super.a",
|
||||
"new.target",
|
||||
"import.meta",
|
||||
"new C()",
|
||||
"new C",
|
||||
"f()",
|
||||
"super()",
|
||||
"a?.b",
|
||||
"a?.[b]",
|
||||
"a?.()",
|
||||
"a?.``",
|
||||
];
|
||||
|
||||
function tryParse(s, f = Function) {
|
||||
try { f(s); } catch {}
|
||||
}
|
||||
|
||||
function tryRun(s, f = Function) {
|
||||
try { f(s)(); } catch {}
|
||||
}
|
||||
|
||||
for (let expr of expressions) {
|
||||
// Evaluate in an expression context.
|
||||
tryRun(`void (${expr}?.());`);
|
||||
tryRun(`void (${expr}?.p());`);
|
||||
|
||||
// Also try parenthesized.
|
||||
tryRun(`void ((${expr})?.());`);
|
||||
tryRun(`void ((${expr})?.p());`);
|
||||
}
|
||||
|
||||
function inClassConstructor(s) {
|
||||
return `class C { constructor() { ${s} } }`;
|
||||
}
|
||||
|
||||
for (let expr of ["super[a]", "super.a", "super()"]) {
|
||||
// Evaluate in an expression context.
|
||||
tryRun(inClassConstructor(`void (${expr}?.());`));
|
||||
tryRun(inClassConstructor(`void (${expr}?.p());`));
|
||||
|
||||
// Also try parenthesized.
|
||||
tryRun(inClassConstructor(`void ((${expr})?.());`));
|
||||
tryRun(inClassConstructor(`void ((${expr})?.p());`));
|
||||
}
|
||||
|
||||
if (typeof parseModule === "function") {
|
||||
const expressions = [
|
||||
"import.meta",
|
||||
"import('')",
|
||||
];
|
||||
|
||||
for (let expr of expressions) {
|
||||
// Evaluate in an expression context.
|
||||
tryParse(`void (${expr}?.());`, parseModule);
|
||||
tryParse(`void (${expr}?.p());`, parseModule);
|
||||
|
||||
// Also try parenthesized.
|
||||
tryParse(`void ((${expr})?.());`, parseModule);
|
||||
tryParse(`void ((${expr})?.p());`, parseModule);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
12
js/src/tests/non262/expressions/optional-chain-super-elem.js
Normal file
12
js/src/tests/non262/expressions/optional-chain-super-elem.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Don't assert.
|
||||
|
||||
var obj = {
|
||||
m() {
|
||||
super[0]?.a
|
||||
}
|
||||
};
|
||||
|
||||
obj.m();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
28
js/src/tests/non262/expressions/optional-chain-tdz.js
Normal file
28
js/src/tests/non262/expressions/optional-chain-tdz.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Test TDZ for optional chaining.
|
||||
|
||||
// TDZ for lexical |let| bindings with optional chaining.
|
||||
{
|
||||
assertThrowsInstanceOf(() => {
|
||||
const Null = null;
|
||||
Null?.[b];
|
||||
b = 0;
|
||||
let b;
|
||||
}, ReferenceError);
|
||||
|
||||
assertThrowsInstanceOf(() => {
|
||||
const Null = null;
|
||||
Null?.[b]();
|
||||
b = 0;
|
||||
let b;
|
||||
}, ReferenceError);
|
||||
|
||||
assertThrowsInstanceOf(() => {
|
||||
const Null = null;
|
||||
delete Null?.[b];
|
||||
b = 0;
|
||||
let b;
|
||||
}, ReferenceError);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
223
js/src/tests/non262/expressions/optional-chain.js
Normal file
223
js/src/tests/non262/expressions/optional-chain.js
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
var BUGNUMBER = 1566143;
|
||||
var summary = "Implement the Optional Chain operator (?.) proposal";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
// These tests are originally from webkit.
|
||||
// webkit specifics have been removed and error messages have been updated.
|
||||
function shouldBe(actual, expected) {
|
||||
if (actual !== expected)
|
||||
throw new Error(`expected ${expected} but got ${actual}`);
|
||||
}
|
||||
|
||||
function shouldThrowSyntaxError(script) {
|
||||
let error;
|
||||
try {
|
||||
eval(script);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (!(error instanceof SyntaxError))
|
||||
throw new Error('Expected SyntaxError!');
|
||||
}
|
||||
|
||||
function shouldNotThrowSyntaxError(script) {
|
||||
let error;
|
||||
try {
|
||||
eval(script);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if ((error instanceof SyntaxError))
|
||||
throw new Error('Unxpected SyntaxError!');
|
||||
}
|
||||
|
||||
function shouldThrowTypeError(func, messagePrefix) {
|
||||
let error;
|
||||
try {
|
||||
func();
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (!(error instanceof TypeError))
|
||||
throw new Error('Expected TypeError!');
|
||||
}
|
||||
function testBasicSuccessCases() {
|
||||
shouldBe(undefined?.valueOf(), undefined);
|
||||
shouldBe(null?.valueOf(), undefined);
|
||||
shouldBe(true?.valueOf(), true);
|
||||
shouldBe(false?.valueOf(), false);
|
||||
shouldBe(0?.valueOf(), 0);
|
||||
shouldBe(1?.valueOf(), 1);
|
||||
shouldBe(''?.valueOf(), '');
|
||||
shouldBe('hi'?.valueOf(), 'hi');
|
||||
shouldBe(({})?.constructor, Object);
|
||||
shouldBe(({ x: 'hi' })?.x, 'hi');
|
||||
shouldBe([]?.length, 0);
|
||||
shouldBe(['hi']?.length, 1);
|
||||
|
||||
shouldBe(undefined?.['valueOf'](), undefined);
|
||||
shouldBe(null?.['valueOf'](), undefined);
|
||||
shouldBe(true?.['valueOf'](), true);
|
||||
shouldBe(false?.['valueOf'](), false);
|
||||
shouldBe(0?.['valueOf'](), 0);
|
||||
shouldBe(1?.['valueOf'](), 1);
|
||||
shouldBe(''?.['valueOf'](), '');
|
||||
shouldBe('hi'?.['valueOf'](), 'hi');
|
||||
shouldBe(({})?.['constructor'], Object);
|
||||
shouldBe(({ x: 'hi' })?.['x'], 'hi');
|
||||
shouldBe([]?.['length'], 0);
|
||||
shouldBe(['hi']?.[0], 'hi');
|
||||
|
||||
shouldBe(undefined?.(), undefined);
|
||||
shouldBe(null?.(), undefined);
|
||||
shouldBe((() => 3)?.(), 3);
|
||||
}
|
||||
|
||||
function testBasicFailureCases() {
|
||||
shouldThrowTypeError(() => true?.(), 'true is not a function');
|
||||
shouldThrowTypeError(() => false?.(), 'false is not a function');
|
||||
shouldThrowTypeError(() => 0?.(), '0 is not a function');
|
||||
shouldThrowTypeError(() => 1?.(), '1 is not a function');
|
||||
shouldThrowTypeError(() => ''?.(), '"" is not a function');
|
||||
shouldThrowTypeError(() => 'hi'?.(), '"hi" is not a function');
|
||||
shouldThrowTypeError(() => ({})?.(), '({}) is not a function');
|
||||
shouldThrowTypeError(() => ({ x: 'hi' })?.(), '({x:"hi"}) is not a function');
|
||||
shouldThrowTypeError(() => []?.(), '[] is not a function');
|
||||
shouldThrowTypeError(() => ['hi']?.(), '[...] is not a function');
|
||||
}
|
||||
|
||||
testBasicSuccessCases();
|
||||
|
||||
testBasicFailureCases();
|
||||
|
||||
shouldThrowTypeError(() => ({})?.i(), '(intermediate value).i is not a function');
|
||||
shouldBe(({}).i?.(), undefined);
|
||||
shouldBe(({})?.i?.(), undefined);
|
||||
shouldThrowTypeError(() => ({})?.['i'](), '(intermediate value)["i"] is not a function');
|
||||
shouldBe(({})['i']?.(), undefined);
|
||||
shouldBe(({})?.['i']?.(), undefined);
|
||||
|
||||
shouldThrowTypeError(() => ({})?.a['b'], 'can\'t access property "b", (intermediate value).a is undefined');
|
||||
shouldBe(({})?.a?.['b'], undefined);
|
||||
shouldBe(null?.a['b']().c, undefined);
|
||||
shouldThrowTypeError(() => ({})?.['a'].b, 'can\'t access property "b", (intermediate value)["a"] is undefined');
|
||||
shouldBe(({})?.['a']?.b, undefined);
|
||||
shouldBe(null?.['a'].b()['c'], undefined);
|
||||
shouldBe(null?.()().a['b'], undefined);
|
||||
|
||||
const o0 = { a: { b() { return this._b.bind(this); }, _b() { return this.__b; }, __b: { c: 42 } } };
|
||||
shouldBe(o0?.a?.['b']?.()?.()?.c, 42);
|
||||
shouldBe(o0?.i?.['j']?.()?.()?.k, undefined);
|
||||
shouldBe((o0.a?._b)?.().c, 42);
|
||||
shouldBe((o0.a?._b)().c, 42);
|
||||
shouldBe((o0.a?.b?.())?.().c, 42);
|
||||
shouldBe((o0.a?.['b']?.())?.().c, 42);
|
||||
|
||||
shouldBe(({ undefined: 3 })?.[null?.a], 3);
|
||||
shouldBe((() => 3)?.(null?.a), 3);
|
||||
|
||||
const o1 = { count: 0, get x() { this.count++; return () => {}; } };
|
||||
o1.x?.y;
|
||||
shouldBe(o1.count, 1);
|
||||
o1.x?.['y'];
|
||||
shouldBe(o1.count, 2);
|
||||
o1.x?.();
|
||||
shouldBe(o1.count, 3);
|
||||
null?.(o1.x);
|
||||
shouldBe(o1.count, 3);
|
||||
|
||||
shouldBe(delete undefined?.foo, true);
|
||||
shouldBe(delete null?.foo, true);
|
||||
shouldBe(delete undefined?.['foo'], true);
|
||||
shouldBe(delete null?.['foo'], true);
|
||||
shouldBe(delete undefined?.(), true);
|
||||
shouldBe(delete null?.(), true);
|
||||
shouldBe(delete ({}).a?.b?.b, true);
|
||||
shouldBe(delete ({a : {b: undefined}}).a?.b?.b, true);
|
||||
shouldBe(delete ({a : {b: undefined}}).a?.["b"]?.["b"], true);
|
||||
|
||||
const o2 = { x: 0, y: 0, z() {} };
|
||||
shouldBe(delete o2?.x, true);
|
||||
shouldBe(o2.x, undefined);
|
||||
shouldBe(o2.y, 0);
|
||||
shouldBe(delete o2?.x, true);
|
||||
shouldBe(delete o2?.['y'], true);
|
||||
shouldBe(o2.y, undefined);
|
||||
shouldBe(delete o2?.['y'], true);
|
||||
shouldBe(delete o2.z?.(), true);
|
||||
|
||||
function greet(name) { return `hey, ${name}${this.suffix ?? '.'}`; }
|
||||
shouldBe(eval?.('greet("world")'), 'hey, world.');
|
||||
shouldBe(greet?.call({ suffix: '!' }, 'world'), 'hey, world!');
|
||||
shouldBe(greet.call?.({ suffix: '!' }, 'world'), 'hey, world!');
|
||||
shouldBe(null?.call({ suffix: '!' }, 'world'), undefined);
|
||||
shouldBe(({}).call?.({ suffix: '!' }, 'world'), undefined);
|
||||
shouldBe(greet?.apply({ suffix: '?' }, ['world']), 'hey, world?');
|
||||
shouldBe(greet.apply?.({ suffix: '?' }, ['world']), 'hey, world?');
|
||||
shouldBe(null?.apply({ suffix: '?' }, ['world']), undefined);
|
||||
shouldBe(({}).apply?.({ suffix: '?' }, ['world']), undefined);
|
||||
shouldThrowSyntaxError('class C {} class D extends C { foo() { return super?.bar; } }');
|
||||
shouldThrowSyntaxError('class C {} class D extends C { foo() { return super?.["bar"]; } }');
|
||||
shouldThrowSyntaxError('class C {} class D extends C { constructor() { super?.(); } }');
|
||||
shouldThrowSyntaxError('const o = { C: class {} }; new o?.C();')
|
||||
shouldThrowSyntaxError('const o = { C: class {} }; new o?.["C"]();')
|
||||
shouldThrowSyntaxError('class C {} new C?.();')
|
||||
shouldThrowSyntaxError('function foo() { new?.target; }');
|
||||
shouldThrowSyntaxError('function tag() {} tag?.``;');
|
||||
shouldThrowSyntaxError('const o = { tag() {} }; o?.tag``;');
|
||||
|
||||
// NOT an optional chain
|
||||
shouldBe(false?.4:5, 5);
|
||||
|
||||
function testSideEffectCountFunction() {
|
||||
let count = 0;
|
||||
let a = {
|
||||
b: {
|
||||
c: {
|
||||
d: () => {
|
||||
count++;
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.b.c.d?.()?.b?.c?.d
|
||||
|
||||
shouldBe(count, 1);
|
||||
}
|
||||
|
||||
function testSideEffectCountGetters() {
|
||||
let count = 0;
|
||||
let a = {
|
||||
get b() {
|
||||
count++;
|
||||
return { c: {} };
|
||||
}
|
||||
}
|
||||
|
||||
a.b?.c?.d;
|
||||
shouldBe(count, 1);
|
||||
a.b?.c?.d;
|
||||
shouldBe(count, 2);
|
||||
}
|
||||
|
||||
testSideEffectCountFunction();
|
||||
testSideEffectCountGetters();
|
||||
|
||||
// stress test SM
|
||||
shouldBe(({a : {b: undefined}}).a.b?.()()(), undefined);
|
||||
shouldBe(({a : {b: undefined}}).a.b?.()?.()(), undefined);
|
||||
shouldBe(({a : {b: () => undefined}}).a.b?.()?.(), undefined);
|
||||
shouldThrowTypeError(() => delete ({a : {b: undefined}}).a?.b.b.c, 'can\'t access property "b", (intermediate value).a.b is undefined');
|
||||
shouldBe(delete ({a : {b: undefined}}).a?.["b"]?.["b"], true);
|
||||
shouldThrowTypeError(() => (({a : {b: () => undefined}}).a.b?.())(), 'undefined is not a function');
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
||||
0
js/src/tests/non262/expressions/shell.js
Normal file
0
js/src/tests/non262/expressions/shell.js
Normal file
0
js/src/tests/non262/shell.js
Normal file
0
js/src/tests/non262/shell.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/assignment-expr.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (AssignmentExpression)
|
||||
esid: sec-variable-statement-runtime-semantics-evaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
VariableDeclaration : BindingPattern Initializer
|
||||
|
||||
1. Let rhs be the result of evaluating Initializer.
|
||||
2. Let rval be GetValue(rhs).
|
||||
3. ReturnIfAbrupt(rval).
|
||||
4. Return the result of performing BindingInitialization for
|
||||
BindingPattern passing rval and undefined as arguments.
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var x = {};
|
||||
|
||||
0, [x?.y = 42] = [23];
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/assignment-expr.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (AssignmentExpression)
|
||||
esid: sec-variable-statement-runtime-semantics-evaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
VariableDeclaration : BindingPattern Initializer
|
||||
|
||||
1. Let rhs be the result of evaluating Initializer.
|
||||
2. Let rval be GetValue(rhs).
|
||||
3. ReturnIfAbrupt(rval).
|
||||
4. Return the result of performing BindingInitialization for
|
||||
BindingPattern passing rval and undefined as arguments.
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
0, [{
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y = 42] = [23];
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/assignment-expr.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (AssignmentExpression)
|
||||
esid: sec-variable-statement-runtime-semantics-evaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
VariableDeclaration : BindingPattern Initializer
|
||||
|
||||
1. Let rhs be the result of evaluating Initializer.
|
||||
2. Let rval be GetValue(rhs).
|
||||
3. ReturnIfAbrupt(rval).
|
||||
4. Return the result of performing BindingInitialization for
|
||||
BindingPattern passing rval and undefined as arguments.
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var y = {};
|
||||
|
||||
0, { x: y?.z = 42 } = { x: 23 };
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/assignment-expr.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (AssignmentExpression)
|
||||
esid: sec-variable-statement-runtime-semantics-evaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
VariableDeclaration : BindingPattern Initializer
|
||||
|
||||
1. Let rhs be the result of evaluating Initializer.
|
||||
2. Let rval be GetValue(rhs).
|
||||
3. ReturnIfAbrupt(rval).
|
||||
4. Return the result of performing BindingInitialization for
|
||||
BindingPattern passing rval and undefined as arguments.
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
0, { x: {
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y = 42} = {x: 42};
|
||||
16
js/src/tests/test262/language/expressions/shell.js
Normal file
16
js/src/tests/test262/language/expressions/shell.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// GENERATED, DO NOT EDIT
|
||||
// file: tcoHelper.js
|
||||
// Copyright (C) 2016 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
description: |
|
||||
This defines the number of consecutive recursive function calls that must be
|
||||
made in order to prove that stack frames are properly destroyed according to
|
||||
ES2015 tail call optimization semantics.
|
||||
defines: [$MAX_ITERATIONS]
|
||||
---*/
|
||||
|
||||
|
||||
|
||||
|
||||
var $MAX_ITERATIONS = 100000;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
should not suppress error if super called on class with no base
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression:
|
||||
SuperCall OptionalChain
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
class C {
|
||||
constructor () {
|
||||
super()?.a;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain on call expression
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression:
|
||||
CallExpression OptionalChain
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
// CallExpression CoverCallExpressionAndAsyncArrowHead
|
||||
function fn () {
|
||||
return {a: 33};
|
||||
};
|
||||
const obj = {
|
||||
fn () {
|
||||
return 44;
|
||||
}
|
||||
}
|
||||
assert.sameValue(33, fn()?.a);
|
||||
assert.sameValue(undefined, fn()?.b);
|
||||
assert.sameValue(44, obj?.fn());
|
||||
|
||||
// CallExpression SuperCall
|
||||
class A {}
|
||||
class B extends A {
|
||||
constructor () {
|
||||
assert.sameValue(undefined, super()?.a);
|
||||
}
|
||||
}
|
||||
new B();
|
||||
|
||||
// CallExpression Arguments
|
||||
function fn2 () {
|
||||
return () => {
|
||||
return {a: 66};
|
||||
};
|
||||
}
|
||||
function fn3 () {
|
||||
return () => {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
assert.sameValue(66, fn2()()?.a);
|
||||
assert.sameValue(undefined, fn3()()?.a);
|
||||
|
||||
// CallExpression [Expression]
|
||||
function fn4 () {
|
||||
return [{a: 77}];
|
||||
}
|
||||
function fn5 () {
|
||||
return [];
|
||||
}
|
||||
assert.sameValue(77, fn4()[0]?.a);
|
||||
assert.sameValue(undefined, fn5()[0]?.a);
|
||||
|
||||
// CallExpression .IdentifierName
|
||||
function fn6 () {
|
||||
return {
|
||||
a: {
|
||||
b: 88
|
||||
}
|
||||
};
|
||||
}
|
||||
assert.sameValue(88, fn6().a?.b);
|
||||
assert.sameValue(undefined, fn6().b?.c);
|
||||
|
||||
// CallExpression TemplateLiteral
|
||||
function fn7 () {
|
||||
return () => {};
|
||||
}
|
||||
assert.sameValue(undefined, fn7()`hello`?.a);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
// This production exists in order to prevent automatic semicolon
|
||||
// insertion rules.
|
||||
null?.
|
||||
`hello`
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
null?.`hello`;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
// This production exists in order to prevent automatic semicolon
|
||||
// insertion rules.
|
||||
null?.fn
|
||||
`hello`
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
null?.fn`hello`;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
const a = function() {};
|
||||
|
||||
// This production exists in order to prevent automatic semicolon
|
||||
// insertion rules.
|
||||
a?.
|
||||
`hello`
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
const a = function() {};
|
||||
|
||||
a?.`hello`;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
const a = {fn() {}};
|
||||
|
||||
// This production exists in order to prevent automatic semicolon
|
||||
// insertion rules.
|
||||
a?.fn
|
||||
`hello`
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
template string passed to tail position of optional chain
|
||||
info: |
|
||||
Static Semantics: Early Errors
|
||||
OptionalChain:
|
||||
?.TemplateLiteral
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
It is a Syntax Error if any code matches this production.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
const a = {fn() {}};
|
||||
|
||||
a?.fn`hello`;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2020 Toru Nagashima. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-optional-chaining-chain-evaluation
|
||||
description: optional call invoked on eval function should be indirect eval.
|
||||
info: |
|
||||
Runtime Semantics: ChainEvaluation
|
||||
OptionalChain: ?. Arguments
|
||||
1. Let thisChain be this OptionalChain.
|
||||
2. Let tailCall be IsInTailPosition(thisChain).
|
||||
3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
|
||||
|
||||
Runtime Semantics: EvaluateCall ( func, ref, arguments, tailPosition )
|
||||
|
||||
...
|
||||
7. Let result be Call(func, thisValue, argList).
|
||||
...
|
||||
|
||||
eval ( x )
|
||||
|
||||
...
|
||||
4. Return ? PerformEval(x, callerRealm, false, false).
|
||||
|
||||
Runtime Semantics: PerformEval ( x, callerRealm, strictCaller, direct )
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const a = 'global';
|
||||
|
||||
function fn() {
|
||||
const a = 'local';
|
||||
return eval?.('a');
|
||||
}
|
||||
|
||||
assert.sameValue(fn(), 'global', 'fn() returns "global" value from indirect eval');
|
||||
|
||||
const b = (a => eval?.('a'))('local');
|
||||
|
||||
assert.sameValue(b, 'global', 'b is "global", from indirect eval not observing parameter');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain in test portion of do while statement
|
||||
info: |
|
||||
IterationStatement
|
||||
do Statement while (OptionalExpression)
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
let count = 0;
|
||||
const obj = {a: true};
|
||||
do {
|
||||
count++;
|
||||
break;
|
||||
} while (obj?.a);
|
||||
assert.sameValue(1, count);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// |reftest| async
|
||||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain RHS of for await statement
|
||||
info: |
|
||||
IterationStatement
|
||||
for await (LeftHandSideExpression of AssignmentExpression) Statement
|
||||
features: [optional-chaining]
|
||||
flags: [async]
|
||||
---*/
|
||||
const obj = {
|
||||
iterable: {
|
||||
[Symbol.asyncIterator]() {
|
||||
return {
|
||||
i: 0,
|
||||
next() {
|
||||
if (this.i < 3) {
|
||||
return Promise.resolve({ value: this.i++, done: false });
|
||||
}
|
||||
return Promise.resolve({ done: true });
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
async function checkAssertions() {
|
||||
let count = 0;
|
||||
for await (const num of obj?.iterable) {
|
||||
count += num;
|
||||
}
|
||||
assert.sameValue(3, count);
|
||||
}
|
||||
checkAssertions().then($DONE, $DONE);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain in test portion of do while statement
|
||||
info: |
|
||||
IterationStatement
|
||||
for (LeftHandSideExpression in Expression) Statement
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
const obj = {
|
||||
inner: {
|
||||
a: 1,
|
||||
b: 2
|
||||
}
|
||||
};
|
||||
let str = '';
|
||||
for (const key in obj?.inner) {
|
||||
str += key;
|
||||
}
|
||||
assert.sameValue('ab', str);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain returning undefined in RHS of for of statement
|
||||
info: |
|
||||
IterationStatement
|
||||
for (LeftHandSideExpression of Expression) Statement
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
for (const key of {}?.a) ;
|
||||
});
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
for (const key of {}?.a) {}
|
||||
});
|
||||
|
||||
const obj = undefined;
|
||||
assert.throws(TypeError, function() {
|
||||
for (const key of obj?.a) {}
|
||||
});
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
for (const key of obj?.a);
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain in init/test/update of for statement
|
||||
info: |
|
||||
IterationStatement
|
||||
for (Expression; Expression; Expression) Statement
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
// OptionalExpression in test.
|
||||
let count;
|
||||
const obj = {a: true};
|
||||
for (count = 0; obj?.a; count++) {
|
||||
if (count > 0) break;
|
||||
}
|
||||
assert.sameValue(count, 1);
|
||||
|
||||
// OptionalExpression in init/test/update.
|
||||
let count2 = 0;
|
||||
const obj2 = undefined;
|
||||
|
||||
for (obj?.a; obj2?.a; obj?.a) { count2++; }
|
||||
assert.sameValue(count2, 0);
|
||||
|
||||
for (obj?.a; undefined?.a; obj?.a) { count2++; }
|
||||
assert.sameValue(count2, 0);
|
||||
|
||||
// Short-circuiting
|
||||
let touched = 0;
|
||||
const obj3 = {
|
||||
get a() {
|
||||
count++;
|
||||
return undefined; // explicit for clarity
|
||||
}
|
||||
};
|
||||
for (count = 0; true; obj3?.a?.[touched++]) {
|
||||
if (count > 0) { break; }
|
||||
}
|
||||
assert.sameValue(count, 1);
|
||||
assert.sameValue(touched, 0);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain in test portion of while statement
|
||||
info: |
|
||||
IterationStatement
|
||||
while (Expression) Statement
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
let count = 0;
|
||||
const obj = {a: true};
|
||||
while (obj?.a) {
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
assert.sameValue(1, count);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// |reftest| async
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain on member expression in async context
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression
|
||||
MemberExpression [PrimaryExpression identifier] OptionalChain
|
||||
features: [optional-chaining]
|
||||
flags: [async]
|
||||
---*/
|
||||
|
||||
const a = undefined;
|
||||
const c = {d: Promise.resolve(11)};
|
||||
async function checkAssertions() {
|
||||
assert.sameValue(await a?.b, undefined);
|
||||
assert.sameValue(await c?.d, 11);
|
||||
|
||||
Promise.prototype.x = 42;
|
||||
var res = await Promise.resolve(undefined)?.x;
|
||||
assert.sameValue(res, 42, 'await unwraps the evaluation of the whole optional chaining expression #1');
|
||||
|
||||
Promise.prototype.y = 43;
|
||||
var res = await Promise.reject(undefined)?.y;
|
||||
assert.sameValue(res, 43, 'await unwraps the evaluation of the whole optional chaining expression #2');
|
||||
|
||||
c.e = Promise.resolve(39);
|
||||
assert.sameValue(await c?.e, 39, 'await unwraps the promise given after the evaluation of the OCE');
|
||||
}
|
||||
checkAssertions().then($DONE, $DONE);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// |reftest| async
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain on member expression in async context
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression:
|
||||
MemberExpression [PrimaryExpression literal] OptionalChain
|
||||
features: [optional-chaining]
|
||||
flags: [async]
|
||||
---*/
|
||||
|
||||
async function checkAssertions() {
|
||||
assert.sameValue(await "hello"?.[0], 'h');
|
||||
assert.sameValue(await null?.a, undefined);
|
||||
}
|
||||
checkAssertions().then($DONE, $DONE);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// |reftest| async
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain on member expression in async context
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression:
|
||||
MemberExpression [PrimaryExpression this] OptionalChain
|
||||
features: [optional-chaining]
|
||||
flags: [async]
|
||||
---*/
|
||||
|
||||
async function thisFn() {
|
||||
return await this?.a
|
||||
}
|
||||
thisFn.call({a: Promise.resolve(33)}).then(function(arg) {
|
||||
assert.sameValue(33, arg);
|
||||
}).then($DONE, $DONE);
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain on member expression
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
// PrimaryExpression
|
||||
// IdentifierReference
|
||||
const a = {b: 22};
|
||||
assert.sameValue(22, a?.b);
|
||||
// this
|
||||
function fn () {
|
||||
return this?.a
|
||||
}
|
||||
assert.sameValue(33, fn.call({a: 33}));
|
||||
// Literal
|
||||
assert.sameValue(undefined, "hello"?.a);
|
||||
assert.sameValue(undefined, null?.a);
|
||||
// ArrayLiteral
|
||||
assert.sameValue(2, [1, 2]?.[1]);
|
||||
// ObjectLiteral
|
||||
assert.sameValue(44, {a: 44}?.a);
|
||||
// FunctionExpression
|
||||
assert.sameValue('a', (function a () {}?.name));
|
||||
// ClassExpression
|
||||
assert.sameValue('Foo', (class Foo {}?.name));
|
||||
// GeneratorFunction
|
||||
assert.sameValue('a', (function * a () {}?.name));
|
||||
// AsyncFunctionExpression
|
||||
assert.sameValue('a', (async function a () {}?.name));
|
||||
// AsyncGeneratorExpression
|
||||
assert.sameValue('a', (async function * a () {}?.name));
|
||||
// RegularExpressionLiteral
|
||||
assert.sameValue(true, /[a-z]/?.test('a'));
|
||||
// TemplateLiteral
|
||||
assert.sameValue('h', `hello`?.[0]);
|
||||
// CoverParenthesizedExpressionAndArrowParameterList
|
||||
assert.sameValue(undefined, ({a: 33}, null)?.a);
|
||||
assert.sameValue(33, (undefined, {a: 33})?.a);
|
||||
|
||||
// MemberExpression [ Expression ]
|
||||
const arr = [{a: 33}];
|
||||
assert.sameValue(33, arr[0]?.a);
|
||||
assert.sameValue(undefined, arr[1]?.a);
|
||||
|
||||
// MemberExpression .IdentifierName
|
||||
const obj = {a: {b: 44}};
|
||||
assert.sameValue(44, obj.a?.b);
|
||||
assert.sameValue(undefined, obj.c?.b);
|
||||
|
||||
// MemberExpression TemplateLiteral
|
||||
function f2 () {
|
||||
return {a: 33};
|
||||
}
|
||||
function f3 () {}
|
||||
assert.sameValue(33, f2`hello world`?.a);
|
||||
assert.sameValue(undefined, f3`hello world`?.a);
|
||||
|
||||
// MemberExpression SuperProperty
|
||||
class A {
|
||||
a () {}
|
||||
undf () {
|
||||
return super.a?.c;
|
||||
}
|
||||
}
|
||||
class B extends A {
|
||||
dot () {
|
||||
return super.a?.name;
|
||||
}
|
||||
expr () {
|
||||
return super['a']?.name;
|
||||
}
|
||||
undf2 () {
|
||||
return super.b?.c;
|
||||
}
|
||||
}
|
||||
const subcls = new B();
|
||||
assert.sameValue('a', subcls.dot());
|
||||
assert.sameValue('a', subcls.expr());
|
||||
assert.sameValue(undefined, subcls.undf2());
|
||||
assert.sameValue(undefined, (new A()).undf());
|
||||
|
||||
// MemberExpression MetaProperty
|
||||
class C {
|
||||
constructor () {
|
||||
assert.sameValue(undefined, new.target?.a);
|
||||
}
|
||||
}
|
||||
new C();
|
||||
|
||||
// new MemberExpression Arguments
|
||||
class D {
|
||||
constructor (val) {
|
||||
this.a = val;
|
||||
}
|
||||
}
|
||||
assert.sameValue(99, new D(99)?.a);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional call invoked on new.target should be equivalent to call
|
||||
info: |
|
||||
OptionalExpression
|
||||
MemberExpression OptionalChain
|
||||
NewTarget OptionalChain
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const newTargetContext = (function() { return this; })();
|
||||
|
||||
let called = false;
|
||||
// should be set to 'undefined' or global context, depending on whether
|
||||
// mode is strict or sloppy.
|
||||
let context = null;
|
||||
function Base() {
|
||||
called = true;
|
||||
context = this;
|
||||
}
|
||||
function Foo(blerg) {
|
||||
new.target?.();
|
||||
}
|
||||
|
||||
Reflect.construct(Foo, [], Base);
|
||||
assert(context === newTargetContext);
|
||||
assert.sameValue(called, true);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2019 Sony Interactive Entertainment Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-optional-chaining-chain-evaluation
|
||||
description: >
|
||||
optional call must preserve this context, as with a non-optional call
|
||||
info: |
|
||||
OptionalChain : ?. Arguments
|
||||
1. Let thisChain be this OptionalChain.
|
||||
2. Let tailCall be IsInTailPosition(thisChain).
|
||||
3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const a = {
|
||||
b() { return this._b; },
|
||||
_b: { c: 42 }
|
||||
};
|
||||
|
||||
assert.sameValue(a?.b().c, 42);
|
||||
assert.sameValue((a?.b)().c, 42);
|
||||
|
||||
assert.sameValue(a.b?.().c, 42);
|
||||
assert.sameValue((a.b)?.().c, 42);
|
||||
|
||||
assert.sameValue(a?.b?.().c, 42);
|
||||
assert.sameValue((a?.b)?.().c, 42);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// |reftest| async
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain expansions in an async context
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression
|
||||
MemberExpression [PrimaryExpression Identifier] OptionalChain
|
||||
OptionalChain OptionalChain ?.[Expression]
|
||||
features: [optional-chaining]
|
||||
flags: [async]
|
||||
---*/
|
||||
|
||||
async function checkAssertions() {
|
||||
assert.sameValue(await {a: [11]}?.a[0], 11);
|
||||
const b = {c: [22, 33]};
|
||||
assert.sameValue(b?.c[await Promise.resolve(1)], 33);
|
||||
function e(val) {
|
||||
return val;
|
||||
}
|
||||
assert.sameValue({d: e}?.d(await Promise.resolve([44, 55]))[1], 55);
|
||||
assert.sameValue(undefined?.arr[
|
||||
await Promise.reject(new Error('unreachable'))
|
||||
], undefined);
|
||||
}
|
||||
checkAssertions().then($DONE, $DONE);
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// |reftest| async
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain expansions in an async context
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression
|
||||
MemberExpression [PrimaryExpression Identifier] OptionalChain
|
||||
OptionalChain ?.[Expression]
|
||||
features: [optional-chaining]
|
||||
flags: [async]
|
||||
---*/
|
||||
|
||||
async function checkAssertions() {
|
||||
assert.sameValue(await [11]?.[0], 11);
|
||||
assert.sameValue([22, 33]?.[await Promise.resolve(1)], 33);
|
||||
assert.sameValue([44, await Promise.resolve(55)]?.[1], 55);
|
||||
assert.sameValue(undefined?.[
|
||||
await Promise.reject(new Error('unreachable'))
|
||||
], undefined);
|
||||
}
|
||||
checkAssertions().then($DONE, $DONE);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain bracket notation containing optional expresion
|
||||
info: |
|
||||
OptionalChain:
|
||||
?. [OptionalExpression]
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
const a = undefined;
|
||||
const b = {e: 0};
|
||||
const c = {};
|
||||
c[undefined] = 11;
|
||||
const d = [22];
|
||||
|
||||
assert.sameValue(undefined, a?.[a?.b]);
|
||||
assert.sameValue(11, c?.[a?.b]);
|
||||
assert.sameValue(22, d?.[b?.e]);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
Productions for ?. Arguments
|
||||
info: |
|
||||
OptionalChain[Yield, Await]:
|
||||
?. Arguments
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
function fn(arg1, arg2, arg3 = 0) {
|
||||
return arg1 + arg2 + arg3;
|
||||
}
|
||||
|
||||
assert.sameValue(fn?.(10, 20), 30, 'regular');
|
||||
assert.sameValue(String?.(42), '42', 'built-in');
|
||||
assert.sameValue(fn ?. (...[10, 20, 40]), 70, 'spread');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
Productions for ?. [Expression]
|
||||
info: |
|
||||
OptionalChain:
|
||||
?.[ Expression ]
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const $ = 'x';
|
||||
const arr = [39, 42];
|
||||
|
||||
arr.true = 'prop';
|
||||
arr[1.1] = 'other prop';
|
||||
|
||||
const obj = {
|
||||
a: 'hello',
|
||||
undefined: 40,
|
||||
$: 0,
|
||||
NaN: 41,
|
||||
null: 42,
|
||||
x: 43,
|
||||
true: 44
|
||||
};
|
||||
|
||||
assert.sameValue(arr?.[0], 39, '[0]');
|
||||
assert.sameValue(arr?.[0, 1], 42, '[0, 1]');
|
||||
assert.sameValue(arr?.[1], 42, '[1]');
|
||||
assert.sameValue(arr?.[1, 0], 39, '[1, 0]');
|
||||
assert.sameValue(arr?.[{}, NaN, undefined, 2, 0, 10 / 10], 42, '[{}, NaN, undefined, 2, 0, 10 / 10]');
|
||||
assert.sameValue(arr?.[true], 'prop', '[true]');
|
||||
assert.sameValue(arr?.[1.1], 'other prop', '[1.1]');
|
||||
|
||||
assert.sameValue(obj?.[undefined], 40, '[undefined]');
|
||||
assert.sameValue(obj?.[NaN], 41, '[NaN]');
|
||||
assert.sameValue(obj?.[null], 42, '[null]');
|
||||
assert.sameValue(obj?.['$'], 0, '["$"]');
|
||||
assert.sameValue(obj?.[$], 43, '[$]');
|
||||
assert.sameValue(obj?.[true], 44, '[true]');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2020 Salesforce.com, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
Productions for ?. IdentifierName
|
||||
info: |
|
||||
OptionalChain[Yield, Await]:
|
||||
?. IdentifierName
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const arr = [10, 11];
|
||||
const obj = {
|
||||
a: 'hello'
|
||||
};
|
||||
|
||||
assert.sameValue(obj?.a, 'hello');
|
||||
assert.sameValue(obj?.\u0061, 'hello');
|
||||
assert.sameValue(obj?.\u{0061}, 'hello');
|
||||
|
||||
assert.sameValue(obj?.\u0062, undefined);
|
||||
assert.sameValue(obj?.\u{0062}, undefined);
|
||||
|
||||
assert.sameValue(arr ?. length, 2);
|
||||
assert.sameValue(arr ?. l\u0065ngth, 2);
|
||||
assert.sameValue(arr ?. l\u{0065}ngth, 2);
|
||||
|
||||
assert.sameValue(obj?.$, undefined);
|
||||
|
||||
obj.$ = 42;
|
||||
assert.sameValue(obj?.$, 42);
|
||||
|
||||
assert.sameValue(obj?._, undefined);
|
||||
|
||||
obj._ = 39;
|
||||
assert.sameValue(obj?._, 39);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
various optional chain expansions
|
||||
info: |
|
||||
OptionalChain[Yield, Await]:
|
||||
?.[Expression]
|
||||
?.IdentifierName
|
||||
?.Arguments
|
||||
?.TemplateLiteral
|
||||
OptionalChain [Expression]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments[?Yield, ?Await]
|
||||
OptionalChain TemplateLiteral
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const arr = [10, 11];
|
||||
const obj = {
|
||||
a: 'hello',
|
||||
b: {val: 13},
|
||||
c(arg1) {
|
||||
return arg1 * 2;
|
||||
},
|
||||
arr: [11, 12]
|
||||
};
|
||||
const i = 0;
|
||||
|
||||
// OptionalChain: ?.[Expression]
|
||||
assert.sameValue(11, arr?.[i + 1]);
|
||||
|
||||
// OptionalChain: ?.IdentifierName
|
||||
assert.sameValue('hello', obj?.a);
|
||||
|
||||
// OptionalChain: ?.Arguments
|
||||
const fn = (arg1, arg2) => {
|
||||
return arg1 + arg2;
|
||||
}
|
||||
assert.sameValue(30, fn?.(10, 20));
|
||||
|
||||
// OptionalChain: OptionalChain [Expression]
|
||||
assert.sameValue(12, obj?.arr[i + 1]);
|
||||
|
||||
// OptionalChain: OptionalChain .IdentifierName
|
||||
assert.sameValue(13, obj?.b.val);
|
||||
|
||||
// OptionalChain: OptionalChain Arguments
|
||||
assert.sameValue(20, obj?.c(10));
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chain on recursive optional expression
|
||||
info: |
|
||||
Left-Hand-Side Expressions
|
||||
OptionalExpression:
|
||||
OptionalExpression OptionalChain
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const obj = {
|
||||
a: {
|
||||
b: 22
|
||||
}
|
||||
};
|
||||
|
||||
function fn () {
|
||||
return {};
|
||||
}
|
||||
|
||||
// OptionalExpression (MemberExpression OptionalChain) OptionalChain
|
||||
assert.sameValue(22, obj?.a?.b);
|
||||
// OptionalExpression (CallExpression OptionalChain) OptionalChain
|
||||
assert.sameValue(undefined, fn()?.a?.b);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
ternary operation with decimal does not evaluate as optional chain
|
||||
info: |
|
||||
Punctuators
|
||||
OptionalChainingPunctuator::
|
||||
?.[lookahead ∉ DecimalDigit]
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const value = true ?.30 : false;
|
||||
assert.sameValue(.30, value);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
accessing optional value on undefined or null returns undefined.
|
||||
info: |
|
||||
If baseValue is undefined or null, then
|
||||
Return undefined.
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const nul = null;
|
||||
const undf = undefined;
|
||||
assert.sameValue(undefined, nul?.a);
|
||||
assert.sameValue(undefined, undf?.b);
|
||||
assert.sameValue(undefined, null?.a);
|
||||
assert.sameValue(undefined, undefined?.b);
|
||||
|
||||
reportCompare(0, 0);
|
||||
0
js/src/tests/test262/language/optional-chaining/shell.js
Normal file
0
js/src/tests/test262/language/optional-chaining/shell.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
demonstrate syntax-based short-circuiting.
|
||||
info: |
|
||||
If the expression on the LHS of ?. evaluates to null/undefined, the RHS is
|
||||
not evaluated
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
const a = undefined;
|
||||
let x = 1;
|
||||
|
||||
a?.[++x] // short-circuiting.
|
||||
a?.b.c(++x).d; // long short-circuiting.
|
||||
|
||||
undefined?.[++x] // short-circuiting.
|
||||
undefined?.b.c(++x).d; // long short-circuiting.
|
||||
|
||||
assert.sameValue(1, x);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// |reftest| error:SyntaxError
|
||||
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
an optional expression cannot be target of assignment
|
||||
info: |
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
LeftHandSideExpression:
|
||||
OptionalExpression
|
||||
Return false.
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
const obj = {};
|
||||
|
||||
obj?.a = 33;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2019 Google, LLC. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional call invoked on super method should be equivalent to call
|
||||
info: |
|
||||
OptionalExpression
|
||||
MemberExpression OptionalChain
|
||||
SuperProperty OptionalChain
|
||||
features: [optional-chaining]
|
||||
---*/
|
||||
|
||||
let called = false;
|
||||
let context;
|
||||
class Base {
|
||||
method() {
|
||||
called = true;
|
||||
context = this;
|
||||
}
|
||||
}
|
||||
class Foo extends Base {
|
||||
method() {
|
||||
super.method?.();
|
||||
}
|
||||
}
|
||||
const foo = new Foo();
|
||||
foo.method();
|
||||
assert(foo === context);
|
||||
assert.sameValue(called, true);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chaining is forbidden in write contexts
|
||||
info: |
|
||||
UpdateExpression[Yield, Await]:
|
||||
LeftHandSideExpression++
|
||||
LeftHandSideExpression--
|
||||
++UnaryExpression
|
||||
--UnaryExpression
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
// LeftHandSideExpression ++
|
||||
const a = {};
|
||||
a?.b++;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright 2019 Google, Inc. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: prod-OptionalExpression
|
||||
description: >
|
||||
optional chaining is forbidden in write contexts
|
||||
info: |
|
||||
UpdateExpression[Yield, Await]:
|
||||
LeftHandSideExpression++
|
||||
LeftHandSideExpression--
|
||||
++UnaryExpression
|
||||
--UnaryExpression
|
||||
features: [optional-chaining]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
// --UnaryExpression
|
||||
const a = {};
|
||||
--a?.b;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var x = {};
|
||||
|
||||
for ([x?.y = 42] in [[23]]) ;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var x = {};
|
||||
|
||||
for ([x?.y] in [[23]]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ([{
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y = 42] in [[23]]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ([{
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y] in [[23]]) ;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var y = {};
|
||||
|
||||
for ({ x: y?.z = 42 } in [{ x: 23 }]) ;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var y = {};
|
||||
|
||||
for ({ x: y?.z } in [{ x: 23 }]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ({ x: {
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y = 42} in [{x: 42}]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-in.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..in statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ({ x: {
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y} in [{x: 42}]) ;
|
||||
0
js/src/tests/test262/language/statements/for-in/shell.js
Normal file
0
js/src/tests/test262/language/statements/for-in/shell.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var x = {};
|
||||
|
||||
for ([x?.y = 42] of [[23]]) ;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-nested-memberexpr-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var x = {};
|
||||
|
||||
for ([x?.y] of [[23]]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ([{
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y = 42] of [[23]]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/array-elem-put-obj-literal-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ([{
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y] of [[23]]) ;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName Initializer) (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var y = {};
|
||||
|
||||
for ({ x: y?.z = 42 } of [{ x: 23 }]) ;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-memberexpr-optchain-prop-ref.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (MemberExpression OptionalChain .IdentifierName) (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
var y = {};
|
||||
|
||||
for ({ x: y?.z } of [{ x: 23 }]) ;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// This file was procedurally generated from the following sources:
|
||||
// - src/dstr-assignment/obj-prop-elem-target-obj-literal-optchain-prop-ref-init.case
|
||||
// - src/dstr-assignment/syntax/for-of.template
|
||||
/*---
|
||||
description: It is a Syntax Error if LeftHandSideExpression of an DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral and AssignmentTargetType(LeftHandSideExpression) is not simple Using Object (For..of statement)
|
||||
esid: sec-for-in-and-for-of-statements-runtime-semantics-labelledevaluation
|
||||
features: [optional-chaining, destructuring-binding]
|
||||
flags: [generated]
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
info: |
|
||||
IterationStatement :
|
||||
for ( LeftHandSideExpression of AssignmentExpression ) Statement
|
||||
|
||||
1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(« »,
|
||||
AssignmentExpression, iterate).
|
||||
2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement,
|
||||
keyResult, assignment, labelSet).
|
||||
|
||||
13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation
|
||||
|
||||
[...]
|
||||
4. If destructuring is true and if lhsKind is assignment, then
|
||||
a. Assert: lhs is a LeftHandSideExpression.
|
||||
b. Let assignmentPattern be the parse of the source text corresponding to
|
||||
lhs using AssignmentPattern as the goal symbol.
|
||||
[...]
|
||||
|
||||
Syntax
|
||||
|
||||
AssignmentElement : DestructuringAssignmentTarget Initializer_opt
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
Static Semantics: Early Errors
|
||||
|
||||
OptionalExpression:
|
||||
MemberExpression OptionalChain
|
||||
CallExpression OptionalChain
|
||||
OptionalExpression OptionalChain
|
||||
|
||||
OptionalChain:
|
||||
?. [ Expression ]
|
||||
?. IdentifierName
|
||||
?. Arguments
|
||||
?. TemplateLiteral
|
||||
OptionalChain [ Expression ]
|
||||
OptionalChain .IdentifierName
|
||||
OptionalChain Arguments
|
||||
OptionalChain TemplateLiteral
|
||||
|
||||
DestructuringAssignmentTarget : LeftHandSideExpression
|
||||
|
||||
- It is a Syntax Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget(LeftHandSideExpression) is not true.
|
||||
|
||||
Static Semantics: IsValidSimpleAssignmentTarget
|
||||
|
||||
LeftHandSideExpression : OptionalExpression
|
||||
1. Return false.
|
||||
|
||||
---*/
|
||||
$DONOTEVALUATE();
|
||||
|
||||
for ({ x: {
|
||||
set y(val) {
|
||||
throw new Test262Error('The property should not be accessed.');
|
||||
}
|
||||
}?.y = 42} of [{x: 42}]) ;
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue