UNPKG

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
"use strict"; 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