UNPKG

@syncfusion/ej2-spreadsheet

Version:

Feature-rich JavaScript Spreadsheet (Excel) control with built-in support for selection, editing, formatting, importing and exporting to Excel

1,026 lines 68.1 kB
import { FormulaError } from './index'; import { CommonErrors, FormulasErrorsStrings, isExternalFileLink } from '../common/index'; import { isNullOrUndefined } from '@syncfusion/ej2-base'; var Parser = /** @class */ (function () { function Parser(parent) { this.emptyStr = ''; this.storedStringText = this.emptyStr; this.sheetToken = '!'; /** @hidden */ this.tokenAdd = 'a'; /** @hidden */ this.tokenSubtract = 's'; /** @hidden */ this.tokenMultiply = 'm'; /** @hidden */ this.tokenDivide = 'd'; /** @hidden */ this.tokenLess = 'l'; this.charEm = 'r'; this.charEp = 'x'; /** @hidden */ this.tokenGreater = 'g'; /** @hidden */ this.tokenEqual = 'e'; /** @hidden */ this.tokenLessEq = 'k'; /** @hidden */ this.tokenGreaterEq = 'j'; /** @hidden */ this.tokenNotEqual = 'o'; /** @hidden */ this.tokenAnd = 'c'; this.tokenEm = 'v'; this.tokenEp = 't'; /** @hidden */ this.tokenOr = String.fromCharCode(126); this.charAnd = 'i'; this.charLess = '<'; this.charGreater = '>'; this.charEqual = '='; this.charLessEq = 'f'; this.charGreaterEq = 'h'; this.charNoEqual = 'z'; this.stringGreaterEq = '>='; this.stringLessEq = '<='; this.stringNoEqual = '<>'; this.stringAnd = '&'; this.stringOr = '^'; this.charOr = 'w'; this.charAdd = '+'; this.charSubtract = '-'; this.charMultiply = '*'; this.charDivide = '/'; this.fixedReference = '$'; this.spaceString = ' '; this.ignoreBracet = false; /** @hidden */ this.isError = false; /** @hidden */ this.isFormulaParsed = false; this.findNamedRange = false; this.stringsColl = new Map(); this.tokens = [ this.tokenAdd, this.tokenSubtract, this.tokenMultiply, this.tokenDivide, this.tokenLess, this.tokenGreater, this.tokenEqual, this.tokenLessEq, this.tokenGreaterEq, this.tokenNotEqual, this.tokenAnd, this.tokenOr ]; this.charNOTop = String.fromCharCode(167); this.specialSym = ['~', '@', '#', '?']; this.isFailureTriggered = false; this.parent = parent; } /** * @hidden * @param {string} text - specify the text * @param {string} fkey - specify the formula key * @returns {string} - returns parse. */ Parser.prototype.parse = function (text, fkey) { var _this = this; if (this.parent.isTextEmpty(text)) { return text; } if (isExternalFileLink(text)) { return this.parent.getErrorStrings()[CommonErrors.Ref]; } if (this.parent.getFormulaCharacter() !== String.fromCharCode(0) && this.parent.getFormulaCharacter() === text[0]) { text = text.substring(1); } if (this.parent.namedRanges.size > 0 || this.parent.storedData.size > 0) { text = this.checkForNamedRangeAndKeyValue(text); this.findNamedRange = false; } text = text.replace(/[-+*/&^]+/g, function (operators) { var firstOp = ''; while (1 < operators.length) { switch (operators.substring(0, 2)) { case '++': operators = '+' + operators.substring(2); break; case '--': operators = '+' + operators.substring(2); break; case '+-': operators = '-' + operators.substring(2); break; case '-+': operators = '-' + operators.substring(2); break; case '*+': operators = '*' + operators.substring(2); break; case '/+': operators = '/' + operators.substring(2); break; case '^+': operators = '^' + operators.substring(2); break; case '&+': operators = '&' + operators.substring(2); break; case '*-': case '/-': case '^-': case '&-': firstOp = operators.substring(0, 1); operators = operators.substring(1); break; default: throw new FormulaError(_this.parent.formulaErrorStrings[FormulasErrorsStrings.InvalidExpression], true); } } return firstOp + operators; }); text = text.split('-' + '(' + '-').join('('); var formulaString = this.storeStrings(text); text = this.storedStringText; var i = 0; if (isNullOrUndefined(formulaString)) { text = text.split(' ').join(''); } text = text.split('=>').join('>='); text = text.split('=<').join('<='); if (text[text.length - 1] !== this.parent.arithMarker || this.indexOfAny(text, this.tokens) !== (text.length - 2)) { text = text.toUpperCase(); } if (text.indexOf(this.sheetToken) > -1) { var family = this.parent.getSheetFamilyItem(this.parent.grid); if (family.sheetNameToParentObject != null && family.sheetNameToParentObject.size > 0) { if (text[0] !== this.sheetToken.toString()) { text = this.parent.setTokensForSheets(text); } var sheetToken = this.parent.getSheetToken(text.split(this.parent.tic).join(this.emptyStr)); var scopedRange = this.checkScopedRange(text.split('"').join(this.emptyStr).split(this.sheetToken).join('')); if (isNullOrUndefined(sheetToken) && sheetToken !== '' && this.parent.namedRanges.size > 0 && scopedRange !== '') { text = scopedRange; } } } text = this.markLibraryFormulas(text); try { text = this.formulaAutoCorrection(text); } catch (ex) { var args = { message: ex.message, exception: ex, isForceCalculable: ex.formulaCorrection, computeForceCalculate: false }; if (!args.isForceCalculable) { throw this.parent.formulaErrorStrings[FormulasErrorsStrings.InvalidExpression]; } if (!this.isFailureTriggered) { this.parent.trigger('onFailure', args); this.isFailureTriggered = true; } if (args.isForceCalculable && args.computeForceCalculate) { text = this.formulaAutoCorrection(text, args); this.parent.storedData.get(fkey).formulaText = '=' + text; } else { throw this.parent.formulaErrorStrings[FormulasErrorsStrings.InvalidExpression]; } } if (!this.ignoreBracet) { i = text.indexOf(')'); while (i > -1) { var k = text.substring(0, i).lastIndexOf('('); if (k === -1) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.MismatchedParentheses]); } if (k === i - 1) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.EmptyExpression]); } var s = this.emptyStr; if (this.ignoreBracet) { s = this.parent.substring(text, k, i - k + 1); } else { s = this.parent.substring(text, k + 1, i - k - 1); } try { text = text.substring(0, k) + this.parseSimple(s) + text.substring(i + 1); } catch (ex) { if (ex === this.parent.formulaErrorStrings[FormulasErrorsStrings.CircularReference]) { throw ex; } var args = this.exceptionArgs(ex); if (!this.isFailureTriggered) { this.parent.trigger('onFailure', args); this.isFailureTriggered = true; } var errorMessage = (typeof args.exception === 'string') ? args.exception : args.message; return (this.parent.getErrorLine(ex) ? '' : '#' + this.parent.getErrorLine(ex) + ': ') + errorMessage; } i = text.indexOf(')'); } } if (!this.ignoreBracet && text.indexOf('(') > -1) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.MismatchedParentheses]); } text = this.parseSimple(text); if (formulaString !== null && formulaString.size > 0) { text = this.setStrings(text, formulaString); } return text; }; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ Parser.prototype.exceptionArgs = function (ex) { return { message: ex.message, exception: ex, isForceCalculable: ex.formulaCorrection, computeForceCalculate: false }; }; Parser.prototype.formulaAutoCorrection = function (formula, args, isSubString) { var arithemeticArr = ['*', '+', '-', '/', '^', '&']; var logicalSym = ['>', '=', '<']; var i = 0; var form = ''; var op = ''; var firstOp = ''; var secondprevOp = ''; var secondnextOp = ''; var firstDigit = ''; var secondDigit = ''; var countDigit = 0; if (this.parent.formulaErrorStrings.indexOf(formula) > -1) { return formula; } else { if (this.indexOfAny(formula, this.specialSym) > -1) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.InvalidExpression], false); } while (i < formula.length) { formula = formula.split('-*').join('-').split('/*').join('/').split('*/').join('*').split('-/').join('-'). split('*+').join('*').split('+*').join('+'); if ((this.parent.isDigit(formula[i]) && ((formula.length > i + 1) && (this.indexOfAny(formula[i + 1], arithemeticArr) > -1)) && ((formula.length > i + 2) && (!isNullOrUndefined(formula[i + 2]) && this.indexOfAny(formula[i + 2], arithemeticArr) > -1))) && (formula[i + 2] !== '-' || (formula[i + 1] !== '*' && formula[i + 1] !== '/' && formula[i + 1] !== '^' && formula[i + 1] !== '&'))) { if (args && args.computeForceCalculate) { if (this.parent.isDigit(formula[i])) { if (countDigit < 1) { firstDigit = formula[i]; firstOp = formula[i + 1]; if (isNullOrUndefined(firstOp)) { firstOp = this.emptyStr; } firstOp = firstOp === '&' ? '' : firstOp; countDigit = countDigit + 1; form = form + firstDigit + firstOp; } else if (countDigit < 2) { secondDigit = formula[i]; secondprevOp = formula[i - 1]; secondnextOp = formula[i + 1]; countDigit = 0; if (secondprevOp === '-') { secondnextOp = isNullOrUndefined(secondnextOp) ? this.emptyStr : secondnextOp; secondnextOp = secondnextOp === '&' ? '' : secondnextOp; form = form + secondprevOp + secondDigit + secondnextOp; } else { secondnextOp = isNullOrUndefined(secondnextOp) ? this.emptyStr : secondnextOp; form = form + secondDigit + secondnextOp; } } i = i + 2; } else { form = (formula[i] === '-') ? form + formula[i] : form; i = i + 1; } } else { throw this.parent.formulaErrorStrings[FormulasErrorsStrings.ImproperFormula]; } } else if ((this.parent.isDigit(formula[i]) || formula[i] === this.parent.rightBracket || this.parent.storedData.has(formula[i].toUpperCase())) && (isNullOrUndefined(formula[i + 1]) || (this.indexOfAny(formula[i + 1], arithemeticArr) > -1 && formula[i + 1] !== '&'))) { op = isNullOrUndefined(formula[i + 1]) ? this.emptyStr : formula[i + 1]; op = op === '&' && formula[i + 2] !== '-' ? '' : op; // for the cases 5&3=>53 and 5&-3=>5-3. form = formula[i - 1] === '-' ? form + formula[i - 1] + formula[i] + op : form + formula[i] + op; i = i + 2; } else if (this.indexOfAny(formula[i], logicalSym) > -1 && !isNullOrUndefined(formula[i - 1]) && !isNullOrUndefined(formula[i + 1])) { form = form + formula[i]; i = i + 1; } else if (formula[i] === 'q') { while (formula[i] !== this.parent.leftBracket) { form = form + formula[i]; i = i + 1; } } else if (formula[i] === this.parent.leftBracket || formula[i] === this.parent.rightBracket || formula[i] === '{' || formula[i] === '}' || formula[i] === '(' || formula[i] === ')') { form = form + formula[i]; i = i + 1; } else if (this.parent.isUpperChar(formula[i]) || formula[i].indexOf(':') > -1 || formula[i] === this.parent.getParseArgumentSeparator() || (formula[i] === '%' && this.parent.isDigit(formula[i - 1]))) { form = form + formula[i]; i = i + 1; } else if (formula[i] === this.parent.tic || formula[i] === ' ' || formula[i] === this.parent.getParseDecimalSeparator() || formula[i] === this.sheetToken || formula[i] === '$' || formula[i] === '_') { form = form + formula[i]; i = i + 1; } else { if (this.parent.isDigit(formula[i])) { form = formula[i - 1] === '-' ? form + formula[i - 1] + formula[i] : form + formula[i]; } if (formula[i] === '-' || formula[i] === '+') { form = form + formula[i]; form = form.split('++').join('+').split('+-').join('-').split('-+').join('-'); } if (formula[i] === '/' || formula[i] === '*' || formula[i] === '^') { form = form + formula[i]; } if (formula[i] === '&' && (isSubString || formula.substring(i + 1).trim()[0] !== 'q')) { form = form + formula[i]; } i = i + 1; } } } form = form === this.emptyStr ? formula : form; if (this.indexOfAny(form[form.length - 1], arithemeticArr) > -1) { form = form.substring(0, form.length - 1); } form = form.split('--').join('-').split('-+').join('-').split('+-').join('-'); return form; }; Parser.prototype.checkScopedRange = function (text) { var _this = this; var scopedRange = this.emptyStr; var b = 'NaN'; var id = this.parent.getSheetID(this.parent.grid); var sheet = this.parent.getSheetFamilyItem(this.parent.grid); if (text[0] === this.sheetToken.toString()) { var i = text.indexOf(this.sheetToken, 1); var v = parseInt(text.substr(1, i - 1), 10); if (i > 1 && !this.parent.isNaN(v)) { text = text.substring(i + 1); id = v; } } var token = '!' + id.toString(); if (sheet === null || sheet.sheetNameToToken == null) { return b; } sheet.sheetNameToToken.forEach(function (value, key) { if (sheet.sheetNameToToken.get(key).toString() === token + '!') { var s_1 = _this.emptyStr; _this.parent.namedRanges.forEach(function (value, key) { /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ if (!isNullOrUndefined(_this.parent.parentObject)) { /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ s_1 = _this.parent.parentObject.getActiveSheet().name + _this.sheetToken + text.toUpperCase(); } else { s_1 = sheet.sheetNameToToken.get(key).toUpperCase(); } if (_this.parent.getNamedRanges().has(s_1)) { scopedRange = (_this.parent.getNamedRanges().get(s_1)).toUpperCase(); b = scopedRange; } }); } }); return b; }; Parser.prototype.storeStrings = function (tempString) { var i = 0; var j = 0; var id = 0; var key = ''; var storedString = null; var condition; var ticLoc = tempString.indexOf(this.parent.tic); if (ticLoc > -1) { i = tempString.indexOf(this.parent.tic); while (i > -1 && tempString.length > 0) { if (storedString === null) { storedString = this.stringsColl; } j = i + 1 < tempString.length ? tempString.indexOf(this.parent.tic, i + 1) : -1; if (j === -1) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.MismatchedTics]); } condition = this.parent.substring(tempString, i, j - i + 1); key = this.parent.tic + this.spaceString + id.toString() + this.parent.tic; storedString = storedString.set(key, condition); tempString = tempString.substring(0, i) + key + tempString.substring(j + 1); i = i + key.length; if (i <= tempString.length) { i = tempString.indexOf(this.parent.tic, i); } id++; } } this.storedStringText = tempString; return storedString; }; Parser.prototype.setStrings = function (text, formulaString) { for (var i = 0; i < formulaString.size; i++) { formulaString.forEach(function (value, key) { text = text.split(key).join(value); }); } return text; }; /** * @hidden * @param {string} formulaText - specify the formula text * @returns {string} - parse simple. */ Parser.prototype.parseSimple = function (formulaText) { var needToContinue = true; var text = formulaText; if (text.length > 0 && text[0] === '+') { text = text.substring(1); } if (text === '#DIV/0!') { return '#DIV/0!'; } if (text === '#NAME?') { return '#NAME?'; } if (text === '') { return text; } if (this.parent.formulaErrorStrings.indexOf(text) > -1) { return text; } text = text.split(this.stringLessEq).join(this.charLessEq); text = text.split(this.stringGreaterEq).join(this.charGreaterEq); text = text.split(this.stringNoEqual).join(this.charNoEqual); text = text.split(this.stringAnd).join(this.charAnd); text = text.split(this.stringOr).join(this.charOr); text = text.split(this.fixedReference).join(this.emptyStr); needToContinue = true; var expTokenArray = [this.tokenEp, this.tokenEm]; var mulTokenArray = [this.tokenMultiply, this.tokenDivide]; var addTokenArray = [this.tokenAdd, this.tokenSubtract]; var mulCharArray = [this.charMultiply, this.charDivide]; var addCharArray = [this.charAdd, this.charSubtract]; var compareTokenArray = [this.tokenLess, this.tokenGreater, this.tokenEqual, this.tokenLessEq, this.tokenGreaterEq, this.tokenNotEqual]; var compareCharArray = [this.charLess, this.charGreater, this.charEqual, this.charLessEq, this.charGreaterEq, this.charNoEqual]; var expCharArray = [this.charEp, this.charEm]; var andTokenArray = [this.tokenAnd]; var andCharArray = [this.charAnd]; var orCharArray = [this.charOr]; var orTokenArray = [this.tokenOr]; text = this.parseSimpleOperators(text, expTokenArray, expCharArray); text = this.parseSimpleOperators(text, orTokenArray, orCharArray); if (needToContinue) { text = this.parseSimpleOperators(text, mulTokenArray, mulCharArray); } if (needToContinue) { text = this.parseSimpleOperators(text, addTokenArray, addCharArray); } if (needToContinue) { text = this.parseSimpleOperators(text, compareTokenArray, compareCharArray); } if (needToContinue) { text = this.parseSimpleOperators(text, andTokenArray, andCharArray); } return text; }; /** * @hidden * @param {string} formulaText - specify the formula text * @param {string[]} markers - specify the markers * @param {string[]} operators - specify the operators * @returns {string} - parse Simple Operators */ Parser.prototype.parseSimpleOperators = function (formulaText, markers, operators) { if (this.parent.getErrorStrings().indexOf(formulaText) > -1) { return formulaText; } var text = formulaText; var i = 0; var op = ''; for (var c = 0; c < operators.length; c++) { op = op + operators[c]; } text = text.split('---').join('-').split('--').join('+').split(this.parent.getParseArgumentSeparator() + '-').join(this.parent.getParseArgumentSeparator() + 'u').split(this.parent.leftBracket + '-').join(this.parent.leftBracket + 'u').split('=-').join('=u'); text = text.split(',+').join(',').split(this.parent.leftBracket + '+').join(this.parent.leftBracket).split('=+').join('=').split('>+').join('>').split('<+').join('<').split('/+').join('/').split('*+').join('*').split('++').join('+').split('*-').join('*u').split('/-').join('/u').split('w-').join('wu').split('i-').join('iu').toString(); text = text.split('>-').join('>u').split('<-').join('<u').split('h-').join('hu').split('f-').join('fu').split('z-').join('zu'); if (text.length > 0 && text[0] === '-') { var tokenOrOp = String.fromCharCode(132); text = text.substring(1).split('-').join(tokenOrOp); text = '0-' + text; text = this.parseSimpleOperators(text, [this.tokenSubtract], [this.charSubtract]); text = text.split(tokenOrOp).join('-'); } else if (text.length > 0 && text[0] === '+') { text = text.substring(1); } else if (text.length > 0 && text[text.length - 1] === '+') { text = text.substring(0, text.length - 1); } try { if (this.indexOfAny(text, operators) > -1) { if (text.includes(' ')) { var newText = ''; for (var index = 0; index < text.length; index++) { var currChar = text[index]; if (operators.indexOf(currChar) >= 0) { newText = newText.trim() + currChar; } else if (currChar === ' ' && operators.indexOf(newText[newText.length - 1]) >= 0) { continue; } else { newText += currChar; } } text = newText; } i = this.indexOfAny(text, operators); var decimalSep = this.parent.getParseDecimalSeparator(); while (i > -1) { var left = ''; var right = ''; var leftIndex = 0; var rightIndex = 0; var isLeftBool = false; var arithOp = ['*', '+', '-', '/', 'w', '=', '<', '>']; var isNotOperator = text[i] === this.charNOTop; var j = 0; if (!isNotOperator) { j = i - 1; if (text[j] === this.parent.arithMarker) { var k = this.findLeftMarker(text.substring(0, j - 1)); if (k < 0) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.CannotParse]); } left = this.parent.substring(text, k + 1, j - k - 1); leftIndex = k + 1; } else if (text[j] === this.parent.rightBracket) { var bracketCount = 0; var k = j - 1; while (k > 0 && (text[k] !== 'q' || bracketCount !== 0)) { if (text[k] === 'q') { bracketCount--; } else if (text[k] === this.parent.rightBracket) { bracketCount++; } k--; } if (k < 0) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.CannotParse]); } left = this.parent.substring(text, k, j - k + 1); leftIndex = k; } else if (text[j] === this.parent.tic[0]) { var l = text.substring(0, j - 1).lastIndexOf(this.parent.tic); if (l < 0) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.CannotParse]); } left = this.parent.substring(text, l, j - l + 1); leftIndex = l; } else { var period = false; while (j > -1 && (this.parent.isDigit(text[j]) || (!period && (text[j] === decimalSep || text[j] === '%')))) { if (!this.parent.isDigit(text[j]) && text[j] !== '%') { period = true; } j = j - 1; } if (j > -1 && period && text[j] === decimalSep) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.NumberContains2DecimalPoints]); } j = j + 1; if (j === 0 || (j > 0 && !this.parent.isUpperChar(text[j - 1]))) { left = 'n' + this.parent.substring(text, j, i - j); leftIndex = j; } else if (j > 0 && text[j - 1] === 'E' && ((text.substring(j - 4, j) === 'TRUE' && (!isNullOrUndefined(text[j - 5]) ? arithOp.indexOf(text[j - 5]) > -1 : true)) || (text.substring(j - 5, j) === 'FALSE' && (!isNullOrUndefined(text[j - 6]) ? arithOp.indexOf(text[j - 6]) > -1 : true))) && (text.substring(j + 1, j + 5) === 'TRUE' || text.substring(j + 1, j + 6) === 'FALSE')) { j = text.substring(j - 4, j) === 'TRUE' ? j - 4 : j - 5; left = text.substring(j, i) === 'TRUE' ? 'n1' : (text.substring(j, i) === 'FALSE' ? 'n0' : left); leftIndex = j; isLeftBool = true; } else { j = j - 1; while (j > -1 && (this.parent.isUpperChar(text[j]) || // Check if character is uppercase alphabets. this.parent.isDigit(text[j]) || // Check if character is a digit. text[j] === '_')) { // Check if character is an underscore ('_'), for defined names cases. j = j - 1; } if (j > -1 && text[j] === this.sheetToken) { j = j - 1; while (j > -1 && text[j] !== this.sheetToken) { j = j - 1; } if (j > -1 && text[j] === this.sheetToken) { j = j - 1; } } if (j > -1 && text[j] === ':') { //// handle range operands j = j - 1; while (j > -1 && this.parent.isDigit(text[j])) { j = j - 1; } while (j > -1 && this.parent.isUpperChar(text[j])) { j = j - 1; } if (j > -1 && text[j] === this.sheetToken) { j--; while (j > -1 && text[j] !== this.sheetToken) { j--; } if (j > -1 && text[j] === this.sheetToken) { j--; } } j = j + 1; left = this.parent.substring(text, j, i - j); left = this.parent.getCellFrom(left); } else { var uFound = false; if (j > 0 && !this.parent.isUpperChar(text[j])) { uFound = text[j] === 'u' && text[j - 1] === this.parent.getParseArgumentSeparator(); } if (!uFound) { j = j + 1; } left = this.parent.substring(text, j, i - j); } this.parent.updateDependentCell(left); leftIndex = j; } if ((this.parent.namedRanges.size > 0 && this.parent.namedRanges.has(left.toUpperCase())) || (this.parent.storedData.has(left.toUpperCase()))) { left = 'n' + this.checkForNamedRangeAndKeyValue(left); } } } else { leftIndex = i; } if (i === text.length - 1) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.ExpressionCannotEndWithAnOperator]); } else { j = i + 1; var uFound = text[j] === 'u'; // for 3*-2 if (uFound) { j = j + 1; } if (text[j] === this.parent.tic[0]) { var k = text.substring(j + 1).indexOf(this.parent.tic); if (k < 0) { throw this.parent.formulaErrorStrings[FormulasErrorsStrings.CannotParse]; } right = this.parent.substring(text, j, k + 2); rightIndex = k + j + 2; } else if (text[j] === this.parent.arithMarker) { var k = this.findRightMarker(text.substring(j + 1)); if (k < 0) { throw new FormulaError(this.parent.formulaErrorStrings[FormulasErrorsStrings.CannotParse]); } right = this.parent.substring(text, j + 1, k); rightIndex = k + j + 2; } else if (text[j] === 'q') { var bracketCount = 0; var k = j + 1; while (k < text.length && (text[k] !== this.parent.rightBracket || bracketCount !== 0)) { if (text[k] === this.parent.rightBracket) { bracketCount++; } else if (text[k] === 'q') { bracketCount--; } k++; } if (k === text.length) { throw this.parent.formulaErrorStrings[FormulasErrorsStrings.CannotParse]; } right = this.parent.substring(text, j, k - j + 1); if (uFound) { right = 'u' + right; } rightIndex = k + 1; } else if (this.parent.isDigit(text[j]) || text[j] === decimalSep) { var period = (text[j] === decimalSep); j = j + 1; while (j < text.length && (this.parent.isDigit(text[j]) || (!period && text[j] === decimalSep))) { if (text[j] === decimalSep) { period = true; } j = j + 1; } if (j < text.length && text[j] === '%') { j += 1; } if (period && j < text.length && text[j] === decimalSep) { throw this.parent.formulaErrorStrings[FormulasErrorsStrings.NumberContains2DecimalPoints]; } right = 'n' + this.parent.substring(text, i + 1, j - i - 1); rightIndex = j; } else if (this.parent.isUpperChar(text[j]) || text[j] === this.sheetToken || text[j] === 'u') { if (text[j] === this.sheetToken) { j = j + 1; while (j < text.length && text[j] !== this.sheetToken) { j = j + 1; } } j = j + 1; var jTemp = 0; var inbracket = false; while (j < text.length && (this.parent.isUpperChar(text[j]) || text[j] === '_' || text[j] === decimalSep || text[j] === '[' || text[j] === ']' || text[j] === '#' || text[j] === ' ' || text[j] === '%' || text[j] === decimalSep && inbracket)) { if (j !== text.length - 1 && text[j] === '[' && text[j + 1] === '[') { inbracket = true; } if (j !== text.length - 1 && text[j] === ']' && text[j + 1] === ']') { inbracket = false; } j++; jTemp++; } var noCellReference = (j === text.length) || !this.parent.isDigit(text[j]); if (jTemp > 1) { while (j < text.length && (this.parent.isUpperChar(text[j]) || this.parent.isDigit(text[j]) || text[j] === ' ' || text[j] === '_')) { j++; } noCellReference = true; } while (j < text.length && this.parent.isDigit(text[j])) { j = j + 1; } if (j < text.length && text[j] === ':') { j = j + 1; if (j < text.length && text[j] === this.sheetToken) { j++; while (j < text.length && text[j] !== this.sheetToken) { j = j + 1; } if (j < text.length && text[j] === this.sheetToken) { j++; } } while (j < text.length && this.parent.isUpperChar(text[j])) { j = j + 1; } while (j < text.length && this.parent.isDigit(text[j])) { j = j + 1; } j = j - 1; right = this.parent.substring(text, i + 1, j - i); right = this.parent.getCellFrom(right); } else { j = j - 1; right = this.parent.substring(text, i + 1, j - i); uFound = text[j] === 'u'; if (uFound) { right = 'u' + right; } } if (noCellReference && right.startsWith(this.sheetToken)) { noCellReference = !this.parent.isCellReference(right); } if (!noCellReference) { this.parent.updateDependentCell(right); } if ((this.parent.namedRanges.size > 0 && this.parent.namedRanges.has(right.toUpperCase())) || (this.parent.storedData.has(right.toUpperCase()))) { right = 'n' + this.checkForNamedRangeAndKeyValue(right); } var isPrevArithOp = ['*', '+', '-', '/', 'w'].indexOf(text[j - right.length]) > -1; right = right === 'TRUE' && (isLeftBool || isPrevArithOp) ? 'n1' : (right === 'FALSE' && (isLeftBool || isPrevArithOp) ? 'n0' : right); rightIndex = j + 1; } } var p = op.indexOf(text[i]); var s = this.parent.arithMarker + left + right + markers[p] + this.parent.arithMarker; if (leftIndex > 0) { s = text.substring(0, leftIndex) + s; } if (rightIndex < text.length) { s = s + text.substring(rightIndex); } s = s.split(this.parent.arithMarker2).join(this.parent.arithMarker.toString()); text = s; i = this.indexOfAny(text, operators); } } else { if (text.length > 0 && (this.parent.isUpperChar(text[0]) || text[0] === this.sheetToken)) { var isCharacter = true; var checkLetter = true; var oneTokenFound = false; var textLen = text.length; for (var k = 0; k < textLen; ++k) { if (text[k] === this.sheetToken) { if (k > 0 && !oneTokenFound) { throw this.parent.getErrorStrings()[CommonErrors.Ref]; } oneTokenFound = true; k++; while (k < textLen && this.parent.isDigit(text[k])) { k++; } if (k === textLen || text[k] !== this.sheetToken) { isCharacter = false; break; } } else { if (!checkLetter && this.parent.isChar(text[k])) { isCharacter = false; break; } if (this.parent.isChar(text[k]) || this.parent.isDigit(text[k]) || text[k] === this.sheetToken) { checkLetter = this.parent.isUpperChar(text[k]); } else { isCharacter = false; break; } } } if (isCharacter) { this.parent.updateDependentCell(text); } } } return text; } catch (ex) { if (ex === this.parent.formulaErrorStrings[FormulasErrorsStrings.CircularReference]) { throw ex; } return ex; } }; /** * @hidden * @param {string} text - specify the text * @param {string[]} operators - specify the operators * @returns {number} - returns index. */ Parser.prototype.indexOfAny = function (text, operators) { for (var i = 0; i < text.length; i++) { if (operators.indexOf(text[i]) > -1) { return i; } } return -1; }; /** * @hidden * @param {string} text - specify the text * @returns {number} - find Left Marker. */ Parser.prototype.findLeftMarker = function (text) { var ret = -1; if (text.indexOf(this.parent.arithMarker) > -1) { var bracketLevel = 0; for (var i = text.length - 1; i >= 0; --i) { if (text[i] === this.parent.rightBracket) { bracketLevel--; } else if (text[i] === this.parent.leftBracket) { bracketLevel++; } else if (text[i] === this.parent.arithMarker && bracketLevel === 0) { ret = i; break; } } } return ret; }; /** * @hidden * @param {string} text - specify the text. * @returns {number} - find Right Marker. */ Parser.prototype.findRightMarker = function (text) { var ret = -1; if (text.indexOf(this.parent.arithMarker) > -1) { var bracketLevel = 0; for (var j = 0; j < text.length; ++j) { if (text[j] === this.parent.rightBracket) { bracketLevel--; } else if (text[j] === this.parent.leftBracket) { bracketLevel++; } else if (text[j] === this.parent.arithMarker && bracketLevel === 0) { ret = j; break; } } } return ret; }; /** * @hidden * @param {string} formula - specify the formula * @param {string} fKey - specify the formula key. * @returns {string} - parse formula. */ Parser.prototype.parseFormula = function (formula, fKey) { if (formula.length > 0 && formula[0] === this.parent.getFormulaCharacter()) { formula = formula.substring(1); } if (formula.indexOf('#REF!') > -1) { return this.parent.getErrorStrings()[CommonErrors.Ref]; } if (formula.length > 0 && formula[0] === '+') { formula = formula.substring(1); } try { this.isFailureTriggered = false; this.isError = false; formula = this.parse(formula.trim(), fKey); this.isFormulaParsed = true; } catch (ex) { var args = this.exceptionArgs(ex); if (!this.isFailureTriggered) { this.parent.trigger('onFailure', args); this.isFailureTriggered = true; } var errorMessage = (typeof args.exception === 'string') ? args.exception : args.message; formula = (isNullOrUndefined(this.parent.getErrorLine(ex)) ? '' : '#' + this.parent.getErrorLine(ex) + ': ') + errorMessage; this.isError = true; } return formula; }; /** * @hidden * @param {string} formula - specify the formula * @returns {string} - mark library formulas. */ Parser.prototype.markLibraryFormulas = function (formula) { var bracCount = 0; var rightParens = formula.indexOf(')'); if (rightParens === -1) { formula = this.markNamedRanges(formula); } else { var _loop_1 = function () { var parenCount = 0; var leftParens = rightParens - 1; while (leftParens > -1 && (formula[leftParens] !== '(' || parenCount !== 0)) { if (formula[leftParens] === ')') { parenCount++; } // else if (formula[leftParens] === ')') { // parenCount--; // } leftParens--; } if (leftParens === -1) { throw new FormulaError(this_1.parent.formulaErrorStrings[FormulasErrorsStrings.MismatchedParentheses]); } var i = leftParens - 1; while (i > -1 && (this_1.parent.isChar(formula[i]))) { i--; } var len = leftParens - i - 1; var libFormula = this_1.parent.substring(formula, i + 1, len); if (len > 0 && !isNullOrUndefined(this_1.parent.getFunction(libFormula))) { var substr = this_1.parent.substring(formula, leftParens, rightParens - leftParens + 1); var argsSep = this_1.parent.getParseArgumentSeparator(); if (libFormula === 'AREAS') { this_1.ignoreBracet = true; } else { this_1.ignoreBracet = false; if (((libFormula.includes('IFS') && libFormula !== 'COUNTIFS') || libFormula === 'MATCH') && substr.includes('{')) { var leftBraceIdx = substr.indexOf('{'); var crite