@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
JavaScript
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