spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
name: dist/Parser/Parser.js
-rw-r--r--
44518
  1"use strict";
  2exports.__esModule = true;
  3var Errors_1 = require("../Errors");
  4var Formulas_1 = require("../Formulas");
  5var Symbols_1 = require("./Symbols");
  6var ParserConstants_1 = require("./ParserConstants");
  7var MoreUtils_1 = require("../Utilities/MoreUtils");
  8var TypeConverter_1 = require("../Utilities/TypeConverter");
  9var Math_1 = require("../Formulas/Math");
 10var Parser = (function () {
 11    var parser = {
 12        lexer: undefined,
 13        Parser: undefined,
 14        trace: function trace() { },
 15        yy: {},
 16        /**
 17         * Perform a reduce action on the given virtual stack. Basically, fetching, deriving, or calculating a value.
 18         * @param rawValueOfReduceOriginToken - Some actions require the origin token to perform a reduce action. For
 19         * example, when reducing the cell reference A1 to it's actual value this value would be "A1".
 20         * @param sharedStateYY - the shared state that has all helpers, and current working object.
 21         * @param reduceActionToPerform - the ReduceAction to perform with the current virtual stack. Since this function
 22         * is only called in one place, this should always be action[1] in that context.
 23         * @param virtualStack - Array of values to use in action.
 24         * @param catchOnFailure - If we are performing an action that could result in a failure, and we cant to catch and
 25         * assign the error thrown, this should be set to true.
 26         * @returns {number|boolean|string}
 27         */
 28        performAction: function (rawValueOfReduceOriginToken, sharedStateYY, reduceActionToPerform, virtualStack, catchOnFailure) {
 29            // For context, this function is only called with `apply`, so `this` is `yyval`.
 30            var vsl = virtualStack.length - 1;
 31            try {
 32                switch (reduceActionToPerform) {
 33                    case 1 /* ReturnLast */:
 34                        return virtualStack[vsl - 1];
 35                    case 2 /* CallVariable */:
 36                        this.$ = sharedStateYY.handler.callVariable.call(this, virtualStack[vsl]);
 37                        break;
 38                    case 5 /* AsNumber */:
 39                        this.$ = TypeConverter_1.TypeConverter.valueToNumber(virtualStack[vsl]);
 40                        break;
 41                    case 6 /* AsString */:
 42                        this.$ = MoreUtils_1.string(virtualStack[vsl]);
 43                        break;
 44                    case 7 /* Ampersand */:
 45                        this.$ = TypeConverter_1.TypeConverter.valueToString(virtualStack[vsl - 2]) + TypeConverter_1.TypeConverter.valueToString(virtualStack[vsl]);
 46                        break;
 47                    case 8 /* Equals */:
 48                        this.$ = Math_1.EQ(virtualStack[vsl - 2], virtualStack[vsl]);
 49                        break;
 50                    case 9 /* Plus */:
 51                        this.$ = Math_1.SUM(virtualStack[vsl - 2], virtualStack[vsl]);
 52                        break;
 53                    case 10 /* LastExpression */:
 54                        this.$ = virtualStack[vsl - 1];
 55                        break;
 56                    case 11 /* LTE */:
 57                        this.$ = Math_1.LTE(virtualStack[vsl - 3], virtualStack[vsl]);
 58                        break;
 59                    case 12 /* GTE */:
 60                        this.$ = Math_1.GTE(virtualStack[vsl - 3], virtualStack[vsl]);
 61                        break;
 62                    case 13 /* NotEqual */:
 63                        this.$ = !Math_1.EQ(virtualStack[vsl - 3], virtualStack[vsl]);
 64                        break;
 65                    case 15 /* GT */:
 66                        this.$ = Math_1.GT(virtualStack[vsl - 2], virtualStack[vsl]);
 67                        break;
 68                    case 16 /* LT */:
 69                        this.$ = Math_1.LT(virtualStack[vsl - 2], virtualStack[vsl]);
 70                        break;
 71                    case 17 /* Minus */:
 72                        this.$ = Math_1.MINUS(virtualStack[vsl - 2], virtualStack[vsl]);
 73                        break;
 74                    case 18 /* Multiply */:
 75                        this.$ = Math_1.MULTIPLY(virtualStack[vsl - 2], virtualStack[vsl]);
 76                        break;
 77                    case 19 /* Divide */:
 78                        this.$ = Math_1.DIVIDE(virtualStack[vsl - 2], virtualStack[vsl]);
 79                        break;
 80                    case 20 /* ToPower */:
 81                        this.$ = Math_1.POWER(virtualStack[vsl - 2], virtualStack[vsl]);
 82                        break;
 83                    case 21 /* InvertNumber */:
 84                        this.$ = TypeConverter_1.TypeConverter.valueToInvertedNumber(virtualStack[vsl]);
 85                        if (isNaN(this.$)) {
 86                            this.$ = 0;
 87                        }
 88                        break;
 89                    case 22 /* ToNumberNANAsZero */:
 90                        this.$ = TypeConverter_1.TypeConverter.valueToNumber(virtualStack[vsl]);
 91                        if (isNaN(this.$)) {
 92                            this.$ = 0;
 93                        }
 94                        break;
 95                    case 23 /* CallFunctionLastBlank */:
 96                        this.$ = sharedStateYY.handler.callFunction.call(this, virtualStack[vsl - 2], '');
 97                        break;
 98                    case 24 /* CallFunctionLastTwoInStack */:
 99                        this.$ = sharedStateYY.handler.callFunction.call(this, virtualStack[vsl - 3], virtualStack[vsl - 1]);
100                        break;
101                    case 28 /* FixedCellValue */:
102                        this.$ = sharedStateYY.handler.fixedCellValue(sharedStateYY.originCellId, virtualStack[vsl]);
103                        break;
104                    case 29 /* FixedCellRangeValue */:
105                        this.$ = sharedStateYY.handler.fixedCellRangeValue(sharedStateYY.originCellId, virtualStack[vsl - 2], virtualStack[vsl]);
106                        break;
107                    case 30 /* CellValue */:
108                        this.$ = sharedStateYY.handler.cellValue(sharedStateYY.originCellId, virtualStack[vsl]);
109                        break;
110                    case 31 /* CellRangeValue */:
111                        this.$ = sharedStateYY.handler.cellRangeValue(sharedStateYY.originCellId, virtualStack[vsl - 2], virtualStack[vsl]);
112                        break;
113                    case 32 /* EnsureIsArray */:
114                        if (MoreUtils_1.isArray(virtualStack[vsl])) {
115                            this.$ = virtualStack[vsl];
116                        }
117                        else {
118                            this.$ = [virtualStack[vsl]];
119                        }
120                        break;
121                    case 33 /* EnsureYYTextIsArray */:
122                        var result_1 = [], arr = eval("[" + rawValueOfReduceOriginToken + "]");
123                        arr.forEach(function (item) {
124                            result_1.push(item);
125                        });
126                        this.$ = result_1;
127                        break;
128                    case 34 /* ReduceInt */:
129                    case 35 /* ReducePercent */:
130                        virtualStack[vsl - 2].push(virtualStack[vsl]);
131                        this.$ = virtualStack[vsl - 2];
132                        break;
133                    case 36 /* WrapCurrentTokenAsArray */:
134                        this.$ = [virtualStack[vsl]];
135                        break;
136                    case 37 /* EnsureLastTwoINArrayAndPush */:
137                        this.$ = (MoreUtils_1.isArray(virtualStack[vsl - 2]) ? virtualStack[vsl - 2] : [virtualStack[vsl - 2]]);
138                        this.$.push(virtualStack[vsl]);
139                        break;
140                    case 38 /* ReflexiveReduce */:
141                        this.$ = virtualStack[vsl];
142                        break;
143                    case 39 /* ReduceFloat */:
144                        this.$ = TypeConverter_1.TypeConverter.valueToNumber(virtualStack[vsl - 2] + '.' + virtualStack[vsl]);
145                        break;
146                    case 40 /* ReducePrevAsPercent */:
147                        this.$ = virtualStack[vsl - 1] * 0.01;
148                        break;
149                    case 41 /* ReduceLastThreeA */:
150                    case 42 /* ReduceLastThreeB */:
151                        this.$ = virtualStack[vsl - 2] + virtualStack[vsl - 1] + virtualStack[vsl];
152                        break;
153                    case 43 /* AsError */:
154                        this.$ = Errors_1.constructErrorByName(virtualStack[vsl]);
155                        break;
156                }
157            }
158            catch (e) {
159                if (catchOnFailure) {
160                    // NOTE: I'm not sure if some of these ReduceAction map correctly in the case of an error.
161                    switch (reduceActionToPerform) {
162                        case 1 /* ReturnLast */:
163                            return virtualStack[vsl - 1];
164                        case 2 /* CallVariable */:
165                        case 5 /* AsNumber */:
166                        case 6 /* AsString */:
167                        case 7 /* Ampersand */:
168                        case 8 /* Equals */:
169                        case 9 /* Plus */:
170                        case 10 /* LastExpression */:
171                        case 11 /* LTE */:
172                        case 12 /* GTE */:
173                        case 13 /* NotEqual */:
174                        case 15 /* GT */:
175                        case 16 /* LT */:
176                        case 17 /* Minus */:
177                        case 18 /* Multiply */:
178                        case 19 /* Divide */:
179                        case 20 /* ToPower */:
180                        case 23 /* CallFunctionLastBlank */:
181                        case 24 /* CallFunctionLastTwoInStack */:
182                        case 28 /* FixedCellValue */:
183                        case 29 /* FixedCellRangeValue */:
184                        case 30 /* CellValue */:
185                        case 31 /* CellRangeValue */:
186                            this.$ = e;
187                            break;
188                        case 21 /* InvertNumber */:
189                            this.$ = e;
190                            if (isNaN(this.$)) {
191                                this.$ = 0;
192                            }
193                            break;
194                        case 22 /* ToNumberNANAsZero */:
195                            this.$ = e;
196                            if (isNaN(this.$)) {
197                                this.$ = 0;
198                            }
199                            break;
200                        case 32 /* EnsureIsArray */:
201                            if (MoreUtils_1.isArray(virtualStack[vsl])) {
202                                this.$ = virtualStack[vsl];
203                            }
204                            else {
205                                this.$ = [virtualStack[vsl]];
206                            }
207                            break;
208                        case 33 /* EnsureYYTextIsArray */:
209                            var result_2 = [], arr = eval("[" + rawValueOfReduceOriginToken + "]");
210                            arr.forEach(function (item) {
211                                result_2.push(item);
212                            });
213                            this.$ = result_2;
214                            break;
215                        case 34 /* ReduceInt */:
216                        case 35 /* ReducePercent */:
217                            virtualStack[vsl - 2].push(virtualStack[vsl]);
218                            this.$ = virtualStack[vsl - 2];
219                            break;
220                        case 36 /* WrapCurrentTokenAsArray */:
221                            this.$ = [virtualStack[vsl]];
222                            break;
223                        case 37 /* EnsureLastTwoINArrayAndPush */:
224                            this.$ = (MoreUtils_1.isArray(virtualStack[vsl - 2]) ? virtualStack[vsl - 2] : [virtualStack[vsl - 2]]);
225                            this.$.push(virtualStack[vsl]);
226                            break;
227                        case 38 /* ReflexiveReduce */:
228                            this.$ = virtualStack[vsl];
229                            break;
230                        case 39 /* ReduceFloat */:
231                            this.$ = parseFloat(virtualStack[vsl - 2] + '.' + virtualStack[vsl]);
232                            break;
233                        case 40 /* ReducePrevAsPercent */:
234                            this.$ = virtualStack[vsl - 1] * 0.01;
235                            break;
236                        case 41 /* ReduceLastThreeA */:
237                        case 42 /* ReduceLastThreeB */:
238                            this.$ = virtualStack[vsl - 2] + virtualStack[vsl - 1] + virtualStack[vsl];
239                            break;
240                    }
241                }
242                else {
243                    throw e;
244                }
245            }
246        },
247        defaultActions: { 19: [ParserConstants_1.REDUCE, 1 /* ReturnLast */] },
248        parseError: function parseError(str, hash) {
249            if (hash.recoverable) {
250                this.trace(str);
251            }
252            else {
253                throw new Errors_1.ParseError(str);
254            }
255        },
256        parse: function parse(input) {
257            var stack = [0], semanticValueStack = [null], locationStack = [], yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
258            var args = locationStack.slice.call(arguments, 1);
259            var lexer = Object.create(this.lexer);
260            var sharedState = {
261                yy: {
262                    parseError: undefined,
263                    lexer: {
264                        parseError: undefined
265                    },
266                    parser: {
267                        parseError: undefined
268                    }
269                }
270            };
271            // copy state
272            for (var k in this.yy) {
273                if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
274                    sharedState.yy[k] = this.yy[k];
275                }
276            }
277            lexer.setInput(input, sharedState.yy);
278            sharedState.yy.lexer = lexer;
279            sharedState.yy.parser = this;
280            if (typeof lexer.yylloc == 'undefined') {
281                lexer.yylloc = {};
282            }
283            var yyloc = lexer.yylloc;
284            locationStack.push(yyloc);
285            var ranges = lexer.options && lexer.options.ranges;
286            if (typeof sharedState.yy.parseError === 'function') {
287                this.parseError = sharedState.yy.parseError;
288            }
289            else {
290                this.parseError = Object.getPrototypeOf(this).parseError;
291            }
292            function popStack(n) {
293                stack.length = stack.length - 2 * n;
294                semanticValueStack.length = semanticValueStack.length - n;
295                locationStack.length = locationStack.length - n;
296            }
297            function lex() {
298                var token = lexer.lex() || EOF;
299                // if token isn't its numeric value, convert
300                if (typeof token !== 'number') {
301                    token = ParserConstants_1.SYMBOL_NAME_TO_INDEX[token] || token;
302                }
303                return token;
304            }
305            var symbol, preErrorSymbol, state, action, result, yyval = {
306                $: undefined,
307                _$: undefined
308            }, p, newState, expected, catchFailuresOn = false;
309            while (true) {
310                // retrieve state number from top of stack
311                state = stack[stack.length - 1];
312                // use default actions if available
313                if (this.defaultActions[state]) {
314                    action = this.defaultActions[state];
315                }
316                else {
317                    if (typeof symbol == 'undefined' || symbol === null) {
318                        symbol = lex();
319                    }
320                    // read action for current state and first input
321                    action = ParserConstants_1.ACTION_TABLE[state] && ParserConstants_1.ACTION_TABLE[state][symbol];
322                }
323                // console.log({
324                //   text: lexer.match,
325                //   token: SYMBOL_INDEX_TO_NAME[symbol] || symbol,
326                //   tokenIndex: symbol,
327                //   line: lexer.yylineno,
328                //   loc: yyloc,
329                //   state: state,
330                //   stack: stack,
331                //   semanticValueStack: semanticValueStack
332                // });
333                // handle parse error
334                if (typeof action === 'undefined' || !action.length || !action[0]) {
335                    var error_rule_depth = void 0;
336                    var errStr = '';
337                    // Return the rule stack depth where the nearest error rule can be found.
338                    // Return FALSE when no error recovery rule was found.
339                    this.locateNearestErrorRecoveryRule = function (state) {
340                        var stack_probe = stack.length - 1;
341                        var depth = 0;
342                        // try to recover from error
343                        for (;;) {
344                            if (MoreUtils_1.isUndefined(state)) {
345                                return false;
346                            }
347                            // check for error recovery rule in this state
348                            if ((TERROR.toString()) in ParserConstants_1.ACTION_TABLE[state]) {
349                                return depth;
350                            }
351                            if (state === 0 || stack_probe < 2) {
352                                return false; // No suitable error recovery rule available.
353                            }
354                            stack_probe -= 2; // popStack(1): [symbol, action]
355                            state = stack[stack_probe];
356                            ++depth;
357                        }
358                    };
359                    if (!recovering) {
360                        // first see if there's any chance at hitting an error recovery rule:
361                        error_rule_depth = this.locateNearestErrorRecoveryRule(state);
362                        // Report error
363                        expected = [];
364                        var expectedIndexes = [];
365                        var tableState = ParserConstants_1.ACTION_TABLE[state];
366                        for (p in ParserConstants_1.ACTION_TABLE[state]) {
367                            if (ParserConstants_1.SYMBOL_INDEX_TO_NAME[p] && p > TERROR) {
368                                expected.push(ParserConstants_1.SYMBOL_INDEX_TO_NAME[p]);
369                                expectedIndexes.push(p);
370                            }
371                        }
372                        if (lexer.showPosition) {
373                            errStr = 'Parse error on line ' + (yylineno + 1) + ":  " + lexer.showPosition() + "  Expecting " + expected.join(', ') + ", got '" + (ParserConstants_1.SYMBOL_INDEX_TO_NAME[symbol] || symbol) + "'";
374                        }
375                        else {
376                            errStr = 'Parse error on line ' + (yylineno + 1) + ": Unexpected " +
377                                (symbol == EOF ? "end of input" :
378                                    ("'" + (ParserConstants_1.SYMBOL_INDEX_TO_NAME[symbol] || symbol) + "'"));
379                        }
380                        this.parseError(errStr, {
381                            text: lexer.match,
382                            token: ParserConstants_1.SYMBOL_INDEX_TO_NAME[symbol] || symbol,
383                            tokenIndex: symbol,
384                            line: lexer.yylineno,
385                            loc: yyloc,
386                            expected: expected,
387                            expectedIndexes: expectedIndexes,
388                            state: state,
389                            tableState: tableState,
390                            stack: stack,
391                            semanticValueStack: semanticValueStack,
392                            recoverable: (error_rule_depth !== false)
393                        });
394                    }
395                    else if (preErrorSymbol !== EOF) {
396                        error_rule_depth = this.locateNearestErrorRecoveryRule(state);
397                    }
398                    // just recovered from another error
399                    if (recovering == 3) {
400                        if (symbol === EOF || preErrorSymbol === EOF) {
401                            throw new Errors_1.ParseError(errStr || 'Parsing halted while starting to recover from another error.');
402                        }
403                        // discard current lookahead and grab another
404                        yyleng = lexer.yyleng;
405                        yytext = lexer.yytext;
406                        yylineno = lexer.yylineno;
407                        yyloc = lexer.yylloc;
408                        symbol = lex();
409                    }
410                    // try to recover from error
411                    if (error_rule_depth === false) {
412                        throw new Errors_1.ParseError(errStr || 'Parsing halted. No suitable error recovery rule available.');
413                    }
414                    popStack(error_rule_depth);
415                    preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token
416                    symbol = TERROR; // insert generic error symbol as new lookahead
417                    state = stack[stack.length - 1];
418                    action = ParserConstants_1.ACTION_TABLE[state] && ParserConstants_1.ACTION_TABLE[state][TERROR];
419                    recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
420                }
421                // this shouldn't happen, unless resolve defaults are off
422                if (action[0] instanceof Array && action.length > 1) {
423                    throw new Errors_1.ParseError('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
424                }
425                // Available actions:
426                //   Shift: continue to process tokens.
427                //   Reduce: enough tokens have been gathered to reduce input through evaluation.
428                //   Accept: return.
429                switch (action[0]) {
430                    case ParserConstants_1.SHIFT: // Shift
431                        stack.push(symbol);
432                        semanticValueStack.push(lexer.yytext);
433                        locationStack.push(lexer.yylloc);
434                        stack.push(action[1]); // push state
435                        // console.log("SHIFT", "literal", lexer.yytext, "   symbol", symbol, "   symbol name", SYMBOL_INDEX_TO_NAME[symbol], "   action", action,
436                        //     "   stack", stack, "   semanticValueStack", semanticValueStack);
437                        symbol = null;
438                        if (Formulas_1.Formulas.isTryCatchFormula(lexer.yytext)) {
439                            catchFailuresOn = true;
440                        }
441                        if (!preErrorSymbol) { // normal execution/no error
442                            yyleng = lexer.yyleng;
443                            yytext = lexer.yytext;
444                            yylineno = lexer.yylineno;
445                            yyloc = lexer.yylloc;
446                            if (recovering > 0) {
447                                recovering--;
448                            }
449                        }
450                        else {
451                            // error just occurred, resume old lookahead f/ before error
452                            symbol = preErrorSymbol;
453                            preErrorSymbol = null;
454                        }
455                        break;
456                    case ParserConstants_1.REDUCE: // Reduce
457                        // console.log("REDUCE", "literal", lexer.yytext, "   symbol", symbol, "   symbol name", SYMBOL_INDEX_TO_NAME[symbol], "   action", action,
458                        //     "   stack", stack, "   semanticValueStack", semanticValueStack);
459                        var currentProduction = ParserConstants_1.PRODUCTIONS[action[1]];
460                        var lengthToReduceStackBy = currentProduction.getLengthToReduceStackBy();
461                        // perform semantic action
462                        yyval.$ = semanticValueStack[semanticValueStack.length - lengthToReduceStackBy]; // default to $$ = $1
463                        // default location, uses first token for firsts, last for lasts
464                        yyval._$ = {
465                            first_line: locationStack[locationStack.length - (lengthToReduceStackBy || 1)].first_line,
466                            last_line: locationStack[locationStack.length - 1].last_line,
467                            first_column: locationStack[locationStack.length - (lengthToReduceStackBy || 1)].first_column,
468                            last_column: locationStack[locationStack.length - 1].last_column
469                        };
470                        if (ranges) {
471                            yyval._$.range = [locationStack[locationStack.length - (lengthToReduceStackBy || 1)].range[0], locationStack[locationStack.length - 1].range[1]];
472                        }
473                        // If we are inside of a formula that should catch errors, then catch and return them.
474                        result = this.performAction.apply(yyval, [yytext, sharedState.yy, action[1], semanticValueStack, catchFailuresOn].concat(args));
475                        if (typeof result !== 'undefined') {
476                            return result;
477                        }
478                        // pop off stack
479                        if (lengthToReduceStackBy) {
480                            stack = stack.slice(0, -1 * lengthToReduceStackBy * 2);
481                            semanticValueStack = semanticValueStack.slice(0, -1 * lengthToReduceStackBy);
482                            locationStack = locationStack.slice(0, -1 * lengthToReduceStackBy);
483                        }
484                        // push non-terminal (reduce)
485                        stack.push(currentProduction.getReplacementSymbol());
486                        semanticValueStack.push(yyval.$);
487                        locationStack.push(yyval._$);
488                        newState = ParserConstants_1.ACTION_TABLE[stack[stack.length - 2]][stack[stack.length - 1]];
489                        stack.push(newState);
490                        break;
491                    case ParserConstants_1.ACCEPT:
492                        // Accept
493                        return true;
494                }
495            }
496        }
497    };
498    parser.lexer = (function () {
499        return ({
500            EOF: 1,
501            parseError: function parseError(str, hash) {
502                if (this.yy.parser) {
503                    this.yy.parser.parseError(str, hash);
504                }
505                else {
506                    throw new Errors_1.ParseError(str);
507                }
508            },
509            // resets the lexer, sets new input
510            setInput: function (input, yy) {
511                this.yy = yy || this.yy || {};
512                this.yy.parseError = function (str, hash) {
513                    throw new Errors_1.ParseError(JSON.stringify({
514                        name: 'Parser error',
515                        message: str,
516                        prop: hash
517                    }));
518                };
519                this._input = input;
520                this._more = this._backtrack = this.done = false;
521                this.yylineno = this.yyleng = 0;
522                this.yytext = this.matched = this.match = '';
523                this.conditionStack = ['INITIAL'];
524                this.yylloc = {
525                    first_line: 1,
526                    first_column: 0,
527                    last_line: 1,
528                    last_column: 0
529                };
530                if (this.options.ranges) {
531                    this.yylloc.range = [0, 0];
532                }
533                this.offset = 0;
534                return this;
535            },
536            // consumes and returns one char from the input
537            input: function () {
538                var ch = this._input[0];
539                this.yytext += ch;
540                this.yyleng++;
541                this.offset++;
542                this.match += ch;
543                this.matched += ch;
544                var lines = ch.match(/(?:\r\n?|\n).*/g);
545                if (lines) {
546                    this.yylineno++;
547                    this.yylloc.last_line++;
548                }
549                else {
550                    this.yylloc.last_column++;
551                }
552                if (this.options.ranges) {
553                    this.yylloc.range[1]++;
554                }
555                this._input = this._input.slice(1);
556                return ch;
557            },
558            // unshifts one char (or a string) into the input
559            unput: function (ch) {
560                var len = ch.length;
561                var lines = ch.split(/(?:\r\n?|\n)/g);
562                this._input = ch + this._input;
563                this.yytext = this.yytext.substr(0, this.yytext.length - len);
564                //this.yyleng -= len;
565                this.offset -= len;
566                var oldLines = this.match.split(/(?:\r\n?|\n)/g);
567                this.match = this.match.substr(0, this.match.length - 1);
568                this.matched = this.matched.substr(0, this.matched.length - 1);
569                if (lines.length - 1) {
570                    this.yylineno -= lines.length - 1;
571                }
572                var r = this.yylloc.range;
573                this.yylloc = {
574                    first_line: this.yylloc.first_line,
575                    last_line: this.yylineno + 1,
576                    first_column: this.yylloc.first_column,
577                    last_column: lines ?
578                        (lines.length === oldLines.length ? this.yylloc.first_column : 0)
579                            + oldLines[oldLines.length - lines.length].length - lines[0].length :
580                        this.yylloc.first_column - len
581                };
582                if (this.options.ranges) {
583                    this.yylloc.range = [r[0], r[0] + this.yyleng - len];
584                }
585                this.yyleng = this.yytext.length;
586                return this;
587            },
588            // When called from action, caches matched text and appends it on next action
589            more: function () {
590                this._more = true;
591                return this;
592            },
593            // displays already matched input, i.e. for error messages
594            pastInput: function () {
595                var past = this.matched.substr(0, this.matched.length - this.match.length);
596                return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
597            },
598            // displays upcoming input, i.e. for error messages
599            upcomingInput: function () {
600                var next = this.match;
601                if (next.length < 20) {
602                    next += this._input.substr(0, 20 - next.length);
603                }
604                return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
605            },
606            // displays the character position where the lexing error occurred, i.e. for error messages
607            showPosition: function () {
608                var pre = this.pastInput();
609                var c = new Array(pre.length + 1).join("-");
610                return pre + this.upcomingInput() + "\n" + c + "^";
611            },
612            // test the lexed token: return FALSE when not a match, otherwise return token
613            testMatch: function (match, indexed_rule) {
614                var token, lines, backup;
615                if (this.options.backtrack_lexer) {
616                    // save context
617                    backup = {
618                        yylineno: this.yylineno,
619                        yylloc: {
620                            first_line: this.yylloc.first_line,
621                            last_line: this.last_line,
622                            first_column: this.yylloc.first_column,
623                            last_column: this.yylloc.last_column
624                        },
625                        yytext: this.yytext,
626                        match: this.match,
627                        matches: this.matches,
628                        matched: this.matched,
629                        yyleng: this.yyleng,
630                        offset: this.offset,
631                        _more: this._more,
632                        _input: this._input,
633                        yy: this.yy,
634                        conditionStack: this.conditionStack.slice(0),
635                        done: this.done
636                    };
637                    if (this.options.ranges) {
638                        backup.yylloc.range = this.yylloc.range.slice(0);
639                    }
640                }
641                lines = match[0].match(/(?:\r\n?|\n).*/g);
642                if (lines) {
643                    this.yylineno += lines.length;
644                }
645                this.yylloc = {
646                    first_line: this.yylloc.last_line,
647                    last_line: this.yylineno + 1,
648                    first_column: this.yylloc.last_column,
649                    last_column: lines ?
650                        lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
651                        this.yylloc.last_column + match[0].length
652                };
653                this.yytext += match[0];
654                this.match += match[0];
655                this.matches = match;
656                this.yyleng = this.yytext.length;
657                if (this.options.ranges) {
658                    this.yylloc.range = [this.offset, this.offset += this.yyleng];
659                }
660                this._more = false;
661                this._backtrack = false;
662                this._input = this._input.slice(match[0].length);
663                this.matched += match[0];
664                token = this.mapRuleIndexToSymbolEnumeration(indexed_rule);
665                if (this.done && this._input) {
666                    this.done = false;
667                }
668                if (token) {
669                    return token;
670                }
671                else if (this._backtrack) {
672                    // recover context
673                    for (var k in backup) {
674                        this[k] = backup[k];
675                    }
676                    return false; // rule action called reject() implying the next rule should be tested instead.
677                }
678                return false;
679            },
680            // return next match in input
681            next: function () {
682                if (this.done) {
683                    return this.EOF;
684                }
685                if (!this._input) {
686                    this.done = true;
687                }
688                var token, match, tempMatch, index;
689                if (!this._more) {
690                    this.yytext = '';
691                    this.match = '';
692                }
693                var rules = this._currentRules();
694                for (var i = 0; i < rules.length; i++) {
695                    tempMatch = this._input.match(ParserConstants_1.RULES[rules[i]]);
696                    if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
697                        match = tempMatch;
698                        index = i;
699                        if (this.options.backtrack_lexer) {
700                            token = this.testMatch(tempMatch, rules[i]);
701                            if (token !== false) {
702                                return token;
703                            }
704                            else if (this._backtrack) {
705                                match = false;
706                                // rule action called reject() implying a rule mis-match.
707                                // implied `continue`
708                            }
709                            else {
710                                // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
711                                return false;
712                            }
713                        }
714                        else if (!this.options.flex) {
715                            break;
716                        }
717                    }
718                }
719                if (match) {
720                    token = this.testMatch(match, rules[index]);
721                    if (token !== false) {
722                        return token;
723                    }
724                    // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
725                    return false;
726                }
727                if (this._input === "") {
728                    return this.EOF;
729                }
730                else {
731                    return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
732                        text: "",
733                        token: null,
734                        line: this.yylineno
735                    });
736                }
737            },
738            // return next match that has a token
739            lex: function lex() {
740                var r = this.next();
741                if (r) {
742                    return r;
743                }
744                else {
745                    return this.lex();
746                }
747            },
748            // produce the lexer rule set which is active for the currently active lexer condition state
749            _currentRules: function _currentRules() {
750                if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
751                    return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
752                }
753                else {
754                    return this.conditions.INITIAL.rules;
755                }
756            },
757            options: {
758            // backtrack_lexer?
759            // ranges?
760            // flex?
761            },
762            mapRuleIndexToSymbolEnumeration: function (ruleIndex) {
763                switch (ruleIndex) {
764                    case 0 /* WhiteSpace */:
765                        // skip whitespace
766                        break;
767                    case 1 /* DoubleQuotes */:
768                        return Symbols_1.Symbol.String;
769                    case 2 /* SingleQuotes */:
770                        return Symbols_1.Symbol.String;
771                    case 3 /* FormulaName */:
772                        return Symbols_1.Symbol.Function;
773                    case 6 /* $A1Cell */:
774                        return Symbols_1.Symbol.FixedCell;
775                    case 7 /* A1Cell */:
776                        return Symbols_1.Symbol.CellUpper;
777                    case 8 /* FormulaNameSimple */:
778                        return Symbols_1.Symbol.Function;
779                    case 9 /* Variable */:
780                        return Symbols_1.Symbol.Variable;
781                    case 10 /* SimpleVariable */:
782                        return Symbols_1.Symbol.Variable;
783                    case 11 /* Integer */:
784                        return Symbols_1.Symbol.NumberUpper;
785                    case 12 /* SelfContainedArray */:
786                        return Symbols_1.Symbol.Array;
787                    case 13 /* DollarSign */:
788                        // skip whitespace??
789                        break;
790                    case 14 /* Ampersand */:
791                        return Symbols_1.Symbol.Ampersand;
792                    case 15 /* SingleWhitespace */:
793                        return ' ';
794                    case 16 /* Period */:
795                        return Symbols_1.Symbol.Decimal;
796                    case 17 /* Colon */:
797                        return Symbols_1.Symbol.Colon;
798                    case 18 /* Semicolon */:
799                        return Symbols_1.Symbol.Semicolon;
800                    case 19 /* Comma */:
801                        return Symbols_1.Symbol.Comma;
802                    case 20 /* Asterisk */:
803                        return Symbols_1.Symbol.Asterisk;
804                    case 21 /* ForwardSlash */:
805                        return Symbols_1.Symbol.Divide;
806                    case 22 /* Minus */:
807                        return Symbols_1.Symbol.Minus;
808                    case 23 /* Plus */:
809                        return Symbols_1.Symbol.Plus;
810                    case 24 /* Caret */:
811                        return Symbols_1.Symbol.Carrot;
812                    case 25 /* OpenParen */:
813                        return Symbols_1.Symbol.LeftParen;
814                    case 26 /* CloseParen */:
815                        return Symbols_1.Symbol.RightParen;
816                    case 27 /* GreaterThan */:
817                        return Symbols_1.Symbol.GreaterThan;
818                    case 28 /* LessThanSign */:
819                        return Symbols_1.Symbol.LessThan;
820                    case 30 /* OpenDoubleQuote */:
821                        return '"';
822                    case 31 /* OpenSingleQuote */:
823                        return "'";
824                    case 32 /* ExclamationPoint */:
825                        return "!";
826                    case 33 /* Equals */:
827                        return Symbols_1.Symbol.Equals;
828                    case 34 /* Percent */:
829                        return Symbols_1.Symbol.Percent;
830                    case 35 /* FullError */:
831                        return Symbols_1.Symbol.FullError;
832                    case 36 /* EndOfString */:
833                        return Symbols_1.Symbol.EOF;
834                }
835            },
836            conditions: {
837                INITIAL: {
838                    rules: [
839                        0 /* WhiteSpace */,
840                        1 /* DoubleQuotes */,
841                        2 /* SingleQuotes */,
842                        3 /* FormulaName */,
843                        6 /* $A1Cell */,
844                        7 /* A1Cell */,
845                        8 /* FormulaNameSimple */,
846                        9 /* Variable */,
847                        10 /* SimpleVariable */,
848                        11 /* Integer */,
849                        12 /* SelfContainedArray */,
850                        13 /* DollarSign */,
851                        14 /* Ampersand */,
852                        15 /* SingleWhitespace */,
853                        16 /* Period */,
854                        17 /* Colon */,
855                        18 /* Semicolon */,
856                        19 /* Comma */,
857                        20 /* Asterisk */,
858                        21 /* ForwardSlash */,
859                        22 /* Minus */,
860                        23 /* Plus */,
861                        24 /* Caret */,
862                        25 /* OpenParen */,
863                        26 /* CloseParen */,
864                        27 /* GreaterThan */,
865                        28 /* LessThanSign */,
866                        30 /* OpenDoubleQuote */,
867                        31 /* OpenSingleQuote */,
868                        32 /* ExclamationPoint */,
869                        33 /* Equals */,
870                        34 /* Percent */,
871                        35 /* FullError */,
872                        36 /* EndOfString */,
873                        37
874                    ],
875                    "inclusive": true
876                }
877            }
878        });
879    })();
880    function Parser() {
881        this.yy = {};
882    }
883    Parser.prototype = parser;
884    parser.Parser = Parser;
885    return new Parser;
886})();
887/**
888 * Creates a new FormulaParser, which parses formulas, and does minimal error handling.
889 *
890 * @param handler should be a Sheet, since the parser needs access to fixedCellValue, cellValue, cellRangeValue, and
891 * fixedCellRangeValue
892 * @returns formula parser instance for use with parser.js
893 * @constructor
894 */
895var FormulaParser = function (handler) {
896    var formulaLexer = function () { };
897    formulaLexer.prototype = Parser.lexer;
898    var formulaParser = function () {
899        this.lexer = new formulaLexer();
900        this.yy = {};
901    };
902    formulaParser.prototype = Parser;
903    var newParser = new formulaParser;
904    newParser.yy.handler = handler;
905    return newParser;
906};
907exports.FormulaParser = FormulaParser;