275 lines
17 KiB
JavaScript
275 lines
17 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /**
|
|
* 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.
|
|
*/
|
|
|
|
exports.default = function (ast, strictCode, env, realm, labelSet) {
|
|
var left = ast.left,
|
|
right = ast.right,
|
|
body = ast.body;
|
|
|
|
|
|
function reportErrorAndThrowIfNotConcrete(val, loc) {
|
|
if (val instanceof _index2.AbstractValue) reportError(realm, loc);
|
|
}
|
|
|
|
try {
|
|
if (left.type === "VariableDeclaration") {
|
|
if (left.kind === "var") {
|
|
// for (var ForBinding in Expression) Statement
|
|
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
|
|
var keyResult = (0, _ForOfStatement.ForInOfHeadEvaluation)(realm, env, [], right, "enumerate", strictCode);
|
|
if (keyResult.isPartialObject() && keyResult.isSimpleObject()) {
|
|
return emitResidualLoopIfSafe(ast, strictCode, env, realm, left, right, keyResult, body);
|
|
}
|
|
reportErrorAndThrowIfNotConcrete(keyResult, right.loc);
|
|
(0, _invariant2.default)(keyResult instanceof _index2.ObjectValue);
|
|
|
|
// 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, varBinding, labelSet).
|
|
return (0, _ForOfStatement.ForInOfBodyEvaluation)(realm, env, left.declarations[0].id, body, keyResult, "varBinding", labelSet, strictCode);
|
|
} else {
|
|
// for (ForDeclaration in Expression) Statement
|
|
// 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, Expression, enumerate).
|
|
var _keyResult = (0, _ForOfStatement.ForInOfHeadEvaluation)(realm, env, _singletons.Environment.BoundNames(realm, left), right, "enumerate", strictCode);
|
|
reportErrorAndThrowIfNotConcrete(_keyResult, right.loc);
|
|
(0, _invariant2.default)(_keyResult instanceof _index2.ObjectValue);
|
|
|
|
// 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, lexicalBinding, labelSet).
|
|
return (0, _ForOfStatement.ForInOfBodyEvaluation)(realm, env, left, body, _keyResult, "lexicalBinding", labelSet, strictCode);
|
|
}
|
|
} else {
|
|
// for (LeftHandSideExpression in Expression) Statement
|
|
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
|
|
var _keyResult2 = (0, _ForOfStatement.ForInOfHeadEvaluation)(realm, env, [], right, "enumerate", strictCode);
|
|
reportErrorAndThrowIfNotConcrete(_keyResult2, right.loc);
|
|
(0, _invariant2.default)(_keyResult2 instanceof _index2.ObjectValue);
|
|
|
|
// 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, assignment, labelSet).
|
|
return (0, _ForOfStatement.ForInOfBodyEvaluation)(realm, env, left, body, _keyResult2, "assignment", labelSet, strictCode);
|
|
}
|
|
} catch (e) {
|
|
if (e instanceof _completions.BreakCompletion) {
|
|
if (!e.target) return (0, _index.UpdateEmpty)(realm, e, realm.intrinsics.undefined).value;
|
|
}
|
|
throw e;
|
|
}
|
|
};
|
|
|
|
var _completions = require("../completions.js");
|
|
|
|
var _environment = require("../environment.js");
|
|
|
|
var _errors = require("../errors.js");
|
|
|
|
var _ForOfStatement = require("./ForOfStatement.js");
|
|
|
|
var _index = require("../methods/index.js");
|
|
|
|
var _singletons = require("../singletons.js");
|
|
|
|
var _index2 = require("../values/index.js");
|
|
|
|
var _invariant = require("../invariant.js");
|
|
|
|
var _invariant2 = _interopRequireDefault(_invariant);
|
|
|
|
var _babelTypes = require("babel-types");
|
|
|
|
var t = _interopRequireWildcard(_babelTypes);
|
|
|
|
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 }; }
|
|
|
|
// helper func to report error
|
|
function reportError(realm, loc) {
|
|
var error = new _errors.CompilerDiagnostic("for in loops over unknown objects are not yet supported", loc, "PP0013", "FatalError");
|
|
realm.handleError(error);
|
|
throw new _errors.FatalError();
|
|
}
|
|
|
|
// ECMA262 13.7.5.11
|
|
|
|
|
|
function emitResidualLoopIfSafe(ast, strictCode, env, realm, lh, obexpr, ob, body) {
|
|
(0, _invariant2.default)(ob.isSimpleObject());
|
|
var oldEnv = realm.getRunningContext().lexicalEnvironment;
|
|
var blockEnv = _singletons.Environment.NewDeclarativeEnvironment(realm, oldEnv);
|
|
realm.getRunningContext().lexicalEnvironment = blockEnv;
|
|
try {
|
|
var envRec = blockEnv.environmentRecord;
|
|
(0, _invariant2.default)(envRec instanceof _environment.DeclarativeEnvironmentRecord, "expected declarative environment record");
|
|
var absStr = _index2.AbstractValue.createFromType(realm, _index2.StringValue);
|
|
var boundName = void 0;
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = _singletons.Environment.BoundNames(realm, lh)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var n = _step.value;
|
|
|
|
(0, _invariant2.default)(boundName === undefined);
|
|
boundName = t.identifier(n);
|
|
envRec.CreateMutableBinding(n, false);
|
|
envRec.InitializeBinding(n, absStr);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
var _realm$evaluateNodeFo = realm.evaluateNodeForEffects(body, strictCode, blockEnv),
|
|
_realm$evaluateNodeFo2 = _slicedToArray(_realm$evaluateNodeFo, 5),
|
|
compl = _realm$evaluateNodeFo2[0],
|
|
gen = _realm$evaluateNodeFo2[1],
|
|
bindings = _realm$evaluateNodeFo2[2],
|
|
properties = _realm$evaluateNodeFo2[3],
|
|
createdObj = _realm$evaluateNodeFo2[4];
|
|
|
|
if (compl instanceof _index2.Value && gen.empty() && bindings.size === 0 && properties.size === 1) {
|
|
(0, _invariant2.default)(createdObj.size === 0); // or there will be more than one property
|
|
var targetObject = void 0;
|
|
var sourceObject = void 0;
|
|
properties.forEach(function (desc, key, map) {
|
|
if (key.object.unknownProperty === key) {
|
|
targetObject = key.object;
|
|
(0, _invariant2.default)(desc !== undefined);
|
|
var sourceValue = desc.value;
|
|
if (sourceValue instanceof _index2.AbstractValue) {
|
|
// because sourceValue was written to key.object.unknownProperty it must be that
|
|
var cond = sourceValue.args[0];
|
|
// and because the write always creates a value of this shape
|
|
(0, _invariant2.default)(cond instanceof _index2.AbstractValue && cond.kind === "template for property name condition");
|
|
if (sourceValue.args[2] instanceof _index2.UndefinedValue) {
|
|
// check that the value that was assigned itself came from
|
|
// an expression of the form sourceObject[absStr].
|
|
var mem = sourceValue.args[1];
|
|
while (mem instanceof _index2.AbstractValue) {
|
|
if (mem.kind === "sentinel member expression" && mem.args[0] instanceof _index2.ObjectValue && mem.args[1] === absStr) {
|
|
sourceObject = mem.args[0];
|
|
break;
|
|
}
|
|
// check if mem is a test for absStr being equal to a known property
|
|
// if so skip over it until we get to the expression of the form sourceObject[absStr].
|
|
var condition = mem.args[0];
|
|
if (condition instanceof _index2.AbstractValue && condition.kind === "check for known property") {
|
|
if (condition.args[0] === absStr) {
|
|
mem = mem.args[2];
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (targetObject instanceof _index2.ObjectValue && sourceObject !== undefined) {
|
|
var o = ob;
|
|
if (ob instanceof _index2.AbstractObjectValue && !ob.values.isTop() && ob.values.getElements().size === 1) {
|
|
// Note that it is not safe, in general, to extract a concrete object from the values domain of
|
|
// an abstract object. We can get away with it here only because the concrete object does not
|
|
// escape the code below and is thus never referenced directly in generated code because of this logic.
|
|
var _iteratorNormalCompletion2 = true;
|
|
var _didIteratorError2 = false;
|
|
var _iteratorError2 = undefined;
|
|
|
|
try {
|
|
for (var _iterator2 = ob.values.getElements()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
var oe = _step2.value;
|
|
o = oe;
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError2 = true;
|
|
_iteratorError2 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
_iterator2.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError2) {
|
|
throw _iteratorError2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var generator = realm.generator;
|
|
(0, _invariant2.default)(generator !== undefined);
|
|
// make target object simple and partial, so that it returns a fully
|
|
// abstract value for every property it is queried for.
|
|
targetObject.makeSimple();
|
|
targetObject.makePartial();
|
|
if (sourceObject === o) {
|
|
// Known enumerable properties of sourceObject can become known properties of targetObject.
|
|
(0, _invariant2.default)(sourceObject.isPartialObject());
|
|
sourceObject.makeNotPartial();
|
|
// EnumerableOwnProperties is sufficient because sourceObject is simple
|
|
var keyValPairs = (0, _index.EnumerableOwnProperties)(realm, sourceObject, "key+value");
|
|
sourceObject.makePartial();
|
|
var _iteratorNormalCompletion3 = true;
|
|
var _didIteratorError3 = false;
|
|
var _iteratorError3 = undefined;
|
|
|
|
try {
|
|
for (var _iterator3 = keyValPairs[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
|
var keyVal = _step3.value;
|
|
|
|
(0, _invariant2.default)(keyVal instanceof _index2.ArrayValue);
|
|
var key = keyVal.$Get("0", keyVal);
|
|
var val = keyVal.$Get("1", keyVal);
|
|
(0, _invariant2.default)(key instanceof _index2.StringValue); // sourceObject is simple
|
|
targetObject.$Set(key, val, targetObject);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError3 = true;
|
|
_iteratorError3 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
|
_iterator3.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError3) {
|
|
throw _iteratorError3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// add loop to generator
|
|
(0, _invariant2.default)(boundName != null);
|
|
generator.emitForInStatement(o, lh, sourceObject, targetObject, boundName);
|
|
return realm.intrinsics.undefined;
|
|
}
|
|
}
|
|
} finally {
|
|
// 6. Set the running execution context's LexicalEnvironment to oldEnv.
|
|
realm.getRunningContext().lexicalEnvironment = oldEnv;
|
|
realm.onDestroyScope(blockEnv);
|
|
}
|
|
|
|
reportError(realm, obexpr.loc);
|
|
(0, _invariant2.default)(false);
|
|
}
|
|
//# sourceMappingURL=ForInStatement.js.map
|