hyperformula-dc
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
663 lines (516 loc) • 25.3 kB
JavaScript
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_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"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import "core-js/modules/es.array.concat.js";
import "core-js/modules/es.array.map.js";
import "core-js/modules/es.symbol.js";
import "core-js/modules/es.symbol.description.js";
import "core-js/modules/es.object.to-string.js";
import "core-js/modules/es.symbol.iterator.js";
import "core-js/modules/es.array.iterator.js";
import "core-js/modules/es.string.iterator.js";
import "core-js/modules/web.dom-collections.iterator.js";
import "core-js/modules/es.array.slice.js";
import "core-js/modules/es.function.name.js";
import "core-js/modules/es.array.from.js";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* @license
* Copyright (c) 2021 Handsoncode. All rights reserved.
*/
import { AbsoluteCellRange, AbsoluteColumnRange, AbsoluteRowRange } from '../AbsoluteCellRange';
import { ArrayValue, NotComputedArray } from '../ArrayValue';
import { CellError, ErrorType, invalidSimpleCellAddress } from '../Cell';
import { ErrorMessage } from '../error-message'; // noinspection TypeScriptPreferShortImport
import { AstNodeType } from '../parser/Ast';
import { coerceRangeToScalar, coerceScalarToString, coerceToRange, fixNegativeZero, isNumberOverflow } from './ArithmeticHelper';
import { CriterionBuilder } from './Criterion';
import { FunctionRegistry } from './FunctionRegistry';
import { InterpreterState } from './InterpreterState';
import { cloneNumber, EmptyValue, getRawValue, isExtendedNumber } from './InterpreterValue';
import { SimpleRangeValue } from './SimpleRangeValue';
export var Interpreter = /*#__PURE__*/function () {
function Interpreter(config, dependencyGraph, columnSearch, stats, arithmeticHelper, functionRegistry, namedExpressions, serialization, arraySizePredictor, dateTimeHelper) {
var _this = this;
_classCallCheck(this, Interpreter);
this.config = config;
this.dependencyGraph = dependencyGraph;
this.columnSearch = columnSearch;
this.stats = stats;
this.arithmeticHelper = arithmeticHelper;
this.functionRegistry = functionRegistry;
this.namedExpressions = namedExpressions;
this.serialization = serialization;
this.arraySizePredictor = arraySizePredictor;
this.dateTimeHelper = dateTimeHelper;
this.equalOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.eq, arg1, arg2);
};
this.notEqualOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.neq, arg1, arg2);
};
this.greaterThanOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.gt, arg1, arg2);
};
this.lessThanOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.lt, arg1, arg2);
};
this.greaterThanOrEqualOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.geq, arg1, arg2);
};
this.lessThanOrEqualOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.leq, arg1, arg2);
};
this.concatOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.concat, coerceScalarToString(arg1), coerceScalarToString(arg2));
};
this.plusOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.addWithEpsilon, _this.arithmeticHelper.coerceScalarToNumberOrError(arg1), _this.arithmeticHelper.coerceScalarToNumberOrError(arg2));
};
this.minusOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.subtract, _this.arithmeticHelper.coerceScalarToNumberOrError(arg1), _this.arithmeticHelper.coerceScalarToNumberOrError(arg2));
};
this.timesOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.multiply, _this.arithmeticHelper.coerceScalarToNumberOrError(arg1), _this.arithmeticHelper.coerceScalarToNumberOrError(arg2));
};
this.powerOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.pow, _this.arithmeticHelper.coerceScalarToNumberOrError(arg1), _this.arithmeticHelper.coerceScalarToNumberOrError(arg2));
};
this.divOp = function (arg1, arg2) {
return binaryErrorWrapper(_this.arithmeticHelper.divide, _this.arithmeticHelper.coerceScalarToNumberOrError(arg1), _this.arithmeticHelper.coerceScalarToNumberOrError(arg2));
};
this.unaryMinusOp = function (arg) {
return unaryErrorWrapper(_this.arithmeticHelper.unaryMinus, _this.arithmeticHelper.coerceScalarToNumberOrError(arg));
};
this.percentOp = function (arg) {
return unaryErrorWrapper(_this.arithmeticHelper.unaryPercent, _this.arithmeticHelper.coerceScalarToNumberOrError(arg));
};
this.unaryPlusOp = function (arg) {
return _this.arithmeticHelper.unaryPlus(arg);
};
this.functionRegistry.initializePlugins(this);
this.criterionBuilder = new CriterionBuilder(config);
}
_createClass(Interpreter, [{
key: "evaluateAst",
value: function evaluateAst(ast, state) {
var val = this.evaluateAstWithoutPostprocessing(ast, state);
if (isExtendedNumber(val)) {
if (isNumberOverflow(getRawValue(val))) {
return new CellError(ErrorType.NUM, ErrorMessage.NaN);
} else {
val = cloneNumber(val, fixNegativeZero(getRawValue(val)));
}
}
if (val instanceof SimpleRangeValue && val.height() === 1 && val.width() === 1) {
var _val$data = _slicedToArray(val.data, 1);
var _val$data$ = _slicedToArray(_val$data[0], 1);
val = _val$data$[0];
}
return wrapperForRootVertex(val, state.formulaVertex);
}
/**
* Calculates cell value from formula abstract syntax tree
*
* @param formula - abstract syntax tree of formula
* @param formulaAddress - address of the cell in which formula is located
*/
}, {
key: "evaluateAstWithoutPostprocessing",
value: function evaluateAstWithoutPostprocessing(ast, state) {
switch (ast.type) {
case AstNodeType.EMPTY:
{
return EmptyValue;
}
case AstNodeType.CELL_REFERENCE:
{
var address = ast.reference.toSimpleCellAddress(state.formulaAddress);
if (invalidSimpleCellAddress(address)) {
return new CellError(ErrorType.REF, ErrorMessage.BadRef);
}
return this.dependencyGraph.getCellValue(address);
}
case AstNodeType.NUMBER:
case AstNodeType.STRING:
{
return ast.value;
}
case AstNodeType.CONCATENATE_OP:
{
var leftResult = this.evaluateAst(ast.left, state);
var rightResult = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.concatOp, leftResult, rightResult, state);
}
case AstNodeType.EQUALS_OP:
{
var _leftResult = this.evaluateAst(ast.left, state);
var _rightResult = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.equalOp, _leftResult, _rightResult, state);
}
case AstNodeType.NOT_EQUAL_OP:
{
var _leftResult2 = this.evaluateAst(ast.left, state);
var _rightResult2 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.notEqualOp, _leftResult2, _rightResult2, state);
}
case AstNodeType.GREATER_THAN_OP:
{
var _leftResult3 = this.evaluateAst(ast.left, state);
var _rightResult3 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.greaterThanOp, _leftResult3, _rightResult3, state);
}
case AstNodeType.LESS_THAN_OP:
{
var _leftResult4 = this.evaluateAst(ast.left, state);
var _rightResult4 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.lessThanOp, _leftResult4, _rightResult4, state);
}
case AstNodeType.GREATER_THAN_OR_EQUAL_OP:
{
var _leftResult5 = this.evaluateAst(ast.left, state);
var _rightResult5 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.greaterThanOrEqualOp, _leftResult5, _rightResult5, state);
}
case AstNodeType.LESS_THAN_OR_EQUAL_OP:
{
var _leftResult6 = this.evaluateAst(ast.left, state);
var _rightResult6 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.lessThanOrEqualOp, _leftResult6, _rightResult6, state);
}
case AstNodeType.PLUS_OP:
{
var _leftResult7 = this.evaluateAst(ast.left, state);
var _rightResult7 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.plusOp, _leftResult7, _rightResult7, state);
}
case AstNodeType.MINUS_OP:
{
var _leftResult8 = this.evaluateAst(ast.left, state);
var _rightResult8 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.minusOp, _leftResult8, _rightResult8, state);
}
case AstNodeType.TIMES_OP:
{
var _leftResult9 = this.evaluateAst(ast.left, state);
var _rightResult9 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.timesOp, _leftResult9, _rightResult9, state);
}
case AstNodeType.POWER_OP:
{
var _leftResult10 = this.evaluateAst(ast.left, state);
var _rightResult10 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.powerOp, _leftResult10, _rightResult10, state);
}
case AstNodeType.DIV_OP:
{
var _leftResult11 = this.evaluateAst(ast.left, state);
var _rightResult11 = this.evaluateAst(ast.right, state);
return this.binaryRangeWrapper(this.divOp, _leftResult11, _rightResult11, state);
}
case AstNodeType.PLUS_UNARY_OP:
{
var result = this.evaluateAst(ast.value, state);
return this.unaryRangeWrapper(this.unaryPlusOp, result, state);
}
case AstNodeType.MINUS_UNARY_OP:
{
var _result = this.evaluateAst(ast.value, state);
return this.unaryRangeWrapper(this.unaryMinusOp, _result, state);
}
case AstNodeType.PERCENT_OP:
{
var _result2 = this.evaluateAst(ast.value, state);
return this.unaryRangeWrapper(this.percentOp, _result2, state);
}
case AstNodeType.FUNCTION_CALL:
{
if (this.config.licenseKeyValidityState !== "valid"
/* VALID */
&& !FunctionRegistry.functionIsProtected(ast.procedureName)) {
return new CellError(ErrorType.LIC, ErrorMessage.LicenseKey(this.config.licenseKeyValidityState));
}
var pluginFunction = this.functionRegistry.getFunction(ast.procedureName);
if (pluginFunction !== undefined) {
return pluginFunction(ast, new InterpreterState(state.formulaAddress, state.arraysFlag || this.functionRegistry.isArrayFunction(ast.procedureName), state.formulaVertex));
} else {
return new CellError(ErrorType.NAME, ErrorMessage.FunctionName(ast.procedureName));
}
}
case AstNodeType.NAMED_EXPRESSION:
{
var namedExpression = this.namedExpressions.nearestNamedExpression(ast.expressionName, state.formulaAddress.sheet);
if (namedExpression) {
return this.dependencyGraph.getCellValue(namedExpression.address);
} else {
return new CellError(ErrorType.NAME, ErrorMessage.NamedExpressionName(ast.expressionName));
}
}
case AstNodeType.CELL_RANGE:
{
if (!this.rangeSpansOneSheet(ast)) {
return new CellError(ErrorType.REF, ErrorMessage.RangeManySheets);
}
var range = AbsoluteCellRange.fromCellRange(ast, state.formulaAddress);
var arrayVertex = this.dependencyGraph.getArray(range);
if (arrayVertex) {
var array = arrayVertex.array;
if (array instanceof NotComputedArray) {
throw new Error('Array should be already computed');
} else if (array instanceof CellError) {
return array;
} else if (array instanceof ArrayValue) {
return SimpleRangeValue.fromRange(array.raw(), range, this.dependencyGraph);
} else {
throw new Error('Unknown array');
}
} else {
return SimpleRangeValue.onlyRange(range, this.dependencyGraph);
}
}
case AstNodeType.COLUMN_RANGE:
{
if (!this.rangeSpansOneSheet(ast)) {
return new CellError(ErrorType.REF, ErrorMessage.RangeManySheets);
}
var _range = AbsoluteColumnRange.fromColumnRange(ast, state.formulaAddress);
return SimpleRangeValue.onlyRange(_range, this.dependencyGraph);
}
case AstNodeType.ROW_RANGE:
{
if (!this.rangeSpansOneSheet(ast)) {
return new CellError(ErrorType.REF, ErrorMessage.RangeManySheets);
}
var _range2 = AbsoluteRowRange.fromRowRangeAst(ast, state.formulaAddress);
return SimpleRangeValue.onlyRange(_range2, this.dependencyGraph);
}
case AstNodeType.PARENTHESIS:
{
return this.evaluateAst(ast.expression, state);
}
case AstNodeType.ARRAY:
{
var totalWidth = undefined;
var ret = [];
var _iterator = _createForOfIteratorHelper(ast.args),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var astRow = _step.value;
var rowHeight = undefined;
var rowRet = [];
var _iterator2 = _createForOfIteratorHelper(astRow),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var astIt = _step2.value;
var arr = coerceToRange(this.evaluateAst(astIt, state));
var height = arr.height();
if (rowHeight === undefined) {
rowHeight = height;
rowRet.push.apply(rowRet, _toConsumableArray(arr.data));
} else if (rowHeight === height) {
for (var i = 0; i < height; i++) {
var _rowRet$i;
(_rowRet$i = rowRet[i]).push.apply(_rowRet$i, _toConsumableArray(arr.data[i]));
}
} else {
return new CellError(ErrorType.REF, ErrorMessage.SizeMismatch);
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
var width = rowRet[0].length;
if (totalWidth === undefined) {
totalWidth = width;
ret.push.apply(ret, rowRet);
} else if (totalWidth === width) {
ret.push.apply(ret, rowRet);
} else {
return new CellError(ErrorType.REF, ErrorMessage.SizeMismatch);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return SimpleRangeValue.onlyValues(ret);
}
case AstNodeType.ERROR_WITH_RAW_INPUT:
case AstNodeType.ERROR:
{
return ast.error;
}
}
}
}, {
key: "getGpuInstance",
value: function getGpuInstance() {
var mode = this.config.gpuMode;
var gpujs = this.config.gpujs;
if (gpujs === undefined) {
throw Error('Cannot instantiate GPU.js. Constructor not provided.');
}
if (!this.gpu) {
this.gpu = new gpujs({
mode: mode
});
}
return this.gpu;
}
}, {
key: "destroyGpu",
value: function destroyGpu() {
var _a;
(_a = this.gpu) === null || _a === void 0 ? void 0 : _a.destroy();
}
}, {
key: "rangeSpansOneSheet",
value: function rangeSpansOneSheet(ast) {
return ast.start.sheet === ast.end.sheet;
}
}, {
key: "unaryRangeWrapper",
value: function unaryRangeWrapper(op, arg, state) {
var _a;
if (arg instanceof SimpleRangeValue && !state.arraysFlag) {
arg = (_a = coerceRangeToScalar(arg, state)) !== null && _a !== void 0 ? _a : new CellError(ErrorType.VALUE, ErrorMessage.ScalarExpected);
}
if (arg instanceof CellError) {
return arg;
}
if (arg instanceof SimpleRangeValue) {
var newRaw = arg.data.map(function (row) {
return row.map(op);
});
return SimpleRangeValue.onlyValues(newRaw);
}
return op(arg);
}
}, {
key: "binaryRangeWrapper",
value: function binaryRangeWrapper(op, arg1, arg2, state) {
var _a, _b;
if (arg1 instanceof SimpleRangeValue && !state.arraysFlag) {
arg1 = (_a = coerceRangeToScalar(arg1, state)) !== null && _a !== void 0 ? _a : new CellError(ErrorType.VALUE, ErrorMessage.ScalarExpected);
}
if (arg1 instanceof CellError) {
return arg1;
}
if (arg2 instanceof SimpleRangeValue && !state.arraysFlag) {
arg2 = (_b = coerceRangeToScalar(arg2, state)) !== null && _b !== void 0 ? _b : new CellError(ErrorType.VALUE, ErrorMessage.ScalarExpected);
}
if (arg2 instanceof CellError) {
return arg2;
}
if (arg1 instanceof SimpleRangeValue || arg2 instanceof SimpleRangeValue) {
if (!(arg1 instanceof SimpleRangeValue)) {
if (arg2.isAdHoc()) {
var raw2 = arg2.data;
for (var i = 0; i < raw2.length; i++) {
for (var j = 0; j < raw2[0].length; j++) {
raw2[i][j] = op(arg1, raw2[i][j]);
}
}
return SimpleRangeValue.onlyValues(raw2);
} else {
arg1 = SimpleRangeValue.fromScalar(arg1);
}
}
if (!(arg2 instanceof SimpleRangeValue)) {
if (arg1.isAdHoc()) {
var raw1 = arg1.data;
for (var _i2 = 0; _i2 < raw1.length; _i2++) {
for (var _j = 0; _j < raw1[0].length; _j++) {
raw1[_i2][_j] = op(raw1[_i2][_j], arg2);
}
}
return SimpleRangeValue.onlyValues(raw1);
} else {
arg2 = SimpleRangeValue.fromScalar(arg2);
}
}
if (arg1.width() === arg2.width() && arg1.height() === arg2.height()) {
if (arg1.isAdHoc()) {
var _raw = arg1.data;
var _raw2 = arg2.data;
for (var _i3 = 0; _i3 < _raw.length; _i3++) {
for (var _j2 = 0; _j2 < _raw[0].length; _j2++) {
_raw[_i3][_j2] = op(_raw[_i3][_j2], _raw2[_i3][_j2]);
}
}
return SimpleRangeValue.onlyValues(_raw);
}
if (arg2.isAdHoc()) {
var _raw3 = arg1.data;
var _raw4 = arg2.data;
for (var _i4 = 0; _i4 < _raw3.length; _i4++) {
for (var _j3 = 0; _j3 < _raw3[0].length; _j3++) {
_raw4[_i4][_j3] = op(_raw3[_i4][_j3], _raw4[_i4][_j3]);
}
}
return SimpleRangeValue.onlyValues(_raw4);
}
}
var width = Math.max(arg1.width(), arg2.width());
var height = Math.max(arg1.height(), arg2.height());
var ret = Array(height);
for (var _i5 = 0; _i5 < height; _i5++) {
ret[_i5] = Array(width);
}
for (var _i6 = 0; _i6 < height; _i6++) {
var i1 = arg1.height() !== 1 ? _i6 : 0;
var i2 = arg2.height() !== 1 ? _i6 : 0;
for (var _j4 = 0; _j4 < width; _j4++) {
var j1 = arg1.width() !== 1 ? _j4 : 0;
var j2 = arg2.width() !== 1 ? _j4 : 0;
if (i1 < arg1.height() && i2 < arg2.height() && j1 < arg1.width() && j2 < arg2.width()) {
ret[_i6][_j4] = op(arg1.data[i1][j1], arg2.data[i2][j2]);
} else {
ret[_i6][_j4] = new CellError(ErrorType.NA);
}
}
}
return SimpleRangeValue.onlyValues(ret);
}
return op(arg1, arg2);
}
}]);
return Interpreter;
}();
function unaryErrorWrapper(op, arg) {
if (arg instanceof CellError) {
return arg;
} else {
return op(arg);
}
}
function binaryErrorWrapper(op, arg1, arg2) {
if (arg1 instanceof CellError) {
return arg1;
} else if (arg2 instanceof CellError) {
return arg2;
} else {
return op(arg1, arg2);
}
}
function wrapperForRootVertex(val, vertex) {
if (val instanceof CellError && vertex !== undefined) {
return val.attachRootVertex(vertex);
}
return val;
}