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);