UNPKG

pip-services4-expressions-node

Version:

Tokenizers, parsers and expression calculators in Node.js / ES2017

382 lines (332 loc) 20 kB
/** @module calculator */ import { FunctionCollection } from "./FunctionCollection"; import { DelegatedFunction } from "./DelegatedFunction"; import { Variant } from "../../variants/Variant"; import { VariantType } from "../../variants/VariantType"; import { IVariantOperations } from "../../variants/IVariantOperations"; import { ExpressionException } from "../ExpressionException"; /** * Implements a list filled with standard functions. */ export class DefaultFunctionCollection extends FunctionCollection { /** * Constructs this list and fills it with the standard functions. */ public constructor() { super(); this.add(new DelegatedFunction("Ticks", this.ticksFunctionCalculator, this)); this.add(new DelegatedFunction("TimeSpan", this.timeSpanFunctionCalculator, this)); this.add(new DelegatedFunction("Now", this.nowFunctionCalculator, this)); this.add(new DelegatedFunction("Date", this.dateFunctionCalculator, this)); this.add(new DelegatedFunction("DayOfWeek", this.dayOfWeekFunctionCalculator, this)); this.add(new DelegatedFunction("Min", this.minFunctionCalculator, this)); this.add(new DelegatedFunction("Max", this.maxFunctionCalculator, this)); this.add(new DelegatedFunction("Sum", this.sumFunctionCalculator, this)); this.add(new DelegatedFunction("If", this.ifFunctionCalculator, this)); this.add(new DelegatedFunction("Choose", this.chooseFunctionCalculator, this)); this.add(new DelegatedFunction("E", this.eFunctionCalculator, this)); this.add(new DelegatedFunction("Pi", this.piFunctionCalculator, this)); this.add(new DelegatedFunction("Rnd", this.rndFunctionCalculator, this)); this.add(new DelegatedFunction("Random", this.rndFunctionCalculator, this)); this.add(new DelegatedFunction("Abs", this.absFunctionCalculator, this)); this.add(new DelegatedFunction("Acos", this.acosFunctionCalculator, this)); this.add(new DelegatedFunction("Asin", this.asinFunctionCalculator, this)); this.add(new DelegatedFunction("Atan", this.atanFunctionCalculator, this)); this.add(new DelegatedFunction("Exp", this.expFunctionCalculator, this)); this.add(new DelegatedFunction("Log", this.logFunctionCalculator, this)); this.add(new DelegatedFunction("Ln", this.logFunctionCalculator, this)); this.add(new DelegatedFunction("Log10", this.log10FunctionCalculator, this)); this.add(new DelegatedFunction("Ceil", this.ceilFunctionCalculator, this)); this.add(new DelegatedFunction("Ceiling", this.ceilFunctionCalculator, this)); this.add(new DelegatedFunction("Floor", this.floorFunctionCalculator, this)); this.add(new DelegatedFunction("Round", this.roundFunctionCalculator, this)); this.add(new DelegatedFunction("Trunc", this.truncFunctionCalculator, this)); this.add(new DelegatedFunction("Truncate", this.truncFunctionCalculator, this)); this.add(new DelegatedFunction("Cos", this.cosFunctionCalculator, this)); this.add(new DelegatedFunction("Sin", this.sinFunctionCalculator, this)); this.add(new DelegatedFunction("Tan", this.tanFunctionCalculator, this)); this.add(new DelegatedFunction("Sqr", this.sqrtFunctionCalculator, this)); this.add(new DelegatedFunction("Sqrt", this.sqrtFunctionCalculator, this)); this.add(new DelegatedFunction("Empty", this.emptyFunctionCalculator, this)); this.add(new DelegatedFunction("Null", this.nullFunctionCalculator, this)); this.add(new DelegatedFunction("Contains", this.containsFunctionCalculator, this)); this.add(new DelegatedFunction("Array", this.arrayFunctionCalculator, this)); } /** * Checks if params contains the correct number of function parameters (must be stored on the top of the params). * @param params A list of function parameters. * @param expectedParamCount The expected number of function parameters. */ protected checkParamCount(params: Variant[], expectedParamCount: number): void { const paramCount = params.length; if (expectedParamCount != paramCount) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected " + expectedParamCount + " parameters but was found " + paramCount); } } /** * Gets function parameter by it's index. * @param params A list of function parameters. * @param paramIndex Index for the function parameter (0 for the first parameter). * @returns Function parameter value. */ protected getParameter(params: Variant[], paramIndex: number): Variant { return params[paramIndex]; } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async ticksFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 0); return Variant.fromLong(new Date().getTime()); } private async timeSpanFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { const paramCount = params.length; if (paramCount != 1 && paramCount != 3 && paramCount != 4 && paramCount != 5) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected 1, 3, 4 or 5 parameters"); } const result = new Variant(); if (paramCount == 1) { const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Long); result.asTimeSpan = value.asLong; } else if (paramCount > 2) { const value1 = variantOperations.convert(this.getParameter(params, 0), VariantType.Long); const value2 = variantOperations.convert(this.getParameter(params, 1), VariantType.Long); const value3 = variantOperations.convert(this.getParameter(params, 2), VariantType.Long); const value4 = paramCount > 3 ? variantOperations.convert(this.getParameter(params, 3), VariantType.Long) : Variant.fromLong(0); const value5 = paramCount > 4 ? variantOperations.convert(this.getParameter(params, 4), VariantType.Long) : Variant.fromLong(0); result.asTimeSpan = (((value1.asLong * 24 + value2.asLong) * 60 + value3.asLong) * 60 + value4.asLong) * 1000 + value5.asLong; } return result; } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async nowFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 0); return Variant.fromDateTime(new Date()); } private async dateFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { const paramCount = params.length; if (paramCount < 1 || paramCount > 7) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected from 1 to 7 parameters"); } if (paramCount == 1) { const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Long); return Variant.fromDateTime(new Date(value.asLong)); } const value1 = variantOperations.convert(this.getParameter(params, 0), VariantType.Integer); const value2 = paramCount > 1 ? variantOperations.convert(this.getParameter(params, 1), VariantType.Integer) : Variant.fromInteger(1); const value3 = paramCount > 2 ? variantOperations.convert(this.getParameter(params, 2), VariantType.Integer) : Variant.fromInteger(1); const value4 = paramCount > 3 ? variantOperations.convert(this.getParameter(params, 3), VariantType.Integer) : Variant.fromInteger(0); const value5 = paramCount > 4 ? variantOperations.convert(this.getParameter(params, 4), VariantType.Integer) : Variant.fromInteger(0); const value6 = paramCount > 5 ? variantOperations.convert(this.getParameter(params, 5), VariantType.Integer) : Variant.fromInteger(0); const value7 = paramCount > 6 ? variantOperations.convert(this.getParameter(params, 6), VariantType.Integer) : Variant.fromInteger(0); const date = new Date(value1.asInteger, value2.asInteger-1, value3.asInteger, value4.asInteger, value5.asInteger, value6.asInteger, value7.asInteger); return Variant.fromDateTime(date); } private async dayOfWeekFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.DateTime); const date = value.asDateTime; return Variant.fromInteger(date.getDay()); } private async minFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { const paramCount = params.length; if (paramCount < 2) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected at least 2 parameters"); } let result = this.getParameter(params, 0); for (let i = 1; i < paramCount; i++) { const value = this.getParameter(params, i); if (variantOperations.more(result, value).asBoolean) { result = value; } } return result; } private async maxFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { const paramCount = params.length; if (paramCount < 2) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected at least 2 parameters"); } let result = this.getParameter(params, 0); for (let i = 1; i < paramCount; i++) { const value = this.getParameter(params, i); if (variantOperations.less(result, value).asBoolean) { result = value; } } return result; } private async sumFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { const paramCount = params.length; if (paramCount < 2) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected at least 2 parameters"); } let result = this.getParameter(params, 0); for (let i = 1; i < paramCount; i++) { const value = this.getParameter(params, i); result = variantOperations.add(result, value); } return result; } private async ifFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 3); const value1 = this.getParameter(params, 0); const value2 = this.getParameter(params, 1); const value3 = this.getParameter(params, 2); const condition = variantOperations.convert(value1, VariantType.Boolean); return condition.asBoolean ? value2 : value3; } private async chooseFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { const paramCount = params.length; if (paramCount < 3) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected at least 3 parameters"); } const value1 = this.getParameter(params, 0); const condition = variantOperations.convert(value1, VariantType.Integer); const paramIndex = condition.asInteger; if (paramCount < paramIndex + 1) { throw new ExpressionException(null, "WRONG_PARAM_COUNT", "Expected at least " + (paramIndex + 1) + " parameters"); } return this.getParameter(params, paramIndex); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async eFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 0); return new Variant(Math.E); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async piFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 0); return new Variant(Math.PI); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async rndFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 0); return new Variant(Math.random()); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async absFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); let value = this.getParameter(params, 0); const result = new Variant(); switch (value.type) { case VariantType.Integer: result.asInteger = Math.abs(value.asInteger); break; case VariantType.Long: result.asLong = Math.abs(value.asLong); break; case VariantType.Float: result.asFloat = Math.abs(value.asFloat); break; case VariantType.Double: result.asDouble = Math.abs(value.asDouble); break; default: value = variantOperations.convert(value, VariantType.Double); result.asDouble = Math.abs(value.asDouble); break; } return result; } private async acosFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.acos(value.asDouble)); } private async asinFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.asin(value.asDouble)); } private async atanFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.atan(value.asDouble)); } private async expFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.exp(value.asDouble)); } private async logFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.log(value.asDouble)); } private async log10FunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.log10(value.asDouble)); } private async ceilFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.ceil(value.asDouble)); } private async floorFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.floor(value.asDouble)); } private async roundFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.round(value.asDouble)); } private async truncFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return Variant.fromInteger(Math.trunc(value.asDouble)); } private async cosFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.cos(value.asDouble)); } private async sinFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.sin(value.asDouble)); } private async tanFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.tan(value.asDouble)); } private async sqrtFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = variantOperations.convert(this.getParameter(params, 0), VariantType.Double); return new Variant(Math.sqrt(value.asDouble)); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async emptyFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 1); const value = this.getParameter(params, 0); return new Variant(value.isEmpty()); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async nullFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 0); return new Variant(); } private async containsFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { this.checkParamCount(params, 2); const containerstr = variantOperations.convert(this.getParameter(params, 0), VariantType.String); const substring = variantOperations.convert(this.getParameter(params, 1), VariantType.String); if (containerstr.isEmpty() || containerstr.isNull()) { return Variant.fromBoolean(false); } return Variant.fromBoolean(containerstr.asString.indexOf(substring.asString) >= 0); } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async arrayFunctionCalculator(params: Variant[], variantOperations: IVariantOperations): Promise<Variant> { return Variant.fromArray(params); } }