commit
message
[ParseEngine] adding tests, indexing rules
author
Ben Vogt <[email protected]>
date
2017-12-09 19:29:28
stats
3 file(s) changed,
1021 insertions(+),
240 deletions(-)
files
src/Parser/ParseEngine.ts
tests.sh
tests/Parser/ParseEngineTest.ts
1diff --git a/src/Parser/ParseEngine.ts b/src/Parser/ParseEngine.ts
2index 3fae5e4..7b73fd2 100644
3--- a/src/Parser/ParseEngine.ts
4+++ b/src/Parser/ParseEngine.ts
5@@ -1,6 +1,55 @@
6 import {
7 ObjectBuilder
8 } from "./ObjectBuilder";
9+import {
10+ constructErrorByName,
11+ ParseError
12+} from "../Errors";
13+import {
14+ Formulas
15+} from "../Formulas";
16+import {
17+ isUndefined
18+} from "../Utilities/MoreUtils";
19+
20+const enum RuleIndex {
21+ WHITE_SPACE = 0,
22+ DOUBLE_QUOTES = 1,
23+ SINGLE_QUOTES = 2,
24+ FORMULA = 3,
25+ $_A1_CELL = 4,
26+ A1_CELL = 5,
27+ FORMULA_NAME_SIMPLE = 6,
28+ VARIABLE = 7,
29+ SIMPLE_VARIABLE = 8,
30+ INTEGER = 9,
31+ OPEN_ARRAY = 10,
32+ CLOSE_ARRAY = 11,
33+ DOLLAR_SIGN = 12,
34+ AMPERSAND_SIGN = 13,
35+ SINGLE_WHITESPACE = 14,
36+ PERIOD = 15,
37+ COLON = 16,
38+ SEMI_COLON = 17,
39+ COMMA = 18,
40+ ASTERISK = 19,
41+ FORWARD_SLASH = 20,
42+ MINUS_SIGN = 21,
43+ PLUS_SIGN = 22,
44+ CARET_SIGN = 23,
45+ OPEN_PAREN = 24,
46+ CLOSE_PAREN = 25,
47+ GREATER_THAN_SIGN = 26,
48+ LESS_THAN_SIGN = 27,
49+ DOUBLE_QUOTE = 28,
50+ SINGLE_QUITE = 29,
51+ EXCLAMATION_POINT = 30,
52+ EQUALS_SIGN = 31,
53+ PERCENT_SIGN = 32,
54+ POUND = 33,
55+ ERROR = 34,
56+ END = 35,
57+}
58
59 // Rules represent the Regular Expressions that will be used in sequence to match a given input to the Parser.
60 const Rules = {
61@@ -45,6 +94,43 @@ const Rules = {
62
63
64 // Sequential rules to use when parsing a given input.
65+let rulesSeqTemp = [];
66+rulesSeqTemp[RuleIndex.WHITE_SPACE] = Rules.WHITE_SPACE;
67+rulesSeqTemp[RuleIndex.DOUBLE_QUOTE] = Rules.DOUBLE_QUOTE;
68+rulesSeqTemp[RuleIndex.SINGLE_QUOTES] = Rules.SINGLE_QUOTES;
69+rulesSeqTemp[RuleIndex.FORMULA] = Rules.FORMULA_NAME;
70+rulesSeqTemp[RuleIndex.$_A1_CELL] = Rules.$_A1_CELL;
71+rulesSeqTemp[RuleIndex.A1_CELL] = Rules.A1_CELL;
72+rulesSeqTemp[RuleIndex.FORMULA_NAME_SIMPLE] = Rules.FORMULA_NAME_SIMPLE;
73+rulesSeqTemp[RuleIndex.VARIABLE] = Rules.VARIABLE;
74+rulesSeqTemp[RuleIndex.SIMPLE_VARIABLE] = Rules.SIMPLE_VARIABLE;
75+rulesSeqTemp[RuleIndex.INTEGER] = Rules.INTEGER;
76+rulesSeqTemp[RuleIndex.OPEN_ARRAY] = Rules.OPEN_ARRAY;
77+rulesSeqTemp[RuleIndex.CLOSE_ARRAY] = Rules.CLOSE_ARRAY;
78+rulesSeqTemp[RuleIndex.AMPERSAND_SIGN] = Rules.AMPERSAND_SIGN;
79+rulesSeqTemp[RuleIndex.SINGLE_WHITESPACE] = Rules.SINGLE_WHITESPACE;
80+rulesSeqTemp[RuleIndex.PERIOD] = Rules.PERIOD;
81+rulesSeqTemp[RuleIndex.COLON] = Rules.COLON;
82+rulesSeqTemp[RuleIndex.SEMI_COLON] = Rules.SEMI_COLON;
83+rulesSeqTemp[RuleIndex.COMMA] = Rules.COMMA;
84+rulesSeqTemp[RuleIndex.ASTERISK] = Rules.ASTERISK;
85+rulesSeqTemp[RuleIndex.FORWARD_SLASH] = Rules.FORWARD_SLASH;
86+rulesSeqTemp[RuleIndex.MINUS_SIGN] = Rules.MINUS_SIGN;
87+rulesSeqTemp[RuleIndex.PLUS_SIGN] = Rules.PLUS_SIGN;
88+rulesSeqTemp[RuleIndex.CARET_SIGN] = Rules.CARET_SIGN;
89+rulesSeqTemp[RuleIndex.OPEN_PAREN] = Rules.OPEN_PAREN;
90+rulesSeqTemp[RuleIndex.CLOSE_PAREN] = Rules.CLOSE_PAREN;
91+rulesSeqTemp[RuleIndex.GREATER_THAN_SIGN] = Rules.GREATER_THAN_SIGN;
92+rulesSeqTemp[RuleIndex.LESS_THAN_SIGN] = Rules.LESS_THAN_SIGN;
93+rulesSeqTemp[RuleIndex.DOUBLE_QUOTE] = Rules.DOUBLE_QUOTE;
94+rulesSeqTemp[RuleIndex.SINGLE_QUITE] = Rules.SINGLE_QUITE;
95+rulesSeqTemp[RuleIndex.EXCLAMATION_POINT] = Rules.EXCLAMATION_POINT;
96+rulesSeqTemp[RuleIndex.EQUALS_SIGN] = Rules.EQUALS_SIGN;
97+rulesSeqTemp[RuleIndex.PERCENT_SIGN] = Rules.PERCENT_SIGN;
98+rulesSeqTemp[RuleIndex.POUND] = Rules.POUND;
99+rulesSeqTemp[RuleIndex.ERROR] = Rules.ERROR;
100+rulesSeqTemp[RuleIndex.END] = Rules.END;
101+
102 const RulesSeq = [
103 Rules.WHITE_SPACE,
104 Rules.DOUBLE_QUOTES,
105@@ -162,6 +248,43 @@ const SYMBOL_NAME_TO_INDEX = {
106 "WHITE_SPACE": Symbol.WHITE_SPACE
107 };
108
109+let symbolIndexToName = {};
110+symbolIndexToName[Symbol.ACCEPT] = "ACCEPT";
111+symbolIndexToName[Symbol.END] = "END";
112+symbolIndexToName[Symbol.ERROR] = "ERROR";
113+symbolIndexToName[Symbol.EXPRESSIONS] = "EXPRESSIONS";
114+symbolIndexToName[Symbol.EXPRESSION] = "EXPRESSION";
115+symbolIndexToName[Symbol.EOF] = "EOF";
116+symbolIndexToName[Symbol.VARIABLE] = "VARIABLE";
117+symbolIndexToName[Symbol.VARIABLE_SEQUENCE] = "VARIABLE_SEQUENCE";
118+symbolIndexToName[Symbol.NUMBER] = "NUMBER";
119+symbolIndexToName[Symbol.STRING] = "STRING";
120+symbolIndexToName[Symbol.FORMULA] = "FORMULA";
121+symbolIndexToName[Symbol.CELL_REF] = "CELL_REF";
122+symbolIndexToName[Symbol.FIXED_CELL_REF] = "FIXED_CELL_REF";
123+symbolIndexToName[Symbol.CELL] = "CELL";
124+symbolIndexToName[Symbol.OPEN_ARRAY] = "OPEN_ARRAY";
125+symbolIndexToName[Symbol.CLOSE_ARRAY] = "CLOSE_ARRAY";
126+symbolIndexToName[Symbol.PERIOD] = ".";
127+symbolIndexToName[Symbol.AMPERSAND] = "&";
128+symbolIndexToName[Symbol.EQUALS] = "=";
129+symbolIndexToName[Symbol.PLUS] = "+";
130+symbolIndexToName[Symbol.OPEN_PAREN] = "(";
131+symbolIndexToName[Symbol.CLOSE_PAREN] = ")";
132+symbolIndexToName[Symbol.LESS_THAN] = "<";
133+symbolIndexToName[Symbol.GREATER_THAN] = ">";
134+symbolIndexToName[Symbol.MINUS] = "-";
135+symbolIndexToName[Symbol.ASTERISK] = "*";
136+symbolIndexToName[Symbol.DIVIDE] = "/";
137+symbolIndexToName[Symbol.CARROT] = "^";
138+symbolIndexToName[Symbol.SEMI_COLON] = ";";
139+symbolIndexToName[Symbol.COLON] = ";";
140+symbolIndexToName[Symbol.COMMA] = ",";
141+symbolIndexToName[Symbol.PERCENT] = "%";
142+symbolIndexToName[Symbol.POUND] = "#";
143+symbolIndexToName[Symbol.EXCLAMATION_POINT] = "!";
144+symbolIndexToName[Symbol.WHITE_SPACE] = "WHITE_SPACE";
145+const SYMBOL_INDEX_TO_NAME = symbolIndexToName;
146
147
148 /**
149@@ -203,7 +326,8 @@ const enum ReduceActions {
150 PERCENT = 27,
151 START_ARRAY = 28,
152 INVERT_NUMBER = 29,
153- EXPRESSION = 30
154+ EXPRESSION = 30,
155+ AS_ARRAY = 31
156 };
157
158 /**
159@@ -297,6 +421,7 @@ productions[ReduceActions.CELL_VALUE] = new ReductionPair(Tree.VARIABLE, 1);
160 productions[ReduceActions.CELL_RANGE_VALUE] = new ReductionPair(Tree.VARIABLE, 3);
161 productions[ReduceActions.PERCENT] = new ReductionPair(Tree.VARIABLE, 3);
162 productions[ReduceActions.AS_ERROR] = new ReductionPair(Tree.ERROR, 1);
163+productions[ReduceActions.AS_ARRAY] = new ReductionPair(Tree.VARIABLE, 1);
164 const PRODUCTIONS = productions;
165
166
167@@ -309,68 +434,23 @@ let table = [];
168 // All functions in the spreadsheet start with a 0-token.
169 // `=`
170 table[Tree.START] = ObjectBuilder
171- .add(Symbol.VARIABLE, Tree.VARIABLE)
172- .add(Symbol.CELL_REF, [REDUCE, ReduceActions.CELL_VALUE])
173- .add(Symbol.FIXED_CELL_REF, [REDUCE, ReduceActions.FIXED_CELL_VAL])
174- .add(Symbol.OPEN_ARRAY, null) // Start array, push until done? Come back to this one.
175- .add(Symbol.OPEN_PAREN, null)
176- .add(Symbol.PLUS, [SHIFT, ReduceActions.AS_NUMBER]) // If we're starting out, the operator is just the regular number.
177- .add(Symbol.MINUS, [SHIFT, ReduceActions.INVERT_NUMBER]) // If we're starting out, the operator is inverting the next number
178- .add(Symbol.WHITE_SPACE, Tree.START) // loop back.
179+ .add(Symbol.NUMBER, Tree.VARIABLE)
180+ .add(Symbol.WHITE_SPACE, Tree.START)
181 .add(Symbol.END, Tree.TERMINATE)
182 .build();
183 table[Tree.VARIABLE] = ObjectBuilder
184 .add(Symbol.PLUS, [SHIFT, ReduceActions.PLUS])
185 .add(Symbol.MINUS, [SHIFT, ReduceActions.MINUS])
186- .add(Symbol.ASTERISK, [SHIFT, ReduceActions.AS_NUMBER]) // maybe
187- .add(Symbol.DIVIDE, [SHIFT, ReduceActions.DIVIDE]) // At this point in processing we have "X /" but we need the second variable
188+ .add(Symbol.ASTERISK, [SHIFT, ReduceActions.MULTIPLY])
189+ .add(Symbol.DIVIDE, [SHIFT, ReduceActions.DIVIDE])
190 .add(Symbol.CARROT, [SHIFT, ReduceActions.TO_POWER])
191 .add(Symbol.PERCENT, [REDUCE, ReduceActions.PERCENT])
192 .add(Symbol.AMPERSAND, [SHIFT, ReduceActions.AMPERSAND])
193- .add(Symbol.GREATER_THAN, Tree.GREATER_THAN) // X>__
194- .add(Symbol.LESS_THAN, Tree.LESS_THAN) // X>__
195- .add(Symbol.EQUALS, Tree.EQUALS) // X=__
196- .add(Symbol.COMMA, Tree.COMMA)
197- .add(Symbol.CLOSE_PAREN, Tree.CLOSE_PAREN)
198- .add(Symbol.WHITE_SPACE, Tree.VARIABLE)
199+ .add(Symbol.WHITE_SPACE, Tree.TERMINATE)
200 .add(Symbol.END, Tree.TERMINATE)
201 .build();
202-// TODO: While almost anything can follow an error, we should really just throw the error, right?
203-table[Tree.ERROR] = ObjectBuilder
204- .add(Symbol.PLUS, null)
205- .add(Symbol.MINUS, null)
206- .add(Symbol.ASTERISK, null)
207- .add(Symbol.DIVIDE, null)
208- .add(Symbol.CARROT, null)
209- .add(Symbol.PERCENT, null)
210- .add(Symbol.AMPERSAND, null)
211- .add(Symbol.GREATER_THAN, null)
212- .add(Symbol.LESS_THAN, null)
213- .add(Symbol.EQUALS, null)
214- .add(Symbol.WHITE_SPACE, null)
215- .add(Symbol.END, null)
216- .build();
217-table[Tree.FORMULA] = ObjectBuilder
218- .add(Symbol.VARIABLE, Tree.VARIABLE)
219- .add(Symbol.FORMULA, Tree.FORMULA)
220- .add(Symbol.CELL_REF, [REDUCE, ReduceActions.CELL_VALUE])
221- .add(Symbol.FIXED_CELL_REF, [REDUCE, ReduceActions.FIXED_CELL_VAL])
222- .add(Symbol.ERROR, null)
223- .add(Symbol.PLUS, null)
224- .add(Symbol.MINUS, null)
225- .add(Symbol.CLOSE_PAREN, [REDUCE, ReduceActions.CALL_FUNCTION])
226- .add(Symbol.OPEN_PAREN, null)
227- .add(Symbol.OPEN_ARRAY, null)
228- .add(Symbol.WHITE_SPACE, null)
229- .add(Symbol.END, null)
230- .build();
231 table[Tree.PLUS] = ObjectBuilder
232- .add(Symbol.NUMBER, null)
233- .add(Symbol.STRING, null)
234- .add(Symbol.BOOLEAN, null)
235- .add(Symbol.PLUS, null)
236- .add(Symbol.MINUS, null)
237- .add(Symbol.PERIOD, null)
238+ .add(Symbol.VARIABLE, null)
239 .add(Symbol.CELL_REF, null)
240 .add(Symbol.FIXED_CELL_REF, null)
241 .add(Symbol.POUND, null)
242@@ -380,12 +460,7 @@ table[Tree.PLUS] = ObjectBuilder
243 .add(Symbol.WHITE_SPACE, null)
244 .build();
245 table[Tree.MINUS] = ObjectBuilder
246- .add(Symbol.NUMBER, null)
247- .add(Symbol.STRING, null)
248- .add(Symbol.BOOLEAN, null)
249- .add(Symbol.PLUS, null)
250- .add(Symbol.MINUS, null)
251- .add(Symbol.PERIOD, null)
252+ .add(Symbol.VARIABLE, null)
253 .add(Symbol.CELL_REF, null)
254 .add(Symbol.FIXED_CELL_REF, null)
255 .add(Symbol.POUND, null)
256@@ -395,12 +470,7 @@ table[Tree.MINUS] = ObjectBuilder
257 .add(Symbol.WHITE_SPACE, null)
258 .build();
259 table[Tree.ASTERISK] = ObjectBuilder
260- .add(Symbol.NUMBER, null)
261- .add(Symbol.STRING, null)
262- .add(Symbol.BOOLEAN, null)
263- .add(Symbol.PLUS, null)
264- .add(Symbol.MINUS, null)
265- .add(Symbol.PERIOD, null)
266+ .add(Symbol.VARIABLE, null)
267 .add(Symbol.CELL_REF, null)
268 .add(Symbol.FIXED_CELL_REF, null)
269 .add(Symbol.POUND, null)
270@@ -410,12 +480,7 @@ table[Tree.ASTERISK] = ObjectBuilder
271 .add(Symbol.WHITE_SPACE, null)
272 .build();
273 table[Tree.SLASH] = ObjectBuilder
274- .add(Symbol.NUMBER, null)
275- .add(Symbol.STRING, null)
276- .add(Symbol.BOOLEAN, null)
277- .add(Symbol.PLUS, null)
278- .add(Symbol.MINUS, null)
279- .add(Symbol.PERIOD, null)
280+ .add(Symbol.VARIABLE, null)
281 .add(Symbol.CELL_REF, null)
282 .add(Symbol.FIXED_CELL_REF, null)
283 .add(Symbol.POUND, null)
284@@ -425,12 +490,7 @@ table[Tree.SLASH] = ObjectBuilder
285 .add(Symbol.WHITE_SPACE, null)
286 .build();
287 table[Tree.CARROT] = ObjectBuilder
288- .add(Symbol.NUMBER, null)
289- .add(Symbol.STRING, null)
290- .add(Symbol.BOOLEAN, null)
291- .add(Symbol.PLUS, null)
292- .add(Symbol.MINUS, null)
293- .add(Symbol.PERIOD, null)
294+ .add(Symbol.VARIABLE, null)
295 .add(Symbol.CELL_REF, null)
296 .add(Symbol.FIXED_CELL_REF, null)
297 .add(Symbol.POUND, null)
298@@ -440,184 +500,774 @@ table[Tree.CARROT] = ObjectBuilder
299 .add(Symbol.WHITE_SPACE, null)
300 .build();
301 table[Tree.AMPERSAND] = ObjectBuilder
302- .add(Symbol.NUMBER, null)
303- .add(Symbol.STRING, null)
304- .add(Symbol.BOOLEAN, null)
305- .add(Symbol.PLUS, null)
306- .add(Symbol.MINUS, null)
307- .add(Symbol.PERIOD, null)
308- .add(Symbol.CELL_REF, null)
309- .add(Symbol.FIXED_CELL_REF, null)
310- .add(Symbol.POUND, null)
311- .add(Symbol.FORMULA, null)
312- .add(Symbol.OPEN_PAREN, null)
313- .add(Symbol.OPEN_ARRAY, null)
314- .add(Symbol.WHITE_SPACE, null)
315- .build();
316-table[Tree.PERCENT] = ObjectBuilder
317- .add(Symbol.PLUS, null)
318- .add(Symbol.MINUS, null)
319- .add(Symbol.ASTERISK, null)
320- .add(Symbol.DIVIDE, null)
321- .add(Symbol.CARROT, null)
322- .add(Symbol.AMPERSAND, null)
323- .add(Symbol.COMMA, null)
324- .add(Symbol.OPEN_PAREN, null)
325- .add(Symbol.OPEN_ARRAY, null)
326- .add(Symbol.WHITE_SPACE, null)
327- .add(Symbol.END, null)
328- .build();;
329-table[Tree.LESS_THAN] = ObjectBuilder
330 .add(Symbol.VARIABLE, null)
331- .add(Symbol.FORMULA, null)
332- .add(Symbol.CELL_REF, null)
333- .add(Symbol.FIXED_CELL_REF, null)
334- .add(Symbol.ERROR, null)
335- .add(Symbol.OPEN_ARRAY, null)
336- .add(Symbol.OPEN_PAREN, null)
337- .add(Symbol.PLUS, null)
338- .add(Symbol.MINUS, null)
339- .add(Symbol.PERIOD, null)
340- .add(Symbol.WHITE_SPACE, null)
341- .add(Symbol.END, null)
342- .build();
343-table[Tree.GREATER_THAN] = ObjectBuilder
344- .add(Symbol.VARIABLE, Tree.VARIABLE)
345- .add(Symbol.FORMULA, null)
346 .add(Symbol.CELL_REF, null)
347 .add(Symbol.FIXED_CELL_REF, null)
348- .add(Symbol.ERROR, null)
349- .add(Symbol.OPEN_ARRAY, null)
350- .add(Symbol.OPEN_PAREN, null)
351- .add(Symbol.PLUS, null)
352- .add(Symbol.MINUS, null)
353- .add(Symbol.PERIOD, null)
354- .add(Symbol.WHITE_SPACE, null)
355- .add(Symbol.END, null)
356- .build();;
357-table[Tree.EQUALS] = ObjectBuilder
358- .add(Symbol.VARIABLE, Tree.VARIABLE)
359- .add(Symbol.FORMULA, null)
360- .add(Symbol.CELL_REF, null)
361- .add(Symbol.FIXED_CELL_REF, null)
362- .add(Symbol.ERROR, null)
363- .add(Symbol.OPEN_ARRAY, null)
364- .add(Symbol.OPEN_PAREN, null)
365- .add(Symbol.PLUS, null)
366- .add(Symbol.MINUS, null)
367- .add(Symbol.PERIOD, null)
368- .add(Symbol.WHITE_SPACE, null)
369- .add(Symbol.END, null)
370- .build();;
371-table[Tree.COMMA] = ObjectBuilder
372- .add(Symbol.VARIABLE, Tree.VARIABLE)
373- .add(Symbol.FORMULA, null)
374- .add(Symbol.CELL_REF, null)
375- .add(Symbol.FIXED_CELL_REF, null)
376- .add(Symbol.ERROR, null)
377- .add(Symbol.PLUS, null)
378- .add(Symbol.MINUS, null)
379- .add(Symbol.PERIOD, null)
380- .add(Symbol.OPEN_PAREN, null)
381- .add(Symbol.OPEN_ARRAY, null)
382- .add(Symbol.WHITE_SPACE, null)
383- .add(Symbol.END, null)
384- .build();
385-table[Tree.OPEN_PAREN] = ObjectBuilder
386- .add(Symbol.VARIABLE, Tree.VARIABLE)
387+ .add(Symbol.POUND, null)
388 .add(Symbol.FORMULA, null)
389- .add(Symbol.CELL_REF, null)
390- .add(Symbol.FIXED_CELL_REF, null)
391- .add(Symbol.ERROR, null)
392- .add(Symbol.PLUS, null)
393- .add(Symbol.MINUS, null)
394- .add(Symbol.PERIOD, null)
395 .add(Symbol.OPEN_PAREN, null)
396 .add(Symbol.OPEN_ARRAY, null)
397 .add(Symbol.WHITE_SPACE, null)
398 .build();
399-table[Tree.CLOSE_PAREN] = ObjectBuilder
400- .add(Symbol.PLUS, null)
401- .add(Symbol.MINUS, null)
402- .add(Symbol.ASTERISK, null)
403- .add(Symbol.DIVIDE, null)
404- .add(Symbol.PERCENT, null)
405- .add(Symbol.CARROT, null)
406- .add(Symbol.COMMA, null)
407- .add(Symbol.CLOSE_ARRAY, null)
408- .add(Symbol.WHITE_SPACE, null)
409- .add(Symbol.END, null)
410- .build();
411-table[Tree.CELL_REF] = ObjectBuilder
412- .add(Symbol.PLUS, null)
413- .add(Symbol.MINUS, null)
414- .add(Symbol.ASTERISK, null)
415- .add(Symbol.DIVIDE, null)
416- .add(Symbol.CARROT, null)
417- .add(Symbol.PERCENT, null)
418- .add(Symbol.AMPERSAND, null)
419- .add(Symbol.GREATER_THAN, null)
420- .add(Symbol.LESS_THAN, null)
421- .add(Symbol.EQUALS, null)
422- .add(Symbol.COMMA, null)
423- .add(Symbol.CLOSE_PAREN, null)
424- .add(Symbol.CLOSE_ARRAY, null)
425- .add(Symbol.WHITE_SPACE, null)
426- .add(Symbol.END, null)
427- .build();
428-table[Tree.FIXED_CELL_REF] = ObjectBuilder
429- .add(Symbol.PLUS, null)
430- .add(Symbol.MINUS, null)
431- .add(Symbol.ASTERISK, null)
432- .add(Symbol.DIVIDE, null)
433- .add(Symbol.CARROT, null)
434- .add(Symbol.PERCENT, null)
435- .add(Symbol.AMPERSAND, null)
436- .add(Symbol.GREATER_THAN, null)
437- .add(Symbol.LESS_THAN, null)
438- .add(Symbol.EQUALS, null)
439- .add(Symbol.COMMA, null)
440- .add(Symbol.CLOSE_PAREN, null)
441- .add(Symbol.CLOSE_ARRAY, null)
442- .add(Symbol.WHITE_SPACE, null)
443- .add(Symbol.END, null)
444- .build();
445-table[Tree.CELL_RANGE_REF] = ObjectBuilder
446- .add(Symbol.PLUS, null)
447- .add(Symbol.MINUS, null)
448- .add(Symbol.ASTERISK, null)
449- .add(Symbol.DIVIDE, null)
450- .add(Symbol.CARROT, null)
451- .add(Symbol.PERCENT, null)
452- .add(Symbol.AMPERSAND, null)
453- .add(Symbol.GREATER_THAN, null)
454- .add(Symbol.LESS_THAN, null)
455- .add(Symbol.EQUALS, null)
456- .add(Symbol.COMMA, null)
457- .add(Symbol.CLOSE_PAREN, null)
458- .add(Symbol.CLOSE_ARRAY, null)
459- .add(Symbol.WHITE_SPACE, null)
460- .add(Symbol.END, null)
461- .build();
462-table[Tree.FIXED_CELL_RANGE_REF] = ObjectBuilder
463- .add(Symbol.PLUS, null)
464- .add(Symbol.MINUS, null)
465- .add(Symbol.ASTERISK, null)
466- .add(Symbol.DIVIDE, null)
467- .add(Symbol.CARROT, null)
468- .add(Symbol.PERCENT, null)
469- .add(Symbol.AMPERSAND, null)
470- .add(Symbol.GREATER_THAN, null)
471- .add(Symbol.LESS_THAN, null)
472- .add(Symbol.EQUALS, null)
473- .add(Symbol.COMMA, null)
474- .add(Symbol.CLOSE_PAREN, null)
475- .add(Symbol.CLOSE_ARRAY, null)
476- .add(Symbol.WHITE_SPACE, null)
477- .add(Symbol.END, null)
478- .build();
479 table[Tree.EXPRESSION] = null;
480 table[Tree.INVERT_NEXT] = null;
481+table[Tree.TERMINATE] = ObjectBuilder
482+ .add(Symbol.END, [ACCEPT, ReduceActions.RETURN_LAST])
483+ .build();
484+const ACTION_TABLE = table;
485+
486+
487+let Parser = (function () {
488+ let parser = {
489+ lexer: undefined,
490+ Parser: undefined,
491+ trace: function trace() {},
492+ yy: {},
493+ /**
494+ * Perform a reduce action on the given virtual stack. Basically, fetching, deriving, or calculating a value.
495+ * @param rawValueOfReduceOriginToken - Some actions require the origin token to perform a reduce action. For
496+ * example, when reducing the cell reference A1 to it's actual value this value would be "A1".
497+ * @param sharedStateYY - the shared state that has all helpers, and current working object.
498+ * @param reduceActionToPerform - the ReduceAction to perform with the current virtual stack. Since this function
499+ * is only called in one place, this should always be action[1] in that context.
500+ * @param virtualStack - Array of values to use in action.
501+ * @param catchOnFailure - If we are performing an action that could result in a failure, and we cant to catch and
502+ * assign the error thrown, this should be set to true.
503+ * @returns {number|boolean|string}
504+ */
505+ performAction: function (rawValueOfReduceOriginToken, sharedStateYY, reduceActionToPerform, virtualStack : Array<any>, catchOnFailure : boolean) {
506+ // For context, this function is only called with `apply`, so `this` is `yyval`.
507+
508+ const vsl = virtualStack.length - 1;
509+ try {
510+ switch (reduceActionToPerform) {
511+ case ReduceActions.RETURN_LAST:
512+ return virtualStack[vsl - 1];
513+ case ReduceActions.CALL_VARIABLE:
514+ this.$ = sharedStateYY.handler.helper.callVariable.call(this, virtualStack[vsl]);
515+ break;
516+ case ReduceActions.AS_NUMBER:
517+ this.$ = sharedStateYY.handler.helper.number(virtualStack[vsl]);
518+ break;
519+ case ReduceActions.AS_STRING:
520+ this.$ = sharedStateYY.handler.helper.string(virtualStack[vsl]);
521+ break;
522+ case ReduceActions.AMPERSAND:
523+ this.$ = sharedStateYY.handler.helper.specialMatch('&', virtualStack[vsl - 2], virtualStack[vsl]);
524+ break;
525+ case ReduceActions.EQUALS:
526+ this.$ = sharedStateYY.handler.helper.logicMatch('=', virtualStack[vsl - 2], virtualStack[vsl]);
527+ break;
528+ case ReduceActions.PLUS:
529+ this.$ = sharedStateYY.handler.helper.mathMatch('+', virtualStack[vsl - 2], virtualStack[vsl]);
530+ break;
531+ case ReduceActions.LAST_NUMBER:
532+ this.$ = sharedStateYY.handler.helper.number(virtualStack[vsl - 1]);
533+ break;
534+ case ReduceActions.LTE:
535+ this.$ = sharedStateYY.handler.helper.logicMatch('<=', virtualStack[vsl - 3], virtualStack[vsl]);
536+ break;
537+ case ReduceActions.GTE:
538+ this.$ = sharedStateYY.handler.helper.logicMatch('>=', virtualStack[vsl - 3], virtualStack[vsl]);
539+ break;
540+ case ReduceActions.NOT_EQ:
541+ this.$ = sharedStateYY.handler.helper.logicMatch('<>', virtualStack[vsl - 3], virtualStack[vsl]);
542+ break;
543+ case ReduceActions.GT:
544+ this.$ = sharedStateYY.handler.helper.logicMatch('>', virtualStack[vsl - 2], virtualStack[vsl]);
545+ break;
546+ case ReduceActions.LT:
547+ this.$ = sharedStateYY.handler.helper.logicMatch('<', virtualStack[vsl - 2], virtualStack[vsl]);
548+ break;
549+ case ReduceActions.MINUS:
550+ this.$ = sharedStateYY.handler.helper.mathMatch('-', virtualStack[vsl - 2], virtualStack[vsl]);
551+ break;
552+ case ReduceActions.MULTIPLY:
553+ this.$ = sharedStateYY.handler.helper.mathMatch('*', virtualStack[vsl - 2], virtualStack[vsl]);
554+ break;
555+ case ReduceActions.DIVIDE:
556+ this.$ = sharedStateYY.handler.helper.mathMatch('/', virtualStack[vsl - 2], virtualStack[vsl]);
557+ break;
558+ case ReduceActions.TO_POWER:
559+ this.$ = sharedStateYY.handler.helper.mathMatch('^', virtualStack[vsl - 2], virtualStack[vsl]);
560+ break;
561+ case ReduceActions.INVERT_NUMBER:
562+ this.$ = sharedStateYY.handler.helper.numberInverted(virtualStack[vsl]);
563+ if (isNaN(this.$)) {
564+ this.$ = 0;
565+ }
566+ break;
567+ case ReduceActions.TO_NUMBER_NAN_AS_ZERO:
568+ this.$ = sharedStateYY.handler.helper.number(virtualStack[vsl]);
569+ if (isNaN(this.$)) {
570+ this.$ = 0;
571+ }
572+ break;
573+ case ReduceActions.CALL_FUNCTION_LAST_BLANK:
574+ this.$ = sharedStateYY.handler.helper.callFunction.call(this, virtualStack[vsl - 2], '');
575+ break;
576+ case ReduceActions.FIXED_CELL_VAL:
577+ this.$ = sharedStateYY.handler.helper.fixedCellValue.call(sharedStateYY.obj, virtualStack[vsl]);
578+ break;
579+ case ReduceActions.FIXED_CELL_RANGE_VAL:
580+ this.$ = sharedStateYY.handler.helper.fixedCellRangeValue.call(sharedStateYY.obj, virtualStack[vsl - 2], virtualStack[vsl]);
581+ break;
582+ case ReduceActions.CELL_VALUE:
583+ this.$ = sharedStateYY.handler.helper.cellValue.call(sharedStateYY.obj, virtualStack[vsl]);
584+ break;
585+ case ReduceActions.CELL_RANGE_VALUE:
586+ this.$ = sharedStateYY.handler.helper.cellRangeValue.call(sharedStateYY.obj, virtualStack[vsl - 2], virtualStack[vsl]);
587+ break;
588+ case ReduceActions.AS_ERROR:
589+ this.$ = constructErrorByName(virtualStack[vsl]);
590+ break;
591+ }
592+ } catch (e) {
593+ if (catchOnFailure) {
594+ // NOTE: I'm not sure if some of these ReduceAction map correctly in the case of an error.
595+ switch (reduceActionToPerform) {
596+ case ReduceActions.RETURN_LAST:
597+ return virtualStack[vsl - 1];
598+ case ReduceActions.CALL_VARIABLE:
599+ case ReduceActions.AS_NUMBER:
600+ case ReduceActions.AS_STRING:
601+ case ReduceActions.AMPERSAND:
602+ case ReduceActions.EQUALS:
603+ case ReduceActions.PLUS:
604+ case ReduceActions.LAST_NUMBER:
605+ case ReduceActions.LTE:
606+ case ReduceActions.GTE:
607+ case ReduceActions.NOT_EQ:
608+ case ReduceActions.NOT:
609+ case ReduceActions.GT:
610+ case ReduceActions.LT:
611+ case ReduceActions.MINUS:
612+ case ReduceActions.MULTIPLY:
613+ case ReduceActions.DIVIDE:
614+ case ReduceActions.TO_POWER:
615+ case ReduceActions.CALL_FUNCTION_LAST_BLANK:
616+ case ReduceActions.CALL_FUNCTION:
617+ case ReduceActions.FIXED_CELL_VAL:
618+ case ReduceActions.FIXED_CELL_RANGE_VAL:
619+ case ReduceActions.CELL_VALUE:
620+ case ReduceActions.CELL_RANGE_VALUE:
621+ this.$ = e;
622+ break;
623+ case ReduceActions.INVERT_NUMBER:
624+ this.$ = e;
625+ if (isNaN(this.$)) {
626+ this.$ = 0;
627+ }
628+ break;
629+ case ReduceActions.TO_NUMBER_NAN_AS_ZERO:
630+ this.$ = e;
631+ if (isNaN(this.$)) {
632+ this.$ = 0;
633+ }
634+ break;
635+ }
636+ } else {
637+ throw e;
638+ }
639+ }
640+ },
641+ defaultActions: {19: [REDUCE, 1]},
642+ parseError: function parseError(str, hash) {
643+ if (hash.recoverable) {
644+ this.trace(str);
645+ } else {
646+ throw new ParseError(str);
647+ }
648+ },
649+ parse: function parse(input) {
650+ let stack = [0],
651+ semanticValueStack = [null],
652+ locationStack = [],
653+ yytext = '',
654+ yylineno = 0,
655+ yyleng = 0,
656+ recovering = 0,
657+ EOF = 1;
658+
659+ let args = locationStack.slice.call(arguments, 1);
660+ let lexer = Object.create(this.lexer);
661+ let sharedState = {
662+ yy: {
663+ parseError: undefined,
664+ lexer: {
665+ parseError: undefined
666+ },
667+ parser: {
668+ parseError: undefined
669+ }
670+ }
671+ };
672+ // copy state
673+ for (let k in this.yy) {
674+ if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
675+ sharedState.yy[k] = this.yy[k];
676+ }
677+ }
678+
679+ lexer.setInput(input, sharedState.yy);
680+ sharedState.yy.lexer = lexer;
681+ sharedState.yy.parser = this;
682+ if (typeof lexer.yylloc == 'undefined') {
683+ lexer.yylloc = {};
684+ }
685+ let yyloc = lexer.yylloc;
686+ locationStack.push(yyloc);
687+
688+ let ranges = false;
689+
690+ if (typeof sharedState.yy.parseError === 'function') {
691+ this.parseError = sharedState.yy.parseError;
692+ } else {
693+ this.parseError = Object.getPrototypeOf(this).parseError;
694+ }
695+
696+ function popStack(n) {
697+ stack.length = stack.length - 2 * n;
698+ semanticValueStack.length = semanticValueStack.length - n;
699+ locationStack.length = locationStack.length - n;
700+ }
701+
702+ function lex() {
703+ let token = lexer.lex() || EOF;
704+ // if token isn't its numeric value, convert
705+ if (typeof token !== 'number') {
706+ token = SYMBOL_NAME_TO_INDEX[token] || token;
707+ }
708+ return token;
709+ }
710+
711+ let symbol,
712+ preErrorSymbol,
713+ state,
714+ action,
715+ result,
716+ yyval = {
717+ $: undefined,
718+ _$: undefined
719+ },
720+ p,
721+ newState,
722+ expected,
723+ catchFailuresOn = false;
724+ while (true) {
725+ // retrieve state number from top of stack
726+ state = stack[stack.length - 1];
727+
728+ // use default actions if available
729+ if (this.defaultActions[state]) {
730+ action = this.defaultActions[state];
731+ } else {
732+ if (typeof symbol == 'undefined'|| symbol === null) {
733+ symbol = lex();
734+ }
735+ // read action for current state and first input
736+ action = ACTION_TABLE[state] && ACTION_TABLE[state][symbol];
737+ console.log(action, state, symbol);
738+ }
739+
740+ // handle parse error
741+ if (typeof action === 'undefined' || !action.length || !action[0]) {
742+ let error_rule_depth;
743+ let errStr = '';
744+
745+ // Return the rule stack depth where the nearest error rule can be found.
746+ // Return FALSE when no error recovery rule was found.
747+ this.locateNearestErrorRecoveryRule = function(state) {
748+ let stack_probe = stack.length - 1;
749+ let depth = 0;
750+
751+ // try to recover from error
752+ for (; ;) {
753+ if (isUndefined(state)) {
754+ return false;
755+ }
756+ if (state === 0 || stack_probe < 2) {
757+ return false; // No suitable error recovery rule available.
758+ }
759+ stack_probe -= 2; // popStack(1): [symbol, action]
760+ state = stack[stack_probe];
761+ ++depth;
762+ }
763+ };
764+
765+ if (!recovering) {
766+ // first see if there's any chance at hitting an error recovery rule:
767+ error_rule_depth = this.locateNearestErrorRecoveryRule(state);
768+
769+ // Report error
770+ expected = [];
771+ let expectedIndexes = [];
772+ let tableState = ACTION_TABLE[state];
773+ for (p in ACTION_TABLE[state]) {
774+ if (SYMBOL_INDEX_TO_NAME[p]) {
775+ expected.push(SYMBOL_INDEX_TO_NAME[p]);
776+ expectedIndexes.push(p);
777+ }
778+ }
779+ if (lexer.showPosition) {
780+ errStr = 'Parse error on line ' + (yylineno + 1) + ": " + lexer.showPosition() + " Expecting " + expected.join(', ') + ", got " + (SYMBOL_INDEX_TO_NAME[symbol] || symbol);
781+ } else {
782+ errStr = 'Parse error on line ' + (yylineno + 1) + ": Unexpected " +
783+ (symbol == EOF ? "end of input" :
784+ ("'" + (SYMBOL_INDEX_TO_NAME[symbol] || symbol) + "'"));
785+ }
786+ this.parseError(errStr, {
787+ text: lexer.match,
788+ token: SYMBOL_INDEX_TO_NAME[symbol] || symbol,
789+ tokenIndex: symbol,
790+ line: lexer.yylineno,
791+ loc: yyloc,
792+ expected: expected,
793+ expectedIndexes: expectedIndexes,
794+ state: state,
795+ tableState: tableState,
796+ stack: stack,
797+ semanticValueStack: semanticValueStack
798+ });
799+ }
800+ }
801+
802+ // this shouldn't happen, unless resolve defaults are off
803+ if (action[0] instanceof Array && action.length > 1) {
804+ throw new ParseError('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
805+ }
806+
807+ // Available actions:
808+ // Shift: continue to process tokens.
809+ // Reduce: enough tokens have been gathered to reduce input through evaluation.
810+ // Accept: return.
811+ switch (action[0]) {
812+ case SHIFT: // Shift
813+ stack.push(symbol);
814+ semanticValueStack.push(lexer.yytext);
815+ locationStack.push(lexer.yylloc);
816+ stack.push(action[1]); // push state
817+ // console.log("SHIFT", "literal", lexer.yytext, " symbol", symbol, " symbol name", SYMBOL_INDEX_TO_NAME[symbol], " action", action,
818+ // " stack", stack, " semanticValueStack", semanticValueStack);
819+ symbol = null;
820+
821+ if (Formulas.isTryCatchFormula(lexer.yytext)) {
822+ catchFailuresOn = true;
823+ }
824+
825+ if (!preErrorSymbol) { // normal execution/no error
826+ yyleng = lexer.yyleng;
827+ yytext = lexer.yytext;
828+ yylineno = lexer.yylineno;
829+ yyloc = lexer.yylloc;
830+ if (recovering > 0) {
831+ recovering--;
832+ }
833+ } else {
834+ // error just occurred, resume old lookahead f/ before error
835+ symbol = preErrorSymbol;
836+ preErrorSymbol = null;
837+ }
838+ break;
839+
840+ case REDUCE: // Reduce
841+ // console.log("REDUCE", "literal", lexer.yytext, " symbol", symbol, " symbol name", SYMBOL_INDEX_TO_NAME[symbol], " action", action,
842+ // " stack", stack, " semanticValueStack", semanticValueStack);
843+ let currentProduction : ReductionPair = PRODUCTIONS[action[1]];
844+
845+ let lengthToReduceStackBy = currentProduction.getLengthToReduceStackBy();
846+
847+ // perform semantic action
848+ yyval.$ = semanticValueStack[semanticValueStack.length - lengthToReduceStackBy]; // default to $$ = $1
849+ // default location, uses first token for firsts, last for lasts
850+ yyval._$ = {
851+ first_line: locationStack[locationStack.length - (lengthToReduceStackBy || 1)].first_line,
852+ last_line: locationStack[locationStack.length - 1].last_line,
853+ first_column: locationStack[locationStack.length - (lengthToReduceStackBy || 1)].first_column,
854+ last_column: locationStack[locationStack.length - 1].last_column
855+ };
856+ if (ranges) {
857+ yyval._$.range = [locationStack[locationStack.length - (lengthToReduceStackBy || 1)].range[0], locationStack[locationStack.length - 1].range[1]];
858+ }
859+ // If we are inside of a formula that should catch errors, then catch and return them.
860+ result = this.performAction.apply(yyval, [yytext, sharedState.yy, action[1], semanticValueStack, catchFailuresOn].concat(args));
861+
862+ if (typeof result !== 'undefined') {
863+ return result;
864+ }
865+
866+ // pop off stack
867+ if (lengthToReduceStackBy) {
868+ stack = stack.slice(0, -1 * lengthToReduceStackBy * 2);
869+ semanticValueStack = semanticValueStack.slice(0, -1 * lengthToReduceStackBy);
870+ locationStack = locationStack.slice(0, -1 * lengthToReduceStackBy);
871+ }
872+
873+ // push non-terminal (reduce)
874+ stack.push(currentProduction.getReplacementTokenIndex());
875+ semanticValueStack.push(yyval.$);
876+ locationStack.push(yyval._$);
877+ newState = ACTION_TABLE[stack[stack.length - 2]][stack[stack.length - 1]];
878+ stack.push(newState);
879+ break;
880+
881+ case ACCEPT:
882+ // Accept
883+ return true;
884+ }
885+
886+ }
887+ }
888+ };
889+
890+ parser.lexer = (function () {
891+ return ({
892+ EOF: 1,
893+
894+ parseError: function parseError(str, hash) {
895+ if (this.yy.parser) {
896+ this.yy.parser.parseError(str, hash);
897+ } else {
898+ throw new ParseError(str);
899+ }
900+ },
901+
902+ // resets the lexer, sets new input
903+ setInput: function (input, yy) {
904+ this.yy = yy || this.yy || {};
905+ this._input = input;
906+ this._more = this._backtrack = this.done = false;
907+ this.yylineno = this.yyleng = 0;
908+ this.yytext = this.matched = this.match = '';
909+ this.conditionStack = ['INITIAL'];
910+ this.yylloc = {
911+ first_line: 1,
912+ first_column: 0,
913+ last_line: 1,
914+ last_column: 0
915+ };
916+ this.offset = 0;
917+ return this;
918+ },
919+
920+ // consumes and returns one char from the input
921+ input: function () {
922+ let ch = this._input[0];
923+ this.yytext += ch;
924+ this.yyleng++;
925+ this.offset++;
926+ this.match += ch;
927+ this.matched += ch;
928+ let lines = ch.match(/(?:\r\n?|\n).*/g);
929+ if (lines) {
930+ this.yylineno++;
931+ this.yylloc.last_line++;
932+ } else {
933+ this.yylloc.last_column++;
934+ }
935+
936+ this._input = this._input.slice(1);
937+ return ch;
938+ },
939+
940+ // unshifts one char (or a string) into the input
941+ unput: function (ch) {
942+ let len = ch.length;
943+ let lines = ch.split(/(?:\r\n?|\n)/g);
944+
945+ this._input = ch + this._input;
946+ this.yytext = this.yytext.substr(0, this.yytext.length - len);
947+ //this.yyleng -= len;
948+ this.offset -= len;
949+ let oldLines = this.match.split(/(?:\r\n?|\n)/g);
950+ this.match = this.match.substr(0, this.match.length - 1);
951+ this.matched = this.matched.substr(0, this.matched.length - 1);
952+
953+ if (lines.length - 1) {
954+ this.yylineno -= lines.length - 1;
955+ }
956+ let r = this.yylloc.range;
957+
958+ this.yylloc = {
959+ first_line: this.yylloc.first_line,
960+ last_line: this.yylineno + 1,
961+ first_column: this.yylloc.first_column,
962+ last_column: lines ?
963+ (lines.length === oldLines.length ? this.yylloc.first_column : 0)
964+ + oldLines[oldLines.length - lines.length].length - lines[0].length :
965+ this.yylloc.first_column - len
966+ };
967+
968+ this.yyleng = this.yytext.length;
969+ return this;
970+ },
971+
972+ // When called from action, caches matched text and appends it on next action
973+ more: function () {
974+ this._more = true;
975+ return this;
976+ },
977+
978+ // When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
979+ reject: function () {
980+ return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
981+ text: "",
982+ token: null,
983+ line: this.yylineno
984+ });
985+ },
986+
987+ // retain first n characters of the match
988+ less: function (n) {
989+ this.unput(this.match.slice(n));
990+ },
991+
992+ // displays already matched input, i.e. for error messages
993+ pastInput: function () {
994+ let past = this.matched.substr(0, this.matched.length - this.match.length);
995+ return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
996+ },
997+
998+ // displays upcoming input, i.e. for error messages
999+ upcomingInput: function () {
1000+ let next = this.match;
1001+ if (next.length < 20) {
1002+ next += this._input.substr(0, 20 - next.length);
1003+ }
1004+ return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
1005+ },
1006+
1007+ // displays the character position where the lexing error occurred, i.e. for error messages
1008+ showPosition: function () {
1009+ let pre = this.pastInput();
1010+ let c = new Array(pre.length + 1).join("-");
1011+ return pre + this.upcomingInput() + "\n" + c + "^";
1012+ },
1013+
1014+ // test the lexed token: return FALSE when not a match, otherwise return token
1015+ test_match: function (match, indexed_rule) {
1016+ let token,
1017+ lines,
1018+ backup;
1019+
1020+
1021+ lines = match[0].match(/(?:\r\n?|\n).*/g);
1022+ if (lines) {
1023+ this.yylineno += lines.length;
1024+ }
1025+ this.yylloc = {
1026+ first_line: this.yylloc.last_line,
1027+ last_line: this.yylineno + 1,
1028+ first_column: this.yylloc.last_column,
1029+ last_column: lines ?
1030+ lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
1031+ this.yylloc.last_column + match[0].length
1032+ };
1033+ this.yytext += match[0];
1034+ this.match += match[0];
1035+ this.matches = match;
1036+ this.yyleng = this.yytext.length;
1037+
1038+ this._more = false;
1039+ this._backtrack = false;
1040+ this._input = this._input.slice(match[0].length);
1041+ this.matched += match[0];
1042+ token = this.mapActionToActionIndex(indexed_rule);
1043+ if (this.done && this._input) {
1044+ this.done = false;
1045+ }
1046+ if (token) {
1047+ return token;
1048+ }
1049+ return false;
1050+ },
1051+
1052+ // return next match in input
1053+ next: function () {
1054+ if (this.done) {
1055+ return this.EOF;
1056+ }
1057+ if (!this._input) {
1058+ this.done = true;
1059+ }
1060+
1061+ let token,
1062+ match,
1063+ tempMatch,
1064+ index;
1065+ if (!this._more) {
1066+ this.yytext = '';
1067+ this.match = '';
1068+ }
1069+ let rules = this._currentRules();
1070+ for (let i = 0; i < rules.length; i++) {
1071+ tempMatch = this._input.match(RulesSeq[rules[i]]);
1072+ if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
1073+ match = tempMatch;
1074+ index = i;
1075+ }
1076+ }
1077+ if (match) {
1078+ token = this.test_match(match, rules[index]);
1079+ console.log("match", match, "index", index, "token", token);
1080+ if (token !== false) {
1081+ return token;
1082+ }
1083+ // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
1084+ return false;
1085+ }
1086+ if (this._input === "") {
1087+ return this.EOF;
1088+ } else {
1089+ return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
1090+ text: "",
1091+ token: null,
1092+ line: this.yylineno
1093+ });
1094+ }
1095+ },
1096+
1097+ // return next match that has a token
1098+ lex: function lex() {
1099+ let r = this.next();
1100+ if (r) {
1101+ return r;
1102+ } else {
1103+ return this.lex();
1104+ }
1105+ },
1106+
1107+ // produce the lexer rule set which is active for the currently active lexer condition state
1108+ _currentRules: function _currentRules() {
1109+ if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
1110+ return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
1111+ } else {
1112+ return this.conditions.INITIAL.rules;
1113+ }
1114+ },
1115+
1116+ mapActionToActionIndex: function (ruleIndex) {
1117+ switch (ruleIndex) {
1118+ case 0:
1119+ // skip whitespace
1120+ break;
1121+ case 1:
1122+ return ReduceActions.LAST_NUMBER;
1123+ case 2:
1124+ return ReduceActions.LAST_NUMBER;
1125+ case 3:
1126+ return ReduceActions.CALL_FUNCTION_LAST_BLANK;
1127+ case 4:
1128+ return ReduceActions.AMPERSAND;
1129+ case 5:
1130+ return ReduceActions.EQUALS;
1131+ case 7:
1132+ return ReduceActions.FIXED_CELL_VAL;
1133+ case 8:
1134+ return ReduceActions.CALL_FUNCTION_LAST_BLANK;
1135+ case 9:
1136+ return ReduceActions.AS_NUMBER;
1137+ case 12:
1138+ return ReduceActions.FIXED_CELL_RANGE_VAL;
1139+ case 13:
1140+ // skip whitespace??
1141+ break;
1142+ case 14:
1143+ return ReduceActions.LTE;
1144+ case 15:
1145+ return ' ';
1146+ case 18:
1147+ return ReduceActions.CELL_VALUE;
1148+ case 19:
1149+ return ReduceActions.CELL_RANGE_VALUE;
1150+ case 20:
1151+ return ReduceActions.TO_POWER;
1152+ case 21:
1153+ return ReduceActions.INVERT_NUMBER;
1154+ case 22:
1155+ return ReduceActions.DIVIDE;
1156+ case 23:
1157+ return ReduceActions.NOT_EQ;
1158+ case 24:
1159+ return ReduceActions.TO_NUMBER_NAN_AS_ZERO;
1160+ case 25:
1161+ return ReduceActions.NOT;
1162+ case 26:
1163+ return ReduceActions.GT;
1164+ case 27:
1165+ return ReduceActions.MINUS;
1166+ case 28:
1167+ return ReduceActions.LT;
1168+ case 29:
1169+ return ReduceActions.MULTIPLY;
1170+ case 30:
1171+ return '"';
1172+ case 31:
1173+ return "'";
1174+ case 32:
1175+ return "!";
1176+ case 33:
1177+ return ReduceActions.GTE;
1178+ case 36:
1179+ return ReduceActions.AS_NUMBER;
1180+ }
1181+ },
1182+ conditions: {
1183+ INITIAL: {
1184+ rules: [
1185+ 0,
1186+ 1,
1187+ 2,
1188+ 3,
1189+ 4,
1190+ 5,
1191+ 6,
1192+ 7,
1193+ 8,
1194+ 9,
1195+ 10,
1196+ 11,
1197+ 12,
1198+ 13,
1199+ 14,
1200+ 15,
1201+ 16,
1202+ 17,
1203+ 18,
1204+ 19,
1205+ 20,
1206+ 21,
1207+ 22,
1208+ 23,
1209+ 24,
1210+ 25,
1211+ 26,
1212+ 27,
1213+ 28,
1214+ 29,
1215+ 30,
1216+ 31,
1217+ 32,
1218+ 33,
1219+ 34,
1220+ 35,
1221+ 36,
1222+ 37
1223+ ],
1224+ "inclusive": true
1225+ }
1226+ }
1227+ });
1228+ })();
1229+ function Parser() {
1230+ this.yy = {};
1231+ }
1232
1233+ Parser.prototype = parser;
1234+ parser.Parser = Parser;
1235+ return new Parser;
1236+})();
1237
1238-table[Tree.TERMINATE] = undefined; // Terminate the end.
1239\ No newline at end of file
1240+export {
1241+ Parser
1242+}
1243\ No newline at end of file
1244diff --git a/tests.sh b/tests.sh
1245index d8b7e40..1899aa7 100755
1246--- a/tests.sh
1247+++ b/tests.sh
1248@@ -4,5 +4,5 @@ echo "$(date) Compiling Tests"
1249 tsc --outDir test_output tests/*.ts
1250 tsc --outDir test_output tests/*/*.ts
1251
1252-node test_output/tests/ParsingTest.js
1253+node test_output/tests/Parser/ParseEngineTest.js
1254 echo "$(date) Tests Done"
1255\ No newline at end of file
1256diff --git a/tests/Parser/ParseEngineTest.ts b/tests/Parser/ParseEngineTest.ts
1257new file mode 100644
1258index 0000000..a00d64c
1259--- /dev/null
1260+++ b/tests/Parser/ParseEngineTest.ts
1261@@ -0,0 +1,37 @@
1262+import {
1263+ Parser
1264+} from "../../src/Parser/ParseEngine";
1265+
1266+
1267+let FormulaParser = function(handler) {
1268+ let formulaLexer = function () {};
1269+ formulaLexer.prototype = Parser.lexer;
1270+
1271+ let formulaParser = function () {
1272+ this.lexer = new formulaLexer();
1273+ this.yy = {};
1274+ };
1275+
1276+ formulaParser.prototype = Parser;
1277+ let newParser = new formulaParser;
1278+ newParser.setObj = function(obj: string) {
1279+ newParser.yy.obj = obj;
1280+ };
1281+
1282+ newParser.yy.parseError = function (str, hash) {
1283+ throw new Error(JSON.stringify({
1284+ name: 'Parser error',
1285+ message: str,
1286+ prop: hash
1287+ }));
1288+ };
1289+
1290+ newParser.yy.handler = handler;
1291+
1292+ return newParser;
1293+};
1294+
1295+let parser = FormulaParser({});
1296+parser.setObj("A1");
1297+
1298+console.log(parser.parse('5'));
1299\ No newline at end of file