Files
2023-08-01 13:49:46 +02:00

483 lines
23 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Emitter = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
* 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.
*/
var _index = require("../values/index.js");
var _generator = require("../utils/generator.js");
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _types = require("./types.js");
var _ResidualFunctions = require("./ResidualFunctions.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// The emitter keeps track of a stack of what's currently being emitted.
// There are two kinds of interesting dependencies the emitter is dealing with:
// 1. Value dependencies:
// If an emission task depends on the result of another emission task which
// is still currently being emitted, then the emission task must be performed later,
// once the dependency is available.
// To this end, the emitter maintains the `_activeValues` and `_waitingForValues` datastructures.
// 2. Generator dependencies:
// For each generator, there's a corresponding "body", i.e. a stream of babel statements
// that the emitter is appending to.
// There's always a "current" body that is currently being emitted to.
// There's also a distinguished `mainBody` to which all statements get directly or indirectly appended.
// If there are multiple generators/bodies involved, then they form a stack.
// Nested bodies are usually composed into an instruction emitted to the outer body.
// For example, two nested generators may yield the then and else-branch of an `if` statement.
// When an emission is supposed to target a body that is the current body, i.e. when it sits
// lower on the stack, then the emission task gets delayed until the next emission task on
// the lower body entry is finished.
// To this end, the emitter maintains the `_activeGeneratorStack` and `_waitingForBodies` datastructures.
var Emitter = exports.Emitter = function () {
function Emitter(residualFunctions) {
_classCallCheck(this, Emitter);
var mainBody = { type: "MainGenerator", parentBody: undefined, entries: [] };
this._waitingForValues = new Map();
this._waitingForBodies = new Map();
this._body = mainBody;
this._declaredAbstractValues = new Map();
this._residualFunctions = residualFunctions;
this._activeStack = [];
this._activeValues = new Set();
this._activeGeneratorStack = [mainBody];
this._finalized = false;
} // Contains all the active generator bodies in stack order.
_createClass(Emitter, [{
key: "beginEmitting",
value: function beginEmitting(dependency, targetBody) {
var isChild = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
(0, _invariant2.default)(!this._finalized);
this._activeStack.push(dependency);
if (dependency instanceof _index.Value) {
(0, _invariant2.default)(!this._activeValues.has(dependency));
this._activeValues.add(dependency);
} else if (dependency instanceof _generator.Generator) {
(0, _invariant2.default)(!this._activeGeneratorStack.includes(targetBody));
this._activeGeneratorStack.push(targetBody);
}
if (isChild) {
targetBody.parentBody = this._body;
}
var oldBody = this._body;
this._body = targetBody;
return oldBody;
}
}, {
key: "emit",
value: function emit(statement) {
(0, _invariant2.default)(!this._finalized);
this._body.entries.push(statement);
this._processCurrentBody();
}
}, {
key: "endEmitting",
value: function endEmitting(dependency, oldBody) {
(0, _invariant2.default)(!this._finalized);
var lastDependency = this._activeStack.pop();
(0, _invariant2.default)(dependency === lastDependency);
if (dependency instanceof _index.Value) {
(0, _invariant2.default)(this._activeValues.has(dependency));
this._activeValues.delete(dependency);
this._processValue(dependency);
} else if (dependency instanceof _generator.Generator) {
(0, _invariant2.default)(this._isEmittingActiveGenerator());
this._activeGeneratorStack.pop();
}
var lastBody = this._body;
this._body = oldBody;
return lastBody;
}
}, {
key: "finalize",
value: function finalize() {
(0, _invariant2.default)(!this._finalized);
(0, _invariant2.default)(this._activeGeneratorStack.length === 1);
(0, _invariant2.default)(this._activeGeneratorStack[0] === this._body);
this._processCurrentBody();
this._activeGeneratorStack.pop();
this._finalized = true;
(0, _invariant2.default)(this._waitingForBodies.size === 0);
(0, _invariant2.default)(this._waitingForValues.size === 0);
(0, _invariant2.default)(this._activeStack.length === 0);
(0, _invariant2.default)(this._activeValues.size === 0);
(0, _invariant2.default)(this._activeGeneratorStack.length === 0);
}
/**
* Emitter is emitting in two modes:
* 1. Emitting to entries in current active generator
* 2. Emitting to body of another scope(generator or residual function)
* This function checks the first condition above.
*/
}, {
key: "_isEmittingActiveGenerator",
value: function _isEmittingActiveGenerator() {
(0, _invariant2.default)(this._activeGeneratorStack.length > 0);
return this._activeGeneratorStack[this._activeGeneratorStack.length - 1] === this._body;
}
}, {
key: "_isGeneratorBody",
value: function _isGeneratorBody(body) {
return body.type === "MainGenerator" || body.type === "Generator";
}
}, {
key: "_processCurrentBody",
value: function _processCurrentBody() {
if (!this._isEmittingActiveGenerator()) {
return;
}
var a = this._waitingForBodies.get(this._body);
if (a === undefined) return;
while (a.length > 0) {
var _a$shift = a.shift(),
_dependencies = _a$shift.dependencies,
_func = _a$shift.func;
this.emitNowOrAfterWaitingForDependencies(_dependencies, _func);
}
this._waitingForBodies.delete(this._body);
}
}, {
key: "_processValue",
value: function _processValue(value) {
var a = this._waitingForValues.get(value);
if (a === undefined) return;
var currentBody = this._body;
while (a.length > 0) {
var _a$shift2 = a.shift(),
_body = _a$shift2.body,
_dependencies2 = _a$shift2.dependencies,
_func2 = _a$shift2.func;
// If body is not generator body no need to wait for it.
if (this._isGeneratorBody(_body) && _body !== currentBody) {
this._emitAfterWaitingForGeneratorBody(_body, _dependencies2, _func2);
} else {
this.emitNowOrAfterWaitingForDependencies(_dependencies2, _func2, _body);
}
}
this._waitingForValues.delete(value);
}
// Find the first ancestor in input generator body stack that is in current active stack.
// It can always find one because the bottom one in the stack is the main generator.
}, {
key: "_getFirstAncestorGeneratorWithActiveBody",
value: function _getFirstAncestorGeneratorWithActiveBody(bodyStack) {
var _this = this;
var activeBody = bodyStack.slice().reverse().find(function (body) {
return _this._activeGeneratorStack.includes(body);
});
(0, _invariant2.default)(activeBody);
return activeBody;
}
// Serialization of a statement related to a value MUST be delayed if
// the creation of the value's identity requires the availability of either:
// 1. a time-dependent value that is declared by some generator entry
// that has not yet been processed
// (tracked by `_declaredAbstractValues`), or
// 2. a value that is also currently being serialized
// (tracked by `_activeValues`).
// 3. a generator body that is higher(near top) in generator body stack.
// (tracked by `_activeGeneratorStack`)
}, {
key: "getReasonToWaitForDependencies",
value: function getReasonToWaitForDependencies(dependencies) {
(0, _invariant2.default)(!this._finalized);
if (Array.isArray(dependencies)) {
var values = dependencies;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = values[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var value = _step.value;
var _delayReason = this.getReasonToWaitForDependencies(value);
if (_delayReason) return _delayReason;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return undefined;
}
var val = dependencies;
if (this._activeValues.has(val)) return val;
var delayReason = void 0;
if (val instanceof _index.BoundFunctionValue) {
delayReason = this.getReasonToWaitForDependencies(val.$BoundTargetFunction);
if (delayReason) return delayReason;
delayReason = this.getReasonToWaitForDependencies(val.$BoundThis);
if (delayReason) return delayReason;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = val.$BoundArguments[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var arg = _step2.value;
delayReason = this.getReasonToWaitForDependencies(arg);
if (delayReason) return delayReason;
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
} else if (val instanceof _index.FunctionValue) {
this._residualFunctions.addFunctionUsage(val, this.getBodyReference());
return undefined;
} else if (val instanceof _index.AbstractValue) {
if (val.hasIdentifier()) {
var valSerializeBodyStack = this._declaredAbstractValues.get(val);
if (!valSerializeBodyStack) {
// Hasn't been serialized yet.
return val;
} else {
// The dependency has already been serialized(declared). But we may still have to wait for
// current generator body to be available, under following conditions:
// 1. Currently emitting in generator body. -- and
// 2. Not emitting in current active generator.(otherwise no need to wait) -- and
// 3. Dependency's active ancestor generator body is higher(near top) in generator stack than current body.
var valActiveAncestorBody = this._getFirstAncestorGeneratorWithActiveBody(valSerializeBodyStack);
(0, _invariant2.default)(this._activeGeneratorStack.includes(valActiveAncestorBody));
if (this._isGeneratorBody(this._body)) {
(0, _invariant2.default)(this._activeGeneratorStack.includes(this._body));
if (!this._isEmittingActiveGenerator() && this._activeGeneratorStack.indexOf(valActiveAncestorBody) > this._activeGeneratorStack.indexOf(this._body)) {
return this._body;
}
}
}
}
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = val.args[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _arg = _step3.value;
delayReason = this.getReasonToWaitForDependencies(_arg);
if (delayReason) return delayReason;
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
} else if (val instanceof _index.ProxyValue) {
delayReason = this.getReasonToWaitForDependencies(val.$ProxyTarget);
if (delayReason) return delayReason;
delayReason = this.getReasonToWaitForDependencies(val.$ProxyHandler);
if (delayReason) return delayReason;
} else if (val instanceof _index.SymbolValue) {
if (val.$Description instanceof _index.Value) {
delayReason = this.getReasonToWaitForDependencies(val.$Description);
if (delayReason) return delayReason;
}
} else if (val instanceof _index.ObjectValue) {
var kind = val.getKind();
switch (kind) {
case "Object":
var proto = val.$Prototype;
if (proto instanceof _index.ObjectValue) {
delayReason = this.getReasonToWaitForDependencies(val.$Prototype);
if (delayReason) return delayReason;
}
break;
case "Date":
(0, _invariant2.default)(val.$DateValue !== undefined);
delayReason = this.getReasonToWaitForDependencies(val.$DateValue);
if (delayReason) return delayReason;
break;
default:
break;
}
}
return undefined;
}
// Wait for a known-to-be active value if a condition is met.
}, {
key: "getReasonToWaitForActiveValue",
value: function getReasonToWaitForActiveValue(value, condition) {
(0, _invariant2.default)(!this._finalized);
(0, _invariant2.default)(this._activeValues.has(value));
return condition ? value : undefined;
}
}, {
key: "_shouldEmitWithoutWaiting",
value: function _shouldEmitWithoutWaiting(delayReason, targetBody) {
/**
* We can directly emit without waiting if:
* 1. No delayReason
* 2. delayReason is a generator body while the target body we are not emitting into is not a generator body.
*/
return !delayReason || !(delayReason instanceof _index.Value) && this._isGeneratorBody(delayReason) && targetBody !== undefined && !this._isGeneratorBody(targetBody);
}
}, {
key: "emitAfterWaiting",
value: function emitAfterWaiting(delayReason, dependencies, func, targetBody) {
if (this._shouldEmitWithoutWaiting(delayReason, targetBody)) {
if (targetBody === undefined || targetBody === this._body) {
// Emit into current body.
func();
} else {
(0, _invariant2.default)(!this._isGeneratorBody(targetBody));
var oldBody = this.beginEmitting(targetBody.type, targetBody);
func();
this.endEmitting(targetBody.type, oldBody);
}
} else {
(0, _invariant2.default)(delayReason !== undefined);
if (delayReason instanceof _index.Value) {
this._emitAfterWaitingForValue(delayReason, dependencies, targetBody === undefined ? this._body : targetBody, func);
} else if (this._isGeneratorBody(delayReason)) {
// delayReason is a generator body.
this._emitAfterWaitingForGeneratorBody(delayReason, dependencies, func);
} else {
// Unknown delay reason.
(0, _invariant2.default)(false);
}
}
}
}, {
key: "_emitAfterWaitingForValue",
value: function _emitAfterWaitingForValue(reason, dependencies, targetBody, func) {
(0, _invariant2.default)(!this._finalized);
(0, _invariant2.default)(!(reason instanceof _index.AbstractValue && this._declaredAbstractValues.has(reason)) || this._activeValues.has(reason));
var a = this._waitingForValues.get(reason);
if (a === undefined) this._waitingForValues.set(reason, a = []);
a.push({ body: targetBody, dependencies: dependencies, func: func });
}
}, {
key: "_emitAfterWaitingForGeneratorBody",
value: function _emitAfterWaitingForGeneratorBody(reason, dependencies, func) {
(0, _invariant2.default)(this._isGeneratorBody(reason));
(0, _invariant2.default)(!this._finalized);
(0, _invariant2.default)(this._activeGeneratorStack.includes(reason));
var b = this._waitingForBodies.get(reason);
if (b === undefined) this._waitingForBodies.set(reason, b = []);
b.push({ dependencies: dependencies, func: func });
}
}, {
key: "emitNowOrAfterWaitingForDependencies",
value: function emitNowOrAfterWaitingForDependencies(dependencies, func, targetBody) {
(0, _invariant2.default)(!this._finalized);
this.emitAfterWaiting(this.getReasonToWaitForDependencies(dependencies), dependencies, func, targetBody);
}
}, {
key: "_cloneGeneratorStack",
value: function _cloneGeneratorStack() {
return this._activeGeneratorStack.slice();
}
}, {
key: "declare",
value: function declare(value) {
(0, _invariant2.default)(!this._finalized);
(0, _invariant2.default)(!this._activeValues.has(value));
(0, _invariant2.default)(value.hasIdentifier());
(0, _invariant2.default)(this._isEmittingActiveGenerator());
this._declaredAbstractValues.set(value, this._cloneGeneratorStack());
this._processValue(value);
}
}, {
key: "hasBeenDeclared",
value: function hasBeenDeclared(value) {
(0, _invariant2.default)(!this._finalized);
return this._declaredAbstractValues.has(value);
}
}, {
key: "getBody",
value: function getBody() {
return this._body;
}
}, {
key: "isCurrentBodyOffspringOf",
value: function isCurrentBodyOffspringOf(targetBody) {
var currentBody = this._body;
while (currentBody !== undefined) {
if (currentBody === targetBody) {
return true;
}
currentBody = currentBody.parentBody;
}
return false;
}
}, {
key: "getBodyReference",
value: function getBodyReference() {
(0, _invariant2.default)(!this._finalized);
return new _types.BodyReference(this._body, this._body.entries.length);
}
}]);
return Emitter;
}();
//# sourceMappingURL=Emitter.js.map