hyperformula-dc
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
453 lines (359 loc) • 18.1 kB
JavaScript
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 _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; }
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 _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 _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 _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; }
import "core-js/modules/es.array.map.js";
import "core-js/modules/es.array.slice.js";
import "core-js/modules/es.number.is-integer.js";
import "core-js/modules/es.number.constructor.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.from.js";
import "core-js/modules/es.function.name.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 } from '../../AbsoluteCellRange';
import { CellError, ErrorType } from '../../Cell';
import { ErrorMessage } from '../../error-message';
import { AstNodeType } from '../../parser';
import { coerceRangeToScalar, coerceScalarToBoolean, coerceScalarToString, coerceToRange } from '../ArithmeticHelper';
import { getRawValue, isExtendedNumber } from '../InterpreterValue';
import { SimpleRangeValue } from '../SimpleRangeValue';
export var ArgumentTypes;
(function (ArgumentTypes) {
/**
* String type.
*/
ArgumentTypes["STRING"] = "STRING";
/**
* Floating point type.
*/
ArgumentTypes["NUMBER"] = "NUMBER";
/**
* Boolean type.
*/
ArgumentTypes["BOOLEAN"] = "BOOLEAN";
/**
* Any non-range value.
*/
ArgumentTypes["SCALAR"] = "SCALAR";
/**
* Any non-range, no-error type.
*/
ArgumentTypes["NOERROR"] = "NOERROR";
/**
* Range type.
*/
ArgumentTypes["RANGE"] = "RANGE";
/**
* Integer type.
*/
ArgumentTypes["INTEGER"] = "INTEGER";
/**
* String representing complex number.
*/
ArgumentTypes["COMPLEX"] = "COMPLEX";
/**
* Range or scalar.
*/
ArgumentTypes["ANY"] = "ANY";
})(ArgumentTypes || (ArgumentTypes = {}));
/**
* Abstract class representing interpreter function plugin.
* Plugin may contain multiple functions. Each function should be of type {@link PluginFunctionType} and needs to be
* included in {@link implementedFunctions}
*/
export var FunctionPlugin = /*#__PURE__*/function () {
function FunctionPlugin(interpreter) {
var _this = this;
_classCallCheck(this, FunctionPlugin);
this.coerceScalarToNumberOrError = function (arg) {
return _this.arithmeticHelper.coerceScalarToNumberOrError(arg);
};
this.runFunction = function (args, state, metadata, fn) {
var _a, _b, _c, _d, _e;
var argumentDefinitions = metadata.parameters;
var argValues;
if (metadata.expandRanges) {
argValues = _this.listOfScalarValues(args, state);
} else {
argValues = args.map(function (ast) {
return [_this.evaluateAst(ast, state), false];
});
}
if (metadata.repeatLastArgs === undefined && argumentDefinitions.length < argValues.length) {
return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber);
}
if (metadata.repeatLastArgs !== undefined && argumentDefinitions.length < argValues.length && (argValues.length - argumentDefinitions.length) % metadata.repeatLastArgs !== 0) {
return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber);
}
argumentDefinitions = _toConsumableArray(argumentDefinitions);
while (argumentDefinitions.length < argValues.length) {
var _argumentDefinitions;
(_argumentDefinitions = argumentDefinitions).push.apply(_argumentDefinitions, _toConsumableArray(argumentDefinitions.slice(argumentDefinitions.length - metadata.repeatLastArgs)));
}
var maxWidth = 1;
var maxHeight = 1;
if (!metadata.vectorizationForbidden && state.arraysFlag) {
for (var i = 0; i < argValues.length; i++) {
var _argValues$i = _slicedToArray(argValues[i], 1),
val = _argValues$i[0];
if (val instanceof SimpleRangeValue && argumentDefinitions[i].argumentType !== ArgumentTypes.RANGE && argumentDefinitions[i].argumentType !== ArgumentTypes.ANY) {
maxHeight = Math.max(maxHeight, val.height());
maxWidth = Math.max(maxWidth, val.width());
}
}
}
for (var _i2 = argValues.length; _i2 < argumentDefinitions.length; _i2++) {
if (((_a = argumentDefinitions[_i2]) === null || _a === void 0 ? void 0 : _a.defaultValue) === undefined) {
if (!((_b = argumentDefinitions[_i2]) === null || _b === void 0 ? void 0 : _b.optionalArg)) {
//not enough values passed as arguments, and there was no default value and argument was not optional
return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber);
}
}
}
var retArr = [];
for (var row = 0; row < maxHeight; row++) {
var rowArr = [];
for (var col = 0; col < maxWidth; col++) {
var argCoerceFailure = undefined;
var coercedArguments = [];
for (var _i3 = 0; _i3 < argumentDefinitions.length; _i3++) {
// eslint-disable-next-line prefer-const
var _ref = (_c = argValues[_i3]) !== null && _c !== void 0 ? _c : [undefined, undefined],
_ref2 = _slicedToArray(_ref, 2),
_val = _ref2[0],
ignorable = _ref2[1];
if (_val instanceof SimpleRangeValue && argumentDefinitions[_i3].argumentType !== ArgumentTypes.RANGE && argumentDefinitions[_i3].argumentType !== ArgumentTypes.ANY) {
if (!metadata.vectorizationForbidden && state.arraysFlag) {
_val = (_d = _val.data[_val.height() !== 1 ? row : 0]) === null || _d === void 0 ? void 0 : _d[_val.width() !== 1 ? col : 0];
}
}
var arg = _val !== null && _val !== void 0 ? _val : (_e = argumentDefinitions[_i3]) === null || _e === void 0 ? void 0 : _e.defaultValue;
if (arg === undefined) {
coercedArguments.push(undefined); //we verified in previous loop that this arg is optional
} else {
//we apply coerce only to non-default values
var coercedArg = _val !== undefined ? _this.coerceToType(arg, argumentDefinitions[_i3], state) : arg;
if (coercedArg !== undefined) {
if (coercedArg instanceof CellError && argumentDefinitions[_i3].argumentType !== ArgumentTypes.SCALAR) {
//if this is first error encountered, store it
argCoerceFailure = argCoerceFailure !== null && argCoerceFailure !== void 0 ? argCoerceFailure : coercedArg;
}
coercedArguments.push(coercedArg);
} else if (!ignorable) {
//if this is first error encountered, store it
argCoerceFailure = argCoerceFailure !== null && argCoerceFailure !== void 0 ? argCoerceFailure : new CellError(ErrorType.VALUE, ErrorMessage.WrongType);
}
}
}
var ret = argCoerceFailure !== null && argCoerceFailure !== void 0 ? argCoerceFailure : _this.returnNumberWrapper(fn.apply(void 0, coercedArguments), metadata.returnNumberType);
if (maxHeight === 1 && maxWidth === 1) {
return ret;
}
if (ret instanceof SimpleRangeValue) {
throw 'Function returning array cannot be vectorized.';
}
rowArr.push(ret);
}
retArr.push(rowArr);
}
return SimpleRangeValue.onlyValues(retArr);
};
this.runFunctionWithReferenceArgument = function (args, state, metadata, noArgCallback, referenceCallback) {
var nonReferenceCallback = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : function () {
return new CellError(ErrorType.NA, ErrorMessage.CellRefExpected);
};
if (args.length === 0) {
return _this.returnNumberWrapper(noArgCallback(), metadata.returnNumberType);
} else if (args.length > 1) {
return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber);
}
var arg = args[0];
while (arg.type === AstNodeType.PARENTHESIS) {
arg = arg.expression;
}
var cellReference;
if (arg.type === AstNodeType.CELL_REFERENCE) {
cellReference = arg.reference.toSimpleCellAddress(state.formulaAddress);
} else if (arg.type === AstNodeType.CELL_RANGE || arg.type === AstNodeType.COLUMN_RANGE || arg.type === AstNodeType.ROW_RANGE) {
try {
cellReference = AbsoluteCellRange.fromAst(arg, state.formulaAddress).start;
} catch (e) {
return new CellError(ErrorType.REF, ErrorMessage.CellRefExpected);
}
}
if (cellReference !== undefined) {
return _this.returnNumberWrapper(referenceCallback(cellReference), metadata.returnNumberType);
}
return _this.runFunction(args, state, metadata, nonReferenceCallback);
};
this.interpreter = interpreter;
this.dependencyGraph = interpreter.dependencyGraph;
this.columnSearch = interpreter.columnSearch;
this.config = interpreter.config;
this.serialization = interpreter.serialization;
this.arraySizePredictor = interpreter.arraySizePredictor;
this.dateTimeHelper = interpreter.dateTimeHelper;
this.arithmeticHelper = interpreter.arithmeticHelper;
}
_createClass(FunctionPlugin, [{
key: "evaluateAst",
value: function evaluateAst(ast, state) {
return this.interpreter.evaluateAst(ast, state);
}
}, {
key: "arraySizeForAst",
value: function arraySizeForAst(ast, state) {
return this.arraySizePredictor.checkArraySizeForAst(ast, state);
}
}, {
key: "listOfScalarValues",
value: function listOfScalarValues(asts, state) {
var ret = [];
var _iterator = _createForOfIteratorHelper(asts),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var argAst = _step.value;
var value = this.evaluateAst(argAst, state);
if (value instanceof SimpleRangeValue) {
var _iterator2 = _createForOfIteratorHelper(value.valuesFromTopLeftCorner()),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var scalarValue = _step2.value;
ret.push([scalarValue, true]);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
} else {
ret.push([value, false]);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return ret;
}
}, {
key: "coerceToType",
value: function coerceToType(arg, coercedType, state) {
var ret;
if (arg instanceof SimpleRangeValue) {
switch (coercedType.argumentType) {
case ArgumentTypes.RANGE:
case ArgumentTypes.ANY:
ret = arg;
break;
default:
{
var coerce = coerceRangeToScalar(arg, state);
if (coerce === undefined) {
return undefined;
}
arg = coerce;
}
}
}
if (!(arg instanceof SimpleRangeValue)) {
switch (coercedType.argumentType) {
case ArgumentTypes.INTEGER:
case ArgumentTypes.NUMBER:
// eslint-disable-next-line no-case-declarations
var coerced = this.coerceScalarToNumberOrError(arg);
if (!isExtendedNumber(coerced)) {
ret = coerced;
break;
} // eslint-disable-next-line no-case-declarations
var value = getRawValue(coerced);
if (coercedType.maxValue !== undefined && value > coercedType.maxValue) {
return new CellError(ErrorType.NUM, ErrorMessage.ValueLarge);
}
if (coercedType.minValue !== undefined && value < coercedType.minValue) {
return new CellError(ErrorType.NUM, ErrorMessage.ValueSmall);
}
if (coercedType.lessThan !== undefined && value >= coercedType.lessThan) {
return new CellError(ErrorType.NUM, ErrorMessage.ValueLarge);
}
if (coercedType.greaterThan !== undefined && value <= coercedType.greaterThan) {
return new CellError(ErrorType.NUM, ErrorMessage.ValueSmall);
}
if (coercedType.argumentType === ArgumentTypes.INTEGER && !Number.isInteger(value)) {
return new CellError(ErrorType.NUM, ErrorMessage.IntegerExpected);
}
ret = coerced;
break;
case ArgumentTypes.STRING:
ret = coerceScalarToString(arg);
break;
case ArgumentTypes.BOOLEAN:
ret = coerceScalarToBoolean(arg);
break;
case ArgumentTypes.SCALAR:
case ArgumentTypes.NOERROR:
case ArgumentTypes.ANY:
ret = arg;
break;
case ArgumentTypes.RANGE:
if (arg instanceof CellError) {
return arg;
}
ret = coerceToRange(arg);
break;
case ArgumentTypes.COMPLEX:
return this.arithmeticHelper.coerceScalarToComplex(getRawValue(arg));
}
}
if (coercedType.passSubtype || ret === undefined) {
return ret;
} else {
return getRawValue(ret);
}
}
}, {
key: "metadata",
value: function metadata(name) {
var params = this.constructor.implementedFunctions[name];
if (params !== undefined) {
return params;
}
throw new Error("No metadata for function ".concat(name, "."));
}
}, {
key: "returnNumberWrapper",
value: function returnNumberWrapper(val, type, format) {
if (type !== undefined && isExtendedNumber(val)) {
return this.arithmeticHelper.ExtendedNumberFactory(getRawValue(val), {
type: type,
format: format
});
} else {
return val;
}
}
}]);
return FunctionPlugin;
}();