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

334 lines
19 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 = simplifyAndRefineAbstractValue;
var _errors = require("../errors.js");
var _index = require("../domains/index.js");
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _realm = require("../realm.js");
var _index2 = require("../values/index.js");
var _singletons = require("../singletons.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); }
function simplifyAndRefineAbstractValue(realm, isCondition, // The value is only used after converting it to a Boolean
value) {
var savedHandler = realm.errorHandler;
var savedIsReadOnly = realm.isReadOnly;
realm.isReadOnly = true;
try {
realm.errorHandler = function () {
throw new _errors.FatalError();
};
return simplify(realm, value, isCondition);
} catch (e) {
return value;
} finally {
realm.errorHandler = savedHandler;
realm.isReadOnly = savedIsReadOnly;
}
}
function simplify(realm, value) {
var isCondition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (value instanceof _index2.ConcreteValue) return value;
(0, _invariant2.default)(value instanceof _index2.AbstractValue);
if (isCondition || value.getType() === _index2.BooleanValue) {
if (_singletons.Path.implies(value)) return realm.intrinsics.true;
if (_singletons.Path.impliesNot(value)) return realm.intrinsics.false;
}
var loc = value.expressionLocation;
var op = value.kind;
switch (op) {
case "!":
{
var _value$args = _slicedToArray(value.args, 1),
x0 = _value$args[0];
var x = simplify(realm, x0, true);
return negate(realm, x, loc, x0.equals(x) ? value : undefined);
}
case "||":
case "&&":
{
var _value$args2 = _slicedToArray(value.args, 2),
_x2 = _value$args2[0],
y0 = _value$args2[1];
var _x3 = simplify(realm, _x2);
var y = simplify(realm, y0);
if (_x3 instanceof _index2.AbstractValue && _x3.equals(y)) return _x3;
// true && y <=> y
// true || y <=> true
if (!_x3.mightNotBeTrue()) return op === "&&" ? y : _x3;
// (x == false) && y <=> x
// false || y <=> y
if (!_x3.mightNotBeFalse()) return op === "||" ? y : _x3;
if (isCondition || _x3.getType() === _index2.BooleanValue && y.getType() === _index2.BooleanValue) {
// (x: boolean) && true <=> x
// x || true <=> true
if (!y.mightNotBeTrue()) return op === "&&" ? _x3 : realm.intrinsics.true;
// (x: boolean) && false <=> false
// (x: boolean) || false <=> x
if (!y.mightNotBeFalse()) return op === "||" ? _x3 : realm.intrinsics.false;
}
if (op === "||" && y instanceof _index2.AbstractValue && y.kind === "||" && _x3.equals(y.args[0]) && !y.args[1].mightNotBeTrue()) return y;
if (_x3.equals(_x2) && y.equals(y0)) return value;
return _index2.AbstractValue.createFromLogicalOp(realm, value.kind, _x3, y, loc);
}
case "==":
case "!=":
case "===":
case "!==":
return simplifyEquality(realm, value);
case "conditional":
{
var _value$args3 = _slicedToArray(value.args, 3),
c0 = _value$args3[0],
_x4 = _value$args3[1],
_y = _value$args3[2];
var c = simplify(realm, c0, true);
var cs = simplify(realm, c0);
var _x5 = simplify(realm, _x4);
var _y2 = simplify(realm, _y);
if (!c.mightNotBeTrue()) return _x5;
if (!c.mightNotBeFalse()) return _y2;
(0, _invariant2.default)(c instanceof _index2.AbstractValue);
if (_singletons.Path.implies(c)) return _x5;
var notc = _index2.AbstractValue.createFromUnaryOp(realm, "!", c);
if (!notc.mightNotBeTrue()) return _y2;
if (!notc.mightNotBeFalse()) return _x5;
(0, _invariant2.default)(notc instanceof _index2.AbstractValue);
if (_singletons.Path.implies(notc)) return _y2;
if (_singletons.Path.implies(_index2.AbstractValue.createFromBinaryOp(realm, "===", value, _x5))) return _x5;
if (_singletons.Path.implies(_index2.AbstractValue.createFromBinaryOp(realm, "!==", value, _x5))) return _y2;
if (_singletons.Path.implies(_index2.AbstractValue.createFromBinaryOp(realm, "!==", value, _y2))) return _x5;
if (_singletons.Path.implies(_index2.AbstractValue.createFromBinaryOp(realm, "===", value, _y2))) return _y2;
// c ? x : x <=> x
if (_x5.equals(_y2)) return _x5;
// x ? x : y <=> x || y
if (cs.equals(_x5)) return _index2.AbstractValue.createFromLogicalOp(realm, "||", _x5, _y2, loc);
// y ? x : y <=> y && x
if (cs.equals(_y2)) return _index2.AbstractValue.createFromLogicalOp(realm, "&&", _y2, _x5, loc);
// c ? (c ? xx : xy) : y <=> c ? xx : y
if (_x5 instanceof _index2.AbstractValue && _x5.kind === "conditional") {
var _x5$args = _slicedToArray(_x5.args, 2),
xc = _x5$args[0],
xx = _x5$args[1];
if (c.equals(xc)) return _index2.AbstractValue.createFromConditionalOp(realm, c, xx, _y2);
}
// c ? x : (c ? y : z) : z <=> c ? x : z
if (_y2 instanceof _index2.AbstractValue && _y2.kind === "conditional") {
var _y2$args = _slicedToArray(_y2.args, 3),
yc = _y2$args[0],
z = _y2$args[2];
if (c.equals(yc)) return _index2.AbstractValue.createFromConditionalOp(realm, c, _x5, z);
}
if (_x5.getType() === _index2.BooleanValue && _y2.getType() === _index2.BooleanValue) {
// c ? true : false <=> c
if (!_x5.mightNotBeTrue() && !_y2.mightNotBeFalse()) return c;
// c ? false : true <=> !c
if (!_x5.mightNotBeFalse() && !_y2.mightNotBeTrue()) return _index2.AbstractValue.createFromUnaryOp(realm, "!", c, true, loc);
}
if (c.equals(c0) && _x5.equals(_x4) && _y2.equals(_y)) return value;
return _index2.AbstractValue.createFromConditionalOp(realm, c, _x5, _y2, value.expressionLocation);
}
case "abstractConcreteUnion":
{
// The union of an abstract value with one or more concrete values.
if (realm.pathConditions.length === 0) return value;
var _value$args4 = _toArray(value.args),
abstractValue = _value$args4[0],
concreteValues = _value$args4.slice(1);
(0, _invariant2.default)(abstractValue instanceof _index2.AbstractValue);
var remainingConcreteValues = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = concreteValues[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var concreteValue = _step.value;
if (_singletons.Path.implies(_index2.AbstractValue.createFromBinaryOp(realm, "!==", value, concreteValue))) continue;
if (_singletons.Path.implies(_index2.AbstractValue.createFromBinaryOp(realm, "===", value, concreteValue))) return concreteValue;
remainingConcreteValues.push(concreteValue);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (remainingConcreteValues.length === 0) return abstractValue;
if (remainingConcreteValues.length === concreteValues.length) return value;
return _index2.AbstractValue.createAbstractConcreteUnion.apply(_index2.AbstractValue, [realm, abstractValue].concat(remainingConcreteValues));
}
default:
return value;
}
}
function simplifyEquality(realm, equality) {
var loc = equality.expressionLocation;
var op = equality.kind;
var _equality$args = _slicedToArray(equality.args, 2),
x = _equality$args[0],
y = _equality$args[1];
if (x instanceof _index2.ConcreteValue) {
;
var _ref = [y, x];
x = _ref[0];
y = _ref[1];
}if (x instanceof _index2.AbstractValue && x.kind === "conditional" && (!y.mightNotBeUndefined() || !y.mightNotBeNull())) {
// try to simplify "(cond ? xx : xy) op undefined/null" to just "cond" or "!cond"
var _x$args = _slicedToArray(x.args, 3),
cond = _x$args[0],
xx = _x$args[1],
xy = _x$args[2];
(0, _invariant2.default)(cond instanceof _index2.AbstractValue); // otherwise the the conditional should not have been created
if (op === "===" || op === "!==") {
// if xx === undefined && xy !== undefined then cond <=> x === undefined
if (!y.mightNotBeUndefined() && !xx.mightNotBeUndefined() && !xy.mightBeUndefined()) return op === "===" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
// if xx !== undefined && xy === undefined then !cond <=> x === undefined
if (!y.mightNotBeUndefined() && !xx.mightBeUndefined() && !xy.mightNotBeUndefined()) return op === "===" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
// if xx === null && xy !== null then cond <=> x === null
if (!y.mightNotBeNull() && !xx.mightNotBeNull() && !xy.mightBeNull()) return op === "===" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
// if xx !== null && xy === null then !cond <=> x === null
if (!y.mightNotBeNull() && !xx.mightBeNull() && !xy.mightNotBeNull()) return op === "===" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
} else {
(0, _invariant2.default)(op === "==" || op === "!=");
// if xx cannot be undefined/null and xy is undefined/null then !cond <=> x == undefined/null
if (!xx.mightBeUndefined() && !xx.mightBeNull() && (!xy.mightNotBeUndefined() || !xy.mightNotBeNull())) return op === "==" ? negate(realm, cond, loc) : makeBoolean(realm, cond, loc);
// if xx is undefined/null and xy cannot be undefined/null then cond <=> x == undefined/null
if ((!xx.mightNotBeUndefined() || !xx.mightNotBeNull()) && !xy.mightBeUndefined() && !xy.mightBeNull()) return op === "==" ? makeBoolean(realm, cond, loc) : negate(realm, cond, loc);
}
}
return equality;
}
function makeBoolean(realm, value) {
var loc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
if (value.getType() === _index2.BooleanValue) return value;
if (value instanceof _index2.ConcreteValue) return new _index2.BooleanValue(realm, _singletons.To.ToBoolean(realm, value));
(0, _invariant2.default)(value instanceof _index2.AbstractValue);
var v = _index2.AbstractValue.createFromUnaryOp(realm, "!", value, true, value.expressionLocation);
if (v instanceof _index2.ConcreteValue) return new _index2.BooleanValue(realm, !_singletons.To.ToBoolean(realm, v));
(0, _invariant2.default)(v instanceof _index2.AbstractValue);
return _index2.AbstractValue.createFromUnaryOp(realm, "!", v, true, loc || value.expressionLocation);
}
function negate(realm, value) {
var loc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
var unsimplifiedNegation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
if (value instanceof _index2.ConcreteValue) return _index.ValuesDomain.computeUnary(realm, "!", value);
(0, _invariant2.default)(value instanceof _index2.AbstractValue);
if (value.kind === "!") {
var _value$args5 = _slicedToArray(value.args, 1),
x = _value$args5[0];
if (x.getType() === _index2.BooleanValue) return simplify(realm, x, true);
if (unsimplifiedNegation !== undefined) return unsimplifiedNegation;
return makeBoolean(realm, x, loc);
}
if (!value.mightNotBeTrue()) return realm.intrinsics.false;
if (!value.mightNotBeFalse()) return realm.intrinsics.true;
// If NaN is not an issue, invert binary ops
if (value.args.length === 2 && !value.args[0].mightBeNumber() && !value.args[1].mightBeNumber()) {
var invertedComparison = void 0;
switch (value.kind) {
case "===":
invertedComparison = "!==";
break;
case "==":
invertedComparison = "!=";
break;
case "!==":
invertedComparison = "===";
break;
case "!=":
invertedComparison = "==";
break;
case "<":
invertedComparison = ">=";
break;
case "<=":
invertedComparison = ">";
break;
case ">":
invertedComparison = "<=";
break;
case ">=":
invertedComparison = "<";
break;
default:
break;
}
if (invertedComparison !== undefined) {
var left = simplify(realm, value.args[0]);
var right = simplify(realm, value.args[1]);
return _index2.AbstractValue.createFromBinaryOp(realm, invertedComparison, left, right, loc || value.expressionLocation);
}
var invertedLogicalOp = void 0;
switch (value.kind) {
case "&&":
invertedLogicalOp = "||";
break;
case "||":
invertedLogicalOp = "&&";
break;
default:
break;
}
if (invertedLogicalOp !== undefined) {
var _left = negate(realm, value.args[0]);
var _right = negate(realm, value.args[1]);
return _index2.AbstractValue.createFromLogicalOp(realm, invertedLogicalOp, _left, _right, loc || value.expressionLocation);
}
}
if (unsimplifiedNegation !== undefined) return unsimplifiedNegation;
return _index2.AbstractValue.createFromUnaryOp(realm, "!", value, true, loc || value.expressionLocation);
}
//# sourceMappingURL=simplifier.js.map