prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
1,279 lines (1,002 loc) • 43 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Reference = exports.LexicalEnvironment = exports.GlobalEnvironmentRecord = exports.FunctionEnvironmentRecord = exports.ObjectEnvironmentRecord = exports.DeclarativeEnvironmentRecord = exports.EnvironmentRecord = undefined;
exports.havocBinding = havocBinding;
exports.mightBecomeAnObject = mightBecomeAnObject;
var _completions = require("./completions.js");
var _errors = require("./errors.js");
var _options = require("./options");
var _realm = require("./realm.js");
var _index = require("./values/index.js");
var _babelGenerator = require("babel-generator");
var _babelGenerator2 = _interopRequireDefault(_babelGenerator);
var _parse = require("./utils/parse.js");
var _parse2 = _interopRequireDefault(_parse);
var _invariant = require("./invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _traverseFast = require("./utils/traverse-fast.js");
var _traverseFast2 = _interopRequireDefault(_traverseFast);
var _index2 = require("./methods/index.js");
var _singletons = require("./singletons.js");
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
var _index3 = require("./domains/index.js");
var _PrimitiveValue = require("./values/PrimitiveValue");
var _PrimitiveValue2 = _interopRequireDefault(_PrimitiveValue);
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; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const sourceMap = require("source-map"); /**
* 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.
*/
function deriveGetBinding(realm, binding) {
let types = _index3.TypesDomain.topVal;
let values = _index3.ValuesDomain.topVal;
(0, _invariant2.default)(realm.generator !== undefined);
return realm.generator.derive(types, values, [], (_, context) => context.serializeBinding(binding));
}
function havocBinding(binding) {
let realm = binding.environment.realm;
if (!binding.hasLeaked) {
realm.recordModifiedBinding(binding).hasLeaked = true;
}
}
// ECMA262 8.1.1
class EnvironmentRecord {
constructor(realm) {
(0, _invariant2.default)(realm, "expected realm");
this.realm = realm;
this.isReadOnly = false;
this.id = EnvironmentRecord.nextId++;
}
}
exports.EnvironmentRecord = EnvironmentRecord;
EnvironmentRecord.nextId = 0;
// ECMA262 8.1.1.1
class DeclarativeEnvironmentRecord extends EnvironmentRecord {
constructor(realm) {
super(realm);
this.bindings = Object.create(null);
this.frozen = false;
}
// Frozen Records cannot have bindings created or deleted but can have bindings updated
// ECMA262 8.1.1.1.1
HasBinding(N) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
// 2. If envRec has a binding for the name that is the value of N, return true.
if (envRec.bindings[N]) return true;
// 3. Return false.
return false;
}
// ECMA262 8.1.1.1.2
CreateMutableBinding(N, D, isGlobal = false) {
(0, _invariant2.default)(!this.frozen);
let realm = this.realm;
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
// 2. Assert: envRec does not already have a binding for N.
(0, _invariant2.default)(!envRec.bindings[N], `shouldn't have the binding ${N}`);
// 3. Create a mutable binding in envRec for N and record that it is uninitialized. If D is true, record that the newly created binding may be deleted by a subsequent DeleteBinding call.
this.bindings[N] = realm.recordModifiedBinding({
initialized: false,
mutable: true,
deletable: D,
environment: envRec,
name: N,
isGlobal: isGlobal,
hasLeaked: false
});
// 4. Return NormalCompletion(empty).
return realm.intrinsics.undefined;
}
// ECMA262 8.1.1.1.3
CreateImmutableBinding(N, S, isGlobal = false) {
(0, _invariant2.default)(!this.frozen);
let realm = this.realm;
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
// 2. Assert: envRec does not already have a binding for N.
(0, _invariant2.default)(!envRec.bindings[N], `shouldn't have the binding ${N}`);
// 3. Create an immutable binding in envRec for N and record that it is uninitialized. If S is true, record that the newly created binding is a strict binding.
this.bindings[N] = realm.recordModifiedBinding({
initialized: false,
strict: S,
deletable: false,
environment: envRec,
name: N,
isGlobal: isGlobal,
hasLeaked: false
});
// 4. Return NormalCompletion(empty).
return realm.intrinsics.undefined;
}
// ECMA262 8.1.1.1.4
InitializeBinding(N, V) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
let binding = envRec.bindings[N];
// 2. Assert: envRec must have an uninitialized binding for N.
(0, _invariant2.default)(binding && !binding.initialized, `shouldn't have the binding ${N}`);
// 3. Set the bound value for N in envRec to V.
this.realm.recordModifiedBinding(binding).value = V;
// 4. Record that the binding for N in envRec has been initialized.
binding.initialized = true;
// 5. Return NormalCompletion(empty).
return this.realm.intrinsics.empty;
}
// ECMA262 8.1.1.1.5
SetMutableBinding(N, V, S) {
// We can mutate frozen bindings because of captured bindings.
let realm = this.realm;
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
let binding = envRec.bindings[N];
// 2. If envRec does not have a binding for N, then
if (!binding) {
// a. If S is true, throw a ReferenceError exception.
if (S) {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError, `${N} not found`);
}
// b. Perform envRec.CreateMutableBinding(N, true).
envRec.CreateMutableBinding(N, true);
// c. Perform envRec.InitializeBinding(N, V).
envRec.InitializeBinding(N, V);
// d. Return NormalCompletion(empty).
return this.realm.intrinsics.empty;
}
// 3. If the binding for N in envRec is a strict binding, let S be true.
if (binding.strict) S = true;
// 4. If the binding for N in envRec has not yet been initialized, throw a ReferenceError exception.
if (!binding.initialized) {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError, `${N} has not yet been initialized`);
} else if (binding.mutable) {
// 5. Else if the binding for N in envRec is a mutable binding, change its bound value to V.
if (binding.hasLeaked) {
_singletons.Havoc.value(realm, V);
(0, _invariant2.default)(realm.generator);
realm.generator.emitBindingAssignment(binding, V);
} else {
realm.recordModifiedBinding(binding).value = V;
}
} else {
// 6. Else,
// a. Assert: This is an attempt to change the value of an immutable binding.
// b. If S is true, throw a TypeError exception.
if (S) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "attempt to change immutable binding");
}
}
// 7. Return NormalCompletion(empty).
return this.realm.intrinsics.empty;
}
// ECMA262 8.1.1.1.6
GetBindingValue(N, S) {
let realm = this.realm;
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
let binding = envRec.bindings[N];
// 2. Assert: envRec has a binding for N.
(0, _invariant2.default)(binding, "expected binding");
// 3. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if (!binding.initialized) {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError);
}
// 4. Return the value currently bound to N in envRec.
if (binding.hasLeaked) {
return deriveGetBinding(realm, binding);
}
(0, _invariant2.default)(binding.value);
return binding.value;
}
// ECMA262 8.1.1.1.7
DeleteBinding(N) {
(0, _invariant2.default)(!this.frozen);
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
let envRec = this;
// 2. Assert: envRec has a binding for the name that is the value of N.
(0, _invariant2.default)(envRec.bindings[N], "expected binding to exist");
// 3. If the binding for N in envRec cannot be deleted, return false.
if (!envRec.bindings[N].deletable) return false;
// 4. Remove the binding for N from envRec.
this.realm.recordModifiedBinding(envRec.bindings[N]).value = undefined;
delete envRec.bindings[N];
// 5. Return true.
return true;
}
// ECMA262 8.1.1.1.8
HasThisBinding() {
// 1. Return false.
return false;
}
// ECMA262 8.1.1.1.9
HasSuperBinding() {
// 1. Return false.
return false;
}
// ECMA262 8.1.1.1.10
WithBaseObject() {
// 1. Return undefined.
return this.realm.intrinsics.undefined;
}
}
exports.DeclarativeEnvironmentRecord = DeclarativeEnvironmentRecord; // ECMA262 8.1.1.2
class ObjectEnvironmentRecord extends EnvironmentRecord {
constructor(realm, obj) {
super(realm);
this.object = obj;
}
// ECMA262 8.1.1.2.1
HasBinding(N) {
let realm = this.realm;
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. Let bindings be the binding object for envRec.
let bindings = this.object;
// 3. Let foundBinding be ? HasProperty(bindings, N).
let foundBinding = (0, _index2.HasProperty)(realm, bindings, N);
// 4. If foundBinding is false, return false.
if (!foundBinding) return false;
// 5. If the withEnvironment flag of envRec is false, return true.
if (!envRec.withEnvironment) return true;
// 6. Let unscopables be ? Get(bindings, @@unscopables).
let unscopables = (0, _index2.Get)(realm, bindings, realm.intrinsics.SymbolUnscopables);
// 7. If Type(unscopables) is Object, then
if (unscopables instanceof _index.ObjectValue || unscopables instanceof _index.AbstractObjectValue) {
// a. Let blocked be ToBoolean(? Get(unscopables, N)).
let blocked = _singletons.To.ToBooleanPartial(realm, (0, _index2.Get)(realm, unscopables, N));
// b. If blocked is true, return false.
if (blocked) return false;
}
unscopables.throwIfNotConcrete();
// 8. Return true.
return true;
}
// ECMA262 8.1.1.2.2
CreateMutableBinding(N, D) {
let realm = this.realm;
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. Let bindings be the binding object for envRec.
let bindings = envRec.object;
// 3. If D is true, let configValue be true; otherwise let configValue be false.
let configValue = D ? true : false;
// 4. Return ? DefinePropertyOrThrow(bindings, N, PropertyDescriptor{[[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: configValue}).
return new _index.BooleanValue(realm, _singletons.Properties.DefinePropertyOrThrow(realm, bindings, N, {
value: realm.intrinsics.undefined,
writable: true,
enumerable: true,
configurable: configValue
}));
}
// ECMA262 8.1.1.2.3
CreateImmutableBinding(N, S) {
// The concrete Environment Record method CreateImmutableBinding is never used within this specification in association with object Environment Records.
(0, _invariant2.default)(false);
}
// ECMA262 8.1.1.2.4
InitializeBinding(N, V) {
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. Assert: envRec must have an uninitialized binding for N.
// 3. Record that the binding for N in envRec has been initialized.
// 4. Return ? envRec.SetMutableBinding(N, V, false).
return envRec.SetMutableBinding(N, V, false);
}
// ECMA262 8.1.1.2.5
SetMutableBinding(N, V, S) {
let realm = this.realm;
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. Let bindings be the binding object for envRec.
let bindings = envRec.object;
// 3. Return ? Set(bindings, N, V, S).
return new _index.BooleanValue(realm, _singletons.Properties.Set(realm, bindings, N, V, S));
}
// ECMA262 8.1.1.2.6
GetBindingValue(N, S) {
let realm = this.realm;
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. Let bindings be the binding object for envRec.
let bindings = envRec.object;
// 3. Let value be ? HasProperty(bindings, N).
let value = (0, _index2.HasProperty)(realm, bindings, N);
// 4. If value is false, then
if (!value) {
// a. If S is false, return the value undefined; otherwise throw a ReferenceError exception.
if (!S) {
return realm.intrinsics.undefined;
} else {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError);
}
}
// 5. Return ? Get(bindings, N).
return (0, _index2.Get)(realm, bindings, N);
}
// ECMA262 8.1.1.2.7
DeleteBinding(N) {
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. Let bindings be the binding object for envRec.
let bindings = envRec.object;
// 3. Return ? bindings.[[Delete]](N).
return bindings.$Delete(N);
}
// ECMA262 8.1.1.2.8
HasThisBinding() {
// 1. Return false.
return false;
}
// ECMA262 8.1.1.2.9
HasSuperBinding() {
// 1. Return false.
return false;
}
// ECMA262 8.1.1.2.10
WithBaseObject() {
// 1. Let envRec be the object Environment Record for which the method was invoked.
let envRec = this;
// 2. If the withEnvironment flag of envRec is true, return the binding object for envRec.
if (envRec.withEnvironment) return envRec.object;
// 3. Otherwise, return undefined.
return this.realm.intrinsics.undefined;
}
}
exports.ObjectEnvironmentRecord = ObjectEnvironmentRecord; // ECMA262 8.1.1.3
class FunctionEnvironmentRecord extends DeclarativeEnvironmentRecord {
// ECMA262 8.1.1.3.1
BindThisValue(V) {
let realm = this.realm;
// 1. Let envRec be the function Environment Record for which the method was invoked.
let envRec = this;
// 2. Assert: envRec.[[ThisBindingStatus]] is not "lexical".
(0, _invariant2.default)(envRec.$ThisBindingStatus !== "lexical", "this binding status shouldn't be lexical");
// 3. If envRec.[[ThisBindingStatus]] is "initialized", throw a ReferenceError exception.
if (envRec.$ThisBindingStatus === "initialized") {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError);
}
// 4. Set envRec.[[ThisValue]] to V.
envRec.$ThisValue = V;
// 5. Set envRec.[[ThisBindingStatus]] to "initialized".
envRec.$ThisBindingStatus = "initialized";
// 6. Return V.
return V;
}
// ECMA262 8.1.1.3.2
HasThisBinding() {
// 1. Let envRec be the function Environment Record for which the method was invoked.
let envRec = this;
// 2. If envRec.[[ThisBindingStatus]] is "lexical", return false; otherwise, return true.
return envRec.$ThisBindingStatus === "lexical" ? false : true;
}
// ECMA262 8.1.1.3.3
HasSuperBinding() {
// 1. Let envRec be the function Environment Record for which the method was invoked.
let envRec = this;
// 2. If envRec.[[ThisBindingStatus]] is "lexical", return false.
if (envRec.$ThisBindingStatus === "lexical") return false;
// 3. If envRec.[[HomeObject]] has the value undefined, return false; otherwise, return true.
if (envRec.$HomeObject === undefined) {
return false;
} else {
return true;
}
}
// ECMA262 8.1.1.3.4
GetThisBinding() {
let realm = this.realm;
// 1. Let envRec be the function Environment Record for which the method was invoked.
let envRec = this;
// 2. Assert: envRec.[[ThisBindingStatus]] is not "lexical".
(0, _invariant2.default)(envRec.$ThisBindingStatus !== "lexical", "this binding status shouldn't be lexical");
// 3. If envRec.[[ThisBindingStatus]] is "uninitialized", throw a ReferenceError exception.
if (envRec.$ThisBindingStatus === "uninitialized") {
throw realm.createErrorThrowCompletion(realm.intrinsics.ReferenceError);
}
// 4. Return envRec.[[ThisValue]].
return envRec.$ThisValue;
}
// ECMA262 8.1.1.3.5
GetSuperBase() {
// 1. Let envRec be the function Environment Record for which the method was invoked.
let envRec = this;
// 2. Let home be the value of envRec.[[HomeObject]].
let home = envRec.$HomeObject;
// 3. If home has the value undefined, return undefined.
if (home === undefined) return this.realm.intrinsics.undefined;
// 4. Assert: Type(home) is Object.
(0, _invariant2.default)(home instanceof _index.ObjectValue, "expected object value");
// 5. Return ? home.[[GetPrototypeOf]]().
return home.$GetPrototypeOf();
}
}
exports.FunctionEnvironmentRecord = FunctionEnvironmentRecord; // ECMA262 8.1.1.4
class GlobalEnvironmentRecord extends EnvironmentRecord {
// ECMA262 8.1.1.4.1
HasBinding(N) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, return true.
if (DclRec.HasBinding(N)) return true;
// 4. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 5. Return ? ObjRec.HasBinding(N).
return ObjRec.HasBinding(N);
}
// ECMA262 8.1.1.4.2
CreateMutableBinding(N, D) {
let realm = this.realm;
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, throw a TypeError exception.
if (DclRec.HasBinding(N)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// 4. Return DclRec.CreateMutableBinding(N, D).
return DclRec.CreateMutableBinding(N, D, true);
}
// ECMA262 8.1.1.4.3
CreateImmutableBinding(N, S) {
let realm = this.realm;
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, throw a TypeError exception.
if (DclRec.HasBinding(N)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// 4. Return DclRec.CreateImmutableBinding(N, S).
return DclRec.CreateImmutableBinding(N, S, true);
}
// ECMA262 8.1.1.4.4
InitializeBinding(N, V) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
if (DclRec.HasBinding(N)) {
// a. Return DclRec.InitializeBinding(N, V).
return DclRec.InitializeBinding(N, V);
}
// 4. Assert: If the binding exists, it must be in the object Environment Record.
// 5. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 6. Return ? ObjRec.InitializeBinding(N, V).
return ObjRec.InitializeBinding(N, V);
}
// ECMA262 8.1.1.4.5
SetMutableBinding(N, V, S) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
if (DclRec.HasBinding(N)) {
// a. Return DclRec.SetMutableBinding(N, V, S).
return DclRec.SetMutableBinding(N, V, S);
}
// 4. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 5. Return ? ObjRec.SetMutableBinding(N, V, S).
return ObjRec.SetMutableBinding(N, V, S);
}
// ECMA262 8.1.1.4.6
GetBindingValue(N, S) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
if (DclRec.HasBinding(N)) {
// a. Return DclRec.GetBindingValue(N, S).
return DclRec.GetBindingValue(N, S);
}
// 4. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 5. Return ? ObjRec.GetBindingValue(N, S).
return ObjRec.GetBindingValue(N, S);
}
// ECMA262 8.1.1.4.7
DeleteBinding(N) {
let realm = this.realm;
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
if (DclRec.HasBinding(N)) {
// a. Return DclRec.DeleteBinding(N).
return DclRec.DeleteBinding(N);
}
// 4. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 5. Let globalObject be the binding object for ObjRec.
let globalObject = ObjRec.object;
// 6. Let existingProp be ? HasOwnProperty(globalObject, N).
let existingProp = (0, _index2.HasOwnProperty)(realm, globalObject, N);
// 7. If existingProp is true, then
if (existingProp) {
// a. Let status be ? ObjRec.DeleteBinding(N).
let status = ObjRec.DeleteBinding(N);
// b. If status is true, then
if (status) {
// i. Let varNames be envRec.[[VarNames]].
let varNames = envRec.$VarNames;
// ii. If N is an element of varNames, remove that element from the varNames.
if (varNames.indexOf(N) >= 0) {
varNames.splice(varNames.indexOf(N), 1);
}
}
// c. Return status.
return status;
}
// 8. Return true.
return true;
}
// ECMA262 8.1.1.4.8
HasThisBinding() {
// 1. Return true.
return true;
}
// ECMA262 8.1.1.4.9
HasSuperBinding() {
// 1. Return true.
return true;
}
// ECMA262 8.1.1.4.10
WithBaseObject() {
// 1. Return undefined.
return this.realm.intrinsics.undefined;
}
// ECMA262 8.1.1.4.11
GetThisBinding() {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
(0, _invariant2.default)(envRec.$GlobalThisValue);
// 2. Return envRec.[[GlobalThisValue]].
return envRec.$GlobalThisValue;
}
// ECMA262 8.1.1.4.12
HasVarDeclaration(N) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let varDeclaredNames be envRec.[[VarNames]].
let varDeclaredNames = envRec.$VarNames;
// 3. If varDeclaredNames contains the value of N, return true.
if (varDeclaredNames.indexOf(N) >= 0) return true;
// 4. Return false.
return false;
}
// ECMA262 8.1.1.4.13
HasLexicalDeclaration(N) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
let DclRec = envRec.$DeclarativeRecord;
// 3. Return DclRec.HasBinding(N).
return DclRec.HasBinding(N);
}
// ECMA262 8.1.1.4.14
HasRestrictedGlobalProperty(N) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
let globalObject = ObjRec.object;
// 4. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
let existingProp = globalObject.$GetOwnProperty(N);
// 5. If existingProp is undefined, return false.
if (!existingProp) return false;
_singletons.Properties.ThrowIfMightHaveBeenDeleted(existingProp.value);
// 6. If existingProp.[[Configurable]] is true, return false.
if (existingProp.configurable) return false;
// 7. Return true.
return true;
}
// ECMA262 8.1.1.4.15
CanDeclareGlobalVar(N) {
let realm = this.realm;
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
let globalObject = ObjRec.object;
// 4. Let hasProperty be ? HasOwnProperty(globalObject, N).
let hasProperty = (0, _index2.HasOwnProperty)(realm, globalObject, N);
// 5. If hasProperty is true, return true.
if (hasProperty) return true;
// 6. Return ? IsExtensible(globalObject).
return (0, _index2.IsExtensible)(realm, globalObject);
}
// ECMA262 8.1.1.4.16
CanDeclareGlobalFunction(N) {
let realm = this.realm;
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
let globalObject = ObjRec.object;
// 4. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
let existingProp = globalObject.$GetOwnProperty(N);
// 5. If existingProp is undefined, return ? IsExtensible(globalObject).
if (!existingProp) return (0, _index2.IsExtensible)(realm, globalObject);
_singletons.Properties.ThrowIfMightHaveBeenDeleted(existingProp.value);
// 6. If existingProp.[[Configurable]] is true, return true.
if (existingProp.configurable) return true;
// 7. If IsDataDescriptor(existingProp) is true and existingProp has attribute values {[[Writable]]: true, [[Enumerable]]: true}, return true.
if ((0, _index2.IsDataDescriptor)(realm, existingProp) && existingProp.writable && existingProp.enumerable) {
return true;
}
// 8. Return false.
return false;
}
// ECMA262 8.1.1.4.17
CreateGlobalVarBinding(N, D) {
let realm = this.realm;
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
let globalObject = ObjRec.object;
// 4. Let hasProperty be ? HasOwnProperty(globalObject, N).
let hasProperty = (0, _index2.HasOwnProperty)(realm, globalObject, N);
// 5. Let extensible be ? IsExtensible(globalObject).
let extensible = (0, _index2.IsExtensible)(realm, globalObject);
// 6. If hasProperty is false and extensible is true, then
if (!hasProperty && extensible) {
// a. Perform ? ObjRec.CreateMutableBinding(N, D).
ObjRec.CreateMutableBinding(N, D);
// b. Perform ? ObjRec.InitializeBinding(N, undefined).
ObjRec.InitializeBinding(N, this.realm.intrinsics.undefined);
}
// 7. Let varDeclaredNames be envRec.[[VarNames]].
let varDeclaredNames = envRec.$VarNames;
// 8. If varDeclaredNames does not contain the value of N, then
if (varDeclaredNames.indexOf(N) < 0) {
// a. Append N to varDeclaredNames.
varDeclaredNames.push(N);
}
// 9. Return NormalCompletion(empty).
}
// ECMA262 8.1.1.4.18
CreateGlobalFunctionBinding(N, V, D) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
let envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
let ObjRec = envRec.$ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
let globalObject = ObjRec.object;
// 4. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
let existingProp = globalObject.$GetOwnProperty(N);
// 5. If existingProp is undefined or existingProp.[[Configurable]] is true, then
let desc;
if (!existingProp || existingProp.configurable) {
// a. Let desc be the PropertyDescriptor{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D}.
desc = { value: V, writable: true, enumerable: true, configurable: D };
} else {
// 6. Else,
_singletons.Properties.ThrowIfMightHaveBeenDeleted(existingProp.value);
// a. Let desc be the PropertyDescriptor{[[Value]]: V }.
desc = { value: V };
}
// 7. Perform ? DefinePropertyOrThrow(globalObject, N, desc).
_singletons.Properties.DefinePropertyOrThrow(this.realm, globalObject, N, desc);
// 8. Record that the binding for N in ObjRec has been initialized.
// 9. Perform ? Set(globalObject, N, V, false).
_singletons.Properties.Set(this.realm, globalObject, N, V, false);
// 10. Let varDeclaredNames be envRec.[[VarNames]].
let varDeclaredNames = envRec.$VarNames;
// 11. If varDeclaredNames does not contain the value of N, then
if (varDeclaredNames.indexOf(N) < 0) {
// a. Append N to varDeclaredNames.
varDeclaredNames.push(N);
}
// 12. Return NormalCompletion(empty).
}
}
exports.GlobalEnvironmentRecord = GlobalEnvironmentRecord; // ECMA262 8.1
let uid = 0;
class LexicalEnvironment {
constructor(realm) {
(0, _invariant2.default)(realm, "expected realm");
this.realm = realm;
this.destroyed = false;
this._uid = uid++;
}
// For debugging it is convenient to have an ID for each of these.
destroy() {
this.destroyed = true;
// Once the containing environment is destroyed, we can no longer add or remove entries from the environmentRecord
// (but we can update existing values).
if (this.environmentRecord instanceof DeclarativeEnvironmentRecord) {
this.environmentRecord.frozen = true;
}
}
assignToGlobal(globalAst, rvalue) {
let globalValue = this.evaluate(globalAst, false);
_singletons.Properties.PutValue(this.realm, globalValue, rvalue);
}
partiallyEvaluateCompletionDeref(ast, strictCode, metadata) {
let [result, partial_ast, partial_io] = this.partiallyEvaluateCompletion(ast, strictCode, metadata);
if (result instanceof Reference) {
result = _singletons.Environment.GetValue(this.realm, result);
}
return [result, partial_ast, partial_io];
}
partiallyEvaluateCompletion(ast, strictCode, metadata) {
try {
return this.partiallyEvaluate(ast, strictCode, metadata);
} catch (err) {
if (err instanceof _completions.Completion) return [err, ast, []];
if (err instanceof Error)
// rethrowing Error should preserve stack trace
throw err;
// let's wrap into a proper Error to create stack trace
throw new _errors.FatalError(err);
}
}
evaluateCompletionDeref(ast, strictCode, metadata) {
let result = this.evaluateCompletion(ast, strictCode, metadata);
if (result instanceof Reference) result = _singletons.Environment.GetValue(this.realm, result);
return result;
}
evaluateCompletion(ast, strictCode, metadata) {
try {
return this.evaluate(ast, strictCode, metadata);
} catch (err) {
if ((err instanceof _completions.JoinedAbruptCompletions || err instanceof _completions.PossiblyNormalCompletion) && err.containsBreakOrContinue()) {
_index.AbstractValue.reportIntrospectionError(err.joinCondition);
throw new _errors.FatalError();
}
if (err instanceof _completions.AbruptCompletion) return err;
if (err instanceof Error)
// rethrowing Error should preserve stack trace
throw err;
// let's wrap into a proper Error to create stack trace
throw new _errors.FatalError(err);
}
}
evaluateAbstractCompletion(ast, strictCode, metadata) {
try {
return this.evaluateAbstract(ast, strictCode, metadata);
} catch (err) {
if (err instanceof _completions.Completion) return err;
if (err instanceof Error)
// rethrowing Error should preserve stack trace
throw err;
// let's wrap into a proper Error to create stack trace
if (err instanceof Object) throw new _errors.FatalError(err.constructor.name + ": " + err);
throw new _errors.FatalError(err);
}
}
concatenateAndParse(sources, sourceType = "script") {
let asts = [];
let code = {};
let directives = [];
for (let source of sources) {
try {
let node = (0, _parse2.default)(this.realm, source.fileContents, source.filePath, sourceType);
if (source.sourceMapContents && source.sourceMapContents.length > 0) this.fixup_source_locations(node, source.sourceMapContents);
this.fixup_filenames(node);
asts = asts.concat(node.program.body);
code[source.filePath] = source.fileContents;
directives = directives.concat(node.program.directives);
} catch (e) {
if (e instanceof _completions.ThrowCompletion) {
let error = e.value;
if (error instanceof _index.ObjectValue) {
let message = error.$Get("message", error);
message.value = `Syntax error: ${message.value}`;
e.location.source = source.filePath;
// the position was not located properly on the
// syntax errors happen on one given position, so start position = end position
e.location.start = { line: e.location.line, column: e.location.column };
e.location.end = { line: e.location.line, column: e.location.column };
let diagnostic = new _errors.CompilerDiagnostic(message.value, e.location, "PP1004", "FatalError");
this.realm.handleError(diagnostic);
throw new _errors.FatalError(message.value);
}
}
throw e;
}
}
return [t.file(t.program(asts, directives)), code];
}
executeSources(sources, sourceType = "script", onParse = undefined) {
let context = new _realm.ExecutionContext();
context.lexicalEnvironment = this;
context.variableEnvironment = this;
context.realm = this.realm;
this.realm.pushContext(context);
let res, code;
try {
let ast;
[ast, code] = this.concatenateAndParse(sources, sourceType);
if (onParse) onParse(ast);
res = this.evaluateCompletion(ast, false);
} finally {
this.realm.popContext(context);
this.realm.onDestroyScope(context.lexicalEnvironment);
if (!this.destroyed) this.realm.onDestroyScope(this);
(0, _invariant2.default)(this.realm.activeLexicalEnvironments.size === 0);
}
if (res instanceof _completions.AbruptCompletion) return [res, code];
return [_singletons.Environment.GetValue(this.realm, res), code];
}
executePartialEvaluator(sources, options = _options.defaultOptions, sourceType = "script") {
let [ast, code] = this.concatenateAndParse(sources, sourceType);
let context = new _realm.ExecutionContext();
context.lexicalEnvironment = this;
context.variableEnvironment = this;
context.realm = this.realm;
this.realm.pushContext(context);
let partialAST;
try {
[, partialAST] = this.partiallyEvaluateCompletionDeref(ast, false);
} finally {
this.realm.popContext(context);
this.realm.onDestroyScope(context.lexicalEnvironment);
if (!this.destroyed) this.realm.onDestroyScope(this);
(0, _invariant2.default)(this.realm.activeLexicalEnvironments.size === 0);
}
(0, _invariant2.default)(partialAST.type === "File");
let fileAst = partialAST;
let prog = t.program(fileAst.program.body, ast.program.directives);
this.fixup_filenames(prog);
// The type signature for generate is not complete, hence the any
return (0, _babelGenerator2.default)(prog, { sourceMaps: options.sourceMaps }, code);
}
execute(code, filename, map = "", sourceType = "script", onParse = undefined) {
let context = new _realm.ExecutionContext();
context.lexicalEnvironment = this;
context.variableEnvironment = this;
context.realm = this.realm;
this.realm.pushContext(context);
let ast, res;
try {
try {
ast = (0, _parse2.default)(this.realm, code, filename, sourceType);
} catch (e) {
if (e instanceof _completions.ThrowCompletion) return e;
throw e;
}
if (onParse) onParse(ast);
if (map.length > 0) this.fixup_source_locations(ast, map);
this.fixup_filenames(ast);
res = this.evaluateCompletion(ast, false);
} finally {
this.realm.popContext(context);
// Avoid destroying "this" scope as execute may be called many times.
if (context.lexicalEnvironment !== this) this.realm.onDestroyScope(context.lexicalEnvironment);
(0, _invariant2.default)(this.realm.activeLexicalEnvironments.size === 1);
}
if (res instanceof _completions.AbruptCompletion) return res;
return _singletons.Environment.GetValue(this.realm, res);
}
fixup_source_locations(ast, map) {
const smc = new sourceMap.SourceMapConsumer(map);
(0, _traverseFast2.default)(ast, node => {
let loc = node.loc;
if (!loc) return false;
fixup(loc, loc.start);
fixup(loc, loc.end);
fixup_comments(node.leadingComments);
fixup_comments(node.innerComments);
fixup_comments(node.trailingComments);
return false;
function fixup(new_loc, new_pos) {
let old_pos = smc.originalPositionFor({ line: new_pos.line, column: new_pos.column });
if (old_pos.source === null) return;
new_pos.line = old_pos.line;
new_pos.column = old_pos.column;
new_loc.source = old_pos.source;
}
function fixup_comments(comments) {
if (!comments) return;
for (let c of comments) {
let cloc = c.loc;
if (!cloc) continue;
fixup(cloc, cloc.start);
fixup(cloc, cloc.end);
}
}
});
}
fixup_filenames(ast) {
(0, _traverseFast2.default)(ast, node => {
let loc = node.loc;
if (!loc || !loc.source) {
node.leadingComments = null;
node.innerComments = null;
node.trailingComments = null;
node.loc = null;
} else {
let filename = loc.source;
loc.filename = filename;
fixup_comments(node.leadingComments, filename);
fixup_comments(node.innerComments, filename);
fixup_comments(node.trailingComments, filename);
}
return false;
function fixup_comments(comments, filename) {
if (!comments) return;
for (let c of comments) {
if (c.loc) {
c.loc.filename = filename;
c.loc.source = filename;
}
}
}
});
}
evaluate(ast, strictCode, metadata) {
if (this.realm.debuggerInstance) {
this.realm.debuggerInstance.checkForActions(ast);
}
let res = this.evaluateAbstract(ast, strictCode, metadata);
(0, _invariant2.default)(res instanceof _index.Value || res instanceof Reference, ast.type);
return res;
}
evaluateAbstract(ast, strictCode, metadata) {
this.realm.currentLocation = ast.loc;
this.realm.testTimeout();
let evaluator = this.realm.evaluators[ast.type];
if (evaluator) {
let result = evaluator(ast, strictCode, this, this.realm, metadata);
return result;
}
throw new TypeError(`Unsupported node type ${ast.type}`);
}
partiallyEvaluate(ast, strictCode, metadata) {
let partialEvaluator = this.realm.partialEvaluators[ast.type];
if (partialEvaluator) {
return partialEvaluator(ast, strictCode, this, this.realm, metadata);
}
let err = new TypeError(`Unsupported node type ${ast.type}`);
throw err;
}
}
exports.LexicalEnvironment = LexicalEnvironment; // ECMA262 6.2.3
// A Reference is a resolved name or property binding. A Reference consists of three components, the base value,
// the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object,
// a Boolean, a String, a Symbol, a Number, or an Environment Record. A base value of undefined indicates that the
// Reference could not be resolved to a binding. The referenced name is a String or Symbol value.
function mightBecomeAnObject(base) {
let type = base.getType();
// The top Value type might be able to become an object. We let it
// pass and error later if it can't.
return type === _index.Value || type === _PrimitiveValue2.default || type === _index.BooleanValue || type === _index.StringValue || type === _index.SymbolValue || type === _index.NumberValue || type === _index.IntegralValue;
}
class Reference {
constructor(base, refName, strict, thisValue) {
(0, _invariant2.default)(base instanceof _index.AbstractObjectValue || base === undefined || base instanceof _index.ObjectValue || base instanceof EnvironmentRecord || mightBecomeAnObject(base));
this.base = base;
this.referencedName = refName;
(0, _invariant2.default)(!(refName instanceof _index.AbstractValue) || !(refName.mightNotBeString() && refName.mightNotBeNumber() && !refName.isSimpleObject() &&
// if the base is a simple abstract object but
// the refName is not simple, this is also okay
base instanceof _index.AbstractValue && !base.isSimpleObject()));
this.strict = strict;
this.thisValue = thisValue;
(0, _invariant2.default)(thisValue === undefined || !(base instanceof EnvironmentRecord));
}
}
exports.Reference = Reference;
//# sourceMappingURL=environment.js.map