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;