spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Parser,TypeConverter] adjusting Parser and TypeConverter number regex to handle sci-notation number Also moving Rules into Parser
author
Ben Vogt <[email protected]>
date
2017-08-31 04:24:44
stats
5 file(s) changed, 237 insertions(+), 247 deletions(-)
files
src/Parser/Parser.ts
src/Parser/Rules.ts
src/Utilities/TypeConverter.ts
tests/SheetFormulaTest.ts
tests/Utilities/TypeConverterTest.ts
  1diff --git a/src/Parser/Parser.ts b/src/Parser/Parser.ts
  2index 10d49fa..e614c78 100644
  3--- a/src/Parser/Parser.ts
  4+++ b/src/Parser/Parser.ts
  5@@ -1,49 +1,131 @@
  6-import {
  7-  RULES,
  8-
  9-  WHITE_SPACE_RULE_INDEX,
 10-  DOUBLE_QUOTES_RULE_INDEX,
 11-  SINGLE_QUOTES_RULE_INDEX,
 12-  FORMULA_NAME_RULE_INDEX,
 13-  DATE_RULE_INDEX,
 14-  TIME_RULE_INDEX,
 15-  $_A1_CELL_RULE_INDEX,
 16-  A1_CELL_RULE_INDEX,
 17-  FORMULA_NAME_SIMPLE_RULE_INDEX,
 18-  VARIABLE_RULE_INDEX,
 19-  SIMPLE_VARIABLE_RILE_INDEX,
 20-  INTEGER_RULE_INDEX,
 21-  OPEN_AND_CLOSE_OF_ARRAY_RULE_INDEX,
 22-  DOLLAR_SIGN_RULE_INDEX,
 23-  AMPERSAND_SIGN_RULE_INDEX,
 24-  SINGLE_WHITESPACE_RULE_INDEX,
 25-  PERIOD_RULE_INDEX,
 26-  COLON_RULE_INDEX,
 27-  SEMI_COLON_RULE_INDEX,
 28-  COMMA_RULE_INDEX,
 29-  ASTERISK_RULE_INDEX,
 30-  FORWARD_SLASH_RULE_INDEX,
 31-  MINUS_SIGN_RULE_INDEX,
 32-  PLUS_SIGN_RULE_INDEX,
 33-  CARET_SIGN_RULE_INDEX,
 34-  OPEN_PAREN_RULE_INDEX,
 35-  CLOSE_PAREN_RULE_INDEX,
 36-  GREATER_THAN_SIGN_RULE_INDEX,
 37-  LESS_THAN_SIGN_RULE_INDEX,
 38-  NOT_RULE_INDEX,
 39-  OPEN_DOUBLE_QUOTE_INDEX,
 40-  OPEN_SINGLE_QUITE_INDEX,
 41-  EXCLAMATION_POINT_RULE_INDEX,
 42-  EQUALS_SIGN_RULE_INDEX,
 43-  PERCENT_SIGN_RULE_INDEX,
 44-  HASH_SIGN_RULE_INDEX,
 45-  END_OF_STRING_RULE_INDEX
 46-} from "./Rules";
 47 import {
 48   ObjectFromPairs
 49 } from "../Utilities/ObjectFromPairs";
 50 
 51 
 52+// Rules represent the Regular Expressions that will be used in sequence to match a given input to the Parser.
 53+const WHITE_SPACE_RULE = /^(?:\s+)/; // rule 0
 54+const DOUBLE_QUOTES_RULE = /^(?:"(\\["]|[^"])*")/; // rule 1
 55+const SINGLE_QUOTES_RULE = /^(?:'(\\[']|[^'])*')/; // rule 2
 56+const FORMULA_NAME_RULE = /^(?:[A-Za-z.]{1,}[A-Za-z_0-9]+(?=[(]))/; // Changed from /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+(?=[(]))/ // rule 3
 57+const DATE_RULE = /^(?:([0]?[1-9]|1[0-2])[:][0-5][0-9]([:][0-5][0-9])?[ ]?(AM|am|aM|Am|PM|pm|pM|Pm))/; // rule 4
 58+const TIME_RULE = /^(?:([0]?[0-9]|1[0-9]|2[0-3])[:][0-5][0-9]([:][0-5][0-9])?)/; // rule 5
 59+const $_A1_CELL_RULE = /^(?:\$[A-Za-z]+\$[0-9]+)/; // rule 6
 60+const A1_CELL_RULE = /^(?:[A-Za-z]+[0-9]+)/; // rules 7
 61+const FORMULA_NAME_SIMPLE_RULE = /^(?:[A-Za-z.]+(?=[(]))/; // rule 8
 62+const VARIABLE_RULE = /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/; // rule 9
 63+const SIMPLE_VARIABLE_RILE = /^(?:[A-Za-z_]+)/; //rule 10
 64+const INTEGER_RULE = /^(?:[0-9]+(?:(?:[eE])(?:[\+-])?[0-9]+)?)/; // Changed from /^(?:[0-9]+)/ // rule 11
 65+const OPEN_AND_CLOSE_OF_ARRAY_RULE = /^(?:\[(.*)?\])/; // rule 12
 66+const DOLLAR_SIGN_RULE = /^(?:\$)/; // rule 13
 67+const AMPERSAND_SIGN_RULE = /^(?:&)/; //rule 14
 68+const SINGLE_WHITESPACE_RULE = /^(?: )/; // rule 15
 69+const PERIOD_RULE = /^(?:[.])/; // rule 16
 70+const COLON_RULE = /^(?::)/; //rule 17
 71+const SEMI_COLON_RULE = /^(?:;)/; // rule 18
 72+const COMMA_RULE = /^(?:,)/; // rule 19
 73+const ASTERISK_RULE = /^(?:\*)/; //rule 20
 74+const FORWARD_SLASH_RULE = /^(?:\/)/; // rule 21
 75+const MINUS_SIGN_RULE = /^(?:-)/; // rule 22
 76+const PLUS_SIGN_RULE = /^(?:\+)/; // rule 23
 77+const CARET_SIGN_RULE = /^(?:\^)/; //rule 24
 78+const OPEN_PAREN_RULE = /^(?:\()/; // rule 25
 79+const CLOSE_PAREN_RULE = /^(?:\))/; // rule 26
 80+const GREATER_THAN_SIGN_RULE = /^(?:>)/; // rule 27
 81+const LESS_THAN_SIGN_RULE = /^(?:<)/; // rule 28
 82+const NOT_RULE = /^(?:NOT\b)/; // rule 29
 83+const OPEN_DOUBLE_QUOTE = /^(?:")/; // rule 30
 84+const OPEN_SINGLE_QUITE = /^(?:')/; // rule 31
 85+const EXCLAMATION_POINT_RULE = /^(?:!)/; // rule 32
 86+const EQUALS_SIGN_RULE = /^(?:=)/; // rule 33
 87+const PERCENT_SIGN_RULE = /^(?:%)/; // rule 34
 88+const HASH_SIGN_RULE = /^(?:[#])/; // rule 35
 89+const END_OF_STRING_RULE = /^(?:$)/; // rule 36
 90+
 91+
 92+
 93+// Sequential rules to use when parsing a given input.
 94+const RULES = [
 95+  WHITE_SPACE_RULE,
 96+  DOUBLE_QUOTES_RULE,
 97+  SINGLE_QUOTES_RULE,
 98+  FORMULA_NAME_RULE,
 99+  DATE_RULE,
100+  TIME_RULE,
101+  $_A1_CELL_RULE,
102+  A1_CELL_RULE,
103+  FORMULA_NAME_SIMPLE_RULE,
104+  VARIABLE_RULE,
105+  SIMPLE_VARIABLE_RILE,
106+  INTEGER_RULE,
107+  OPEN_AND_CLOSE_OF_ARRAY_RULE,
108+  DOLLAR_SIGN_RULE,
109+  AMPERSAND_SIGN_RULE,
110+  SINGLE_WHITESPACE_RULE,
111+  PERIOD_RULE,
112+  COLON_RULE,
113+  SEMI_COLON_RULE,
114+  COMMA_RULE,
115+  ASTERISK_RULE,
116+  FORWARD_SLASH_RULE,
117+  MINUS_SIGN_RULE,
118+  PLUS_SIGN_RULE,
119+  CARET_SIGN_RULE,
120+  OPEN_PAREN_RULE,
121+  CLOSE_PAREN_RULE,
122+  GREATER_THAN_SIGN_RULE,
123+  LESS_THAN_SIGN_RULE,
124+  NOT_RULE,
125+  OPEN_DOUBLE_QUOTE,
126+  OPEN_SINGLE_QUITE,
127+  EXCLAMATION_POINT_RULE,
128+  EQUALS_SIGN_RULE,
129+  PERCENT_SIGN_RULE,
130+  HASH_SIGN_RULE,
131+  END_OF_STRING_RULE
132+];
133+
134+// While it is unlikely that an index for a given rule will change, initializing them with `indexOf` will allow me to
135+// change their ordering without having to find and replace indexes manually.
136+const WHITE_SPACE_RULE_INDEX = RULES.indexOf(WHITE_SPACE_RULE);
137+const DOUBLE_QUOTES_RULE_INDEX = RULES.indexOf(DOUBLE_QUOTES_RULE);
138+const SINGLE_QUOTES_RULE_INDEX = RULES.indexOf(SINGLE_QUOTES_RULE);
139+const FORMULA_NAME_RULE_INDEX = RULES.indexOf(FORMULA_NAME_RULE);
140+const DATE_RULE_INDEX = RULES.indexOf(DATE_RULE);
141+const TIME_RULE_INDEX = RULES.indexOf(TIME_RULE);
142+const $_A1_CELL_RULE_INDEX = RULES.indexOf($_A1_CELL_RULE);
143+const A1_CELL_RULE_INDEX = RULES.indexOf(A1_CELL_RULE);
144+const FORMULA_NAME_SIMPLE_RULE_INDEX = RULES.indexOf(FORMULA_NAME_SIMPLE_RULE);
145+const VARIABLE_RULE_INDEX = RULES.indexOf(VARIABLE_RULE);
146+const SIMPLE_VARIABLE_RILE_INDEX = RULES.indexOf(SIMPLE_VARIABLE_RILE);
147+const INTEGER_RULE_INDEX = RULES.indexOf(INTEGER_RULE);
148+const OPEN_AND_CLOSE_OF_ARRAY_RULE_INDEX = RULES.indexOf(OPEN_AND_CLOSE_OF_ARRAY_RULE);
149+const DOLLAR_SIGN_RULE_INDEX = RULES.indexOf(DOLLAR_SIGN_RULE);
150+const AMPERSAND_SIGN_RULE_INDEX = RULES.indexOf(AMPERSAND_SIGN_RULE);
151+const SINGLE_WHITESPACE_RULE_INDEX = RULES.indexOf(SINGLE_WHITESPACE_RULE);
152+const PERIOD_RULE_INDEX = RULES.indexOf(PERIOD_RULE);
153+const COLON_RULE_INDEX = RULES.indexOf(COLON_RULE);
154+const SEMI_COLON_RULE_INDEX = RULES.indexOf(SEMI_COLON_RULE);
155+const COMMA_RULE_INDEX = RULES.indexOf(COMMA_RULE);
156+const ASTERISK_RULE_INDEX = RULES.indexOf(ASTERISK_RULE);
157+const FORWARD_SLASH_RULE_INDEX = RULES.indexOf(FORWARD_SLASH_RULE);
158+const MINUS_SIGN_RULE_INDEX = RULES.indexOf(MINUS_SIGN_RULE);
159+const PLUS_SIGN_RULE_INDEX = RULES.indexOf(PLUS_SIGN_RULE);
160+const CARET_SIGN_RULE_INDEX = RULES.indexOf(CARET_SIGN_RULE);
161+const OPEN_PAREN_RULE_INDEX = RULES.indexOf(OPEN_PAREN_RULE);
162+const CLOSE_PAREN_RULE_INDEX = RULES.indexOf(CLOSE_PAREN_RULE);
163+const GREATER_THAN_SIGN_RULE_INDEX = RULES.indexOf(GREATER_THAN_SIGN_RULE);
164+const LESS_THAN_SIGN_RULE_INDEX = RULES.indexOf(LESS_THAN_SIGN_RULE);
165+const NOT_RULE_INDEX = RULES.indexOf(NOT_RULE);
166+const OPEN_DOUBLE_QUOTE_INDEX = RULES.indexOf(OPEN_DOUBLE_QUOTE);
167+const OPEN_SINGLE_QUITE_INDEX = RULES.indexOf(OPEN_SINGLE_QUITE);
168+const EXCLAMATION_POINT_RULE_INDEX = RULES.indexOf(EXCLAMATION_POINT_RULE);
169+const EQUALS_SIGN_RULE_INDEX = RULES.indexOf(EQUALS_SIGN_RULE);
170+const PERCENT_SIGN_RULE_INDEX = RULES.indexOf(PERCENT_SIGN_RULE);
171+const HASH_SIGN_RULE_INDEX = RULES.indexOf(HASH_SIGN_RULE);
172+const END_OF_STRING_RULE_INDEX = RULES.indexOf(END_OF_STRING_RULE);
173+
174+
175 /**
176  * Actions to take when processing tokens one by one. We're always either taking the next token, reducing our current
177  * tokens, or accepting and returning.
178diff --git a/src/Parser/Rules.ts b/src/Parser/Rules.ts
179deleted file mode 100644
180index 99ca32e..0000000
181--- a/src/Parser/Rules.ts
182+++ /dev/null
183@@ -1,163 +0,0 @@
184-// Rules represent the Regular Expressions that will be used in sequence to match a given input to the Parser.
185-const WHITE_SPACE_RULE = /^(?:\s+)/; // rule 0
186-const DOUBLE_QUOTES_RULE = /^(?:"(\\["]|[^"])*")/; // rule 1
187-const SINGLE_QUOTES_RULE = /^(?:'(\\[']|[^'])*')/; // rule 2
188-const FORMULA_NAME_RULE = /^(?:[A-Za-z.]{1,}[A-Za-z_0-9]+(?=[(]))/; // Changed from /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+(?=[(]))/ // rule 3
189-const DATE_RULE = /^(?:([0]?[1-9]|1[0-2])[:][0-5][0-9]([:][0-5][0-9])?[ ]?(AM|am|aM|Am|PM|pm|pM|Pm))/; // rule 4
190-const TIME_RULE = /^(?:([0]?[0-9]|1[0-9]|2[0-3])[:][0-5][0-9]([:][0-5][0-9])?)/; // rule 5
191-const $_A1_CELL_RULE = /^(?:\$[A-Za-z]+\$[0-9]+)/; // rule 6
192-const A1_CELL_RULE = /^(?:[A-Za-z]+[0-9]+)/; // rules 7
193-const FORMULA_NAME_SIMPLE_RULE = /^(?:[A-Za-z.]+(?=[(]))/; // rule 8
194-const VARIABLE_RULE = /^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/; // rule 9
195-const SIMPLE_VARIABLE_RILE = /^(?:[A-Za-z_]+)/; //rule 10
196-const INTEGER_RULE = /^(?:[0-9]+)/; //rule 11
197-const OPEN_AND_CLOSE_OF_ARRAY_RULE = /^(?:\[(.*)?\])/; // rule 12
198-const DOLLAR_SIGN_RULE = /^(?:\$)/; // rule 13
199-const AMPERSAND_SIGN_RULE = /^(?:&)/; //rule 14
200-const SINGLE_WHITESPACE_RULE = /^(?: )/; // rule 15
201-const PERIOD_RULE = /^(?:[.])/; // rule 16
202-const COLON_RULE = /^(?::)/; //rule 17
203-const SEMI_COLON_RULE = /^(?:;)/; // rule 18
204-const COMMA_RULE = /^(?:,)/; // rule 19
205-const ASTERISK_RULE = /^(?:\*)/; //rule 20
206-const FORWARD_SLASH_RULE = /^(?:\/)/; // rule 21
207-const MINUS_SIGN_RULE = /^(?:-)/; // rule 22
208-const PLUS_SIGN_RULE = /^(?:\+)/; // rule 23
209-const CARET_SIGN_RULE = /^(?:\^)/; //rule 24
210-const OPEN_PAREN_RULE = /^(?:\()/; // rule 25
211-const CLOSE_PAREN_RULE = /^(?:\))/; // rule 26
212-const GREATER_THAN_SIGN_RULE = /^(?:>)/; // rule 27
213-const LESS_THAN_SIGN_RULE = /^(?:<)/; // rule 28
214-const NOT_RULE = /^(?:NOT\b)/; // rule 29
215-const OPEN_DOUBLE_QUOTE = /^(?:")/; // rule 30
216-const OPEN_SINGLE_QUITE = /^(?:')/; // rule 31
217-const EXCLAMATION_POINT_RULE = /^(?:!)/; // rule 32
218-const EQUALS_SIGN_RULE = /^(?:=)/; // rule 33
219-const PERCENT_SIGN_RULE = /^(?:%)/; // rule 34
220-const HASH_SIGN_RULE = /^(?:[#])/; // rule 35
221-const END_OF_STRING_RULE = /^(?:$)/; // rule 36
222-
223-
224-
225-// Sequential rules to use when parsing a given input.
226-const RULES = [
227-  WHITE_SPACE_RULE,
228-  DOUBLE_QUOTES_RULE,
229-  SINGLE_QUOTES_RULE,
230-  FORMULA_NAME_RULE,
231-  DATE_RULE,
232-  TIME_RULE,
233-  $_A1_CELL_RULE,
234-  A1_CELL_RULE,
235-  FORMULA_NAME_SIMPLE_RULE,
236-  VARIABLE_RULE,
237-  SIMPLE_VARIABLE_RILE,
238-  INTEGER_RULE,
239-  OPEN_AND_CLOSE_OF_ARRAY_RULE,
240-  DOLLAR_SIGN_RULE,
241-  AMPERSAND_SIGN_RULE,
242-  SINGLE_WHITESPACE_RULE,
243-  PERIOD_RULE,
244-  COLON_RULE,
245-  SEMI_COLON_RULE,
246-  COMMA_RULE,
247-  ASTERISK_RULE,
248-  FORWARD_SLASH_RULE,
249-  MINUS_SIGN_RULE,
250-  PLUS_SIGN_RULE,
251-  CARET_SIGN_RULE,
252-  OPEN_PAREN_RULE,
253-  CLOSE_PAREN_RULE,
254-  GREATER_THAN_SIGN_RULE,
255-  LESS_THAN_SIGN_RULE,
256-  NOT_RULE,
257-  OPEN_DOUBLE_QUOTE,
258-  OPEN_SINGLE_QUITE,
259-  EXCLAMATION_POINT_RULE,
260-  EQUALS_SIGN_RULE,
261-  PERCENT_SIGN_RULE,
262-  HASH_SIGN_RULE,
263-  END_OF_STRING_RULE
264-];
265-
266-// While it is unlikely that an index for a given rule will change, initializing them with `indexOf` will allow me to
267-// change their ordering without having to find and replace indexes manually.
268-const WHITE_SPACE_RULE_INDEX = RULES.indexOf(WHITE_SPACE_RULE);
269-const DOUBLE_QUOTES_RULE_INDEX = RULES.indexOf(DOUBLE_QUOTES_RULE);
270-const SINGLE_QUOTES_RULE_INDEX = RULES.indexOf(SINGLE_QUOTES_RULE);
271-const FORMULA_NAME_RULE_INDEX = RULES.indexOf(FORMULA_NAME_RULE);
272-const DATE_RULE_INDEX = RULES.indexOf(DATE_RULE);
273-const TIME_RULE_INDEX = RULES.indexOf(TIME_RULE);
274-const $_A1_CELL_RULE_INDEX = RULES.indexOf($_A1_CELL_RULE);
275-const A1_CELL_RULE_INDEX = RULES.indexOf(A1_CELL_RULE);
276-const FORMULA_NAME_SIMPLE_RULE_INDEX = RULES.indexOf(FORMULA_NAME_SIMPLE_RULE);
277-const VARIABLE_RULE_INDEX = RULES.indexOf(VARIABLE_RULE);
278-const SIMPLE_VARIABLE_RILE_INDEX = RULES.indexOf(SIMPLE_VARIABLE_RILE);
279-const INTEGER_RULE_INDEX = RULES.indexOf(INTEGER_RULE);
280-const OPEN_AND_CLOSE_OF_ARRAY_RULE_INDEX = RULES.indexOf(OPEN_AND_CLOSE_OF_ARRAY_RULE);
281-const DOLLAR_SIGN_RULE_INDEX = RULES.indexOf(DOLLAR_SIGN_RULE);
282-const AMPERSAND_SIGN_RULE_INDEX = RULES.indexOf(AMPERSAND_SIGN_RULE);
283-const SINGLE_WHITESPACE_RULE_INDEX = RULES.indexOf(SINGLE_WHITESPACE_RULE);
284-const PERIOD_RULE_INDEX = RULES.indexOf(PERIOD_RULE);
285-const COLON_RULE_INDEX = RULES.indexOf(COLON_RULE);
286-const SEMI_COLON_RULE_INDEX = RULES.indexOf(SEMI_COLON_RULE);
287-const COMMA_RULE_INDEX = RULES.indexOf(COMMA_RULE);
288-const ASTERISK_RULE_INDEX = RULES.indexOf(ASTERISK_RULE);
289-const FORWARD_SLASH_RULE_INDEX = RULES.indexOf(FORWARD_SLASH_RULE);
290-const MINUS_SIGN_RULE_INDEX = RULES.indexOf(MINUS_SIGN_RULE);
291-const PLUS_SIGN_RULE_INDEX = RULES.indexOf(PLUS_SIGN_RULE);
292-const CARET_SIGN_RULE_INDEX = RULES.indexOf(CARET_SIGN_RULE);
293-const OPEN_PAREN_RULE_INDEX = RULES.indexOf(OPEN_PAREN_RULE);
294-const CLOSE_PAREN_RULE_INDEX = RULES.indexOf(CLOSE_PAREN_RULE);
295-const GREATER_THAN_SIGN_RULE_INDEX = RULES.indexOf(GREATER_THAN_SIGN_RULE);
296-const LESS_THAN_SIGN_RULE_INDEX = RULES.indexOf(LESS_THAN_SIGN_RULE);
297-const NOT_RULE_INDEX = RULES.indexOf(NOT_RULE);
298-const OPEN_DOUBLE_QUOTE_INDEX = RULES.indexOf(OPEN_DOUBLE_QUOTE);
299-const OPEN_SINGLE_QUITE_INDEX = RULES.indexOf(OPEN_SINGLE_QUITE);
300-const EXCLAMATION_POINT_RULE_INDEX = RULES.indexOf(EXCLAMATION_POINT_RULE);
301-const EQUALS_SIGN_RULE_INDEX = RULES.indexOf(EQUALS_SIGN_RULE);
302-const PERCENT_SIGN_RULE_INDEX = RULES.indexOf(PERCENT_SIGN_RULE);
303-const HASH_SIGN_RULE_INDEX = RULES.indexOf(HASH_SIGN_RULE);
304-const END_OF_STRING_RULE_INDEX = RULES.indexOf(END_OF_STRING_RULE);
305-
306-export {
307-  RULES,
308-
309-  WHITE_SPACE_RULE_INDEX,
310-  DOUBLE_QUOTES_RULE_INDEX,
311-  SINGLE_QUOTES_RULE_INDEX,
312-  FORMULA_NAME_RULE_INDEX,
313-  DATE_RULE_INDEX,
314-  TIME_RULE_INDEX,
315-  $_A1_CELL_RULE_INDEX,
316-  A1_CELL_RULE_INDEX,
317-  FORMULA_NAME_SIMPLE_RULE_INDEX,
318-  VARIABLE_RULE_INDEX,
319-  SIMPLE_VARIABLE_RILE_INDEX,
320-  INTEGER_RULE_INDEX,
321-  OPEN_AND_CLOSE_OF_ARRAY_RULE_INDEX,
322-  DOLLAR_SIGN_RULE_INDEX,
323-  AMPERSAND_SIGN_RULE_INDEX,
324-  SINGLE_WHITESPACE_RULE_INDEX,
325-  PERIOD_RULE_INDEX,
326-  COLON_RULE_INDEX,
327-  SEMI_COLON_RULE_INDEX,
328-  COMMA_RULE_INDEX,
329-  ASTERISK_RULE_INDEX,
330-  FORWARD_SLASH_RULE_INDEX,
331-  MINUS_SIGN_RULE_INDEX,
332-  PLUS_SIGN_RULE_INDEX,
333-  CARET_SIGN_RULE_INDEX,
334-  OPEN_PAREN_RULE_INDEX,
335-  CLOSE_PAREN_RULE_INDEX,
336-  GREATER_THAN_SIGN_RULE_INDEX,
337-  LESS_THAN_SIGN_RULE_INDEX,
338-  NOT_RULE_INDEX,
339-  OPEN_DOUBLE_QUOTE_INDEX,
340-  OPEN_SINGLE_QUITE_INDEX,
341-  EXCLAMATION_POINT_RULE_INDEX,
342-  EQUALS_SIGN_RULE_INDEX,
343-  PERCENT_SIGN_RULE_INDEX,
344-  HASH_SIGN_RULE_INDEX,
345-  END_OF_STRING_RULE_INDEX,
346-}
347\ No newline at end of file
348diff --git a/src/Utilities/TypeConverter.ts b/src/Utilities/TypeConverter.ts
349index 235b2b4..4b196cb 100644
350--- a/src/Utilities/TypeConverter.ts
351+++ b/src/Utilities/TypeConverter.ts
352@@ -67,21 +67,21 @@ const Y2K_YEAR = 2000;
353  * @returns {Moment} mutated and altered.
354  */
355 function matchTimestampAndMutateMoment(timestampString : string, momentToMutate: moment.Moment) : moment.Moment {
356-  var matches = timestampString.match(TIMESTAMP);
357+  let  matches = timestampString.match(TIMESTAMP);
358   if (matches && matches[1] !== undefined) { // 10am
359-    var hours = parseInt(matches[2]);
360+    let  hours = parseInt(matches[2]);
361     if (hours > 12) {
362       throw new Error();
363     }
364     momentToMutate.add(hours, 'hours');
365   } else if (matches && matches[6] !== undefined) { // 10:10
366-    var hours = parseInt(matches[7]);
367-    var minutes = parseInt(matches[8]);
368+    let  hours = parseInt(matches[7]);
369+    let  minutes = parseInt(matches[8]);
370     momentToMutate.add(hours, 'hours').add(minutes, 'minutes');
371   } else if (matches && matches[11] !== undefined) { // 10:10am
372-    var hours = parseInt(matches[13]);
373-    var minutes = parseInt(matches[14]);
374-    var pmTrue = (matches[16].toLowerCase() === "pm");
375+    let  hours = parseInt(matches[13]);
376+    let  minutes = parseInt(matches[14]);
377+    let  pmTrue = (matches[16].toLowerCase() === "pm");
378     if (hours > 12) {
379       throw new Error();
380     }
381@@ -95,15 +95,15 @@ function matchTimestampAndMutateMoment(timestampString : string, momentToMutate:
382     }
383     momentToMutate.add(minutes, 'minutes');
384   } else if (matches && matches[17] !== undefined) { // 10:10:10
385-    var hours = parseInt(matches[19]);
386-    var minutes = parseInt(matches[20]);
387-    var seconds = parseInt(matches[21]);
388+    let  hours = parseInt(matches[19]);
389+    let  minutes = parseInt(matches[20]);
390+    let  seconds = parseInt(matches[21]);
391     momentToMutate.add(hours, 'hours').add(minutes, 'minutes').add(seconds, 'seconds');
392   } else if (matches && matches[23] !== undefined) { // // 10:10:10am
393-    var hours = parseInt(matches[25]);
394-    var minutes = parseInt(matches[26]);
395-    var seconds = parseInt(matches[27]);
396-    var pmTrue = (matches[28].toLowerCase() === "pm");
397+    let  hours = parseInt(matches[25]);
398+    let  minutes = parseInt(matches[26]);
399+    let  seconds = parseInt(matches[27]);
400+    let  pmTrue = (matches[28].toLowerCase() === "pm");
401     if (hours > 12) {
402       throw new Error();
403     }
404@@ -123,7 +123,7 @@ function matchTimestampAndMutateMoment(timestampString : string, momentToMutate:
405 }
406 
407 /**
408- * Static class of helpers used to convert various types to each other.
409+ * Static class of helpers used to convert let ious types to each other.
410  */
411 class TypeConverter {
412 
413@@ -137,7 +137,7 @@ class TypeConverter {
414    * @returns {number} representing time of day
415    */
416   static stringToTimeNumber(timeString: string) : number {
417-    var m;
418+    let  m;
419     try {
420       m = matchTimestampAndMutateMoment(timeString, moment.utc([FIRST_YEAR]).startOf("year"));
421     } catch (e) {
422@@ -156,7 +156,7 @@ class TypeConverter {
423    * @returns {moment}
424    */
425   private static parseStringToMoment(dateString : string) : moment.Moment {
426-    var m;
427+    let  m;
428 
429     /**
430      * Creates moment object from years, months and days.
431@@ -166,13 +166,13 @@ class TypeConverter {
432      * @returns {Moment} created moment
433      */
434     function createMoment(years, months, days) : moment.Moment {
435-      var actualYear = years;
436+      let  actualYear = years;
437       if (years >= 0 && years < 30) {
438         actualYear = Y2K_YEAR + years;
439       } else if (years >= 30 && years < 100) {
440         actualYear = FIRST_YEAR + years;
441       }
442-      var tmpMoment = moment.utc([actualYear]).startOf("year");
443+      let  tmpMoment = moment.utc([actualYear]).startOf("year");
444       if (typeof months === "string") {
445         tmpMoment.month(months);
446       } else {
447@@ -188,11 +188,11 @@ class TypeConverter {
448     // Check YEAR_MONTHDIG, YYYY(fd)MM, '1992/06'
449     // NOTE: Must come before YEAR_MONTHDIG_DAY matching.
450     if (m === undefined) {
451-      var matches = dateString.match(YEAR_MONTHDIG);
452+      let  matches = dateString.match(YEAR_MONTHDIG);
453       if (matches && matches.length >= 6) {
454-        var years = parseInt(matches[3]);
455-        var months = parseInt(matches[5]) - 1; // Months are zero indexed.
456-        var tmpMoment = createMoment(years, months, 0);
457+        let  years = parseInt(matches[3]);
458+        let  months = parseInt(matches[5]) - 1; // Months are zero indexed.
459+        let  tmpMoment = createMoment(years, months, 0);
460         if (matches[6] !== undefined) {
461           tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
462         }
463@@ -202,16 +202,16 @@ class TypeConverter {
464 
465     // Check YEAR_MONTHDIG_DAY, YYYY(fd)MM(fd)DD, "1992/06/24"
466     if (m === undefined) {
467-      var matches = dateString.match(YEAR_MONTHDIG_DAY);
468+      let  matches = dateString.match(YEAR_MONTHDIG_DAY);
469       if (matches && matches.length >= 8) {
470         // Check delimiters. If they're not the same, throw error.
471         if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
472           throw new Error();
473         }
474-        var years = parseInt(matches[3]);
475-        var months = parseInt(matches[5]) - 1; // Months are zero indexed.
476-        var days = parseInt(matches[7]) - 1; // Days are zero indexed.
477-        var tmpMoment = createMoment(years, months, days);
478+        let  years = parseInt(matches[3]);
479+        let  months = parseInt(matches[5]) - 1; // Months are zero indexed.
480+        let  days = parseInt(matches[7]) - 1; // Days are zero indexed.
481+        let  tmpMoment = createMoment(years, months, days);
482         if (matches.length >= 9 && matches[8] !== undefined) {
483           tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
484         }
485@@ -222,11 +222,11 @@ class TypeConverter {
486     // Check MONTHDIG_YEAR, MM(fd)YYYY, '06/1992'
487     // NOTE: Must come before MONTHDIG_DAY_YEAR matching.
488     if (m === undefined) {
489-      var matches = dateString.match(MONTHDIG_YEAR);
490+      let  matches = dateString.match(MONTHDIG_YEAR);
491       if (matches && matches.length >= 6) {
492-        var years = parseInt(matches[5]);
493-        var months = parseInt(matches[3]) - 1; // Months are zero indexed.
494-        var tmpMoment = createMoment(years, months, 0);
495+        let  years = parseInt(matches[5]);
496+        let  months = parseInt(matches[3]) - 1; // Months are zero indexed.
497+        let  tmpMoment = createMoment(years, months, 0);
498         if (matches[6] !== undefined) {
499           tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
500         }
501@@ -236,16 +236,16 @@ class TypeConverter {
502 
503     // Check MONTHDIG_DAY_YEAR, MM(fd)DD(fd)YYYY, "06/24/1992"
504     if (m === undefined) {
505-      var matches = dateString.match(MONTHDIG_DAY_YEAR);
506+      let  matches = dateString.match(MONTHDIG_DAY_YEAR);
507       if (matches && matches.length >= 8) {
508         // Check delimiters. If they're not the same, throw error.
509         if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
510           throw new Error();
511         }
512-        var years = parseInt(matches[7]);
513-        var months = parseInt(matches[3]) - 1; // Months are zero indexed.
514-        var days = parseInt(matches[5]) - 1; // Days are zero indexed.
515-        var tmpMoment = createMoment(years, months, days);
516+        let  years = parseInt(matches[7]);
517+        let  months = parseInt(matches[3]) - 1; // Months are zero indexed.
518+        let  days = parseInt(matches[5]) - 1; // Days are zero indexed.
519+        let  tmpMoment = createMoment(years, months, days);
520         if (matches.length >= 9 && matches[8] !== undefined) {
521           tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
522         }
523@@ -256,11 +256,11 @@ class TypeConverter {
524     // Check MONTHNAME_YEAR, Month(fd)YYYY, 'Aug 1992'
525     // NOTE: Needs to come before DAY_MONTHNAME_YEAR matching.
526     if (m === undefined) {
527-      var matches = dateString.match(MONTHNAME_YEAR);
528+      let  matches = dateString.match(MONTHNAME_YEAR);
529       if (matches && matches.length >= 6) {
530-        var years = parseInt(matches[5]);
531-        var monthName = matches[3];
532-        var tmpMoment = createMoment(years, monthName, 0);
533+        let  years = parseInt(matches[5]);
534+        let  monthName = matches[3];
535+        let  tmpMoment = createMoment(years, monthName, 0);
536         if (matches[6] !== undefined) {
537           tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
538         }
539@@ -270,16 +270,16 @@ class TypeConverter {
540 
541     // Check MONTHNAME_DAY_YEAR, Month(fd)DD(fd)YYYY, 'Aug 19 2020'
542     if (m === undefined) {
543-      var matches = dateString.match(MONTHNAME_DAY_YEAR);
544+      let  matches = dateString.match(MONTHNAME_DAY_YEAR);
545       if (matches && matches.length >= 8) {
546         // Check delimiters. If they're not the same, throw error.
547         if (matches[4].replace(/\s*/g, '') !== matches[6].replace(/\s*/g, '')) {
548           throw new Error();
549         }
550-        var years = parseInt(matches[7]);
551-        var monthName = matches[3];
552-        var days = parseInt(matches[5]) - 1; // Days are zero indexed.
553-        var tmpMoment = createMoment(years, monthName, days);
554+        let  years = parseInt(matches[7]);
555+        let  monthName = matches[3];
556+        let  days = parseInt(matches[5]) - 1; // Days are zero indexed.
557+        let  tmpMoment = createMoment(years, monthName, days);
558         if (matches.length >= 9 && matches[8] !== undefined) {
559           tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
560         }
561@@ -289,18 +289,18 @@ class TypeConverter {
562 
563     // Check DAY_MONTHNAME_YEAR, DD(fd)Month(fd)YYYY, '24/July/1992'
564     if (m === undefined) {
565-      var matches = dateString.match(DAY_MONTHNAME_YEAR);
566+      let  matches = dateString.match(DAY_MONTHNAME_YEAR);
567       if (matches && matches.length >= 8) {
568-        var years = parseInt(matches[7]);
569-        var monthName = matches[5];
570-        var days = parseInt(matches[3]) - 1; // Days are zero indexed.
571-        var firstDelimiter = matches[4].replace(/\s*/g, '');
572-        var secondDelimiter = matches[6].replace(/\s*/g, '');
573+        let  years = parseInt(matches[7]);
574+        let  monthName = matches[5];
575+        let  days = parseInt(matches[3]) - 1; // Days are zero indexed.
576+        let  firstDelimiter = matches[4].replace(/\s*/g, '');
577+        let  secondDelimiter = matches[6].replace(/\s*/g, '');
578         // Check delimiters. If they're not the same, and the first one isn't a space, throw error.
579         if (firstDelimiter !== secondDelimiter && firstDelimiter !== "") {
580           throw new Error();
581         }
582-        var tmpMoment = createMoment(years, monthName, days);
583+        let  tmpMoment = createMoment(years, monthName, days);
584         if (matches.length >= 9 && matches[8] !== undefined) {
585           tmpMoment = matchTimestampAndMutateMoment(matches[8], tmpMoment);
586         }
587@@ -310,11 +310,11 @@ class TypeConverter {
588 
589     // Check YEAR_MONTHNAME, YYYY(fd)Month, '1992/Aug'
590     if (m === undefined) {
591-      var matches = dateString.match(YEAR_MONTHNAME);
592+      let  matches = dateString.match(YEAR_MONTHNAME);
593       if (matches && matches.length >= 6) {
594-        var years = parseInt(matches[3]);
595-        var monthName = matches[5];
596-        var tmpMoment = createMoment(years, monthName, 0);
597+        let  years = parseInt(matches[3]);
598+        let  monthName = matches[5];
599+        let  tmpMoment = createMoment(years, monthName, 0);
600         if (matches[6] !== undefined) {
601           tmpMoment = matchTimestampAndMutateMoment(matches[6], tmpMoment);
602         }
603@@ -331,7 +331,7 @@ class TypeConverter {
604    */
605   public static stringToDateNumber(dateString : string) : number {
606     // m will be set and valid or invalid, or will remain undefined
607-    var m;
608+    let  m;
609     try {
610       m = TypeConverter.parseStringToMoment(dateString);
611     } catch (e) {
612@@ -345,7 +345,7 @@ class TypeConverter {
613 
614   /**
615    * Converts strings to numbers, returning undefined if string cannot be parsed to number. Examples: "100", "342424",
616-   * "10%", "33.213131", "41.1231", "10e1", "10E1", "10.44E1", "-$9.29", "+$9.29", "1,000.1", "2000,000,000".
617+   * "10%", "33.213131", "41.1231", "10e+1", "10E-1", "10.44E1", "-$9.29", "+$9.29", "1,000.1", "2000,000,000".
618    * For reference see: https://regex101.com/r/PwghnF/9/
619    * @param value to parse.
620    * @returns {number} or undefined
621@@ -358,32 +358,34 @@ class TypeConverter {
622       return x !== undefined;
623     }
624 
625-    var NUMBER_REGEX = /^ *(\+|\-)? *(\$)? *(\+|\-)? *((\d+)?(,\d{3})?(,\d{3})?(,\d{3})?(,\d{3})?)? *(\.)? *(\d*)? *(e|E)? *(\d*)? *(%)? *$/;
626+    // var NUMBER_REGEX = /^ *(\+|\-)? *(\$)? *(\+|\-)? *((\d+)?(,\d{3})?(,\d{3})?(,\d{3})?(,\d{3})?)? *(\.)? *(\d*)? *(e|E)? *(\d*)? *(%)? *$/;
627+    let NUMBER_REGEX = /^ *(\+|\-)? *(\$)? *(\+|\-)? *((\d+)?(,\d{3})?(,\d{3})?(,\d{3})?(,\d{3})?)? *(\.)? *(\d*)? *(e|E)? *(\+|\-)? *(\d*)? *(%)? *$/;
628     var matches = value.match(NUMBER_REGEX);
629     if (matches !== null) {
630-      var firstSign = matches[1];
631-      var currency = matches[2];
632-      var secondSign = matches[3];
633-      var wholeNumberWithCommas = matches[4];
634-      var decimalPoint = matches[10];
635-      var decimalNumber = matches[11];
636-      var sciNotation = matches[12];
637-      var sciNotationFactor = matches[13];
638-      var percentageSign = matches[14];
639+      let  firstSign = matches[1];
640+      let  currency = matches[2];
641+      let  secondSign = matches[3];
642+      let  wholeNumberWithCommas = matches[4];
643+      let  decimalPoint = matches[10];
644+      let  decimalNumber = matches[11];
645+      let  sciNotation = matches[12];
646+      let  sciNotationSign = matches[13];
647+      let  sciNotationFactor = matches[14];
648+      let  percentageSign = matches[15];
649 
650       // Number is not valid if it is a currency and in scientific notation.
651       if (isDefined(currency) && isDefined(sciNotation)) {
652-        return undefined;
653+        return;
654       }
655       // Number is not valid if there are two signs.
656       if (isDefined(firstSign) && isDefined(secondSign)) {
657-        return undefined;
658+        return;
659       }
660       // Number is not valid if we have 'sciNotation' but no 'sciNotationFactor'
661       if (isDefined(sciNotation) && isUndefined(sciNotationFactor)) {
662-        return undefined
663+        return;
664       }
665-      var activeSign;
666+      let  activeSign;
667       if (isUndefined(firstSign) && isUndefined(secondSign)) {
668         activeSign = "+";
669       } else if (!isUndefined(firstSign)) {
670@@ -391,22 +393,21 @@ class TypeConverter {
671       } else {
672         activeSign = secondSign;
673       }
674-      var x;
675+      let  x;
676       if (isDefined(wholeNumberWithCommas)) {
677         if (isDefined(decimalNumber) && isDefined(decimalNumber)) {
678-          // console.log("parsing:", value, activeSign + wholeNumberWithCommas.split(",").join("") + decimalPoint + decimalNumber);
679           x = parseFloat(activeSign + wholeNumberWithCommas.split(",").join("") + decimalPoint + decimalNumber);
680         } else {
681-          // console.log("parsing:", value, activeSign + wholeNumberWithCommas.split(",").join(""))
682           x = parseFloat(activeSign + wholeNumberWithCommas.split(",").join(""));
683         }
684       } else {
685-        // console.log("parsing:", value, activeSign + "0" + decimalPoint + decimalNumber);
686         x = parseFloat(activeSign + "0" + decimalPoint + decimalNumber);
687       }
688 
689       if (isDefined(sciNotation) && isDefined(sciNotationFactor)) {
690-        x = x * Math.pow(10, parseInt(sciNotationFactor));
691+        sciNotationSign = isDefined(sciNotationSign) ? sciNotationSign : "+";
692+        // x + "e" + "-" + "10"
693+        x = parseFloat(x.toString() + sciNotation.toString() + "" + sciNotationSign.toString() + sciNotationFactor.toString())
694       }
695       if (!isUndefined(percentageSign)) {
696         x = x * 0.01;
697@@ -416,7 +417,7 @@ class TypeConverter {
698       try {
699         return TypeConverter.stringToDateNumber(value);
700       } catch (_) {
701-        return undefined;
702+        return;
703       }
704     }
705   }
706@@ -443,9 +444,9 @@ class TypeConverter {
707       if (value === "") {
708         return 0;
709       }
710-      var n = TypeConverter.stringToNumber(value);
711+      let  n = TypeConverter.stringToNumber(value);
712       if (n === undefined) {
713-        throw new ValueError("Function ____ expects number values, but is text and cannot be coerced to a number.");
714+        throw new ValueError("Function expects number values, but is text and cannot be coerced to a number.");
715       }
716       return n;
717     } else if (typeof value === "boolean") {
718@@ -735,7 +736,7 @@ class TypeConverter {
719    * @returns {number} representing time of day between 0 and 1, exclusive on end.
720    */
721   public static unitsToTimeNumber(hours: number, minutes: number, seconds: number): number {
722-    var v = (((hours % 24) * 60 * 60) + ((minutes) * 60) + (seconds)) / 86400;
723+    let  v = (((hours % 24) * 60 * 60) + ((minutes) * 60) + (seconds)) / 86400;
724     return v % 1;
725   }
726 }
727@@ -745,7 +746,7 @@ class TypeConverter {
728  * @param n number to check
729  * @returns {number} n as long as it's not zero.
730  */
731-var checkForDevideByZero = function(n : number) : number {
732+let  checkForDevideByZero = function(n : number) : number {
733   n = +n;  // Coerce to number.
734   if (!n) {  // Matches +0, -0, NaN
735     throw new DivZeroError("Evaluation of function caused a divide by zero error.");
736diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
737index 1401d3d..c68e037 100644
738--- a/tests/SheetFormulaTest.ts
739+++ b/tests/SheetFormulaTest.ts
740@@ -996,8 +996,13 @@ test("Sheet numbers/math", function(){
741   assertFormulaEquals('= 10%', 0.1);
742   assertFormulaEquals('= 10% + 1', 1.1);
743   assertFormulaEquals('= "10e1" + 0', 100);
744-  // assertFormulaEquals('= 10e1', 100);
745-  assertFormulaEquals('= "1,000,000" + 0', 1000000);
746+  assertFormulaEquals('= 10e1', 100);
747+  assertFormulaEquals('= 10e-1', 1);
748+  assertFormulaEquals('= 10e+1', 100);
749+  assertFormulaEquals('= 10E1', 100);
750+  assertFormulaEquals('= 10E-1', 1);
751+  assertFormulaEquals('= 10E+1', 100);
752+  assertFormulaEquals('= "1,000,000"  + 0', 1000000);
753   assertFormulaEqualsError('= "10e" + 10', VALUE_ERROR);
754   assertFormulaEquals('= "+$10.00" + 0', 10);
755   assertFormulaEquals('= "-$10.00" + 0', -10);
756diff --git a/tests/Utilities/TypeConverterTest.ts b/tests/Utilities/TypeConverterTest.ts
757index ba0aeec..527b085 100644
758--- a/tests/Utilities/TypeConverterTest.ts
759+++ b/tests/Utilities/TypeConverterTest.ts
760@@ -228,8 +228,12 @@ test("TypeConverter.stringToNumber", function () {
761   assertEquals(TypeConverter.stringToNumber("10e1"), 100);
762   assertEquals(TypeConverter.stringToNumber("10e2"), 1000);
763   assertEquals(TypeConverter.stringToNumber("10E1"), 100);
764-  assertEquals(TypeConverter.stringToNumber("10.44E1"), 104.39999999999999);
765+  assertEquals(TypeConverter.stringToNumber("10.44E1"), 104.4);
766   assertEquals(TypeConverter.stringToNumber("10.44E10"), 104400000000);
767+  assertEquals(TypeConverter.stringToNumber("10e-1"), 1);
768+  assertEquals(TypeConverter.stringToNumber("10e+1"), 100);
769+  assertEquals(TypeConverter.stringToNumber("10E-1"), 1);
770+  assertEquals(TypeConverter.stringToNumber("10E+1"), 100);
771   assertEquals(TypeConverter.stringToNumber("$10"), 10);
772   assertEquals(TypeConverter.stringToNumber("$0.1"), 0.1);
773   assertEquals(TypeConverter.stringToNumber("$10.1"), 10.1);