prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
1,024 lines (844 loc) • 38.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EnvironmentImplementation = undefined;
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _index = require("../values/index.js");
var _environment = require("../environment.js");
var _completions = require("../completions.js");
var _errors = require("../errors.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 }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
/**
* 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.
*/
class EnvironmentImplementation {
// ECMA262 6.2.3
// IsSuperReference(V). Returns true if this reference has a thisValue component.
IsSuperReference(realm, V) {
return V.thisValue !== undefined;
}
// ECMA262 6.2.3
// HasPrimitiveBase(V). Returns true if Type(base) is Boolean, String, Symbol, or Number.
HasPrimitiveBase(realm, V) {
let base = this.GetBase(realm, V);
// void | ObjectValue | BooleanValue | StringValue | SymbolValue | NumberValue | EnvironmentRecord | AbstractValue;
if (!base || base instanceof _environment.EnvironmentRecord) return false;
let type = base.getType();
return type === _index.BooleanValue || type === _index.StringValue || type === _index.SymbolValue || type === _index.NumberValue || type === _index.IntegralValue;
}
// ECMA262 6.2.3
// GetReferencedName(V). Returns the referenced name component of the reference V.
GetReferencedName(realm, V) {
if (V.referencedName instanceof _index.AbstractValue) {
_index.AbstractValue.reportIntrospectionError(V.referencedName);
throw new _errors.FatalError();
}
return V.referencedName;
}
GetReferencedNamePartial(realm, V) {
return V.referencedName;
}
// ECMA262 6.2.3.1
GetValue(realm, V) {
let val = this._dereference(realm, V);
if (val instanceof _index.AbstractValue) return realm.simplifyAndRefineAbstractValue(val);
return val;
}
GetConditionValue(realm, V) {
let val = this._dereference(realm, V);
if (val instanceof _index.AbstractValue) return realm.simplifyAndRefineAbstractCondition(val);
return val;
}
_dereference(realm, V) {
// This step is not necessary as we propagate completions with exceptions.
// 1. ReturnIfAbrupt(V).
// 2. If Type(V) is not Reference, return V.
if (!(V instanceof _environment.Reference)) return V;
// 3. Let base be GetBase(V).
let base = this.GetBase(realm, V);
// 4. If IsUnresolvableReference(V) is true, throw a ReferenceError exception.
if (this.IsUnresolvableReference(realm, V)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError, `${V.referencedName.toString()} is not defined`);
}
// 5. If IsPropertyReference(V) is true, then
if (this.IsPropertyReference(realm, V)) {
if (base instanceof _index.AbstractValue) {
// Ensure that abstract values are coerced to objects. This might yield
// an operation that might throw.
base = _singletons.To.ToObjectPartial(realm, base);
}
// a. If HasPrimitiveBase(V) is true, then
if (this.HasPrimitiveBase(realm, V)) {
// i. Assert: In this case, base will never be null or undefined.
(0, _invariant2.default)(base instanceof _index.Value && !(0, _index2.HasSomeCompatibleType)(base, _index.UndefinedValue, _index.NullValue));
// ii. Let base be To.ToObject(base).
base = _singletons.To.ToObjectPartial(realm, base);
}
(0, _invariant2.default)(base instanceof _index.ObjectValue || base instanceof _index.AbstractObjectValue);
// b. Return ? base.[[Get]](GetReferencedName(V), GetThisValue(V)).
return base.$GetPartial(this.GetReferencedNamePartial(realm, V), (0, _index2.GetThisValue)(realm, V));
}
// 6. Else base must be an Environment Record,
if (base instanceof _environment.EnvironmentRecord) {
// a. Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V)) (see 8.1.1).
let referencedName = this.GetReferencedName(realm, V);
(0, _invariant2.default)(typeof referencedName === "string");
return base.GetBindingValue(referencedName, this.IsStrictReference(realm, V));
}
(0, _invariant2.default)(false);
}
// ECMA262 6.2.3
// IsStrictReference(V). Returns the strict reference flag component of the reference V.
IsStrictReference(realm, V) {
return V.strict;
}
// ECMA262 6.2.3
// IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.
IsPropertyReference(realm, V) {
// V.base is AbstractValue | void | ObjectValue | BooleanValue | StringValue | SymbolValue | NumberValue | EnvironmentRecord;
return V.base instanceof _index.AbstractValue || V.base instanceof _index.ObjectValue || this.HasPrimitiveBase(realm, V);
}
// ECMA262 6.2.3
// GetBase(V). Returns the base value component of the reference V.
GetBase(realm, V) {
return V.base;
}
// ECMA262 6.2.3
// IsUnresolvableReference(V). Returns true if the base value is undefined and false otherwise.
IsUnresolvableReference(realm, V) {
return !V.base;
}
// ECMA262 8.1.2.2
NewDeclarativeEnvironment(realm, E, active = true) {
// 1. Let env be a new Lexical Environment.
let env = new _environment.LexicalEnvironment(realm);
if (active) realm.activeLexicalEnvironments.add(env);
// 2. Let envRec be a new declarative Environment Record containing no bindings.
let envRec = new _environment.DeclarativeEnvironmentRecord(realm);
// 3. Set env's EnvironmentRecord to envRec.
env.environmentRecord = envRec;
// 4. Set the outer lexical environment reference of env to E.
env.parent = E;
// 5. Return env.
return env;
}
BoundNames(realm, node) {
return Object.keys(t.getOuterBindingIdentifiers(node));
}
// ECMA262 13.3.3.2
ContainsExpression(realm, node) {
if (!node) {
return false;
}
switch (node.type) {
case "ObjectPattern":
for (let prop of node.properties) {
if (this.ContainsExpression(realm, prop)) return true;
}
return false;
case "ArrayPattern":
for (let elem of node.elements) {
if (this.ContainsExpression(realm, elem)) return true;
}
return false;
case "RestElement":
return this.ContainsExpression(realm, node.argument);
case "AssignmentPattern":
return true;
default:
return false;
}
}
// ECMA262 8.3.2
ResolveBinding(realm, name, strict, env) {
// 1. If env was not passed or if env is undefined, then
if (!env) {
// a. Let env be the running execution context's LexicalEnvironment.
env = realm.getRunningContext().lexicalEnvironment;
}
// 2. Assert: env is a Lexical Environment.
(0, _invariant2.default)(env instanceof _environment.LexicalEnvironment, "expected lexical environment");
// 3. If the code matching the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
// 4. Return ? GetIdentifierReference(env, name, strict).
return this.GetIdentifierReference(realm, env, name, strict);
}
// ECMA262 8.1.2.1
GetIdentifierReference(realm, lex, name, strict) {
// 1. If lex is the value null, then
if (!lex) {
// a. Return a value of type Reference whose base value is undefined, whose referenced name is name, and whose strict reference flag is strict.
return new _environment.Reference(undefined, name, strict);
}
// 2. Let envRec be lex's EnvironmentRecord.
let envRec = lex.environmentRecord;
// 3. Let exists be ? envRec.HasBinding(name).
let exists = envRec.HasBinding(name);
// 4. If exists is true, then
if (exists) {
// a. Return a value of type Reference whose base value is envRec, whose referenced name is name, and whose strict reference flag is strict.
return new _environment.Reference(envRec, name, strict);
} else {
// 5. Else,
// a. Let outer be the value of lex's outer environment reference.
let outer = lex.parent;
// b. Return ? GetIdentifierReference(outer, name, strict).
return this.GetIdentifierReference(realm, outer, name, strict);
}
}
// ECMA262 6.2.3.4
InitializeReferencedBinding(realm, V, W) {
// 1. ReturnIfAbrupt(V).
// 2. ReturnIfAbrupt(W).
// 3. Assert: Type(V) is Reference.
(0, _invariant2.default)(V instanceof _environment.Reference, "expected reference");
// 4. Assert: IsUnresolvableReference(V) is false.
(0, _invariant2.default)(!this.IsUnresolvableReference(realm, V), "expected resolvable reference");
// 5. Let base be GetBase(V).
let base = this.GetBase(realm, V);
// 6. Assert: base is an Environment Record.
(0, _invariant2.default)(base instanceof _environment.EnvironmentRecord, "expected environment record");
// 7. Return base.InitializeBinding(GetReferencedName(V), W).
let referencedName = this.GetReferencedName(realm, V);
(0, _invariant2.default)(typeof referencedName === "string");
return base.InitializeBinding(referencedName, W);
}
// ECMA262 13.2.14
BlockDeclarationInstantiation(realm, strictCode, body, env) {
// 1. Let envRec be env's EnvironmentRecord.
let envRec = env.environmentRecord;
// 2. Assert: envRec is a declarative Environment Record.
(0, _invariant2.default)(envRec instanceof _environment.DeclarativeEnvironmentRecord, "expected declarative environment record");
// 3. Let declarations be the LexicallyScopedDeclarations of code.
let declarations = [];
for (let node of body) {
if (node.type === "ClassDeclaration" || node.type === "FunctionDeclaration" || node.type === "VariableDeclaration" && node.kind !== "var") {
declarations.push(node);
}
}
// 4. For each element d in declarations do
for (let d of declarations) {
// a. For each element dn of the BoundNames of d do
for (let dn of this.BoundNames(realm, d)) {
if (envRec.HasBinding(dn)) {
//ECMA262 13.2.1
throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, dn + " already declared");
}
// i. If IsConstantDeclaration of d is true, then
if (d.type === "VariableDeclaration" && d.kind === "const") {
// 1. Perform ! envRec.CreateImmutableBinding(dn, true).
envRec.CreateImmutableBinding(dn, true);
} else {
// ii. Else,
// 1. Perform ! envRec.CreateMutableBinding(dn, false).
envRec.CreateMutableBinding(dn, false);
}
}
// b. If d is a GeneratorDeclaration production or a FunctionDeclaration production, then
if (d.type === "FunctionDeclaration") {
// i. Let fn be the sole element of the BoundNames of d.
let fn = this.BoundNames(realm, d)[0];
// ii. Let fo be the result of performing InstantiateFunctionObject for d with argument env.
let fo = env.evaluate(d, strictCode);
(0, _invariant2.default)(fo instanceof _index.Value);
// iii. Perform envRec.InitializeBinding(fn, fo).
envRec.InitializeBinding(fn, fo);
}
}
}
// ECMA262 8.1.2.5
NewGlobalEnvironment(realm, G, thisValue) {
// 1. Let env be a new Lexical Environment.
let env = new _environment.LexicalEnvironment(realm);
// 2. Let objRec be a new object Environment Record containing G as the binding object.
let objRec = new _environment.ObjectEnvironmentRecord(realm, G);
// 3. Let dclRec be a new declarative Environment Record containing no bindings.
let dclRec = new _environment.DeclarativeEnvironmentRecord(realm);
// 4. Let globalRec be a new global Environment Record.
let globalRec = new _environment.GlobalEnvironmentRecord(realm);
// 5. Set globalRec.[[ObjectRecord]] to objRec.
globalRec.$ObjectRecord = objRec;
// 6. Set globalRec.[[GlobalThisValue]] to thisValue.
globalRec.$GlobalThisValue = thisValue;
// 7. Set globalRec.[[DeclarativeRecord]] to dclRec.
globalRec.$DeclarativeRecord = dclRec;
// 8. Set globalRec.[[VarNames]] to a new empty List.
globalRec.$VarNames = [];
// 9. Set env's EnvironmentRecord to globalRec.
env.environmentRecord = globalRec;
realm.activeLexicalEnvironments.add(env);
// 10. Set the outer lexical environment reference of env to null.
env.parent = null;
// 11. Return env.
return env;
}
// ECMA262 8.1.2.3
NewObjectEnvironment(realm, O, E) {
// 1. Let env be a new Lexical Environment.
let env = new _environment.LexicalEnvironment(realm);
realm.activeLexicalEnvironments.add(env);
// 2. Let envRec be a new object Environment Record containing O as the binding object.
let envRec = new _environment.ObjectEnvironmentRecord(realm, O);
// 3. Set env's EnvironmentRecord to envRec.
env.environmentRecord = envRec;
// 4. Set the outer lexical environment reference of env to E.
env.parent = E;
// 5. Return env.
return env;
}
// ECMA262 8.1.2.4
NewFunctionEnvironment(realm, F, newTarget) {
// 1. Assert: F is an ECMAScript function.
(0, _invariant2.default)(F instanceof _index.ECMAScriptFunctionValue, "expected a function");
// 2. Assert: Type(newTarget) is Undefined or Object.
(0, _invariant2.default)(newTarget === undefined || newTarget instanceof _index.ObjectValue, "expected undefined or object value for new target");
// 3. Let env be a new Lexical Environment.
let env = new _environment.LexicalEnvironment(realm);
realm.activeLexicalEnvironments.add(env);
// 4. Let envRec be a new function Environment Record containing no bindings.
let envRec = new _environment.FunctionEnvironmentRecord(realm);
// 5. Set envRec.[[FunctionObject]] to F.
envRec.$FunctionObject = F;
// 6. If F's [[ThisMode]] internal slot is lexical, set envRec.[[ThisBindingStatus]] to "lexical".
if (F.$ThisMode === "lexical") {
envRec.$ThisBindingStatus = "lexical";
} else {
// 7. Else, set envRec.[[ThisBindingStatus]] to "uninitialized".
envRec.$ThisBindingStatus = "uninitialized";
}
// 8. Let home be the value of F's [[HomeObject]] internal slot.
let home = F.$HomeObject;
// 9. Set envRec.[[HomeObject]] to home.
envRec.$HomeObject = home;
// 10. Set envRec.[[NewTarget]] to newTarget.
envRec.$NewTarget = newTarget;
// 11. Set env's EnvironmentRecord to envRec.
env.environmentRecord = envRec;
// 12. Set the outer lexical environment reference of env to the value of F's [[Environment]] internal slot.
env.parent = F.$Environment;
// 13. Return env.
return env;
}
// ECMA262 8.3.1
GetActiveScriptOrModule(realm) {
// The GetActiveScriptOrModule abstract operation is used to determine the running script or module, based on the active function object.
// GetActiveScriptOrModule performs the following steps:
//
// If the execution context stack is empty, return null.
if (realm.contextStack.length === 0) return null;
// Let ec be the topmost execution context on the execution context stack whose Function component's [[ScriptOrModule]] component is not null.
// If such an execution context exists, return ec's Function component's [[ScriptOrModule]] slot's value.
let ec;
for (let i = realm.contextStack.length - 1; i >= 0; i--) {
ec = realm.contextStack[i];
let F = ec.function;
if (F == null) continue;
if (F.$ScriptOrModule instanceof Object) {
return F.$ScriptOrModule;
}
}
// Otherwise, let ec be the running execution context.
ec = realm.getRunningContext();
// Assert: ec's ScriptOrModule component is not null.
(0, _invariant2.default)(ec.ScriptOrModule !== null);
// Return ec's ScriptOrModule component.
return ec.ScriptOrModule;
}
// ECMA262 8.3.3
GetThisEnvironment(realm) {
// 1. Let lex be the running execution context's LexicalEnvironment.
let lex = realm.getRunningContext().lexicalEnvironment;
// 2. Repeat
while (true) {
// a. Let envRec be lex's EnvironmentRecord.
let envRec = lex.environmentRecord;
// b. Let exists be envRec.HasThisBinding().
let exists = envRec.HasThisBinding();
// c. If exists is true, return envRec.
if (exists) return envRec;
// d. Let outer be the value of lex's outer environment reference.
let outer = lex.parent;
(0, _invariant2.default)(outer);
// e. Let lex be outer.
lex = outer;
}
(0, _invariant2.default)(false);
}
// ECMA262 8.3.4
ResolveThisBinding(realm) {
// 1. Let envRec be GetThisEnvironment( ).
let envRec = this.GetThisEnvironment(realm);
// 2. Return ? envRec.GetThisBinding().
return envRec.GetThisBinding();
}
BindingInitialization(realm, node, value, strictCode, environment) {
if (node.type === "ArrayPattern") {
// ECMA262 13.3.3.5
// 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
};
let result;
// 3. Let result be IteratorBindingInitialization for ArrayBindingPattern using iteratorRecord and environment as arguments.
try {
result = this.IteratorBindingInitialization(realm, node.elements, iteratorRecord, strictCode, environment);
} 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.NormalCompletion(realm.intrinsics.undefined));
if (completion instanceof _completions.AbruptCompletion) {
throw completion;
}
}
// 5. Return result.
return result;
} else if (node.type === "ObjectPattern") {
// ECMA262 13.3.3.5
// BindingPattern : ObjectBindingPattern
// 1. Perform ? RequireObjectCoercible(value).
(0, _index2.RequireObjectCoercible)(realm, value);
// 2. Return the result of performing BindingInitialization for ObjectBindingPattern using value and environment as arguments.
for (let property of node.properties) {
let env = environment ? environment : realm.getRunningContext().lexicalEnvironment;
// 1. Let P be the result of evaluating PropertyName.
let P = (0, _ObjectExpression.EvalPropertyName)(property, env, realm, strictCode);
// 2. ReturnIfAbrupt(P).
// 3. Return the result of performing KeyedBindingInitialization for BindingElement using value, environment, and P as arguments.
this.KeyedBindingInitialization(realm, property.value, value, strictCode, environment, P);
}
} else if (node.type === "Identifier") {
// ECMA262 12.1.5
// 1. Let name be StringValue of Identifier.
let name = node.name;
// 2. Return ? InitializeBoundName(name, value, environment).
return this.InitializeBoundName(realm, name, value, environment);
} else {
(0, _invariant2.default)(node.type === "VariableDeclaration");
// ECMA262 13.7.5.9
for (let decl of node.declarations) {
this.BindingInitialization(realm, decl.id, value, strictCode, environment);
}
}
}
// ECMA262 13.3.3.6
// ECMA262 14.1.19
IteratorBindingInitialization(realm, formals, iteratorRecord, strictCode, environment) {
let env = environment ? environment : realm.getRunningContext().lexicalEnvironment;
// Check if the last formal 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 (formals.length > 0) {
let lastFormal = formals[formals.length - 1];
if (lastFormal !== null && lastFormal.type === "RestElement") {
restEl = lastFormal;
formals = formals.slice(0, -1);
}
}
for (let param of formals) {
if (param === null) {
// Elision handling in IteratorDestructuringAssignmentEvaluation
// 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;
}
let Initializer;
if (param.type === "AssignmentPattern") {
Initializer = param.right;
param = param.left;
}
if (param.type === "Identifier") {
// SingleNameBinding : BindingIdentifier Initializer
// 1. Let bindingId be StringValue of BindingIdentifier.
let bindingId = param.name;
// 2. Let lhs be ? ResolveBinding(bindingId, environment).
let lhs = this.ResolveBinding(realm, param.name, strictCode, environment);
// Initialized later in the algorithm.
let v;
// 3. 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 4, but we do it
// here so that Flow knows `v` will always be initialized by step 5.
v = realm.intrinsics.undefined;
} else {
// e. Else,
// i. Let v be IteratorValue(next).
try {
v = (0, _index2.IteratorValue)(realm, next);
} catch (e) {
// ii. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
}
// iii. ReturnIfAbrupt(v).
throw e;
}
}
} else {
// 4. If iteratorRecord.[[Done]] is true, let v be undefined.
v = realm.intrinsics.undefined;
}
// 5. 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 v be ? GetValue(defaultValue).
v = this.GetValue(realm, defaultValue);
// c. If IsAnonymousFunctionDefinition(Initializer) is true, then
if ((0, _index2.IsAnonymousFunctionDefinition)(realm, Initializer) && v instanceof _index.ObjectValue) {
// i. Let hasNameProperty be ? HasOwnProperty(v, "name").
let hasNameProperty = (0, _index2.HasOwnProperty)(realm, v, "name");
// ii. If hasNameProperty is false, perform SetFunctionName(v, bindingId).
if (hasNameProperty === false) {
_singletons.Functions.SetFunctionName(realm, v, bindingId);
}
}
}
// 6. If environment is undefined, return ? PutValue(lhs, v).
if (!environment) {
_singletons.Properties.PutValue(realm, lhs, v);
continue;
}
// 7. Return InitializeReferencedBinding(lhs, v).
this.InitializeReferencedBinding(realm, lhs, v);
continue;
} else {
(0, _invariant2.default)(param.type === "ObjectPattern" || param.type === "ArrayPattern");
// BindingElement : BindingPatternInitializer
// Initialized later in the algorithm.
let v;
// 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;
// Normally this assignment would be done in step 2, but we do it
// here so that Flow knows `v` will always be initialized by step 3.
v = realm.intrinsics.undefined;
} else {
// e. Else,
// i. Let v be IteratorValue(next).
try {
v = (0, _index2.IteratorValue)(realm, next);
} catch (e) {
// ii. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
}
// iii. ReturnIfAbrupt(v).
throw e;
}
}
} else {
// 2. If iteratorRecord.[[Done]] is true, let v be undefined.
v = realm.intrinsics.undefined;
}
// 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 v be ? GetValue(defaultValue).
v = this.GetValue(realm, defaultValue);
}
// 4. Return the result of performing BindingInitialization of BindingPattern with v and environment as the arguments.
this.BindingInitialization(realm, param, v, strictCode, environment);
continue;
}
}
// Handle the rest element if we have one.
if (restEl && restEl.argument.type === "Identifier") {
// BindingRestElement : ...BindingIdentifier
// 1. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier, environment).
let lhs = this.ResolveBinding(realm, restEl.argument.name, strictCode, environment);
// 2. Let A be ArrayCreate(0).
let A = _singletons.Create.ArrayCreate(realm, 0);
// 3. Let n be 0.
let n = 0;
// 4. Repeat,
while (true) {
// Initialized later in the algorithm.
let next;
// a. If iteratorRecord.[[Done]] is false, then
if (iteratorRecord.$Done === false) {
// i. Let next be IteratorStep(iteratorRecord.[[Iterator]]).
try {
next = (0, _index2.IteratorStep)(realm, iteratorRecord.$Iterator);
} catch (e) {
// ii. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
}
// iii. ReturnIfAbrupt(next).
throw e;
}
// iv. If next is false, set iteratorRecord.[[Done]] to true.
if (next === false) {
iteratorRecord.$Done = true;
}
}
// b. If iteratorRecord.[[Done]] is true, then
if (iteratorRecord.$Done === true) {
// i. If environment is undefined, return ? PutValue(lhs, A).
if (!environment) {
_singletons.Properties.PutValue(realm, lhs, A);
break;
}
// ii. Return InitializeReferencedBinding(lhs, A).
this.InitializeReferencedBinding(realm, lhs, A);
break;
}
// Given the nature of the algorithm this should always be true, however
// it is difficult to arrange the code in such a way where Flow's control
// flow analysis will pick that up, so we add an invariant here.
(0, _invariant2.default)(next instanceof _index.ObjectValue);
// c. Let nextValue be IteratorValue(next).
let nextValue;
try {
nextValue = (0, _index2.IteratorValue)(realm, next);
} catch (e) {
// d. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
}
// e. ReturnIfAbrupt(nextValue).
throw e;
}
// f. Let status be CreateDataProperty(A, ! To.ToString(n), nextValue).
let status = _singletons.Create.CreateDataProperty(realm, A, n.toString(), nextValue);
// g. Assert: status is true.
(0, _invariant2.default)(status, "expected to create data property");
// h. Increment n by 1.
n += 1;
}
} else if (restEl) {
(0, _invariant2.default)(restEl.argument.type === "ArrayPattern" || restEl.argument.type === "ObjectPattern");
// 1. Let A be ArrayCreate(0).
let A = _singletons.Create.ArrayCreate(realm, 0);
// 2. Let n be 0.
let n = 0;
// 3. Repeat,
while (true) {
// Initialized later in the algorithm.
let next;
// a. If iteratorRecord.[[Done]] is false, then
if (iteratorRecord.$Done === false) {
// i. Let next be IteratorStep(iteratorRecord.[[Iterator]]).
try {
next = (0, _index2.IteratorStep)(realm, iteratorRecord.$Iterator);
} catch (e) {
// ii. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
}
// iii. ReturnIfAbrupt(next).
throw e;
}
// iv. If next is false, set iteratorRecord.[[Done]] to true.
if (next === false) {
iteratorRecord.$Done = true;
}
}
// b. If iteratorRecord.[[Done]] is true, then
if (iteratorRecord.$Done === true) {
// i. Return the result of performing BindingInitialization of BindingPattern with A and environment as the arguments.
this.BindingInitialization(realm, restEl.argument, A, strictCode, environment);
break;
}
// Given the nature of the algorithm this should always be true, however
// it is difficult to arrange the code in such a way where Flow's control
// flow analysis will pick that up, so we add an invariant here.
(0, _invariant2.default)(next instanceof _index.ObjectValue);
// c. Let nextValue be IteratorValue(next).
let nextValue;
try {
nextValue = (0, _index2.IteratorValue)(realm, next);
} catch (e) {
// d. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
if (e instanceof _completions.AbruptCompletion) {
iteratorRecord.$Done = true;
}
// e. ReturnIfAbrupt(nextValue).
throw e;
}
// f. Let status be CreateDataProperty(A, ! To.ToString(n), nextValue).
let status = _singletons.Create.CreateDataProperty(realm, A, n.toString(), nextValue);
// g. Assert: status is true.
(0, _invariant2.default)(status, "expected to create data property");
// h. Increment n by 1.
n += 1;
}
}
}
// ECMA262 12.1.5.1
InitializeBoundName(realm, name, value, environment) {
// 1. Assert: Type(name) is String.
(0, _invariant2.default)(typeof name === "string", "expected name to be a string");
// 2. If environment is not undefined, then
if (environment) {
// a. Let env be the EnvironmentRecord component of environment.
let env = environment.environmentRecord;
// b. Perform env.InitializeBinding(name, value).
env.InitializeBinding(name, value);
// c. Return NormalCompletion(undefined).
return realm.intrinsics.undefined;
} else {
// 3. Else,
// a. Let lhs be ResolveBinding(name).
// Note that the undefined environment implies non-strict.
let lhs = this.ResolveBinding(realm, name, false);
// b. Return ? PutValue(lhs, value).
return _singletons.Properties.PutValue(realm, lhs, value);
}
}
// ECMA262 12.3.1.3 and 13.7.5.6
IsDestructuring(ast) {
switch (ast.type) {
case "VariableDeclaration":
for (let decl of ast.declarations) {
switch (decl.type) {
case "VariableDeclarator":
switch (decl.id.type) {
case "ArrayPattern":
case "AssignmentPattern":
case "ObjectPattern":
return true;
default:
break;
}
break;
default:
break;
}
}
return false;
case "ArrayLiteral":
case "ObjectLiteral":
return true;
case "ArrayPattern":
case "ObjectPattern":
return true;
default:
return false;
}
}
// ECMA262 13.3.3.7
KeyedBindingInitialization(realm, node, value, strictCode, environment, propertyName) {
let env = environment ? environment : realm.getRunningContext().lexicalEnvironment;
let Initializer;
if (node.type === "AssignmentPattern") {
Initializer = node.right;
node = node.left;
}
if (node.type === "Identifier") {
// SingleNameBinding : BindingIdentifier Initializer
// 1. Let bindingId be StringValue of BindingIdentifier.
let bindingId = node.name;
// 2. Let lhs be ? ResolveBinding(bindingId, environment).
let lhs = this.ResolveBinding(realm, bindingId, strictCode, environment);
// 3. Let v be ? GetV(value, propertyName).
let v = (0, _index2.GetV)(realm, value, propertyName);
// 4. 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 v be ? GetValue(defaultValue).
v = this.GetValue(realm, defaultValue);
// c. If IsAnonymousFunctionDefinition(Initializer) is true, then
if ((0, _index2.IsAnonymousFunctionDefinition)(realm, Initializer) && v instanceof _index.ObjectValue) {
// i. Let hasNameProperty be ? HasOwnProperty(v, "name").
let hasNameProperty = (0, _index2.HasOwnProperty)(realm, v, "name");
// ii. If hasNameProperty is false, perform SetFunctionName(v, bindingId).
if (hasNameProperty === false) {
_singletons.Functions.SetFunctionName(realm, v, bindingId);
}
}
}
// 5. If environment is undefined, return ? PutValue(lhs, v).
if (!environment) return _singletons.Properties.PutValue(realm, lhs, v);
// 6. Return InitializeReferencedBinding(lhs, v).
return this.InitializeReferencedBinding(realm, lhs, v);
} else if (node.type === "ObjectPattern" || node.type === "ArrayPattern") {
// BindingElement : BindingPattern Initializer
// 1. Let v be ? GetV(value, propertyName).
let v = (0, _index2.GetV)(realm, value, propertyName);
// 2. 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 v be ? GetValue(defaultValue).
v = this.GetValue(realm, defaultValue);
}
// 3. Return the result of performing BindingInitialization for BindingPattern passing v and environment as arguments.
return this.BindingInitialization(realm, node, v, strictCode, env);
}
}
}
exports.EnvironmentImplementation = EnvironmentImplementation;
//# sourceMappingURL=environment.js.map