prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
531 lines (376 loc) • 24 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.DestructuringAssignmentEvaluation = DestructuringAssignmentEvaluation;
exports.IteratorDestructuringAssignmentEvaluation = IteratorDestructuringAssignmentEvaluation;
exports.KeyedDestructuringAssignmentEvaluation = KeyedDestructuringAssignmentEvaluation;
var _invariant = _interopRequireDefault(require("../invariant.js"));
var _environment = require("../environment.js");
var _index = require("../values/index.js");
var _completions = require("../completions.js");
var _ObjectExpression = require("../evaluators/ObjectExpression.js");
var _index2 = require("./index.js");
var _singletons = require("../singletons.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/* strict-local */
function RestDestructuringAssignmentEvaluation(realm, property, value, excludedNames, strictCode, env) {
let DestructuringAssignmentTarget = property.argument;
let lref; // 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
if (DestructuringAssignmentTarget.type !== "ObjectPattern" && DestructuringAssignmentTarget.type !== "ArrayPattern") {
// a. Let lref be the result of evaluating DestructuringAssignmentTarget.
lref = env.evaluate(DestructuringAssignmentTarget, strictCode); // b. ReturnIfAbrupt(lref).
} // 2. Let restObj be ObjectCreate(%ObjectPrototype%).
let restObj = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype); // 3. Let assignStatus be CopyDataProperties(restObj, value, excludedNames).
/* let assignStatus = */
_singletons.Create.CopyDataProperties(realm, restObj, value, excludedNames); // 4. ReturnIfAbrupt(assignStatus).
// 5. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
if (DestructuringAssignmentTarget.type !== "ObjectPattern" && DestructuringAssignmentTarget.type !== "ArrayPattern") {
(0, _invariant.default)(lref); // Return PutValue(lref, restObj).
return _singletons.Properties.PutValue(realm, lref, restObj);
} // 6. Let nestedAssignmentPattern be the parse of the source text corresponding to DestructuringAssignmentTarget using either AssignmentPattern[?Yield, ?Await] as the goal symbol, adopting the parameter values from AssignmentRestElement.
let nestedAssignmentPattern = DestructuringAssignmentTarget;
return DestructuringAssignmentEvaluation(realm, nestedAssignmentPattern, restObj, strictCode, env);
}
function PropertyDestructuringAssignmentEvaluation(realm, properties, value, strictCode, env) {
// Base condition for recursive call below
if (properties.length === 0) {
return [];
}
let AssignmentProperty = properties.slice(-1)[0];
let AssignmentPropertyList = properties.slice(0, -1); // 1. Let propertyNames be the result of performing PropertyDestructuringAssignmentEvaluation for AssignmentPropertyList using value as the argument.
let propertyNames = PropertyDestructuringAssignmentEvaluation(realm, AssignmentPropertyList, value, strictCode, env); // 2. ReturnIfAbrupt(status propertyNames).
// Let nextNames be the result of performing PropertyDestructuringAssignmentEvaluation for AssignmentProperty using value as the argument.
let nextNames; // AssignmentProperty : IdentifierReference Initializer
if (AssignmentProperty.key.type === "Identifier" && (AssignmentProperty.value.type === "Identifier" && AssignmentProperty.value.name === AssignmentProperty.key.name || AssignmentProperty.value.type === "AssignmentPattern" && AssignmentProperty.value.left.name === AssignmentProperty.key.name) && AssignmentProperty.computed === false) {
let Initializer;
if (AssignmentProperty.value.type === "AssignmentPattern") {
Initializer = AssignmentProperty.value.right;
} // 1. Let P be StringValue of IdentifierReference.
let P = AssignmentProperty.key.name; // 2. Let lref be ? ResolveBinding(P).
let lref = _singletons.Environment.ResolveBinding(realm, P, strictCode, env); // 3. Let v be ? GetV(value, P).
let v = (0, _index2.GetV)(realm, value, P); // 4. If Initializer is present and v is undefined, then
if (Initializer !== undefined && v instanceof _index.UndefinedValue) {
// 4a. Let defaultValue be the result of evaluating Initializer.
let defaultValue = env.evaluate(Initializer, strictCode); // 4b. Let v be ? GetValue(defaultValue).
v = _singletons.Environment.GetValue(realm, defaultValue); // 4c. If IsAnonymousFunctionDefinition(Initializer) is true, then
if ((0, _index2.IsAnonymousFunctionDefinition)(realm, Initializer)) {
(0, _invariant.default)(v instanceof _index.ObjectValue); // i. Let hasNameProperty be ? HasOwnProperty(v, "name").
let hasNameProperty = (0, _index2.HasOwnProperty)(realm, v, "name"); // j. If hasNameProperty is false, perform SetFunctionName(v, P).
if (hasNameProperty === false) {
_singletons.Functions.SetFunctionName(realm, v, P);
}
}
} // Perform ? PutValue(lref, v).
_singletons.Properties.PutValue(realm, lref, v); // Return a new List containing P.
nextNames = [new _index.StringValue(realm, P)];
} else {
// AssignmentProperty : PropertyName:AssignmentElement
// 1. Let name be the result of evaluating PropertyName.
let name = (0, _ObjectExpression.EvalPropertyName)(AssignmentProperty, env, realm, strictCode); // 2. ReturnIfAbrupt(name).
// 3. Let status be the result of performing KeyedDestructuringAssignmentEvaluation of AssignmentElement with value and name as the arguments.
/* let status = */
KeyedDestructuringAssignmentEvaluation(realm, // $FlowFixMe
AssignmentProperty.value, value, name, strictCode, env); // 4. ReturnIfAbrupt(status).
// 5. Return a new List containing name.
nextNames = [name];
} // 4. ReturnIfAbrupt(nextNames).
(0, _invariant.default)(nextNames instanceof Array); // 5. Append each item in nextNames to the end of propertyNames.
propertyNames = propertyNames.concat(nextNames); // 6. Return propertyNames.
return propertyNames;
} // 2.1 Object Rest/Spread Properties
function DestructuringAssignmentEvaluation(realm, pattern, value, strictCode, env) {
if (pattern.type === "ObjectPattern") {
let AssignmentPropertyList = [],
AssignmentRestElement = null;
for (let property of pattern.properties) {
if (property.type === "RestElement") {
AssignmentRestElement = property;
} else {
AssignmentPropertyList.push(property);
}
} // ObjectAssignmentPattern:
// { AssignmentPropertyList }
// { AssignmentPropertyList, }
if (!AssignmentRestElement) {
// 1. Perform ? RequireObjectCoercible(value).
(0, _index2.RequireObjectCoercible)(realm, value); // 2. Perform ? PropertyDestructuringAssignmentEvaluation for AssignmentPropertyList using value as the argument.
PropertyDestructuringAssignmentEvaluation(realm, AssignmentPropertyList, value, strictCode, env); // 3. Return NormalCompletion(empty).
return realm.intrinsics.empty;
} // ObjectAssignmentPattern : { AssignmentRestElement }
if (AssignmentPropertyList.length === 0) {
// 1. Let excludedNames be a new empty List.
let excludedNames = []; // 2. Return the result of performing RestDestructuringAssignmentEvaluation of AssignmentRestElement with value and excludedNames as the arguments.
return RestDestructuringAssignmentEvaluation(realm, AssignmentRestElement, value, excludedNames, strictCode, env);
} else {
// ObjectAssignmentPattern : { AssignmentPropertyList, AssignmentRestElement }
// 1. Let excludedNames be the result of performing ? PropertyDestructuringAssignmentEvaluation for AssignmentPropertyList using value as the argument.
let excludedNames = PropertyDestructuringAssignmentEvaluation(realm, AssignmentPropertyList, value, strictCode, env); // 2. Return the result of performing RestDestructuringAssignmentEvaluation of AssignmentRestElement with value and excludedNames as the arguments.
return RestDestructuringAssignmentEvaluation(realm, AssignmentRestElement, value, excludedNames, strictCode, env);
}
} else if (pattern.type === "ArrayPattern") {
// 1. Let iterator be ? GetIterator(value).
let iterator = (0, _index2.GetIterator)(realm, value); // 2. Let iteratorRecord be Record {[[Iterator]]: iterator, [[Done]]: false}.
let iteratorRecord = {
$Iterator: iterator,
$Done: false
}; // 3. Let result be the result of performing IteratorDestructuringAssignmentEvaluation of AssignmentElementList using iteratorRecord as the argument.
let result;
try {
result = IteratorDestructuringAssignmentEvaluation(realm, pattern.elements, iteratorRecord, strictCode, env);
} catch (error) {
// 4. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iterator, result).
if (iteratorRecord.$Done === false && error instanceof _completions.AbruptCompletion) {
throw (0, _index2.IteratorClose)(realm, iterator, error);
}
throw error;
} // 4. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iterator, result).
if (iteratorRecord.$Done === false) {
let completion = (0, _index2.IteratorClose)(realm, iterator, new _completions.SimpleNormalCompletion(realm.intrinsics.undefined));
if (completion instanceof _completions.AbruptCompletion) {
throw completion;
}
} // 5. Return result.
return result;
}
} // ECMA262 12.15.5.3
function IteratorDestructuringAssignmentEvaluation(realm, _elements, iteratorRecord, strictCode, env) {
let elements = _elements; // Check if the last element is a rest element. If so then we want to save the
// element and handle it separately after we iterate through the other
// formals. This also enforces that a rest element may only ever be in the
// last position.
let restEl;
if (elements.length > 0) {
let lastEl = elements[elements.length - 1];
if (lastEl !== null && lastEl.type === "RestElement") {
restEl = lastEl;
elements = elements.slice(0, -1);
}
}
for (let element of elements) {
if (element === null) {
// Elision handling
// 1. If iteratorRecord.[[Done]] is false, then
if (iteratorRecord.$Done === false) {
// a. Let next be IteratorStep(iteratorRecord.[[Iterator]]).
let next;
try {
next = (0, _index2.IteratorStep)(realm, iteratorRecord.$Iterator);
} catch (e) {
// b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
} // c. ReturnIfAbrupt(next).
throw e;
} // d. If next is false, set iteratorRecord.[[Done]] to true.
if (next === false) {
iteratorRecord.$Done = true;
}
} // 2. Return NormalCompletion(empty).
continue;
} // AssignmentElement : DestructuringAssignmentTarget Initializer
let DestructuringAssignmentTarget;
let Initializer;
if (element.type === "AssignmentPattern") {
Initializer = element.right;
DestructuringAssignmentTarget = element.left;
} else {
DestructuringAssignmentTarget = element;
}
let lref; // 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
//
// The spec assumes we haven't yet distinguished between literals and
// patterns, but our parser does that work for us. That means we check for
// "*Pattern" instead of "*Literal" like the spec text suggests.
if (DestructuringAssignmentTarget.type !== "ObjectPattern" && DestructuringAssignmentTarget.type !== "ArrayPattern") {
// a. Let lref be the result of evaluating DestructuringAssignmentTarget.
lref = env.evaluate(DestructuringAssignmentTarget, strictCode); // b. ReturnIfAbrupt(lref).
}
let value; // 2. If iteratorRecord.[[Done]] is false, then
if (iteratorRecord.$Done === false) {
// a. Let next be IteratorStep(iteratorRecord.[[Iterator]]).
let next;
try {
next = (0, _index2.IteratorStep)(realm, iteratorRecord.$Iterator);
} catch (e) {
// b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
} // c. ReturnIfAbrupt(next).
throw e;
} // d. If next is false, set iteratorRecord.[[Done]] to true.
if (next === false) {
iteratorRecord.$Done = true; // Normally this assignment would be done in step 3, but we do it
// here so that Flow knows `value` will always be initialized by step 4.
value = realm.intrinsics.undefined;
} else {
// e. Else,
// i. Let value be IteratorValue(next).
try {
value = (0, _index2.IteratorValue)(realm, next);
} catch (e) {
// ii. If value is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
} // iii. ReturnIfAbrupt(v).
throw e;
}
}
} else {
// 3. If iteratorRecord.[[Done]] is true, let value be undefined.
value = realm.intrinsics.undefined;
}
let v; // 4. If Initializer is present and value is undefined, then
if (Initializer && value instanceof _index.UndefinedValue) {
// a. Let defaultValue be the result of evaluating Initializer.
let defaultValue = env.evaluate(Initializer, strictCode); // b. Let v be ? GetValue(defaultValue).
v = _singletons.Environment.GetValue(realm, defaultValue);
} else {
// 5. Else, let v be value.
v = value;
} // 6. If DestructuringAssignmentTarget is an ObjectLiteral or an ArrayLiteral, then
//
// The spec assumes we haven't yet distinguished between literals and
// patterns, but our parser does that work for us. That means we check for
// "*Pattern" instead of "*Literal" like the spec text suggests.
if (DestructuringAssignmentTarget.type === "ObjectPattern" || DestructuringAssignmentTarget.type === "ArrayPattern") {
// a. Let nestedAssignmentPattern be the parse of the source text corresponding to DestructuringAssignmentTarget using either AssignmentPattern or AssignmentPattern[Yield] as the goal symbol depending upon whether this AssignmentElement has the [Yield] parameter.
let nestedAssignmentPattern = DestructuringAssignmentTarget; // b. Return the result of performing DestructuringAssignmentEvaluation of nestedAssignmentPattern with v as the argument.
DestructuringAssignmentEvaluation(realm, nestedAssignmentPattern, v, strictCode, env);
continue;
} // We know `lref` exists because of how the algorithm is setup, but tell
// Flow that `lref` exists with an `invariant()`.
(0, _invariant.default)(lref); // 7. If Initializer is present and value is undefined and IsAnonymousFunctionDefinition(Initializer) and IsIdentifierRef of DestructuringAssignmentTarget are both true, then
if (Initializer && value instanceof _index.UndefinedValue && (0, _index2.IsAnonymousFunctionDefinition)(realm, Initializer) && (0, _index2.IsIdentifierRef)(realm, DestructuringAssignmentTarget) && v instanceof _index.ObjectValue) {
// a. Let hasNameProperty be ? HasOwnProperty(v, "name").
let hasNameProperty = (0, _index2.HasOwnProperty)(realm, v, "name"); // b. If hasNameProperty is false, perform SetFunctionName(v, GetReferencedName(lref)).
if (hasNameProperty === false) {
// All of the nodes that may be evaluated to produce lref create
// references. Assert this with an invariant as GetReferencedName may
// not be called with a value.
(0, _invariant.default)(lref instanceof _environment.Reference);
_singletons.Functions.SetFunctionName(realm, v, _singletons.Environment.GetReferencedName(realm, lref));
}
} // 8. Return ? PutValue(lref, v).
_singletons.Properties.PutValue(realm, lref, v);
continue;
} // Handle the rest element if we have one.
if (restEl) {
// AssignmentRestElement : ...DestructuringAssignmentTarget
let DestructuringAssignmentTarget = restEl.argument;
let lref; // 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
//
// The spec assumes we haven't yet distinguished between literals and
// patterns, but our parser does that work for us. That means we check for
// "*Pattern" instead of "*Literal" like the spec text suggests.
if (DestructuringAssignmentTarget.type !== "ObjectPattern" && DestructuringAssignmentTarget.type !== "ArrayPattern") {
// a. Let lref be the result of evaluating DestructuringAssignmentTarget.
lref = env.evaluate(DestructuringAssignmentTarget, strictCode); // b. ReturnIfAbrupt(lref).
} // 2. Let A be ArrayCreate(0).
let A = _singletons.Create.ArrayCreate(realm, 0); // 3. Let n be 0.
let n = 0; // 4. Repeat while iteratorRecord.[[Done]] is false,
while (iteratorRecord.$Done === false) {
// a. Let next be IteratorStep(iteratorRecord.[[Iterator]]).
let next;
try {
next = (0, _index2.IteratorStep)(realm, iteratorRecord.$Iterator);
} catch (e) {
// b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
} // c. ReturnIfAbrupt(next).
throw e;
} // d. If next is false, set iteratorRecord.[[Done]] to true.
if (next === false) {
iteratorRecord.$Done = true;
} else {
// e. Else,
// i. Let nextValue be IteratorValue(next).
let nextValue;
try {
nextValue = (0, _index2.IteratorValue)(realm, next);
} catch (e) {
// ii. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
} // iii. ReturnIfAbrupt(nextValue).
throw e;
} // iv. Let status be CreateDataProperty(A, ! ToString(n), nextValue).
let status = _singletons.Create.CreateDataProperty(realm, A, n.toString(), nextValue); // v. Assert: status is true.
(0, _invariant.default)(status, "expected to create data property"); // vi. Increment n by 1.
n += 1;
}
} // 5. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
if (DestructuringAssignmentTarget.type !== "ObjectPattern" && DestructuringAssignmentTarget.type !== "ArrayPattern") {
// `lref` will always be defined at this point. Let Flow know with an
// invariant.
(0, _invariant.default)(lref); // a. Return ? PutValue(lref, A).
return _singletons.Properties.PutValue(realm, lref, A);
} else {
// 6. Let nestedAssignmentPattern be the parse of the source text corresponding to DestructuringAssignmentTarget using either AssignmentPattern or AssignmentPattern[Yield] as the goal symbol depending upon whether this AssignmentElement has the [Yield] parameter.
let nestedAssignmentPattern = DestructuringAssignmentTarget; // 7. Return the result of performing DestructuringAssignmentEvaluation of nestedAssignmentPattern with A as the argument.
return DestructuringAssignmentEvaluation(realm, nestedAssignmentPattern, A, strictCode, env);
}
}
} // ECMA262 12.15.5.4
function KeyedDestructuringAssignmentEvaluation(realm, node, value, propertyName, strictCode, env) {
let DestructuringAssignmentTarget;
let Initializer;
if (node.type === "AssignmentPattern") {
Initializer = node.right;
DestructuringAssignmentTarget = node.left;
} else {
DestructuringAssignmentTarget = node;
}
let lref; // 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
//
// The spec assumes we haven't yet distinguished between literals and
// patterns, but our parser does that work for us. That means we check for
// "*Pattern" instead of "*Literal" like the spec text suggests.
if (DestructuringAssignmentTarget.type !== "ObjectPattern" && DestructuringAssignmentTarget.type !== "ArrayPattern") {
// a. Let lref be the result of evaluating DestructuringAssignmentTarget.
lref = env.evaluate(DestructuringAssignmentTarget, strictCode); // b. ReturnIfAbrupt(lref).
}
let rhsValue; // 2. Let v be ? GetV(value, propertyName).
let v = (0, _index2.GetV)(realm, value, propertyName); // 3. If Initializer is present and v is undefined, then
if (Initializer && v instanceof _index.UndefinedValue) {
// a. Let defaultValue be the result of evaluating Initializer.
let defaultValue = env.evaluate(Initializer, strictCode); // b. Let rhsValue be ? GetValue(defaultValue).
rhsValue = _singletons.Environment.GetValue(realm, defaultValue);
} else {
// 4. Else, let rhsValue be v.
rhsValue = v;
} // 5. If DestructuringAssignmentTarget is an ObjectLiteral or an ArrayLiteral, then
//
// The spec assumes we haven't yet distinguished between literals and
// patterns, but our parser does that work for us. That means we check for
// "*Pattern" instead of "*Literal" like the spec text suggests.
if (DestructuringAssignmentTarget.type === "ObjectPattern" || DestructuringAssignmentTarget.type === "ArrayPattern") {
// a. Let assignmentPattern be the parse of the source text corresponding to DestructuringAssignmentTarget using either AssignmentPattern or AssignmentPattern[Yield] as the goal symbol depending upon whether this AssignmentElement has the [Yield] parameter.
let assignmentPattern = DestructuringAssignmentTarget; // b. Return the result of performing DestructuringAssignmentEvaluation of assignmentPattern with rhsValue as the argument.
return DestructuringAssignmentEvaluation(realm, assignmentPattern, rhsValue, strictCode, env);
} // `lref` will always be defined at this point. Let Flow know with an
// invariant.
(0, _invariant.default)(lref); // 6. If Initializer is present and v is undefined and IsAnonymousFunctionDefinition(Initializer) and IsIdentifierRef of DestructuringAssignmentTarget are both true, then
if (Initializer && v instanceof _index.UndefinedValue && (0, _index2.IsAnonymousFunctionDefinition)(realm, Initializer) && (0, _index2.IsIdentifierRef)(realm, DestructuringAssignmentTarget) && rhsValue instanceof _index.ObjectValue) {
// a. Let hasNameProperty be ? HasOwnProperty(rhsValue, "name").
let hasNameProperty = (0, _index2.HasOwnProperty)(realm, rhsValue, "name"); // b. If hasNameProperty is false, perform SetFunctionName(rhsValue, GetReferencedName(lref)).
if (hasNameProperty === false) {
// All of the nodes that may be evaluated to produce lref create
// references. Assert this with an invariant as GetReferencedName may
// not be called with a value.
(0, _invariant.default)(lref instanceof _environment.Reference);
_singletons.Functions.SetFunctionName(realm, rhsValue, _singletons.Environment.GetReferencedName(realm, lref));
}
} // 7. Return ? PutValue(lref, rhsValue).
return _singletons.Properties.PutValue(realm, lref, rhsValue);
}
//# sourceMappingURL=destructuring.js.map