From b01927ee88ea180642e66670a2d7bee30ab9cc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Uzna=C5=84ski?= <40573492+izulin@users.noreply.github.com> Date: Fri, 28 May 2021 14:46:38 +0200 Subject: [PATCH] Pu/vectorization (#673) * parsing of matrices * size prediction * evaluation, parsing, unparsing * tests * doc * linter * compiles * linter * small refactor * kind of works * cleanup * linter * extra config options * tests * config * Update CHANGELOG.md * docs --- CHANGELOG.md | 2 + docs/guide/built-in-functions.md | 2 +- docs/guide/custom-functions.md | 8 + src/MatrixSize.ts | 31 +++- src/interpreter/plugin/AbsPlugin.ts | 4 +- src/interpreter/plugin/ArrayPlugin.ts | 7 +- src/interpreter/plugin/BitShiftPlugin.ts | 6 +- .../plugin/BitwiseLogicOperationsPlugin.ts | 8 +- src/interpreter/plugin/BooleanPlugin.ts | 62 +++---- src/interpreter/plugin/CharPlugin.ts | 6 +- src/interpreter/plugin/CodePlugin.ts | 6 +- src/interpreter/plugin/ComplexPlugin.ts | 54 +++--- src/interpreter/plugin/CountBlankPlugin.ts | 4 +- src/interpreter/plugin/CountUniquePlugin.ts | 4 +- src/interpreter/plugin/DateTimePlugin.ts | 56 +++--- src/interpreter/plugin/DegreesPlugin.ts | 4 +- src/interpreter/plugin/DeltaPlugin.ts | 4 +- src/interpreter/plugin/ExpPlugin.ts | 4 +- src/interpreter/plugin/FinancialPlugin.ts | 56 +++--- src/interpreter/plugin/FormulaTextPlugin.ts | 7 +- src/interpreter/plugin/FunctionPlugin.ts | 170 +++++++++++------- src/interpreter/plugin/InformationPlugin.ts | 58 +++--- src/interpreter/plugin/IsEvenPlugin.ts | 4 +- src/interpreter/plugin/IsOddPlugin.ts | 4 +- src/interpreter/plugin/LogarithmPlugin.ts | 8 +- src/interpreter/plugin/LookupPlugin.ts | 8 +- src/interpreter/plugin/MathConstantsPlugin.ts | 6 +- src/interpreter/plugin/MathPlugin.ts | 30 ++-- src/interpreter/plugin/MatrixPlugin.ts | 12 +- src/interpreter/plugin/MedianPlugin.ts | 8 +- src/interpreter/plugin/ModuloPlugin.ts | 4 +- src/interpreter/plugin/PowerPlugin.ts | 4 +- src/interpreter/plugin/RadiansPlugin.ts | 4 +- .../plugin/RadixConversionPlugin.ts | 30 ++-- src/interpreter/plugin/RandomPlugin.ts | 6 +- src/interpreter/plugin/RomanPlugin.ts | 6 +- src/interpreter/plugin/RoundingPlugin.ts | 38 ++-- src/interpreter/plugin/SimpleArithmertic.ts | 32 ++-- src/interpreter/plugin/SqrtPlugin.ts | 4 +- .../plugin/StatisticalAggregationPlugin.ts | 52 +++--- src/interpreter/plugin/StatisticalPlugin.ts | 94 +++++----- src/interpreter/plugin/SumifPlugin.ts | 12 +- src/interpreter/plugin/SumprodPlugin.ts | 4 +- src/interpreter/plugin/TextPlugin.ts | 38 ++-- src/interpreter/plugin/TrigonometryPlugin.ts | 44 ++--- src/parser/FormulaParser.ts | 3 + test/arrays.spec.ts | 72 ++++++++ test/interpreter/aliases.spec.ts | 4 + test/interpreter/function-switch.spec.ts | 8 - test/interpreter/function-trunc.spec.ts | 70 -------- 50 files changed, 627 insertions(+), 545 deletions(-) delete mode 100644 test/interpreter/function-trunc.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index db4a369d84..bf23cf6156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added ARRAY_CONSTRAIN function. (#661) - Added casting to scalars from non-range arrays. (#663) - Added support for range interpolation. (#665) +- Added parsing of arrays in formulas (together with respective config options for separators). (#671) +- Added support for vectorization of scalar functions. (#673) - Added support for time in JS `Date()` objects on the input. (#648) - Added validation of API argument types for simple types. (#654) - Added named expression handling to engine factories. (#680) diff --git a/docs/guide/built-in-functions.md b/docs/guide/built-in-functions.md index d43e727873..63142f14a6 100644 --- a/docs/guide/built-in-functions.md +++ b/docs/guide/built-in-functions.md @@ -216,7 +216,7 @@ Total number of functions: **{{ $page.functionsCount }}** | IFNA | Returns the value if the cell does not contains the #N/A (value not available) error value, or the alternative value if it does. | IFNA(Value; Alternate_value) | | IFERROR | Returns the value if the cell does not contains an error value, or the alternative value if it does. | IFERROR(Value; Alternate_value) | | NOT | Complements (inverts) a logical value. | NOT(Logicalvalue) | -| SWITCH | For each value on the input array, tests its value against cases and returns corresponding value. | SWITCH(Array; Case1, Value1[, Case2, Value2[..., Case_n, Value_n[, Default]]]) | +| SWITCH | Evaluates a list of arguments, consisting of an expression followed by a value. | SWITCH(Expression1, Value1[, Expression2, Value2[..., Expression_n, Value_n]]) | | OR | Returns TRUE if at least one argument is TRUE. | OR(Logicalvalue1; Logicalvalue2 ...Logicalvalue30) | | TRUE | The logical value is set to TRUE. | TRUE() | | XOR | Returns true if an odd number of arguments evaluates to TRUE. | XOR(Logicalvalue1; Logicalvalue2 ...Logicalvalue30) | diff --git a/docs/guide/custom-functions.md b/docs/guide/custom-functions.md index 87486f7007..e3cbad067f 100644 --- a/docs/guide/custom-functions.md +++ b/docs/guide/custom-functions.md @@ -57,6 +57,14 @@ class CountHF extends FunctionPlugin { }; } ``` + +Similarly, there are other useful properties. +`isDependentOnSheetStructureChange` marks functions that need to be recalculated with +each change of the shape of the engine sheets. +`doesNotNeedArgumentsToBeComputed` marks functions that treat references or ranges in their arguments +as arguments that do not create dependency. Other arguments are properly evaluated. +`arrayFunction` denotes functions that enable array arithmetic in its arguments and nested expressions. +`vectorizationForbidden` when set prevents function from ever being vectorized (however, it is up to implementation of a function to properly handle vectorization). ## Aliases Aliases are available since the version. diff --git a/src/MatrixSize.ts b/src/MatrixSize.ts index 315d9214c7..cde19ea675 100644 --- a/src/MatrixSize.ts +++ b/src/MatrixSize.ts @@ -4,10 +4,13 @@ */ import {AbsoluteCellRange} from './AbsoluteCellRange' -import {SimpleCellAddress} from './Cell' +import {CellError, ErrorType, SimpleCellAddress} from './Cell' import {Config} from './Config' +import {ErrorMessage} from './error-message' import {FunctionRegistry} from './interpreter/FunctionRegistry' import {InterpreterState} from './interpreter/InterpreterState' +import {ArgumentTypes} from './interpreter/plugin/FunctionPlugin' +import {SimpleRangeValue} from './interpreter/SimpleRangeValue' import {Ast, AstNodeType} from './parser' export class MatrixSize { @@ -169,7 +172,31 @@ export class MatrixSizePredictor { return new MatrixSize(width, height) } default: { - return new MatrixSize(1, 1) + if(metadata === undefined || metadata.expandRanges || !state.arraysFlag || metadata.vectorizationForbidden || metadata.parameters === undefined) { + return new MatrixSize(1, 1) + } + const argumentDefinitions = [...metadata.parameters] + if (metadata.repeatLastArgs === undefined && argumentDefinitions.length < subChecks.length) { + return MatrixSize.error() + } + if (metadata.repeatLastArgs !== undefined && argumentDefinitions.length < subChecks.length && + (subChecks.length - argumentDefinitions.length) % metadata.repeatLastArgs !== 0) { + return MatrixSize.error() + } + + while(argumentDefinitions.length < subChecks.length) { + argumentDefinitions.push(...argumentDefinitions.slice(argumentDefinitions.length-metadata.repeatLastArgs!)) + } + + let maxWidth = 1 + let maxHeight = 1 + for(let i=0;i{ @@ -18,7 +18,7 @@ export class AbsPlugin extends FunctionPlugin implements FunctionPluginTypecheck }, } - public abs(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public abs(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ABS'), Math.abs) } } diff --git a/src/interpreter/plugin/ArrayPlugin.ts b/src/interpreter/plugin/ArrayPlugin.ts index 957ab94929..bd0a2f24be 100644 --- a/src/interpreter/plugin/ArrayPlugin.ts +++ b/src/interpreter/plugin/ArrayPlugin.ts @@ -28,6 +28,7 @@ export class ArrayPlugin extends FunctionPlugin implements FunctionPluginTypeche {argumentType: ArgumentTypes.INTEGER, minValue: 1}, {argumentType: ArgumentTypes.INTEGER, minValue: 1}, ], + vectorizationForbidden: true, }, 'FILTER': { method: 'filter', @@ -40,12 +41,12 @@ export class ArrayPlugin extends FunctionPlugin implements FunctionPluginTypeche } } - public arrayformula(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public arrayformula(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ARRAYFORMULA'), (value) => value) } public arrayconstrain(ast: ProcedureAst, state: InterpreterState): InterpreterValue { - return this.runMatrixFunction(ast.args, state, this.metadata('ARRAY_CONSTRAIN'), (range: SimpleRangeValue, numRows: number, numCols: number) => { + return this.runFunction(ast.args, state, this.metadata('ARRAY_CONSTRAIN'), (range: SimpleRangeValue, numRows: number, numCols: number) => { numRows = Math.min(numRows, range.height()) numCols = Math.min(numCols, range.width()) const data: InternalScalarValue[][] = range.data @@ -58,7 +59,7 @@ export class ArrayPlugin extends FunctionPlugin implements FunctionPluginTypeche } public filter(ast: ProcedureAst, state: InterpreterState): InterpreterValue { - return this.runMatrixFunction(ast.args, state, this.metadata('FILTER'), (rangeVals: SimpleRangeValue, ...rangeFilters: SimpleRangeValue[]) => { + return this.runFunction(ast.args, state, this.metadata('FILTER'), (rangeVals: SimpleRangeValue, ...rangeFilters: SimpleRangeValue[]) => { for(const filter of rangeFilters) { if (rangeVals.width() !== filter.width() || rangeVals.height() !== filter.height()) { return new CellError(ErrorType.NA, ErrorMessage.EqualLength) diff --git a/src/interpreter/plugin/BitShiftPlugin.ts b/src/interpreter/plugin/BitShiftPlugin.ts index 99eea2a973..a22dcf1965 100644 --- a/src/interpreter/plugin/BitShiftPlugin.ts +++ b/src/interpreter/plugin/BitShiftPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' const MAX_48BIT_INTEGER = 281474976710655 @@ -32,11 +32,11 @@ export class BitShiftPlugin extends FunctionPlugin implements FunctionPluginType }, } - public bitlshift(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bitlshift(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BITLSHIFT'), shiftLeft) } - public bitrshift(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bitrshift(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BITRSHIFT'), shiftRight) } } diff --git a/src/interpreter/plugin/BitwiseLogicOperationsPlugin.ts b/src/interpreter/plugin/BitwiseLogicOperationsPlugin.ts index 8a2f90c540..90ec6dab3f 100644 --- a/src/interpreter/plugin/BitwiseLogicOperationsPlugin.ts +++ b/src/interpreter/plugin/BitwiseLogicOperationsPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class BitwiseLogicOperationsPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -33,19 +33,19 @@ export class BitwiseLogicOperationsPlugin extends FunctionPlugin implements Func }, } - public bitand(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bitand(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BITAND'), (left: number, right: number) => left & right ) } - public bitor(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bitor(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BITOR'), (left: number, right: number) => left | right ) } - public bitxor(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bitxor(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BITXOR'), (left: number, right: number) => left ^ right ) diff --git a/src/interpreter/plugin/BooleanPlugin.ts b/src/interpreter/plugin/BooleanPlugin.ts index 43d621dd30..d7dd2cffa8 100644 --- a/src/interpreter/plugin/BooleanPlugin.ts +++ b/src/interpreter/plugin/BooleanPlugin.ts @@ -65,11 +65,11 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec 'SWITCH': { method: 'switch', parameters: [ - {argumentType: ArgumentTypes.RANGE}, + {argumentType: ArgumentTypes.NOERROR}, {argumentType: ArgumentTypes.SCALAR, passSubtype: true}, {argumentType: ArgumentTypes.SCALAR, passSubtype: true}, ], - repeatLastArgs: 1, + repeatLastArgs: 1, }, 'IFERROR': { method: 'iferror', @@ -103,7 +103,7 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec * @param ast * @param state */ - public literalTrue(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public literalTrue(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TRUE'), () => true) } @@ -115,7 +115,7 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec * @param ast * @param state */ - public literalFalse(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public literalFalse(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FALSE'), () => false) } @@ -141,7 +141,7 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec * @param ast * @param state */ - public and(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public and(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('AND'), (...args) => !args.some((arg: boolean) => !arg) ) @@ -155,17 +155,17 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec * @param ast * @param state */ - public or(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public or(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('OR'), (...args) => args.some((arg: boolean) => arg) ) } - public not(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public not(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NOT'), (arg) => !arg) } - public xor(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public xor(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('XOR'), (...args) => { let cnt = 0 args.forEach((arg: boolean) => { @@ -177,37 +177,27 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec }) } - public switch(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { - return this.runMatrixFunction(ast.args, state, this.metadata('SWITCH'), (selectorArr: SimpleRangeValue, ...args) => { + public switch(ast: ProcedureAst, state: InterpreterState): InterpreterValue { + return this.runFunction(ast.args, state, this.metadata('SWITCH'), (selector, ...args) => { const n = args.length - const ret: InternalScalarValue[][] = [] - for(const row of selectorArr.data) { - const newrow: InternalScalarValue[] = row.map( (selector) => { - let i = 0 - if(selector instanceof CellError) { - return selector - } - for (; i + 1 < n; i += 2) { - if (args[i] instanceof CellError) { - continue - } - if (this.interpreter.arithmeticHelper.eq(selector, args[i] as InternalNoErrorScalarValue)) { - return args[i + 1] - } - } - if (i < n) { - return args[i] - } else { - return new CellError(ErrorType.NA, ErrorMessage.NoDefault) - } - }) - ret.push(newrow) + let i = 0 + for (; i + 1 < n; i += 2) { + if (args[i] instanceof CellError) { + continue + } + if (this.interpreter.arithmeticHelper.eq(selector, args[i] as InternalNoErrorScalarValue)) { + return args[i + 1] + } + } + if (i < n) { + return args[i] + } else { + return new CellError(ErrorType.NA, ErrorMessage.NoDefault) } - return SimpleRangeValue.onlyValues(ret) }) } - public iferror(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public iferror(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IFERROR'), (arg1: InternalScalarValue, arg2: InternalScalarValue) => { if (arg1 instanceof CellError) { return arg2 @@ -217,7 +207,7 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec }) } - public ifna(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ifna(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IFNA'), (arg1: InternalScalarValue, arg2: InternalScalarValue) => { if (arg1 instanceof CellError && arg1.type === ErrorType.NA) { return arg2 @@ -227,7 +217,7 @@ export class BooleanPlugin extends FunctionPlugin implements FunctionPluginTypec }) } - public choose(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public choose(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHOOSE'), (selector, ...args) => { if (selector > args.length) { return new CellError(ErrorType.NUM, ErrorMessage.Selector) diff --git a/src/interpreter/plugin/CharPlugin.ts b/src/interpreter/plugin/CharPlugin.ts index 25b63932cf..f82abbc770 100644 --- a/src/interpreter/plugin/CharPlugin.ts +++ b/src/interpreter/plugin/CharPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class CharPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -26,7 +26,7 @@ export class CharPlugin extends FunctionPlugin implements FunctionPluginTypechec }, } - public char(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public char(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHAR'), (value: number) => { if (value < 1 || value >= 256) { return new CellError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds) @@ -36,7 +36,7 @@ export class CharPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public unichar(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public unichar(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHAR'), (value: number) => { if (value < 1 || value >= 1114112) { return new CellError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds) diff --git a/src/interpreter/plugin/CodePlugin.ts b/src/interpreter/plugin/CodePlugin.ts index 68603c47d7..9b26956b39 100644 --- a/src/interpreter/plugin/CodePlugin.ts +++ b/src/interpreter/plugin/CodePlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class CodePlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -26,7 +26,7 @@ export class CodePlugin extends FunctionPlugin implements FunctionPluginTypechec }, } - public code(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public code(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CODE'), (value: string) => { if (value.length === 0) { return new CellError(ErrorType.VALUE, ErrorMessage.EmptyString) @@ -35,7 +35,7 @@ export class CodePlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public unicode(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public unicode(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('UNICODE'), (value: string) => { return value.codePointAt(0) ?? new CellError(ErrorType.VALUE, ErrorMessage.EmptyString) }) diff --git a/src/interpreter/plugin/ComplexPlugin.ts b/src/interpreter/plugin/ComplexPlugin.ts index 460c341187..e3c7adeed9 100644 --- a/src/interpreter/plugin/ComplexPlugin.ts +++ b/src/interpreter/plugin/ComplexPlugin.ts @@ -8,7 +8,7 @@ import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {coerceComplexToString, complex} from '../ArithmeticHelper' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue, RawInterpreterValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue, RawInterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class ComplexPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -178,7 +178,7 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType }, } - public complex(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public complex(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COMPLEX'), (re: number, im: number, unit: string) => { if(unit !== 'i' && unit !== 'j') { @@ -189,23 +189,23 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType ) } - public imabs(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imabs(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMABS'), abs) } - public imaginary(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imaginary(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMAGINARY'), ([re, im]: complex) => im ) } - public imreal(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imreal(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMREAL'), ([re, im]: complex) => re ) } - public imargument(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imargument(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMARGUMENT'), ([re, im]: complex) => { if(re===0 && im===0) { @@ -216,79 +216,79 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType ) } - public imconjugate(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imconjugate(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMCONJUGATE'), ([re, im]: complex) => coerceComplexToString([re, -im]) ) } - public imcos(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imcos(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMCOS'), (arg: complex) => coerceComplexToString(cos(arg)) ) } - public imcosh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imcosh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMCOSH'), (arg: complex) => coerceComplexToString(cosh(arg)) ) } - public imcot(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imcot(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMCOT'), (arg: complex) => coerceComplexToString(div(cos(arg), sin(arg))) ) } - public imcsc(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imcsc(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMCSC'), (arg: complex) => coerceComplexToString(div([1, 0], sin(arg))) ) } - public imcsch(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imcsch(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMCSCH'), (arg: complex) => coerceComplexToString(div([1, 0], sinh(arg))) ) } - public imsec(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsec(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSEC'), (arg: complex) => coerceComplexToString(div([1, 0], cos(arg))) ) } - public imsech(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsech(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSECH'), (arg: complex) => coerceComplexToString(div([1, 0], cosh(arg))) ) } - public imsin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSIN'), (arg: complex) => coerceComplexToString(sin(arg)) ) } - public imsinh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsinh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSINH'), (arg: complex) => coerceComplexToString(sinh(arg)) ) } - public imtan(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imtan(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMTAN'), (arg: complex) => coerceComplexToString(div(sin(arg), cos(arg))) ) } - public imdiv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imdiv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMDIV'), (arg1: complex, arg2: complex) => coerceComplexToString(div(arg1, arg2)) ) } - public improduct(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public improduct(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMPRODUCT'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceComplexExactRanges(args) @@ -304,7 +304,7 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType ) } - public imsum(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsum(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSUM'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceComplexExactRanges(args) @@ -320,25 +320,25 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType ) } - public imsub(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsub(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSUB'), (arg1: complex, arg2: complex) => coerceComplexToString(sub(arg1, arg2)) ) } - public imexp(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imexp(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMEXP'), (arg: complex) => coerceComplexToString(exp(arg)) ) } - public imln(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imln(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMLN'), (arg: complex) => coerceComplexToString(ln(arg)) ) } - public imlog10(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imlog10(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMLOG10'), (arg: complex) => { const [re, im] = ln(arg) @@ -348,7 +348,7 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType ) } - public imlog2(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imlog2(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMLOG2'), (arg: complex) => { const [re, im] = ln(arg) @@ -358,13 +358,13 @@ export class ComplexPlugin extends FunctionPlugin implements FunctionPluginType ) } - public impower(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public impower(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMPOWER'), (arg: complex, n: number) => coerceComplexToString(power(arg, n)) ) } - public imsqrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public imsqrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IMSQRT'), (arg: complex) => coerceComplexToString(power(arg, 0.5)) ) diff --git a/src/interpreter/plugin/CountBlankPlugin.ts b/src/interpreter/plugin/CountBlankPlugin.ts index 812dd59256..e9327f4eea 100644 --- a/src/interpreter/plugin/CountBlankPlugin.ts +++ b/src/interpreter/plugin/CountBlankPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {EmptyValue, InternalScalarValue, RawScalarValue} from '../InterpreterValue' +import {EmptyValue, InternalScalarValue, InterpreterValue, RawScalarValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' /** @@ -24,7 +24,7 @@ export class CountBlankPlugin extends FunctionPlugin implements FunctionPluginTy }, } - public countblank(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public countblank(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COUNTBLANK'), (...args: RawScalarValue[]) => { let counter = 0 args.forEach((arg) => { diff --git a/src/interpreter/plugin/CountUniquePlugin.ts b/src/interpreter/plugin/CountUniquePlugin.ts index 929619dc0c..35cdba5220 100644 --- a/src/interpreter/plugin/CountUniquePlugin.ts +++ b/src/interpreter/plugin/CountUniquePlugin.ts @@ -6,7 +6,7 @@ import {CellError, ErrorType} from '../../Cell' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {EmptyValueType, InternalScalarValue, RawScalarValue} from '../InterpreterValue' +import {EmptyValueType, InternalScalarValue, InterpreterValue, RawScalarValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' /** @@ -32,7 +32,7 @@ export class CountUniquePlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public countunique(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public countunique(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COUNTUNIQUE'), (...args: RawScalarValue[]) => { const valuesSet = new Set() const errorsSet = new Set() diff --git a/src/interpreter/plugin/DateTimePlugin.ts b/src/interpreter/plugin/DateTimePlugin.ts index 67c643f3cd..5f55615fba 100644 --- a/src/interpreter/plugin/DateTimePlugin.ts +++ b/src/interpreter/plugin/DateTimePlugin.ts @@ -24,7 +24,7 @@ import { EmptyValue, getRawValue, InternalNoErrorScalarValue, - InternalScalarValue, + InternalScalarValue, InterpreterValue, isExtendedNumber, NumberType, RawNoErrorScalarValue, @@ -242,7 +242,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType * @param ast * @param state */ - public date(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public date(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DATE'), (year, month, day) => { const d = Math.trunc(day) let m = Math.trunc(month) @@ -267,7 +267,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType }) } - public time(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public time(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TIME'), (h, m, s) => { const ret = timeToNumber({hours: Math.trunc(h), minutes: Math.trunc(m), seconds: Math.trunc(s)}) @@ -279,7 +279,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public eomonth(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public eomonth(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EOMONTH'), (dateNumber, numberOfMonthsToShift) => { const date = this.interpreter.dateHelper.numberToSimpleDate(dateNumber) let ret: Maybe = this.interpreter.dateHelper.dateToNumber(this.interpreter.dateHelper.endOfMonth(offsetMonth(date, numberOfMonthsToShift))) @@ -291,13 +291,13 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType }) } - public day(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public day(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DAY'), (dateNumber) => this.interpreter.dateHelper.numberToSimpleDate(dateNumber).day ) } - public days(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public days(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DAYS'), (endDate, startDate) => Math.trunc(endDate) - Math.trunc(startDate)) } @@ -309,7 +309,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType * @param ast * @param state */ - public month(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public month(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MONTH'), (dateNumber) => this.interpreter.dateHelper.numberToSimpleDate(dateNumber).month ) @@ -323,25 +323,25 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType * @param ast * @param state */ - public year(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public year(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('YEAR'), (dateNumber) => this.interpreter.dateHelper.numberToSimpleDate(dateNumber).year ) } - public hour(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public hour(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HOUR'), (timeNumber) => numberToSimpleTime(roundToNearestSecond(timeNumber)%1).hours ) } - public minute(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public minute(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MINUTE'), (timeNumber) => numberToSimpleTime(roundToNearestSecond(timeNumber)%1).minutes ) } - public second(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public second(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SECOND'), (timeNumber) => numberToSimpleTime(roundToNearestSecond(timeNumber)%1).seconds ) @@ -355,13 +355,13 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType * @param ast * @param state */ - public text(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public text(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TEXT'), (numberRepresentation, formatArg) => format(numberRepresentation, formatArg, this.config, this.interpreter.dateHelper) ) } - public weekday(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public weekday(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('WEEKDAY'), (day: number, type: number) => { const absoluteDay = Math.floor(this.interpreter.dateHelper.relativeNumberToAbsoluteNumber(day)) @@ -377,7 +377,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public weeknum(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public weeknum(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('WEEKNUM'), (day: number, type: number) => { const absoluteDay = Math.floor(this.interpreter.dateHelper.relativeNumberToAbsoluteNumber(day)) @@ -396,7 +396,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public isoweeknum(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isoweeknum(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISOWEEKNUM'), this.isoweeknumCore) } @@ -413,7 +413,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType return ret } - public datevalue(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public datevalue(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DATEVALUE'), (date: string) => { const {dateTime} = this.interpreter.dateHelper.parseDateTimeFromConfigFormats(date) @@ -429,7 +429,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public timevalue(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public timevalue(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TIMEVALUE'), (date: string) => { const dateNumber = this.interpreter.dateHelper.dateStringToDateNumber(date) @@ -441,7 +441,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public now(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public now(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NOW'), () => { const now = new Date() @@ -451,7 +451,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public today(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public today(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TODAY'), () => { const now = new Date() @@ -460,7 +460,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public edate(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public edate(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EDATE'), (dateNumber: number, delta: number) => { const date = this.interpreter.dateHelper.numberToSimpleDate(dateNumber) @@ -475,7 +475,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public datedif(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public datedif(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DATEDIF'), (startDate: number, endDate: number, unit: string) => { if(startDate > endDate) { @@ -522,7 +522,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public days360(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public days360(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DAYS360'), this.days360Core) } @@ -539,7 +539,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType return 360 * (nEnd.year - nStart.year) + 30*(nEnd.month-nStart.month) + nEnd.day-nStart.day } - public yearfrac(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public yearfrac(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('YEARFRAC'), (startDate: number, endDate: number, mode: number) => { startDate = Math.trunc(startDate) @@ -567,7 +567,7 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public interval(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public interval(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('INTERVAL'), (arg: number) => { arg = Math.trunc(arg) @@ -593,25 +593,25 @@ export class DateTimePlugin extends FunctionPlugin implements FunctionPluginType ) } - public networkdays(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public networkdays(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NETWORKDAYS'), (start, end, holidays) => this.networkdayscore(start, end, 1, holidays) ) } - public networkdaysintl(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public networkdaysintl(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NETWORKDAYS.INTL'), (start, end, weekend, holidays) => this.networkdayscore(start, end, weekend, holidays) ) } - public workday(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public workday(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('WORKDAY'), (start, end, holidays) => this.workdaycore(start, end, 1, holidays) ) } - public workdayintl(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public workdayintl(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('WORKDAY.INTL'), (start, end, weekend, holidays) => this.workdaycore(start, end, weekend, holidays) ) diff --git a/src/interpreter/plugin/DegreesPlugin.ts b/src/interpreter/plugin/DegreesPlugin.ts index d7167e4b6a..b1c68b2aa4 100644 --- a/src/interpreter/plugin/DegreesPlugin.ts +++ b/src/interpreter/plugin/DegreesPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class DegreesPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -18,7 +18,7 @@ export class DegreesPlugin extends FunctionPlugin implements FunctionPluginTypec }, } - public degrees(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public degrees(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DEGREES'), (arg) => arg * (180 / Math.PI) ) diff --git a/src/interpreter/plugin/DeltaPlugin.ts b/src/interpreter/plugin/DeltaPlugin.ts index 8a96c567bc..aee6d74869 100644 --- a/src/interpreter/plugin/DeltaPlugin.ts +++ b/src/interpreter/plugin/DeltaPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class DeltaPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -19,7 +19,7 @@ export class DeltaPlugin extends FunctionPlugin implements FunctionPluginTypeche }, } - public delta(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public delta(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DELTA'), (left: number, right: number) => (left === right ? 1 : 0) ) diff --git a/src/interpreter/plugin/ExpPlugin.ts b/src/interpreter/plugin/ExpPlugin.ts index 9ce4d19ccc..cce6ef8d80 100644 --- a/src/interpreter/plugin/ExpPlugin.ts +++ b/src/interpreter/plugin/ExpPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class ExpPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -26,7 +26,7 @@ export class ExpPlugin extends FunctionPlugin implements FunctionPluginTypecheck * @param ast * @param state */ - public exp(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public exp(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EXP'), Math.exp) } } diff --git a/src/interpreter/plugin/FinancialPlugin.ts b/src/interpreter/plugin/FinancialPlugin.ts index 5389231d9c..bcd1020360 100644 --- a/src/interpreter/plugin/FinancialPlugin.ts +++ b/src/interpreter/plugin/FinancialPlugin.ts @@ -10,7 +10,7 @@ import {InterpreterState} from '../InterpreterState' import { EmptyValue, getRawValue, - InternalScalarValue, + InternalScalarValue, InterpreterValue, isExtendedNumber, NumberType, RawInterpreterValue @@ -283,23 +283,23 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp }, } - public pmt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public pmt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PMT'), pmtCore) } - public ipmt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ipmt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('IPMT'), ipmtCore) } - public ppmt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ppmt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PPMT'), ppmtCore) } - public fv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FV'), fvCore) } - public cumipmt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public cumipmt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CUMIPMT'), (rate: number, periods: number, value: number, start: number, end: number, type: number) => { if (start > end) { @@ -314,7 +314,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public cumprinc(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public cumprinc(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CUMPRINC'), (rate: number, periods: number, value: number, start: number, end: number, type: number) => { if (start > end) { @@ -329,7 +329,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public db(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public db(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DB'), (cost: number, salvage: number, life: number, period: number, month: number) => { if ((month===12 && period > life) || (period > life+1)) { @@ -361,7 +361,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public ddb(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ddb(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DDB'), (cost: number, salvage: number, life: number, period: number, factor: number) => { if (period > life) { @@ -385,7 +385,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public dollarde(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public dollarde(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DOLLARDE'), (dollar, fraction) => { if (fraction < 1) { @@ -401,7 +401,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public dollarfr(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public dollarfr(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DOLLARFR'), (dollar, fraction) => { if (fraction < 1) { @@ -417,7 +417,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public effect(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public effect(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EFFECT'), (rate: number, periods: number) => { periods = Math.trunc(periods) @@ -426,7 +426,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public ispmt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ispmt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISPMT'), (rate, period, periods, value) => { if(periods===0) { @@ -437,7 +437,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public nominal(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public nominal(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NOMINAL'), (rate: number, periods: number) => { periods = Math.trunc(periods) @@ -446,7 +446,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public nper(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public nper(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NPER'), (rate, payment, present, future, type) => { if(rate === 0) { @@ -463,7 +463,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public rate(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public rate(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RATE'), (periods, payment, present, future, type, guess) => { if(guess<=-1) { @@ -505,7 +505,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public pv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public pv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PV'), (rate, periods, payment, future, type) => { type = type ? 1 : 0 @@ -525,7 +525,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public rri(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public rri(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RRI'), (periods, present, future) => { if (present === 0 || (future < 0 && present > 0) || (future > 0 && present < 0)) { @@ -537,7 +537,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public sln(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sln(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SLN'), (cost, salvage, life) => { if (life === 0) { @@ -548,7 +548,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public syd(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public syd(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SYD'), (cost, salvage, life, period) => { if (period > life) { @@ -559,7 +559,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public tbilleq(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tbilleq(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TBILLEQ'), (settlement, maturity, discount) => { settlement = Math.round(settlement) @@ -585,7 +585,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public tbillprice(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tbillprice(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TBILLPRICE'), (settlement, maturity, discount) => { settlement = Math.round(settlement) @@ -611,7 +611,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public tbillyield(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tbillyield(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TBILLYIELD'), (settlement, maturity, price) => { settlement = Math.round(settlement) @@ -630,7 +630,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public fvschedule(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fvschedule(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FVSCHEDULE'), (value: number, ratios: SimpleRangeValue) => { const vals = ratios.valuesFromTopLeftCorner() @@ -650,7 +650,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp }) } - public npv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public npv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NPV'), (rate: number, ...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -662,7 +662,7 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public mirr(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public mirr(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MIRR'), (range: SimpleRangeValue, frate: number, rrate: number) => { const vals = this.interpreter.arithmeticHelper.manyToExactNumbers(range.valuesFromTopLeftCorner()) @@ -707,13 +707,13 @@ export class FinancialPlugin extends FunctionPlugin implements FunctionPluginTyp ) } - public pduration(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public pduration(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PDURATION'), (rate: number, pv: number, fv: number) => (Math.log(fv) - Math.log(pv))/Math.log(1+rate) ) } - public xnpv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public xnpv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('XNPV'), (rate: number, values: SimpleRangeValue, dates: SimpleRangeValue) => { const valArr = values.valuesFromTopLeftCorner() diff --git a/src/interpreter/plugin/FormulaTextPlugin.ts b/src/interpreter/plugin/FormulaTextPlugin.ts index d90f4f25bf..9df0739250 100644 --- a/src/interpreter/plugin/FormulaTextPlugin.ts +++ b/src/interpreter/plugin/FormulaTextPlugin.ts @@ -8,7 +8,7 @@ import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {FunctionPlugin} from '../index' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPluginTypecheck} from './FunctionPlugin' export class FormulaTextPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -19,7 +19,8 @@ export class FormulaTextPlugin extends FunctionPlugin implements FunctionPluginT {argumentType: ArgumentTypes.NOERROR} ], doesNotNeedArgumentsToBeComputed: true, - isDependentOnSheetStructureChange: true + isDependentOnSheetStructureChange: true, + vectorizationForbidden: true, }, } @@ -31,7 +32,7 @@ export class FormulaTextPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public formulatext(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public formulatext(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunctionWithReferenceArgument(ast.args, state, this.metadata('FORMULATEXT'), () => new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber), (cellReference: SimpleCellAddress) => this.serialization.getCellFormula(cellReference) ?? new CellError(ErrorType.NA, ErrorMessage.Formula) diff --git a/src/interpreter/plugin/FunctionPlugin.ts b/src/interpreter/plugin/FunctionPlugin.ts index 73376f3ad6..257a9240df 100644 --- a/src/interpreter/plugin/FunctionPlugin.ts +++ b/src/interpreter/plugin/FunctionPlugin.ts @@ -38,30 +38,55 @@ export interface ImplementedFunctions { [formulaId: string]: FunctionMetadata, } -export interface FunctionArguments { +export interface FunctionMetadata { + /** + * Internal and engine. + */ parameters?: FunctionArgument[], + /** + * Internal. * Used for functions with variable number of arguments -- tells how many last arguments can be repeated indefinitely. */ repeatLastArgs?: number, /** + * Internal. * Ranges in arguments are inlined to (possibly multiple) scalar arguments. */ expandRanges?: boolean, /** + * Internal. * Return number value is packed into this subtype. */ returnNumberType?: NumberType, -} - -export interface FunctionMetadata extends FunctionArguments { + /** + * Engine. + */ method: string, + /** + * Engine. + */ isVolatile?: boolean, + /** + * Engine. + */ isDependentOnSheetStructureChange?: boolean, + /** + * Engine. + */ doesNotNeedArgumentsToBeComputed?: boolean, + /** + * Engine. + */ arrayFunction?: boolean, + + /** + * Internal. + * Some function do not allow vectorization: array-output, and special functions. + */ + vectorizationForbidden?: boolean, } export interface FunctionPluginDefinition { @@ -289,90 +314,109 @@ export abstract class FunctionPlugin implements FunctionPluginTypecheck InternalScalarValue - ) => { - return this.runFunctionTemplate(args, state, functionDefinition, fn) - } - - protected runMatrixFunction = ( - args: Ast[], - state: InterpreterState, - functionDefinition: FunctionArguments, - fn: (...arg: any) => InterpreterValue + metadata: FunctionMetadata, + fn: (...arg: any) => InterpreterValue, ) => { - return this.runFunctionTemplate(args, state, functionDefinition, fn) - } + let argumentDefinitions: FunctionArgument[] = metadata.parameters! + let argValues: [InterpreterValue, boolean][] - private runFunctionTemplate = ( - args: Ast[], - state: InterpreterState, - functionDefinition: FunctionArguments, - fn: (...arg: any) => any - ) => { - const argumentDefinitions: FunctionArgument[] = functionDefinition.parameters! - let scalarValues: [InterpreterValue, boolean][] - - if (functionDefinition.expandRanges) { - scalarValues = this.listOfScalarValues(args, state) + if (metadata.expandRanges) { + argValues = this.listOfScalarValues(args, state) } else { - scalarValues = args.map((ast) => [this.evaluateAst(ast, state), false]) + argValues = args.map((ast) => [this.evaluateAst(ast, state), false]) } - const coercedArguments: Maybe[] = [] - let argCoerceFailure: Maybe = undefined - if (functionDefinition.repeatLastArgs === undefined && argumentDefinitions.length < scalarValues.length) { + if (metadata.repeatLastArgs === undefined && argumentDefinitions.length < argValues.length) { return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber) } - if (functionDefinition.repeatLastArgs !== undefined && scalarValues.length > argumentDefinitions.length && - (scalarValues.length - argumentDefinitions.length) % functionDefinition.repeatLastArgs !== 0) { + if (metadata.repeatLastArgs !== undefined && argumentDefinitions.length < argValues.length && + (argValues.length - argumentDefinitions.length) % metadata.repeatLastArgs !== 0) { return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber) } - for (let i = 0, j = 0; i < Math.max(scalarValues.length, argumentDefinitions.length); i++, j++) { - // i points to where are we in the scalarValues list, - // j points to where are we in the argumentDefinitions list - if (j === argumentDefinitions.length) { - j -= functionDefinition.repeatLastArgs! + argumentDefinitions = [...argumentDefinitions] + while(argumentDefinitions.length < argValues.length) { + argumentDefinitions.push(...argumentDefinitions.slice(argumentDefinitions.length-metadata.repeatLastArgs!)) + } + + let maxWidth = 1 + let maxHeight = 1 + if(!metadata.vectorizationForbidden && state.arraysFlag) { + for(let i=0;i = undefined + const coercedArguments: Maybe[] = [] + for (let i = 0; i < argumentDefinitions.length; i++) { + // eslint-disable-next-line prefer-const + let [val, ignorable] = argValues[i] ?? [undefined, undefined] + if(val instanceof SimpleRangeValue && argumentDefinitions[i].argumentType !== ArgumentTypes.RANGE && argumentDefinitions[i].argumentType !== ArgumentTypes.ANY) { + if(!metadata.vectorizationForbidden && state.arraysFlag) { + val = val.data[val.height()!==1 ? row : 0]?.[val.width()!==1 ? col : 0] + } } - coercedArguments.push(coercedArg) - } else if (!ignorable) { - //if this is first error encountered, store it - argCoerceFailure = argCoerceFailure ?? (new CellError(ErrorType.VALUE, ErrorMessage.WrongType)) + const arg = val ?? argumentDefinitions[i]?.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 + const coercedArg = val !== undefined ? this.coerceToType(arg, argumentDefinitions[i], state) : arg + if (coercedArg !== undefined) { + if (coercedArg instanceof CellError && argumentDefinitions[i].argumentType !== ArgumentTypes.SCALAR) { + //if this is first error encountered, store it + argCoerceFailure = argCoerceFailure ?? coercedArg + } + coercedArguments.push(coercedArg) + } else if (!ignorable) { + //if this is first error encountered, store it + argCoerceFailure = argCoerceFailure ?? (new CellError(ErrorType.VALUE, ErrorMessage.WrongType)) + } + } + } + + const ret = argCoerceFailure ?? this.returnNumberWrapper(fn(...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 argCoerceFailure ?? this.returnNumberWrapper(fn(...coercedArguments), functionDefinition.returnNumberType) + return SimpleRangeValue.onlyValues(retArr) } protected runFunctionWithReferenceArgument = ( args: Ast[], state: InterpreterState, - argumentDefinitions: FunctionArguments, + metadata: FunctionMetadata, noArgCallback: () => InternalScalarValue | RawScalarValue, referenceCallback: (reference: SimpleCellAddress) => InternalScalarValue, nonReferenceCallback: (...arg: any) => InternalScalarValue = () => new CellError(ErrorType.NA, ErrorMessage.CellRefExpected) ) => { if (args.length === 0) { - return this.returnNumberWrapper(noArgCallback(), argumentDefinitions.returnNumberType) + return this.returnNumberWrapper(noArgCallback(), metadata.returnNumberType) } else if (args.length > 1) { return new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber) } @@ -395,10 +439,10 @@ export abstract class FunctionPlugin implements FunctionPluginTypecheck(val: T | ExtendedNumber, type?: NumberType, format?: FormatInfo): T | ExtendedNumber { if(type !== undefined && isExtendedNumber(val)) { return this.interpreter.arithmeticHelper.ExtendedNumberFactory(getRawValue(val), {type, format}) } else { diff --git a/src/interpreter/plugin/InformationPlugin.ts b/src/interpreter/plugin/InformationPlugin.ts index 6b83bc7a73..8ba8355570 100644 --- a/src/interpreter/plugin/InformationPlugin.ts +++ b/src/interpreter/plugin/InformationPlugin.ts @@ -8,7 +8,7 @@ import {FormulaVertex} from '../../DependencyGraph/FormulaCellVertex' import {ErrorMessage} from '../../error-message' import {AstNodeType, ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {EmptyValue, InternalScalarValue, isExtendedNumber} from '../InterpreterValue' +import {EmptyValue, InternalScalarValue, InterpreterValue, isExtendedNumber} from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' @@ -24,6 +24,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT ], isDependentOnSheetStructureChange: true, doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, }, 'COLUMNS': { method: 'columns', @@ -32,6 +33,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT ], isDependentOnSheetStructureChange: true, doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, }, 'ISBINARY': { method: 'isbinary', @@ -50,7 +52,8 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT parameters: [ {argumentType: ArgumentTypes.NOERROR} ], - doesNotNeedArgumentsToBeComputed: true + doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, }, 'ISNA': { method: 'isna', @@ -62,7 +65,8 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT method: 'isref', parameters: [ {argumentType: ArgumentTypes.SCALAR} - ] + ], + vectorizationForbidden: true, }, 'ISERROR': { method: 'iserror', @@ -119,6 +123,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT ], isDependentOnSheetStructureChange: true, doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, }, 'ROWS': { method: 'rows', @@ -127,20 +132,23 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT ], isDependentOnSheetStructureChange: true, doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, }, 'SHEET': { method: 'sheet', parameters: [ - {argumentType: ArgumentTypes.NOERROR} + {argumentType: ArgumentTypes.STRING} ], - doesNotNeedArgumentsToBeComputed: true + doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, }, 'SHEETS': { method: 'sheets', parameters: [ - {argumentType: ArgumentTypes.NOERROR} + {argumentType: ArgumentTypes.STRING} ], - doesNotNeedArgumentsToBeComputed: true + doesNotNeedArgumentsToBeComputed: true, + vectorizationForbidden: true, } } @@ -152,7 +160,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isbinary(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isbinary(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISBINARY'), (arg: string) => /^[01]{1,10}$/.test(arg) ) @@ -166,7 +174,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public iserr(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public iserr(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISERR'), (arg: InternalScalarValue) => (arg instanceof CellError && arg.type !== ErrorType.NA) ) @@ -180,7 +188,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public iserror(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public iserror(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISERROR'), (arg: InternalScalarValue) => (arg instanceof CellError) ) @@ -194,7 +202,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isformula(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isformula(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunctionWithReferenceArgument(ast.args, state, this.metadata('ISFORMULA'), () => new CellError(ErrorType.NA, ErrorMessage.WrongArgNumber), (reference: SimpleCellAddress) => { @@ -212,7 +220,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isblank(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isblank(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISBLANK'), (arg: InternalScalarValue) => (arg === EmptyValue) ) @@ -226,7 +234,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isna(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isna(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISNA'), (arg: InternalScalarValue) => (arg instanceof CellError && arg.type == ErrorType.NA) ) @@ -240,7 +248,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isnumber(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isnumber(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISNUMBER'), isExtendedNumber) } @@ -252,7 +260,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public islogical(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public islogical(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISLOGICAL'), (arg: InternalScalarValue) => (typeof arg === 'boolean') ) @@ -266,7 +274,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isref(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isref(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISREF'), (arg: InternalScalarValue) => (arg instanceof CellError && (arg.type == ErrorType.REF || arg.type == ErrorType.CYCLE)) ) @@ -280,7 +288,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public istext(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public istext(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISTEXT'), (arg: InternalScalarValue) => (typeof arg === 'string') ) @@ -294,7 +302,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public isnontext(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isnontext(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISNONTEXT'), (arg: InternalScalarValue) => !(typeof arg === 'string') ) @@ -308,7 +316,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public column(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public column(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunctionWithReferenceArgument(ast.args, state, this.metadata('COLUMN'), () => state.formulaAddress.col + 1, (reference: SimpleCellAddress) => reference.col + 1 @@ -346,7 +354,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public row(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public row(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunctionWithReferenceArgument(ast.args, state, this.metadata('ROW'), () => state.formulaAddress.row + 1, (reference: SimpleCellAddress) => reference.row + 1 @@ -384,7 +392,7 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state */ - public index(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public index(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('INDEX'), (rangeValue: SimpleRangeValue, row: number, col: number) => { if (col < 1 || row < 1) { return new CellError(ErrorType.VALUE, ErrorMessage.LessThanOne) @@ -419,8 +427,8 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state * */ - public sheet(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { - return this.runFunctionWithReferenceArgument(ast.args, state, {parameters: [{argumentType: ArgumentTypes.STRING}]}, + public sheet(ast: ProcedureAst, state: InterpreterState): InterpreterValue { + return this.runFunctionWithReferenceArgument(ast.args, state, this.metadata('SHEET'), () => state.formulaAddress.sheet + 1, (reference: SimpleCellAddress) => reference.sheet + 1, (value: string) => { @@ -443,8 +451,8 @@ export class InformationPlugin extends FunctionPlugin implements FunctionPluginT * @param ast * @param state * */ - public sheets(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { - return this.runFunctionWithReferenceArgument(ast.args, state, {parameters: [{argumentType: ArgumentTypes.STRING}]}, + public sheets(ast: ProcedureAst, state: InterpreterState): InterpreterValue { + return this.runFunctionWithReferenceArgument(ast.args, state, this.metadata('SHEETS'), () => this.dependencyGraph.sheetMapping.numberOfSheets(), // return number of sheets if no argument () => 1, // return 1 for valid reference () => new CellError(ErrorType.VALUE, ErrorMessage.CellRefExpected) // error otherwise diff --git a/src/interpreter/plugin/IsEvenPlugin.ts b/src/interpreter/plugin/IsEvenPlugin.ts index b62a2c2105..49edd7ef03 100644 --- a/src/interpreter/plugin/IsEvenPlugin.ts +++ b/src/interpreter/plugin/IsEvenPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class IsEvenPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -18,7 +18,7 @@ export class IsEvenPlugin extends FunctionPlugin implements FunctionPluginTypech }, } - public iseven(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public iseven(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISEVEN'), (val) => (val % 2 === 0) ) diff --git a/src/interpreter/plugin/IsOddPlugin.ts b/src/interpreter/plugin/IsOddPlugin.ts index c5b7d6a927..ba15165781 100644 --- a/src/interpreter/plugin/IsOddPlugin.ts +++ b/src/interpreter/plugin/IsOddPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class IsOddPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -18,7 +18,7 @@ export class IsOddPlugin extends FunctionPlugin implements FunctionPluginTypeche }, } - public isodd(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public isodd(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ISODD'), (val) => (val % 2 === 1) ) diff --git a/src/interpreter/plugin/LogarithmPlugin.ts b/src/interpreter/plugin/LogarithmPlugin.ts index 72882f1561..7b264395f9 100644 --- a/src/interpreter/plugin/LogarithmPlugin.ts +++ b/src/interpreter/plugin/LogarithmPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class LogarithmPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -32,17 +32,17 @@ export class LogarithmPlugin extends FunctionPlugin implements FunctionPluginTyp }, } - public log10(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public log10(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LOG10'), Math.log10) } - public log(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public log(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LOG'), (arg: number, base: number) => Math.log(arg) / Math.log(base) ) } - public ln(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ln(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LN'), Math.log) } } diff --git a/src/interpreter/plugin/LookupPlugin.ts b/src/interpreter/plugin/LookupPlugin.ts index cf6de715fb..5e48336737 100644 --- a/src/interpreter/plugin/LookupPlugin.ts +++ b/src/interpreter/plugin/LookupPlugin.ts @@ -12,7 +12,7 @@ import {ProcedureAst} from '../../parser' import {StatType} from '../../statistics' import {zeroIfEmpty} from '../ArithmeticHelper' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue, RawNoErrorScalarValue, } from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue, RawNoErrorScalarValue, } from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' @@ -54,7 +54,7 @@ export class LookupPlugin extends FunctionPlugin implements FunctionPluginTypech * @param ast * @param state */ - public vlookup(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public vlookup(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('VLOOKUP'), (key: RawNoErrorScalarValue, rangeValue: SimpleRangeValue, index: number, sorted: boolean) => { const range = rangeValue.range @@ -78,7 +78,7 @@ export class LookupPlugin extends FunctionPlugin implements FunctionPluginTypech * @param ast * @param formulaAddress */ - public hlookup(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public hlookup(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HLOOKUP'), (key: RawNoErrorScalarValue, rangeValue: SimpleRangeValue, index: number, sorted: boolean) => { const range = rangeValue.range if (range === undefined) { @@ -95,7 +95,7 @@ export class LookupPlugin extends FunctionPlugin implements FunctionPluginTypech }) } - public match(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public match(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MATCH'), (key: RawNoErrorScalarValue, rangeValue: SimpleRangeValue, sorted: number) => { return this.doMatch(zeroIfEmpty(key), rangeValue, sorted) }) diff --git a/src/interpreter/plugin/MathConstantsPlugin.ts b/src/interpreter/plugin/MathConstantsPlugin.ts index 45b03e25d0..b2124c1c97 100644 --- a/src/interpreter/plugin/MathConstantsPlugin.ts +++ b/src/interpreter/plugin/MathConstantsPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export const PI = parseFloat(Math.PI.toFixed(14)) @@ -24,13 +24,13 @@ export class MathConstantsPlugin extends FunctionPlugin implements FunctionPlugi }, } - public pi(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public pi(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PI'), () => PI ) } - public sqrtpi(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sqrtpi(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SQRTPI'), (arg: number) => Math.sqrt(PI*arg) ) diff --git a/src/interpreter/plugin/MathPlugin.ts b/src/interpreter/plugin/MathPlugin.ts index 1d6339f4a9..3784e8720d 100644 --- a/src/interpreter/plugin/MathPlugin.ts +++ b/src/interpreter/plugin/MathPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue, RawInterpreterValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue, RawInterpreterValue} from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' @@ -113,7 +113,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec }, } - public fact(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fact(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FACT'), (arg: number) => { arg = Math.trunc(arg) @@ -125,7 +125,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public factdouble(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public factdouble(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FACTDOUBLE'), (arg: number) => { arg = Math.trunc(arg) @@ -138,7 +138,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public combin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public combin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COMBIN'), (n: number, m: number) => { if(m>n) { @@ -150,7 +150,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public combina(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public combina(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COMBINA'), (n: number, m: number) => { n = Math.trunc(n) @@ -167,7 +167,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public gcd(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gcd(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GCD'), (...args: RawInterpreterValue[]) => { const processedArgs = this.interpreter.arithmeticHelper.coerceNumbersCoerceRangesDropNulls(args) @@ -190,7 +190,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public lcm(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public lcm(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LCM'), (...args: RawInterpreterValue[]) => { const processedArgs = this.interpreter.arithmeticHelper.coerceNumbersCoerceRangesDropNulls(args) @@ -213,7 +213,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public mround(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public mround(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MROUND'), (nom: number, denom: number) => { if(denom===0) { @@ -227,7 +227,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public multinomial(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public multinomial(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MULTINOMIAL'), (...args: number[]) => { let n = 0 @@ -247,7 +247,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public quotient(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public quotient(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('QUOTIENT'), (nom: number, denom: number) => { if(denom===0) { @@ -258,7 +258,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public seriessum(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public seriessum(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SERIESSUM'), (x: number, n: number, m: number, range: SimpleRangeValue) => { const coefs = this.interpreter.arithmeticHelper.manyToOnlyNumbersDropNulls(range.valuesFromTopLeftCorner()) @@ -276,7 +276,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public sign(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sign(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SIGN'), (arg: number) => { if(arg>0) { @@ -290,7 +290,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public sumx2my2(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sumx2my2(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUMX2MY2'), (rangeX: SimpleRangeValue, rangeY: SimpleRangeValue) => { const valsX = rangeX.valuesFromTopLeftCorner() @@ -318,7 +318,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public sumx2py2(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sumx2py2(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUMX2PY2'), (rangeX: SimpleRangeValue, rangeY: SimpleRangeValue) => { const valsX = rangeX.valuesFromTopLeftCorner() @@ -346,7 +346,7 @@ export class MathPlugin extends FunctionPlugin implements FunctionPluginTypechec ) } - public sumxmy2(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sumxmy2(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUMXMY2'), (rangeX: SimpleRangeValue, rangeY: SimpleRangeValue) => { const valsX = rangeX.valuesFromTopLeftCorner() diff --git a/src/interpreter/plugin/MatrixPlugin.ts b/src/interpreter/plugin/MatrixPlugin.ts index e4e17a2b51..d0cae3595b 100644 --- a/src/interpreter/plugin/MatrixPlugin.ts +++ b/src/interpreter/plugin/MatrixPlugin.ts @@ -36,12 +36,14 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech {argumentType: ArgumentTypes.RANGE}, {argumentType: ArgumentTypes.RANGE}, ], + vectorizationForbidden: true, }, 'TRANSPOSE': { method: 'transpose', parameters: [ {argumentType: ArgumentTypes.RANGE}, ], + vectorizationForbidden: true, }, 'MAXPOOL': { method: 'maxpool', @@ -50,6 +52,7 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech {argumentType: ArgumentTypes.NUMBER}, {argumentType: ArgumentTypes.NUMBER, optionalArg: true}, ], + vectorizationForbidden: true, }, 'MEDIANPOOL': { method: 'medianpool', @@ -58,6 +61,7 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech {argumentType: ArgumentTypes.NUMBER}, {argumentType: ArgumentTypes.NUMBER, optionalArg: true}, ], + vectorizationForbidden: true, }, } @@ -73,7 +77,7 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech } public mmult(ast: ProcedureAst, state: InterpreterState): InterpreterValue { - return this.runMatrixFunction(ast.args, state, this.metadata('MMULT'), (leftMatrix: SimpleRangeValue, rightMatrix: SimpleRangeValue) => { + return this.runFunction(ast.args, state, this.metadata('MMULT'), (leftMatrix: SimpleRangeValue, rightMatrix: SimpleRangeValue) => { if (!leftMatrix.hasOnlyNumbers() || !rightMatrix.hasOnlyNumbers()) { return new CellError(ErrorType.VALUE, ErrorMessage.NumberRange) } @@ -95,7 +99,7 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech } public maxpool(ast: ProcedureAst, state: InterpreterState): InterpreterValue { - return this.runMatrixFunction(ast.args, state, this.metadata('MAXPOOL'), (matrix: SimpleRangeValue, windowSize: number, stride: number = windowSize) => { + return this.runFunction(ast.args, state, this.metadata('MAXPOOL'), (matrix: SimpleRangeValue, windowSize: number, stride: number = windowSize) => { if (!matrix.hasOnlyNumbers()) { return new CellError(ErrorType.VALUE, ErrorMessage.NumberRange) } @@ -118,7 +122,7 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech } public medianpool(ast: ProcedureAst, state: InterpreterState): InterpreterValue { - return this.runMatrixFunction(ast.args, state, this.metadata('MEDIANPOOL'), (matrix: SimpleRangeValue, windowSize: number, stride: number = windowSize) => { + return this.runFunction(ast.args, state, this.metadata('MEDIANPOOL'), (matrix: SimpleRangeValue, windowSize: number, stride: number = windowSize) => { if (!matrix.hasOnlyNumbers()) { return new CellError(ErrorType.VALUE, ErrorMessage.NumberRange) } @@ -183,7 +187,7 @@ export class MatrixPlugin extends FunctionPlugin implements FunctionPluginTypech } public transpose(ast: ProcedureAst, state: InterpreterState): InterpreterValue { - return this.runMatrixFunction(ast.args, state, this.metadata('TRANSPOSE'), (matrix: SimpleRangeValue) => { + return this.runFunction(ast.args, state, this.metadata('TRANSPOSE'), (matrix: SimpleRangeValue) => { if (!matrix.hasOnlyNumbers()) { return new CellError(ErrorType.VALUE, ErrorMessage.NumberRange) } diff --git a/src/interpreter/plugin/MedianPlugin.ts b/src/interpreter/plugin/MedianPlugin.ts index 49e4817d63..c82468234e 100644 --- a/src/interpreter/plugin/MedianPlugin.ts +++ b/src/interpreter/plugin/MedianPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue, RawScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue, RawScalarValue} from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' @@ -48,7 +48,7 @@ export class MedianPlugin extends FunctionPlugin implements FunctionPluginTypech * @param ast * @param state */ - public median(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public median(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MEDIAN'), (...args: RawScalarValue[]) => { const values = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -67,7 +67,7 @@ export class MedianPlugin extends FunctionPlugin implements FunctionPluginTypech }) } - public large(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public large(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LARGE'), (range: SimpleRangeValue, n: number) => { const vals = this.interpreter.arithmeticHelper.manyToExactNumbers(range.valuesFromTopLeftCorner()) @@ -84,7 +84,7 @@ export class MedianPlugin extends FunctionPlugin implements FunctionPluginTypech ) } - public small(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public small(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SMALL'), (range: SimpleRangeValue, n: number) => { const vals = this.interpreter.arithmeticHelper.manyToExactNumbers(range.valuesFromTopLeftCorner()) diff --git a/src/interpreter/plugin/ModuloPlugin.ts b/src/interpreter/plugin/ModuloPlugin.ts index c1a7b0ebf0..b1ae60eae9 100644 --- a/src/interpreter/plugin/ModuloPlugin.ts +++ b/src/interpreter/plugin/ModuloPlugin.ts @@ -6,7 +6,7 @@ import {CellError, ErrorType} from '../../Cell' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class ModuloPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -20,7 +20,7 @@ export class ModuloPlugin extends FunctionPlugin implements FunctionPluginTypech }, } - public mod(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public mod(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MOD'), (dividend: number, divisor: number) => { if (divisor === 0) { return new CellError(ErrorType.DIV_BY_ZERO) diff --git a/src/interpreter/plugin/PowerPlugin.ts b/src/interpreter/plugin/PowerPlugin.ts index fb55232e10..e41ad1a369 100644 --- a/src/interpreter/plugin/PowerPlugin.ts +++ b/src/interpreter/plugin/PowerPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class PowerPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -19,7 +19,7 @@ export class PowerPlugin extends FunctionPlugin implements FunctionPluginTypeche }, } - public power(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public power(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('POWER'), Math.pow) } } diff --git a/src/interpreter/plugin/RadiansPlugin.ts b/src/interpreter/plugin/RadiansPlugin.ts index 4512be8cdc..35da007a02 100644 --- a/src/interpreter/plugin/RadiansPlugin.ts +++ b/src/interpreter/plugin/RadiansPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class RadiansPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -18,7 +18,7 @@ export class RadiansPlugin extends FunctionPlugin implements FunctionPluginTypec }, } - public radians(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public radians(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RADIANS'), (arg) => arg * (Math.PI / 180) ) diff --git a/src/interpreter/plugin/RadixConversionPlugin.ts b/src/interpreter/plugin/RadixConversionPlugin.ts index 1d87d4d08b..4e1861f2ef 100644 --- a/src/interpreter/plugin/RadixConversionPlugin.ts +++ b/src/interpreter/plugin/RadixConversionPlugin.ts @@ -9,7 +9,7 @@ import {padLeft} from '../../format/format' import {Maybe} from '../../Maybe' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' const MAX_LENGTH = 10 @@ -118,25 +118,25 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }, } - public dec2bin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public dec2bin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DEC2BIN'), (value, places) => decimalToBaseWithExactPadding(value, 2, places) ) } - public dec2oct(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public dec2oct(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DEC2OCT'), (value, places) => decimalToBaseWithExactPadding(value, 8, places) ) } - public dec2hex(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public dec2hex(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DEC2HEX'), (value, places) => decimalToBaseWithExactPadding(value, 16, places) ) } - public bin2dec(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bin2dec(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BIN2DEC'), (binary) => { const binaryWithSign = coerceStringToBase(binary, 2, MAX_LENGTH) if(binaryWithSign === undefined) { @@ -146,7 +146,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public bin2oct(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bin2oct(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BIN2OCT'), (binary, places) => { const binaryWithSign = coerceStringToBase(binary, 2, MAX_LENGTH) if(binaryWithSign === undefined) { @@ -156,7 +156,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public bin2hex(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public bin2hex(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BIN2HEX'), (binary, places) => { const binaryWithSign = coerceStringToBase(binary, 2, MAX_LENGTH) if(binaryWithSign === undefined) { @@ -166,7 +166,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public oct2dec(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public oct2dec(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('OCT2DEC'), (octal) => { const octalWithSign = coerceStringToBase(octal, 8, MAX_LENGTH) if(octalWithSign === undefined) { @@ -176,7 +176,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public oct2bin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public oct2bin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('OCT2BIN'), (octal, places) => { const octalWithSign = coerceStringToBase(octal, 8, MAX_LENGTH) if(octalWithSign === undefined) { @@ -186,7 +186,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public oct2hex(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public oct2hex(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('OCT2HEX'), (octal, places) => { const octalWithSign = coerceStringToBase(octal, 8, MAX_LENGTH) if(octalWithSign === undefined) { @@ -196,7 +196,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public hex2dec(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public hex2dec(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HEX2DEC'), (hexadecimal) => { const hexadecimalWithSign = coerceStringToBase(hexadecimal, 16, MAX_LENGTH) if(hexadecimalWithSign === undefined) { @@ -206,7 +206,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public hex2bin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public hex2bin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HEX2BIN'), (hexadecimal, places) => { const hexadecimalWithSign = coerceStringToBase(hexadecimal, 16, MAX_LENGTH) if(hexadecimalWithSign === undefined) { @@ -216,7 +216,7 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public hex2oct(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public hex2oct(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HEX2OCT'), (hexadecimal, places) => { const hexadecimalWithSign = coerceStringToBase(hexadecimal, 16, MAX_LENGTH) if(hexadecimalWithSign === undefined) { @@ -226,11 +226,11 @@ export class RadixConversionPlugin extends FunctionPlugin implements FunctionPlu }) } - public base(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public base(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BASE'), decimalToBaseWithMinimumPadding) } - public decimal(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public decimal(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DECIMAL'), (arg, base) => { const input = coerceStringToBase(arg, base, DECIMAL_NUMBER_OF_BITS) if(input === undefined) { diff --git a/src/interpreter/plugin/RandomPlugin.ts b/src/interpreter/plugin/RandomPlugin.ts index a49185d264..457c3b7f55 100644 --- a/src/interpreter/plugin/RandomPlugin.ts +++ b/src/interpreter/plugin/RandomPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class RandomPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -36,11 +36,11 @@ export class RandomPlugin extends FunctionPlugin implements FunctionPluginTypech * @param ast * @param state */ - public rand(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public rand(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RAND'), Math.random) } - public randbetween(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public randbetween(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RANDBETWEEN'), (lower: number, upper: number) => { if(upper{ @@ -27,7 +27,7 @@ export class RomanPlugin extends FunctionPlugin implements FunctionPluginTypeche }, } - public roman(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public roman(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ROMAN'), (val: number, mode: RawScalarValue) => { val = Math.trunc(val) @@ -52,7 +52,7 @@ export class RomanPlugin extends FunctionPlugin implements FunctionPluginTypeche ) } - public arabic(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public arabic(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ARABIC'), (inputString: string) => { inputString = inputString.trim().toUpperCase() diff --git a/src/interpreter/plugin/RoundingPlugin.ts b/src/interpreter/plugin/RoundingPlugin.ts index 9db385b6c7..d6cebdfd23 100644 --- a/src/interpreter/plugin/RoundingPlugin.ts +++ b/src/interpreter/plugin/RoundingPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export function findNextOddNumber(arg: number): number { @@ -43,13 +43,6 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType { argumentType: ArgumentTypes.NUMBER, defaultValue: 0}, ], }, - 'TRUNC': { - method: 'trunc', - parameters: [ - { argumentType: ArgumentTypes.NUMBER }, - { argumentType: ArgumentTypes.NUMBER, defaultValue: 0}, - ], - }, 'INT': { method: 'intFunc', parameters: [ @@ -116,9 +109,10 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType public static aliases = { 'ISO.CEILING': 'CEILING.PRECISE', + 'TRUNC': 'ROUNDDOWN', } - public roundup(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public roundup(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ROUNDDOWN'), (numberToRound: number, places: number): number => { const placesMultiplier = Math.pow(10, places) if (numberToRound < 0) { @@ -129,7 +123,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public rounddown(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public rounddown(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ROUNDDOWN'), (numberToRound: number, places: number): number => { const placesMultiplier = Math.pow(10, places) if (numberToRound < 0) { @@ -140,7 +134,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public round(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public round(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ROUND'), (numberToRound: number, places: number): number => { const placesMultiplier = Math.pow(10, places) if (numberToRound < 0) { @@ -151,11 +145,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public trunc(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { - return this.rounddown(ast, state) - } - - public intFunc(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public intFunc(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('INT'), (coercedNumberToRound) => { if (coercedNumberToRound < 0) { return -Math.floor(-coercedNumberToRound) @@ -165,7 +155,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public even(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public even(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EVEN'), (coercedNumberToRound) => { if (coercedNumberToRound < 0) { return -findNextEvenNumber(-coercedNumberToRound) @@ -175,7 +165,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public odd(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public odd(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ODD'), (coercedNumberToRound) => { if (coercedNumberToRound < 0) { return -findNextOddNumber(-coercedNumberToRound) @@ -185,7 +175,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public ceilingmath(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ceilingmath(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CEILING.MATH'), (value: number, significance: number, mode: number) => { if (significance === 0 || value === 0) { @@ -201,7 +191,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public ceiling(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ceiling(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CEILING'), (value: number, significance: number) => { if(value === 0) { @@ -219,7 +209,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public ceilingprecise(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ceilingprecise(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CEILING.PRECISE'), (value: number, significance: number) => { if (significance === 0 || value === 0) { @@ -230,7 +220,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public floormath(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public floormath(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FLOOR.MATH'), (value: number, significance: number, mode: number) => { if (significance === 0 || value === 0) { @@ -246,7 +236,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public floor(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public floor(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FLOOR'), (value: number, significance: number) => { if(value === 0) { @@ -264,7 +254,7 @@ export class RoundingPlugin extends FunctionPlugin implements FunctionPluginType }) } - public floorprecise(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public floorprecise(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FLOOR.PRECISE'), (value: number, significance: number) => { if (significance === 0 || value === 0) { diff --git a/src/interpreter/plugin/SimpleArithmertic.ts b/src/interpreter/plugin/SimpleArithmertic.ts index 3b0fb8690e..d6ba1cd931 100644 --- a/src/interpreter/plugin/SimpleArithmertic.ts +++ b/src/interpreter/plugin/SimpleArithmertic.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class SimpleArithmerticPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -114,91 +114,91 @@ export class SimpleArithmerticPlugin extends FunctionPlugin implements FunctionP }, } - public add(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public add(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.ADD'), this.interpreter.arithmeticHelper.addWithEpsilon ) } - public concat(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public concat(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.CONCAT'), this.interpreter.arithmeticHelper.concat ) } - public divide(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public divide(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.DIVIDE'), this.interpreter.arithmeticHelper.divide ) } - public eq(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public eq(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.EQ'), this.interpreter.arithmeticHelper.eq ) } - public gt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.GT'), this.interpreter.arithmeticHelper.gt ) } - public gte(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gte(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.GTE'), this.interpreter.arithmeticHelper.geq ) } - public lt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public lt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.LT'), this.interpreter.arithmeticHelper.lt ) } - public lte(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public lte(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.LTE'), this.interpreter.arithmeticHelper.leq ) } - public minus(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public minus(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.MINUS'), this.interpreter.arithmeticHelper.subtract ) } - public multiply(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public multiply(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.MULTIPLY'), this.interpreter.arithmeticHelper.multiply ) } - public ne(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ne(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.NE'), this.interpreter.arithmeticHelper.neq ) } - public pow(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public pow(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.POW'), this.interpreter.arithmeticHelper.pow ) } - public uminus(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public uminus(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.UMINUS'), this.interpreter.arithmeticHelper.unaryMinus ) } - public upercent(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public upercent(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.UNARY_PERCENT'), this.interpreter.arithmeticHelper.unaryPercent ) } - public uplus(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public uplus(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HF.UPLUS'), this.interpreter.arithmeticHelper.unaryPlus ) diff --git a/src/interpreter/plugin/SqrtPlugin.ts b/src/interpreter/plugin/SqrtPlugin.ts index cbb4ef3679..7b75a5fd1d 100644 --- a/src/interpreter/plugin/SqrtPlugin.ts +++ b/src/interpreter/plugin/SqrtPlugin.ts @@ -5,7 +5,7 @@ import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' export class SqrtPlugin extends FunctionPlugin implements FunctionPluginTypecheck{ @@ -18,7 +18,7 @@ export class SqrtPlugin extends FunctionPlugin implements FunctionPluginTypeche }, } - public sqrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sqrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SQRT'), Math.sqrt) } } diff --git a/src/interpreter/plugin/StatisticalAggregationPlugin.ts b/src/interpreter/plugin/StatisticalAggregationPlugin.ts index 89a30d48e7..ee72979721 100644 --- a/src/interpreter/plugin/StatisticalAggregationPlugin.ts +++ b/src/interpreter/plugin/StatisticalAggregationPlugin.ts @@ -7,7 +7,13 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {getRawValue, InternalScalarValue, isExtendedNumber, RawInterpreterValue} from '../InterpreterValue' +import { + getRawValue, + InternalScalarValue, + InterpreterValue, + isExtendedNumber, + RawInterpreterValue +} from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import { centralF, @@ -31,28 +37,28 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun parameters: [ {argumentType: ArgumentTypes.ANY}, ], - repeatLastArgs: 1 + repeatLastArgs: 1, }, 'DEVSQ': { method: 'devsq', parameters: [ {argumentType: ArgumentTypes.ANY}, ], - repeatLastArgs: 1 + repeatLastArgs: 1, }, 'GEOMEAN': { method: 'geomean', parameters: [ {argumentType: ArgumentTypes.ANY}, ], - repeatLastArgs: 1 + repeatLastArgs: 1, }, 'HARMEAN': { method: 'harmean', parameters: [ {argumentType: ArgumentTypes.ANY}, ], - repeatLastArgs: 1 + repeatLastArgs: 1, }, 'CORREL': { method: 'correl', @@ -132,14 +138,14 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun parameters: [ {argumentType: ArgumentTypes.ANY}, ], - repeatLastArgs: 1 + repeatLastArgs: 1, }, 'SKEW.P': { method: 'skewp', parameters: [ {argumentType: ArgumentTypes.ANY}, ], - repeatLastArgs: 1 + repeatLastArgs: 1, }, } public static aliases = { @@ -154,7 +160,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun SKEWP: 'SKEW.P', } - public avedev(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public avedev(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('AVEDEV'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -169,7 +175,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public devsq(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public devsq(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('DEVSQ'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -183,7 +189,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public geomean(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public geomean(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GEOMEAN'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -202,7 +208,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public harmean(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public harmean(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HARMEAN'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -221,7 +227,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public correl(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public correl(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CORREL'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { if (dataX.numberOfElements() !== dataY.numberOfElements()) { @@ -239,7 +245,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public rsq(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public rsq(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RSQ'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { if (dataX.numberOfElements() !== dataY.numberOfElements()) { @@ -258,7 +264,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public covariancep(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public covariancep(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COVARIANCE.P'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { if (dataX.numberOfElements() !== dataY.numberOfElements()) { @@ -280,7 +286,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public covariances(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public covariances(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COVARIANCE.S'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { if (dataX.numberOfElements() !== dataY.numberOfElements()) { @@ -299,7 +305,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public ztest(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ztest(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('Z.TEST'), (range: SimpleRangeValue, x: number, sigma?: number) => { const vals = this.interpreter.arithmeticHelper.manyToExactNumbers(range.valuesFromTopLeftCorner()) @@ -324,7 +330,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun ) } - public ftest(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ftest(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('F.TEST'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { const arrX = this.interpreter.arithmeticHelper.manyToExactNumbers(dataX.valuesFromTopLeftCorner()) @@ -349,7 +355,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public steyx(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public steyx(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('STEYX'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { if (dataX.numberOfElements() !== dataY.numberOfElements()) { @@ -368,7 +374,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public slope(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public slope(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SLOPE'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { if (dataX.numberOfElements() !== dataY.numberOfElements()) { @@ -387,7 +393,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public chisqtest(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public chisqtest(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHISQ.TEST'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue) => { const r = dataX.height() @@ -417,7 +423,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public ttest(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public ttest(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T.TEST'), (dataX: SimpleRangeValue, dataY: SimpleRangeValue, tails: number, type: number) => { const arrX = this.interpreter.arithmeticHelper.manyToExactNumbers(dataX.valuesFromTopLeftCorner()) @@ -473,7 +479,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public skew(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public skew(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SKEW'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) @@ -493,7 +499,7 @@ export class StatisticalAggregationPlugin extends FunctionPlugin implements Fun }) } - public skewp(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public skewp(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SKEW.P'), (...args: RawInterpreterValue[]) => { const coerced = this.interpreter.arithmeticHelper.coerceNumbersExactRanges(args) diff --git a/src/interpreter/plugin/StatisticalPlugin.ts b/src/interpreter/plugin/StatisticalPlugin.ts index 66fd3e00c5..8a03f037dc 100644 --- a/src/interpreter/plugin/StatisticalPlugin.ts +++ b/src/interpreter/plugin/StatisticalPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {besseli, besselj, besselk, bessely} from './3rdparty/bessel/bessel' import { beta, @@ -426,7 +426,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin POISSONDIST: 'POISSON.DIST', } - public erf(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public erf(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ERF'), (lowerBound, upperBound) => { if (upperBound === undefined) { return erf(lowerBound) @@ -436,12 +436,12 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin }) } - public erfc(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public erfc(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ERFC'), erfc) } - public expondist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public expondist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EXPON.DIST'), (x: number, lambda: number, cumulative: boolean) => { if(cumulative) { @@ -453,23 +453,23 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public fisher(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fisher(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FISHER'), (x: number) => Math.log((1 + x) / (1 - x)) / 2 ) } - public fisherinv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fisherinv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FISHERINV'), (y: number) => 1 - 2 / (Math.exp(2 * y) + 1) ) } - public gamma(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gamma(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GAMMA'), gammafn) } - public gammadist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gammadist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GAMMA.DIST'), (value: number, alphaVal: number, betaVal: number, cumulative: boolean) => { if(cumulative) { @@ -481,21 +481,21 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public gammaln(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gammaln(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GAMMALN'), gammaln) } - public gammainv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gammainv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GAMMA.INV'), gamma.inv) } - public gauss(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public gauss(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('GAUSS'), (z: number) => normal.cdf(z, 0, 1) - 0.5 ) } - public betadist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public betadist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BETA.DIST'), (x: number, alphaVal: number, betaVal: number, cumulative: boolean, A: number, B: number) => { if(x<=A) { @@ -513,7 +513,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public betainv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public betainv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BETA.INV'), (x: number, alphaVal: number, betaVal: number, A: number, B: number) => { if (A >= B) { @@ -525,7 +525,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public binomialdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public binomialdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BINOM.DIST'), (succ: number, trials: number, prob: number, cumulative: boolean) => { if(succ>trials) { @@ -542,7 +542,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public binomialinv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public binomialinv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BINOM.INV'), (trials: number, prob: number, alpha: number) => { trials = Math.trunc(trials) @@ -561,31 +561,31 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public besselifn(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public besselifn(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BESSELI'), (x: number, n: number) => besseli(x, Math.trunc(n)) ) } - public besseljfn(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public besseljfn(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BESSELJ'), (x: number, n: number) => besselj(x, Math.trunc(n)) ) } - public besselkfn(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public besselkfn(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BESSELK'), (x: number, n: number) => besselk(x, Math.trunc(n)) ) } - public besselyfn(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public besselyfn(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('BESSELY'), (x: number, n: number) => bessely(x, Math.trunc(n)) ) } - public chisqdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public chisqdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHISQ.DIST'), (x: number, deg: number, cumulative: boolean) => { deg = Math.trunc(deg) @@ -598,25 +598,25 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public chisqdistrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public chisqdistrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHISQ.DIST.RT'), (x: number, deg: number) => 1 - chisquare.cdf(x, Math.trunc(deg)) ) } - public chisqinv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public chisqinv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHISQ.INV'), (p: number, deg: number) => chisquare.inv(p, Math.trunc(deg)) ) } - public chisqinvrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public chisqinvrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CHISQ.INV.RT'), (p: number, deg: number) => chisquare.inv(1.0 - p, Math.trunc(deg)) ) } - public fdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('F.DIST'), (x: number, deg1: number, deg2: number, cumulative: boolean) => { deg1 = Math.trunc(deg1) @@ -630,26 +630,26 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public fdistrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public fdistrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('F.DIST.RT'), (x: number, deg1: number, deg2: number) => 1 - centralF.cdf(x, Math.trunc(deg1), Math.trunc(deg2)) ) } - public finv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public finv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('F.INV'), (p: number, deg1: number, deg2: number) => centralF.inv(p, Math.trunc(deg1), Math.trunc(deg2)) ) } - public finvrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public finvrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('F.INV.RT'), (p: number, deg1: number, deg2: number) => centralF.inv(1.0 - p, Math.trunc(deg1), Math.trunc(deg2)) ) } - public weibulldist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public weibulldist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('WEIBULL.DIST'), (x: number, shape: number, scale: number, cumulative: boolean) => { if(cumulative) { @@ -661,7 +661,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public poissondist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public poissondist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('POISSON.DIST'), (x: number, mean: number, cumulative: boolean) => { x = Math.trunc(x) @@ -674,7 +674,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public hypgeomdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public hypgeomdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('HYPGEOM.DIST'), (s: number, numberS: number, populationS: number, numberPop: number, cumulative: boolean) => { if(s > numberS || s > populationS || numberS > numberPop || populationS > numberPop) { @@ -697,7 +697,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public tdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T.DIST'), (x: number, deg: number, cumulative: boolean) => { deg = Math.trunc(deg) @@ -710,37 +710,37 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public tdist2t(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tdist2t(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T.DIST.2T'), (x: number, deg: number) => (1 - studentt.cdf(x, Math.trunc(deg))) * 2 ) } - public tdistrt(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tdistrt(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T.DIST.RT'), (x: number, deg: number) => 1 - studentt.cdf(x, Math.trunc(deg)) ) } - public tdistold(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tdistold(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TDIST'), (x: number, deg: number, mode: number) => mode*(1 - studentt.cdf(x, Math.trunc(deg))) ) } - public tinv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tinv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T.INV'), (p: number, deg: number) => studentt.inv(p, Math.trunc(deg)) ) } - public tinv2t(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tinv2t(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T.INV.2T'), (p: number, deg: number) => studentt.inv(1-p/2, Math.trunc(deg)) ) } - public lognormdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public lognormdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LOGNORM.DIST'), (x: number, mean: number, stddev: number, cumulative: boolean) => { if(cumulative) { @@ -752,13 +752,13 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public lognorminv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public lognorminv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LOGNORM.INV'), (p: number, mean: number, stddev: number) => lognormal.inv(p, mean, stddev) ) } - public normdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public normdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NORM.DIST'), (x: number, mean: number, stddev: number, cumulative: boolean) => { if(cumulative) { @@ -770,13 +770,13 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public norminv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public norminv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NORM.INV'), (p: number, mean: number, stddev: number) => normal.inv(p, mean, stddev) ) } - public normsdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public normsdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NORM.S.DIST'), (x: number, cumulative: boolean) => { if(cumulative) { @@ -788,19 +788,19 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public normsinv(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public normsinv(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NORM.S.INV'), (p: number) => normal.inv(p, 0, 1) ) } - public phi(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public phi(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PHI'), (x: number) => normal.pdf(x, 0, 1) ) } - public negbinomdist(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public negbinomdist(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('NEGBINOM.DIST'), (nf: number, ns: number, p: number, cumulative: boolean) => { nf = Math.trunc(nf) @@ -814,7 +814,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public confidencenorm(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public confidencenorm(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CONFIDENCE.NORM'), // eslint-disable-next-line // @ts-ignore @@ -822,7 +822,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public confidencet(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public confidencet(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CONFIDENCE.T'), (alpha: number, stddev: number, size: number) => { size = Math.trunc(size) @@ -836,7 +836,7 @@ export class StatisticalPlugin extends FunctionPlugin implements FunctionPlugin ) } - public standardize(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public standardize(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('STANDARDIZE'), (x: number, mean: number, stddev: number) => (x-mean)/stddev ) diff --git a/src/interpreter/plugin/SumifPlugin.ts b/src/interpreter/plugin/SumifPlugin.ts index b42100c63a..1c5c57a763 100644 --- a/src/interpreter/plugin/SumifPlugin.ts +++ b/src/interpreter/plugin/SumifPlugin.ts @@ -9,7 +9,7 @@ import {Maybe} from '../../Maybe' import {ProcedureAst} from '../../parser' import {Condition, CriterionFunctionCompute} from '../CriterionFunctionCompute' import {InterpreterState} from '../InterpreterState' -import {getRawValue, InternalScalarValue, isExtendedNumber, RawScalarValue} from '../InterpreterValue' +import {getRawValue, InternalScalarValue, InterpreterValue, isExtendedNumber, RawScalarValue} from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' @@ -113,7 +113,7 @@ export class SumifPlugin extends FunctionPlugin implements FunctionPluginTypeche * @param ast * @param state */ - public sumif(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sumif(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUMIF'), (conditionArg: SimpleRangeValue, criterionValue: RawScalarValue, valuesArg: Maybe) => { const criterion = this.interpreter.criterionBuilder.fromCellValue(criterionValue, this.interpreter.arithmeticHelper) @@ -134,7 +134,7 @@ export class SumifPlugin extends FunctionPlugin implements FunctionPluginTypeche ) } - public sumifs(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sumifs(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUMIFS'), (values: SimpleRangeValue, ...args) => { const conditions: Condition[] = [] for (let i = 0; i < args.length; i += 2) { @@ -156,7 +156,7 @@ export class SumifPlugin extends FunctionPlugin implements FunctionPluginTypeche }) } - public averageif(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public averageif(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('AVERAGEIF'), (conditionArg: SimpleRangeValue, criterionValue: RawScalarValue, valuesArg: Maybe) => { const criterion = this.interpreter.criterionBuilder.fromCellValue(criterionValue, this.interpreter.arithmeticHelper) @@ -199,7 +199,7 @@ export class SumifPlugin extends FunctionPlugin implements FunctionPluginTypeche * @param ast * @param state */ - public countif(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public countif(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COUNTIF'), (conditionArg: SimpleRangeValue, criterionValue: RawScalarValue) => { const criterion = this.interpreter.criterionBuilder.fromCellValue(criterionValue, this.interpreter.arithmeticHelper) @@ -218,7 +218,7 @@ export class SumifPlugin extends FunctionPlugin implements FunctionPluginTypeche ) } - public countifs(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public countifs(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COUNTIFS'), (...args) => { const conditions: Condition[] = [] for (let i = 0; i < args.length; i += 2) { diff --git a/src/interpreter/plugin/SumprodPlugin.ts b/src/interpreter/plugin/SumprodPlugin.ts index 2ce06cfd93..2d7bbd4cc4 100644 --- a/src/interpreter/plugin/SumprodPlugin.ts +++ b/src/interpreter/plugin/SumprodPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {getRawValue, InternalScalarValue, isExtendedNumber} from '../InterpreterValue' +import {getRawValue, InternalScalarValue, InterpreterValue, isExtendedNumber} from '../InterpreterValue' import {SimpleRangeValue} from '../SimpleRangeValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' @@ -22,7 +22,7 @@ export class SumprodPlugin extends FunctionPlugin implements FunctionPluginTypec }, } - public sumproduct(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sumproduct(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUMPRODUCT'), (left: SimpleRangeValue, right: SimpleRangeValue) => { if (left.numberOfElements() !== right.numberOfElements()) { return new CellError(ErrorType.VALUE, ErrorMessage.EqualLength) diff --git a/src/interpreter/plugin/TextPlugin.ts b/src/interpreter/plugin/TextPlugin.ts index 8323007ccf..316b803633 100644 --- a/src/interpreter/plugin/TextPlugin.ts +++ b/src/interpreter/plugin/TextPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue, RawScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue, RawScalarValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' /** @@ -152,7 +152,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec * @param ast * @param state */ - public concatenate(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public concatenate(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CONCATENATE'), (...args) => { return ''.concat(...args) }) @@ -166,7 +166,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec * @param ast * @param state */ - public split(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public split(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SPLIT'), (stringToSplit: string, indexToUse: number) => { const splittedString = stringToSplit.split(' ') @@ -178,44 +178,44 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public len(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public len(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LEN'), (arg: string) => { return arg.length }) } - public lower(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public lower(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LOWER'), (arg: string) => { return arg.toLowerCase() }) } - public trim(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public trim(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TRIM'), (arg: string) => { return arg.replace(/^ +| +$/g, '').replace(/ +/g, ' ') }) } - public proper(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public proper(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('PROPER'), (arg: string) => { return arg.replace(/\w\S*/g, word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase()) }) } - public clean(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public clean(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CLEAN'), (arg: string) => { // eslint-disable-next-line no-control-regex return arg.replace(/[\u0000-\u001F]/g, '') }) } - public exact(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public exact(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('EXACT'), (left: string, right: string) => { return left === right }) } - public rept(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public rept(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('REPT'), (text: string, count: number) => { if (count < 0) { return new CellError(ErrorType.VALUE, ErrorMessage.NegativeCount) @@ -224,7 +224,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public right(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public right(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('RIGHT'), (text: string, length: number) => { if (length < 0) { return new CellError(ErrorType.VALUE, ErrorMessage.NegativeLength) @@ -235,7 +235,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public left(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public left(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('LEFT'), (text: string, length: number) => { if (length < 0) { return new CellError(ErrorType.VALUE, ErrorMessage.NegativeLength) @@ -244,7 +244,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public mid(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public mid(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('MID'), (text: string, startPosition: number, numberOfChars: number) => { if (startPosition < 1) { return new CellError(ErrorType.VALUE, ErrorMessage.LessThanOne) @@ -256,7 +256,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public replace(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public replace(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('REPLACE'), (text: string, startPosition: number, numberOfChars: number, newText: string) => { if (startPosition < 1) { return new CellError(ErrorType.VALUE, ErrorMessage.LessThanOne) @@ -268,7 +268,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public search(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public search(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SEARCH'), (pattern, text: string, startIndex: number) => { if (startIndex < 1 || startIndex > text.length) { return new CellError(ErrorType.VALUE, ErrorMessage.LengthBounds) @@ -288,7 +288,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public substitute(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public substitute(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SUBSTITUTE'), (text: string, oldText: string, newText: string, occurrence: number | undefined) => { const oldTextRegexp = new RegExp(oldText, 'g') @@ -312,7 +312,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public find(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public find(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('FIND'), (pattern, text: string, startIndex: number) => { if (startIndex < 1 || startIndex > text.length) { return new CellError(ErrorType.VALUE, ErrorMessage.IndexBounds) @@ -325,7 +325,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public t(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public t(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('T'), (arg: RawScalarValue) => { if (arg instanceof CellError) { return arg @@ -334,7 +334,7 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec }) } - public upper(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public upper(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('UPPER'), (arg: string) => { return arg.toUpperCase() }) diff --git a/src/interpreter/plugin/TrigonometryPlugin.ts b/src/interpreter/plugin/TrigonometryPlugin.ts index 2d0e55fd0a..89db32d532 100644 --- a/src/interpreter/plugin/TrigonometryPlugin.ts +++ b/src/interpreter/plugin/TrigonometryPlugin.ts @@ -7,7 +7,7 @@ import {CellError, ErrorType} from '../../Cell' import {ErrorMessage} from '../../error-message' import {ProcedureAst} from '../../parser' import {InterpreterState} from '../InterpreterState' -import {InternalScalarValue} from '../InterpreterValue' +import {InternalScalarValue, InterpreterValue} from '../InterpreterValue' import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin' import {PI} from './MathConstantsPlugin' @@ -154,31 +154,31 @@ export class TrigonometryPlugin extends FunctionPlugin implements FunctionPlugin * @param ast * @param state */ - public acos(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public acos(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ACOS'), Math.acos) } - public asin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public asin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ASIN'), Math.asin) } - public cos(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public cos(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COS'), Math.cos) } - public sin(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sin(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SIN'), Math.sin) } - public tan(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tan(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TAN'), Math.tan) } - public atan(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public atan(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ATAN'), Math.atan) } - public atan2(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public atan2(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ATAN2'), (x: number, y: number) => { if(x===0 && y===0) { @@ -189,73 +189,73 @@ export class TrigonometryPlugin extends FunctionPlugin implements FunctionPlugin ) } - public cot(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public cot(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COT'), (arg) => (arg === 0) ? new CellError(ErrorType.DIV_BY_ZERO) : (1 / Math.tan(arg)) ) } - public acot(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public acot(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ACOT'), (arg) => (arg === 0) ? PI/2 : Math.atan(1/arg) ) } - public sec(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sec(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SEC'), (arg: number) => 1 / Math.cos(arg) ) } - public csc(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public csc(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CSC'), (arg) => (arg === 0) ? new CellError(ErrorType.DIV_BY_ZERO) : (1 / Math.sin(arg)) ) } - public sinh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sinh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SINH'), Math.sinh) } - public asinh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public asinh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ASINH'), Math.asinh) } - public cosh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public cosh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COSH'), Math.cosh) } - public acosh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public acosh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ACOSH'), Math.acosh) } - public tanh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public tanh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('TANH'), Math.tanh) } - public atanh(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public atanh(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ATANH'), Math.atanh) } - public coth(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public coth(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('COTH'), (arg) => (arg === 0) ? new CellError(ErrorType.DIV_BY_ZERO) : (1 / Math.tanh(arg)) ) } - public acoth(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public acoth(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('ACOTH'), (arg) => (arg === 0) ? new CellError(ErrorType.NUM, ErrorMessage.NonZero) : Math.atanh(1/arg) ) } - public sech(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public sech(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('SECH'), (arg: number) => 1 / Math.cosh(arg) ) } - public csch(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { + public csch(ast: ProcedureAst, state: InterpreterState): InterpreterValue { return this.runFunction(ast.args, state, this.metadata('CSCH'), (arg) => (arg === 0) ? new CellError(ErrorType.DIV_BY_ZERO) : (1 / Math.sinh(arg)) ) diff --git a/src/parser/FormulaParser.ts b/src/parser/FormulaParser.ts index 0867093b17..3a873c0a12 100644 --- a/src/parser/FormulaParser.ts +++ b/src/parser/FormulaParser.ts @@ -766,6 +766,9 @@ export class FormulaParser extends EmbeddedActionsParser { return buildParenthesisAst(expression, lParenToken.leadingWhitespace, rParenToken.leadingWhitespace) }) + + + /** * Returns {@link CellReferenceAst} or {@link CellRangeAst} based on OFFSET function arguments * diff --git a/test/arrays.spec.ts b/test/arrays.spec.ts index 9687b36b0c..0d2928631f 100644 --- a/test/arrays.spec.ts +++ b/test/arrays.spec.ts @@ -249,3 +249,75 @@ describe('array parsing', () => { expect(engine.getSheetValues(0)).toEqual([[1, 2, 3, 4], [5, 14, 16, -11], [6, 18, 20, -12], [13, 14, 15, 16]]) }) }) + +describe('vectorization', () => { + it('1 arg function row', () => { + const engine = HyperFormula.buildFromArray([['=ABS({-2,-1,1,2})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[2, 1, 1, 2]]) + }) + + it('1 arg function column', () => { + const engine = HyperFormula.buildFromArray([['=ABS({2;-2})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[2], [2]]) + }) + + it('1 arg function square', () => { + const engine = HyperFormula.buildFromArray([['=ABS({1,2;-1,-2})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[1, 2], [1, 2]]) + }) + + it('1 arg function no flag - should cast to scalar', () => { + const engine = HyperFormula.buildFromArray([['=ABS({-2,-1,1,2})']], {useArrayArithmetic: false}) + expect(engine.getSheetValues(0)).toEqual([[2]]) + }) + + it('multi arg function', () => { + const engine = HyperFormula.buildFromArray([['=DATE({1,2},1,1)']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[367, 732]]) + }) + + it('multi arg function #2', () => { + const engine = HyperFormula.buildFromArray([['=DATE({1,2},{1,2},{1,2})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[367, 764]]) + }) + + it('multi arg function #3', () => { + const engine = HyperFormula.buildFromArray([['=DATE({1,2},{1;2},{1})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[367, 732], [398, 763]]) + }) + + it('multi arg function #4', () => { + const engine = HyperFormula.buildFromArray([['=DATE({1,2},{1,2,3},{1})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[367, 763, detailedError(ErrorType.VALUE, ErrorMessage.InvalidDate)]]) + }) + + it('mixed types', () => { + const engine = HyperFormula.buildFromArray([['=ZTEST({1,2,1},{2;3})']], {useArrayArithmetic: true}) + const val = engine.getSheetValues(0) + expect(val.length).toEqual(2) + expect(val[0].length).toEqual(1) + expect(val[1].length).toEqual(1) + }) + + it('no vectorization here #1', () => { + const engine = HyperFormula.buildFromArray([['=SUM({1,2,1},{2;3})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[9]]) + }) + + it('no vectorization here #2', () => { + const engine = HyperFormula.buildFromArray([['=AND({TRUE(),FALSE()},{TRUE();FALSE()})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[false]]) + }) + + it('vectorize with defaults', () => { + const engine = HyperFormula.buildFromArray([['=IF({TRUE(),FALSE()},{1;2;3}, {2;3})']], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[1, 2], [2, 3], [3, false]]) + }) + + it('should work with switch', () => { + const engine = HyperFormula.buildFromArray([ + ['=SWITCH({1,2,3},1,2,3,4,5)'] + ], {useArrayArithmetic: true}) + expect(engine.getSheetValues(0)).toEqual([[2, 5, 4]]) + }) +}) diff --git a/test/interpreter/aliases.spec.ts b/test/interpreter/aliases.spec.ts index 6de40e1362..76800ba875 100644 --- a/test/interpreter/aliases.spec.ts +++ b/test/interpreter/aliases.spec.ts @@ -203,4 +203,8 @@ describe('Function aliases', () => { it('ISO.CEILING should be an alias of CEILING.PRECISE', () => { expect(engine.getFunctionPlugin('ISO.CEILING')!.aliases!['ISO.CEILING']).toEqual('CEILING.PRECISE') }) + + it('TRUNC should be an alias of ROUNDDOWN', () => { + expect(engine.getFunctionPlugin('TRUNC')!.aliases!['TRUNC']).toEqual('ROUNDDOWN') + }) }) diff --git a/test/interpreter/function-switch.spec.ts b/test/interpreter/function-switch.spec.ts index 2019a0790b..eeda8ac9b1 100644 --- a/test/interpreter/function-switch.spec.ts +++ b/test/interpreter/function-switch.spec.ts @@ -21,14 +21,6 @@ describe('Interpreter - SWITCH function', () => { expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.NoDefault)) }) - it('Should work with arrays', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=SWITCH(A1:C1,1,2,3,4,5)'] - ], {useArrayArithmetic: false}) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [2, 5, 4]]) - }) - it('Should work with precision', () => { const engine = HyperFormula.buildFromArray([ ['1', '1.0000000001', '3', '1.0000000000001', '5'], diff --git a/test/interpreter/function-trunc.spec.ts b/test/interpreter/function-trunc.spec.ts deleted file mode 100644 index a741b4e38f..0000000000 --- a/test/interpreter/function-trunc.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../src' -import {ErrorType} from '../../src/Cell' -import {ErrorMessage} from '../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TRUNC', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUNC()', '=TRUNC(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUNC(1.3)', '=TRUNC(1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUNC(-1.3)', '=TRUNC(-1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-1) - expect(engine.getCellValue(adr('B1'))).toBe(-1) - }) - - it('works with positive rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUNC(1.43, 1)', '=TRUNC(1.47, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1.4) - expect(engine.getCellValue(adr('B1'))).toBe(1.4) - }) - - it('works with negative rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUNC(43, -1)', '=TRUNC(47, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(40) - expect(engine.getCellValue(adr('B1'))).toBe(40) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUNC("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(42) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=TRUNC(A1)', '=TRUNC(42, A1)', '=TRUNC(A1, FOO())'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -})