UNPKG

pip-services4-expressions-node

Version:

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

821 lines (737 loc) 32.2 kB
/** @module variants */ import { Variant } from './Variant'; import { VariantType } from './VariantType'; import { IVariantOperations } from "./IVariantOperations"; /** * Implements an abstractd variant operations manager object. */ export abstract class AbstractVariantOperations implements IVariantOperations { /** * Convert variant type to string representation * @param value a variant type to be converted. * @returns a string representation of the type. */ protected typeToString(value: VariantType): string { switch (value) { case VariantType.Null: return "Null"; case VariantType.Integer: return "Integer"; case VariantType.Long: return "Long"; case VariantType.Float: return "Float"; case VariantType.Double: return "Double"; case VariantType.String: return "String"; case VariantType.Boolean: return "Boolean"; case VariantType.DateTime: return "DateTime"; case VariantType.TimeSpan: return "TimeSpan"; case VariantType.Object: return "Object"; case VariantType.Array: return "Array"; default: return "Unknown"; } } /** * Converts variant to specified type * @param value A variant value to be converted. * @param newType A type of object to be returned. * @returns A converted Variant value. */ public abstract convert(value: Variant, newType: VariantType): Variant; /** * Performs '+' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public add(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger + value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong + value2.asLong; return result; case VariantType.Float: result.asFloat = value1.asFloat + value2.asFloat; return result; case VariantType.Double: result.asDouble = value1.asDouble + value2.asDouble; return result; case VariantType.TimeSpan: result.asTimeSpan = value1.asTimeSpan + value2.asTimeSpan; return result; case VariantType.String: result.asString = value1.asString + value2.asString; return result; } throw new Error("Operation '+' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '-' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public sub(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger - value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong - value2.asLong; return result; case VariantType.Float: result.asFloat = value1.asFloat - value2.asFloat; return result; case VariantType.Double: result.asDouble = value1.asDouble - value2.asDouble; return result; case VariantType.TimeSpan: result.asTimeSpan = value1.asTimeSpan - value2.asTimeSpan; return result; case VariantType.DateTime: result.asTimeSpan = value1.asDateTime.getTime() - value2.asDateTime.getTime(); return result; } throw new Error("Operation '-' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '*' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public mul(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger * value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong * value2.asLong; return result; case VariantType.Float: result.asFloat = value1.asFloat * value2.asFloat; return result; case VariantType.Double: result.asDouble = value1.asDouble * value2.asDouble; return result; } throw new Error("Operation '*' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '/' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public div(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger / value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong / value2.asLong; return result; case VariantType.Float: result.asFloat = value1.asFloat / value2.asFloat; return result; case VariantType.Double: result.asDouble = value1.asDouble / value2.asDouble; return result; } throw new Error("Operation '/' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '%' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public mod(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger % value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong % value2.asLong; return result; } throw new Error("Operation '%' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '^' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public pow(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Performs operation. switch (value1.type) { case VariantType.Integer: case VariantType.Long: case VariantType.Float: case VariantType.Double: // Converts second operant to the type of the first operand. value1 = this.convert(value1, VariantType.Double); value2 = this.convert(value2, VariantType.Double); result.asDouble = value1.asDouble * value2.asDouble; return result; } throw new Error("Operation '^' is not supported for type " + this.typeToString(value1.type)); } /** * Performs AND operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public and(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger & value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong & value2.asLong; return result; case VariantType.Boolean: result.asBoolean = value1.asBoolean && value2.asBoolean; return result; } throw new Error("Operation AND is not supported for type " + this.typeToString(value1.type)); } /** * Performs OR operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public or(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger | value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong | value2.asLong; return result; case VariantType.Boolean: result.asBoolean = value1.asBoolean || value2.asBoolean; return result; } throw new Error("Operation OR is not supported for type " + this.typeToString(value1.type)); } /** * Performs XOR operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public xor(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger ^ value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong ^ value2.asLong; return result; case VariantType.Boolean: result.asBoolean = (value1.asBoolean && !value2.asBoolean) || (!value1.asBoolean && value2.asBoolean); return result; } throw new Error("Operation XOR is not supported for type " + this.typeToString(value1.type)); } /** * Performs '<<' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public lsh(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, VariantType.Integer); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger << value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong << value2.asInteger; return result; } throw new Error("Operation '<<' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '>>' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public rsh(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, VariantType.Integer); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asInteger = value1.asInteger >> value2.asInteger; return result; case VariantType.Long: result.asLong = value1.asLong >> value2.asInteger; return result; } throw new Error("Operation '>>' is not supported for type " + this.typeToString(value1.type)); } /** * Performs NOT operation for a variant. * @param value The operand for this operation. * @returns A result variant object. */ public not(value: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value.type == VariantType.Null) { return result; } // Performs operation. switch (value.type) { case VariantType.Integer: result.asInteger = ~value.asInteger; return result; case VariantType.Long: result.asLong = ~value.asLong; return result; case VariantType.Boolean: result.asBoolean = !value.asBoolean; return result; } throw new Error("Operation NOT is not supported for type " + this.typeToString(value.type)); } /** * Performs unary '-' operation for a variant. * @param value The operand for this operation. * @returns A result variant object. */ public negative(value: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value.type == VariantType.Null) { return result; } // Performs operation. switch (value.type) { case VariantType.Integer: result.asInteger = -value.asInteger; return result; case VariantType.Long: result.asLong = -value.asLong; return result; case VariantType.Float: result.asFloat = -value.asFloat; return result; case VariantType.Double: result.asDouble = -value.asDouble; return result; } throw new Error("Operation unary '-' is not supported for type " + this.typeToString(value.type)); } /** * Performs '=' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public equal(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null && value2.type == VariantType.Null) { result.asBoolean = true; return result; } if (value1.type == VariantType.Null || value2.type == VariantType.Null) { result.asBoolean = false; return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asBoolean = value1.asInteger == value2.asInteger; return result; case VariantType.Long: result.asBoolean = value1.asLong == value2.asLong; return result; case VariantType.Float: result.asBoolean = value1.asFloat == value2.asFloat; return result; case VariantType.Double: result.asBoolean = value1.asDouble == value2.asDouble; return result; case VariantType.String: result.asBoolean = value1.asString == value2.asString; return result; case VariantType.TimeSpan: result.asBoolean = value1.asTimeSpan == value2.asTimeSpan; return result; case VariantType.DateTime: result.asBoolean = value1.asDateTime.getTime() == value2.asDateTime.getTime(); return result; case VariantType.Boolean: result.asBoolean = value1.asBoolean == value2.asBoolean; return result; case VariantType.Object: result.asObject = value1.asObject == value2.asObject; return result; } throw new Error("Operation '=' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '<>' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public notEqual(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null && value2.type == VariantType.Null) { result.asBoolean = false; return result; } if (value1.type == VariantType.Null || value2.type == VariantType.Null) { result.asBoolean = true; return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asBoolean = value1.asInteger != value2.asInteger; return result; case VariantType.Long: result.asBoolean = value1.asLong != value2.asLong; return result; case VariantType.Float: result.asBoolean = value1.asFloat != value2.asFloat; return result; case VariantType.Double: result.asBoolean = value1.asDouble != value2.asDouble; return result; case VariantType.String: result.asBoolean = value1.asString != value2.asString; return result; case VariantType.TimeSpan: result.asBoolean = value1.asTimeSpan != value2.asTimeSpan; return result; case VariantType.DateTime: result.asBoolean = value1.asDateTime.getTime() != value2.asDateTime.getTime(); return result; case VariantType.Boolean: result.asBoolean = value1.asBoolean != value2.asBoolean; return result; case VariantType.Object: result.asObject = value1.asObject != value2.asObject; return result; } throw new Error("Operation '<>' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '>' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public more(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asBoolean = value1.asInteger > value2.asInteger; return result; case VariantType.Long: result.asBoolean = value1.asLong > value2.asLong; return result; case VariantType.Float: result.asBoolean = value1.asFloat > value2.asFloat; return result; case VariantType.Double: result.asBoolean = value1.asDouble > value2.asDouble; return result; case VariantType.String: result.asBoolean = value1.asString > value2.asString; return result; case VariantType.TimeSpan: result.asBoolean = value1.asTimeSpan > value2.asTimeSpan; return result; case VariantType.DateTime: result.asBoolean = value1.asDateTime.getTime() > value2.asDateTime.getTime(); return result; } throw new Error("Operation '>' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '<' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public less(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asBoolean = value1.asInteger < value2.asInteger; return result; case VariantType.Long: result.asBoolean = value1.asLong < value2.asLong; return result; case VariantType.Float: result.asBoolean = value1.asFloat < value2.asFloat; return result; case VariantType.Double: result.asBoolean = value1.asDouble < value2.asDouble; return result; case VariantType.String: result.asBoolean = value1.asString < value2.asString; return result; case VariantType.TimeSpan: result.asBoolean = value1.asTimeSpan < value2.asTimeSpan; return result; case VariantType.DateTime: result.asBoolean = value1.asDateTime.getTime() < value2.asDateTime.getTime(); return result; } throw new Error("Operation '<' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '>=' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public moreEqual(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asBoolean = value1.asInteger >= value2.asInteger; return result; case VariantType.Long: result.asBoolean = value1.asLong >= value2.asLong; return result; case VariantType.Float: result.asBoolean = value1.asFloat >= value2.asFloat; return result; case VariantType.Double: result.asBoolean = value1.asDouble >= value2.asDouble; return result; case VariantType.String: result.asBoolean = value1.asString >= value2.asString; return result; case VariantType.TimeSpan: result.asBoolean = value1.asTimeSpan >= value2.asTimeSpan; return result; case VariantType.DateTime: result.asBoolean = value1.asDateTime.getTime() >= value2.asDateTime.getTime(); return result; } throw new Error("Operation '>=' is not supported for type " + this.typeToString(value1.type)); } /** * Performs '<=' operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public lessEqual(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Converts second operant to the type of the first operand. value2 = this.convert(value2, value1.type); // Performs operation. switch (value1.type) { case VariantType.Integer: result.asBoolean = value1.asInteger <= value2.asInteger; return result; case VariantType.Long: result.asBoolean = value1.asLong <= value2.asLong; return result; case VariantType.Float: result.asBoolean = value1.asFloat <= value2.asFloat; return result; case VariantType.Double: result.asBoolean = value1.asDouble <= value2.asDouble; return result; case VariantType.String: result.asBoolean = value1.asString <= value2.asString; return result; case VariantType.TimeSpan: result.asBoolean = value1.asTimeSpan <= value2.asTimeSpan; return result; case VariantType.DateTime: result.asBoolean = value1.asDateTime.getTime() <= value2.asDateTime.getTime(); return result; } throw new Error("Operation '<=' is not supported for type " + this.typeToString(value1.type)); } /** * Performs IN operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public in(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } // Processes null arrays. if (value1.asObject == null) { result.asBoolean = false; return result; } if (value1.type == VariantType.Array) { const array = value1.asArray; for (const element of array) { const eq = this.equal(value2, element); if (eq.type == VariantType.Boolean && eq.asBoolean) { result.asBoolean = true; return result; } } result.asBoolean = false; return result; } return this.equal(value1, value2); } /** * Performs [] operation for two variants. * @param value1 The first operand for this operation. * @param value2 The second operand for this operation. * @returns A result variant object. */ public getElement(value1: Variant, value2: Variant): Variant { const result = new Variant(); // Processes VariantType.Null values. if (value1.type == VariantType.Null || value2.type == VariantType.Null) { return result; } value2 = this.convert(value2, VariantType.Integer); if (value1.type == VariantType.Array) { return value1.getByIndex(value2.asInteger); } else if (value1.type == VariantType.String) { result.asString = value1.asString.charAt(value2.asInteger); return result; } throw new Error("Operation '[]' is not supported for type " + this.typeToString(value1.type)); } }