Files
asciidisco.com/build/node_modules/prepack/lib/utils/generator.js
2023-08-01 13:49:46 +02:00

624 lines
28 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PreludeGenerator = exports.NameGenerator = exports.Generator = undefined;
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"); } }; }();
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 _index2 = require("../domains/index.js");
var _base = require("base62");
var base62 = _interopRequireWildcard(_base);
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _internalizer = require("./internalizer.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function serializeBody(generator, context) {
var statements = context.serializeGenerator(generator);
return t.blockStatement(statements);
}
var Generator = exports.Generator = function () {
function Generator(realm, name) {
_classCallCheck(this, Generator);
(0, _invariant2.default)(realm.useAbstractInterpretation);
var realmPreludeGenerator = realm.preludeGenerator;
(0, _invariant2.default)(realmPreludeGenerator);
this.preludeGenerator = realmPreludeGenerator;
this.parent = realm.generator;
this.realm = realm;
this._entries = [];
this.id = realm.nextGeneratorId++;
this._name = name;
}
_createClass(Generator, [{
key: "getName",
value: function getName() {
return this._name || "#" + this.id;
}
}, {
key: "getAsPropertyNameExpression",
value: function getAsPropertyNameExpression(key) {
var canBeIdentifier = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
// If key is a non-negative numeric string literal, parse it and set it as a numeric index instead.
var index = Number.parseInt(key, 10);
if (index >= 0 && index.toString() === key) {
return t.numericLiteral(index);
}
if (canBeIdentifier) {
// TODO #1020: revert this when Unicode identifiers are supported by all targetted JavaScript engines
var keyIsAscii = /^[\u0000-\u007f]*$/.test(key);
if (t.isValidIdentifier(key) && keyIsAscii) return t.identifier(key);
}
return t.stringLiteral(key);
}
}, {
key: "getParent",
value: function getParent() {
return this.parent;
}
}, {
key: "empty",
value: function empty() {
return this._entries.length === 0;
}
// Will force the array of Values to be serialized but not emit anything for a buildNode
}, {
key: "appendRoots",
value: function appendRoots(values) {
this._addEntry({
args: values
});
}
}, {
key: "emitGlobalDeclaration",
value: function emitGlobalDeclaration(key, value) {
this.preludeGenerator.declaredGlobals.add(key);
if (!(value instanceof _index.UndefinedValue)) this.emitGlobalAssignment(key, value, true);
}
}, {
key: "emitGlobalAssignment",
value: function emitGlobalAssignment(key, value, strictMode) {
var _this = this;
this._addEntry({
args: [value],
buildNode: function buildNode(_ref) {
var _ref2 = _slicedToArray(_ref, 1),
valueNode = _ref2[0];
return t.expressionStatement(t.assignmentExpression("=", _this.preludeGenerator.globalReference(key, !strictMode), valueNode));
}
});
}
}, {
key: "emitGlobalDelete",
value: function emitGlobalDelete(key, strictMode) {
var _this2 = this;
this._addEntry({
args: [],
buildNode: function buildNode(_ref3) {
var _ref4 = _toArray(_ref3);
return t.expressionStatement(t.unaryExpression("delete", _this2.preludeGenerator.globalReference(key, !strictMode)));
}
});
}
}, {
key: "emitBindingAssignment",
value: function emitBindingAssignment(binding, value) {
this._addEntry({
args: [value],
buildNode: function buildNode(_ref5, context) {
var _ref6 = _slicedToArray(_ref5, 1),
valueNode = _ref6[0];
return t.expressionStatement(t.assignmentExpression("=", context.serializeBinding(binding), valueNode));
}
});
}
}, {
key: "emitPropertyAssignment",
value: function emitPropertyAssignment(object, key, value) {
if (object.refuseSerialization) return;
var propName = this.getAsPropertyNameExpression(key);
this._addEntry({
args: [object, value],
buildNode: function buildNode(_ref7) {
var _ref8 = _slicedToArray(_ref7, 2),
objectNode = _ref8[0],
valueNode = _ref8[1];
return t.expressionStatement(t.assignmentExpression("=", t.memberExpression(objectNode, propName, !t.isIdentifier(propName)), valueNode));
}
});
}
}, {
key: "emitDefineProperty",
value: function emitDefineProperty(object, key, desc) {
var isDescChanged = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
if (object.refuseSerialization) return;
if (desc.enumerable && desc.configurable && desc.writable && desc.value && !isDescChanged) {
var descValue = desc.value;
(0, _invariant2.default)(descValue instanceof _index.Value);
this.emitPropertyAssignment(object, key, descValue);
} else {
desc = Object.assign({}, desc);
var _descValue = desc.value || object.$Realm.intrinsics.undefined;
(0, _invariant2.default)(_descValue instanceof _index.Value);
this._addEntry({
args: [object, _descValue, desc.get || object.$Realm.intrinsics.undefined, desc.set || object.$Realm.intrinsics.undefined],
buildNode: function buildNode(_, context) {
return context.emitDefinePropertyBody(object, key, desc);
}
});
}
}
}, {
key: "emitPropertyDelete",
value: function emitPropertyDelete(object, key) {
if (object.refuseSerialization) return;
var propName = this.getAsPropertyNameExpression(key);
this._addEntry({
args: [object],
buildNode: function buildNode(_ref9) {
var _ref10 = _slicedToArray(_ref9, 1),
objectNode = _ref10[0];
return t.expressionStatement(t.unaryExpression("delete", t.memberExpression(objectNode, propName, !t.isIdentifier(propName))));
}
});
}
}, {
key: "emitCall",
value: function emitCall(createCallee, args) {
this._addEntry({
args: args,
buildNode: function buildNode(values) {
return t.expressionStatement(t.callExpression(createCallee(), [].concat(_toConsumableArray(values))));
}
});
}
}, {
key: "emitConsoleLog",
value: function emitConsoleLog(method, args) {
var _this3 = this;
this.emitCall(function () {
return t.memberExpression(t.identifier("console"), t.identifier(method));
}, args.map(function (v) {
return typeof v === "string" ? new _index.StringValue(_this3.realm, v) : v;
}));
}
// test must be a temporal value, which means that it must have a defined intrinsicName
}, {
key: "emitDoWhileStatement",
value: function emitDoWhileStatement(test, body) {
this._addEntry({
args: [],
buildNode: function buildNode(_ref11, context) {
var _ref12 = _toArray(_ref11);
var testId = test.intrinsicName;
(0, _invariant2.default)(testId !== undefined);
var statements = context.serializeGenerator(body);
var block = t.blockStatement(statements);
return t.doWhileStatement(t.identifier(testId), block);
},
dependencies: [body]
});
}
}, {
key: "emitInvariant",
value: function emitInvariant(args, violationConditionFn, appendLastToInvariantFn) {
if (this.realm.omitInvariants) return;
this._addEntry({
args: args,
buildNode: function buildNode(nodes) {
var throwString = t.stringLiteral("Prepack model invariant violation");
if (appendLastToInvariantFn) {
var last = nodes.pop();
throwString = t.binaryExpression("+", t.stringLiteral("Prepack model invariant violation: "), appendLastToInvariantFn(last));
}
var condition = violationConditionFn(nodes);
var throwblock = t.blockStatement([t.throwStatement(t.newExpression(t.identifier("Error"), [throwString]))]);
return t.ifStatement(condition, throwblock);
}
});
}
}, {
key: "emitCallAndCaptureResult",
value: function emitCallAndCaptureResult(types, values, createCallee, args, kind) {
return this.derive(types, values, args, function (nodes) {
return t.callExpression(createCallee(), nodes);
});
}
}, {
key: "emitStatement",
value: function emitStatement(args, buildNode_) {
this._addEntry({
args: args,
buildNode: buildNode_
});
}
}, {
key: "emitVoidExpression",
value: function emitVoidExpression(types, values, args, buildNode_) {
this._addEntry({
args: args,
buildNode: function buildNode(nodes) {
return t.expressionStatement(buildNode_ instanceof Function ? buildNode_(nodes) : buildNode_);
}
});
return this.realm.intrinsics.undefined;
}
}, {
key: "emitForInStatement",
value: function emitForInStatement(o, lh, sourceObject, targetObject, boundName) {
this._addEntry({
// duplicate args to ensure refcount > 1
args: [o, targetObject, sourceObject, targetObject, sourceObject],
buildNode: function buildNode(_ref13) {
var _ref14 = _slicedToArray(_ref13, 6),
obj = _ref14[0],
tgt = _ref14[1],
src = _ref14[2],
obj1 = _ref14[3],
tgt1 = _ref14[4],
src1 = _ref14[5];
return t.forInStatement(lh, obj, t.blockStatement([t.expressionStatement(t.assignmentExpression("=", t.memberExpression(tgt, boundName, true), t.memberExpression(src, boundName, true)))]));
}
});
}
}, {
key: "derive",
value: function derive(types, values, args, buildNode_, optionalArgs) {
(0, _invariant2.default)(buildNode_ instanceof Function || args.length === 0);
var id = t.identifier(this.preludeGenerator.nameGenerator.generate("derived"));
this.preludeGenerator.derivedIds.set(id.name, args);
var options = {};
if (optionalArgs && optionalArgs.kind) options.kind = optionalArgs.kind;
var Constructor = _index.Value.isTypeCompatibleWith(types.getType(), _index.ObjectValue) ? _index.AbstractObjectValue : _index.AbstractValue;
var res = new Constructor(this.realm, types, values, 0, [], id, options);
this._addEntry({
isPure: optionalArgs ? optionalArgs.isPure : undefined,
declared: res,
args: args,
buildNode: function buildNode(nodes, context) {
return t.variableDeclaration("var", [t.variableDeclarator(id, buildNode_ instanceof Function ? buildNode_(nodes, context) : buildNode_)]);
}
});
var type = types.getType();
res.intrinsicName = id.name;
if (optionalArgs && optionalArgs.skipInvariant) return res;
var typeofString = void 0;
if (type instanceof _index.FunctionValue) typeofString = "function";else if (type === _index.UndefinedValue) (0, _invariant2.default)(false);else if (type === _index.NullValue) (0, _invariant2.default)(false);else if (type === _index.StringValue) typeofString = "string";else if (type === _index.BooleanValue) typeofString = "boolean";else if (type === _index.NumberValue) typeofString = "number";else if (type === _index.SymbolValue) typeofString = "symbol";else if (type === _index.ObjectValue) typeofString = "object";
if (typeofString !== undefined) {
// Verify that the types are as expected, a failure of this invariant
// should mean the model is wrong.
this.emitInvariant([res, res], function (nodes) {
(0, _invariant2.default)(typeofString !== undefined);
var condition = t.binaryExpression("!==", t.unaryExpression("typeof", nodes[0]), t.stringLiteral(typeofString));
if (typeofString === "object") {
condition = t.logicalExpression("&&", condition, t.binaryExpression("!==", t.unaryExpression("typeof", nodes[0]), t.stringLiteral("function")));
condition = t.logicalExpression("||", condition, t.binaryExpression("===", nodes[0], _internalizer.nullExpression));
}
return condition;
}, function (node) {
return node;
});
}
return res;
}
}, {
key: "serialize",
value: function serialize(context) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this._entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var entry = _step.value;
if (!entry.isPure || !entry.declared || !context.canOmit(entry.declared)) {
var nodes = entry.args.map(function (boundArg, i) {
return context.serializeValue(boundArg);
});
if (entry.buildNode) context.emit(entry.buildNode(nodes, context));
if (entry.declared !== undefined) context.declare(entry.declared);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}, {
key: "visitEntry",
value: function visitEntry(entry, callbacks) {
if (entry.isPure && entry.declared && callbacks.canSkip(entry.declared)) {
callbacks.recordDelayedEntry(entry);
} else {
if (entry.declared) callbacks.recordDeclaration(entry.declared);
callbacks.visitValues(entry.args);
if (entry.dependencies) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = entry.dependencies[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var dependency = _step2.value;
callbacks.visitGenerator(dependency);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}
}
}, {
key: "visit",
value: function visit(callbacks) {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = this._entries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var entry = _step3.value;
this.visitEntry(entry, callbacks);
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
}, {
key: "_addEntry",
value: function _addEntry(entry) {
this._entries.push(entry);
}
}, {
key: "appendGenerator",
value: function appendGenerator(other, leadingComment) {
if (other.empty()) return;
this._addEntry({
args: [],
buildNode: function buildNode(args, context) {
var statements = context.serializeGenerator(other);
var block = t.blockStatement(statements);
if (leadingComment.length > 0) block.leadingComments = [{ type: "BlockComment", value: leadingComment }];
return block;
},
dependencies: [other]
});
}
}, {
key: "composeGenerators",
value: function composeGenerators(generator1, generator2) {
this._addEntry({
args: [],
buildNode: function buildNode(_ref15, context) {
var _ref16 = _toArray(_ref15);
var statements = [];
if (!generator1.empty()) statements.push(serializeBody(generator1, context));
if (!generator2.empty()) statements.push(serializeBody(generator2, context));
return t.blockStatement(statements);
},
dependencies: [generator1, generator2]
});
}
}, {
key: "joinGenerators",
value: function joinGenerators(joinCondition, generator1, generator2) {
this._addEntry({
args: [joinCondition],
buildNode: function buildNode(_ref17, context) {
var _ref18 = _slicedToArray(_ref17, 1),
cond = _ref18[0];
var block1 = generator1.empty() ? null : serializeBody(generator1, context);
var block2 = generator2.empty() ? null : serializeBody(generator2, context);
if (block1) return t.ifStatement(cond, block1, block2);
(0, _invariant2.default)(block2);
return t.ifStatement(t.unaryExpression("!", cond), block2);
},
dependencies: [generator1, generator2]
});
}
}]);
return Generator;
}();
// some characters are invalid within a JavaScript identifier,
// such as: . , : ( ) ' " ` [ ] -
// so we replace these character instacnes with an underscore
function replaceInvalidCharactersWithUnderscore(string) {
return string.replace(/[.,:\(\)\"\'\`\[\]\-]/g, "_");
}
var NameGenerator = exports.NameGenerator = function () {
function NameGenerator(forbiddenNames, debugNames, uniqueSuffix, prefix) {
_classCallCheck(this, NameGenerator);
this.prefix = prefix;
this.uidCounter = 0;
this.debugNames = debugNames;
this.forbiddenNames = forbiddenNames;
this.uniqueSuffix = uniqueSuffix;
}
_createClass(NameGenerator, [{
key: "generate",
value: function generate(debugSuffix) {
var id = void 0;
do {
id = this.prefix + base62.encode(this.uidCounter++);
if (this.uniqueSuffix.length > 0) id += this.uniqueSuffix;
if (this.debugNames) {
if (debugSuffix) id += "_" + replaceInvalidCharactersWithUnderscore(debugSuffix);else id += "_";
}
} while (this.forbiddenNames.has(id));
return id;
}
}]);
return NameGenerator;
}();
var PreludeGenerator = exports.PreludeGenerator = function () {
function PreludeGenerator(debugNames, uniqueSuffix) {
_classCallCheck(this, PreludeGenerator);
this.prelude = [];
this.derivedIds = new Map();
this.memoizedRefs = new Map();
this.nameGenerator = new NameGenerator(new Set(), !!debugNames, uniqueSuffix || "", "_$");
this.usesThis = false;
this.declaredGlobals = new Set();
}
_createClass(PreludeGenerator, [{
key: "createNameGenerator",
value: function createNameGenerator(prefix) {
return new NameGenerator(this.nameGenerator.forbiddenNames, this.nameGenerator.debugNames, this.nameGenerator.uniqueSuffix, prefix);
}
}, {
key: "convertStringToMember",
value: function convertStringToMember(str) {
var _this4 = this;
return str.split(".").map(function (name) {
return name === "global" ? _this4.memoizeReference(name) : t.identifier(name);
}).reduce(function (obj, prop) {
return t.memberExpression(obj, prop);
});
}
}, {
key: "globalReference",
value: function globalReference(key) {
var globalScope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (globalScope && t.isValidIdentifier(key)) return t.identifier(key);
var keyNode = t.isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key);
return t.memberExpression(this.memoizeReference("global"), keyNode, !t.isIdentifier(keyNode));
}
}, {
key: "memoizeReference",
value: function memoizeReference(key) {
var ref = this.memoizedRefs.get(key);
if (ref) return ref;
var init = void 0;
if (key.includes("(") || key.includes("[")) {
// Horrible but effective hack:
// Some internal object have intrinsic names such as
// ([][Symbol.iterator]().__proto__.__proto__)
// and
// RegExp.prototype[Symbol.match]
// which get turned into a babel node here.
// TODO: We should properly parse such a string, and memoize all references in it separately.
// Instead, we just turn it into a funky identifier, which Babel seems to accept.
init = t.identifier(key);
} else if (key === "global") {
this.usesThis = true;
init = t.thisExpression();
} else {
var i = key.lastIndexOf(".");
if (i === -1) {
init = t.memberExpression(this.memoizeReference("global"), t.identifier(key));
} else {
init = t.memberExpression(this.memoizeReference(key.substr(0, i)), t.identifier(key.substr(i + 1)));
}
}
ref = t.identifier(this.nameGenerator.generate(key));
this.prelude.push(t.variableDeclaration("var", [t.variableDeclarator(ref, init)]));
this.memoizedRefs.set(key, ref);
return ref;
}
}]);
return PreludeGenerator;
}();
//# sourceMappingURL=generator.js.map