spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
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