spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[ParseEngineTest] directly testing parser
author
Ben Vogt <[email protected]>
date
2017-12-10 03:21:40
stats
2 file(s) changed, 199 insertions(+), 3 deletions(-)
files
src/Parser/ParserConstants.ts
tests/Parser/ParseEngineTest.ts
  1diff --git a/src/Parser/ParserConstants.ts b/src/Parser/ParserConstants.ts
  2index 40f512f..f049bf5 100644
  3--- a/src/Parser/ParserConstants.ts
  4+++ b/src/Parser/ParserConstants.ts
  5@@ -334,6 +334,10 @@ symbolIndexToName[Symbol.EXCLAMATION_POINT] = "!";
  6 const SYMBOL_INDEX_TO_NAME = symbolIndexToName;
  7 
  8 
  9+const enum State {
 10+  START = 0
 11+}
 12+
 13 
 14 /**
 15  * Array of to map rules to to LexActions and other rules. A single index in the object (e.g. `{2: 13}`) indicates the
 16@@ -342,7 +346,7 @@ const SYMBOL_INDEX_TO_NAME = symbolIndexToName;
 17  */
 18 let table = [];
 19 // All functions in the spreadsheet start with a 0-token.
 20-table[0] = ObjectBuilder
 21+table[State.START] = ObjectBuilder
 22   .add(Symbol.ERROR, 13)
 23   .add(Symbol.EXPRESSIONS, 1)
 24   .add(Symbol.EXPRESSION, 2)
 25diff --git a/tests/Parser/ParseEngineTest.ts b/tests/Parser/ParseEngineTest.ts
 26index c837841..cc8cc92 100644
 27--- a/tests/Parser/ParseEngineTest.ts
 28+++ b/tests/Parser/ParseEngineTest.ts
 29@@ -2,9 +2,12 @@ import {
 30   Parser
 31 } from "../../src/Parser/Parser";
 32 import {TypeConverter} from "../../src/Utilities/TypeConverter";
 33-import {DivZeroError, NameError} from "../../src/Errors";
 34+import {
 35+  DIV_ZERO_ERROR, DivZeroError, NA_ERROR, NameError, NULL_ERROR, NUM_ERROR, PARSE_ERROR,
 36+  REF_ERROR, VALUE_ERROR
 37+} from "../../src/Errors";
 38 import {Formulas} from "../../src/Formulas";
 39-import {assertEquals, test} from "../Utils/Asserts";
 40+import {assertEquals, catchAndAssertEquals, test} from "../Utils/Asserts";
 41 
 42 
 43 let FormulaParser = function(handler) {
 44@@ -319,8 +322,195 @@ test("Declare number", function () {
 45   assertEquals(parser.parse('5'), 5);
 46 });
 47 
 48-console.log("\n\n\n\n\n\n\n");
 49-
 50 test("Number multiplication", function () {
 51   assertEquals(parser.parse('5*5'), 25);
 52-});
 53\ No newline at end of file
 54+});
 55+
 56+
 57+
 58+test("Parse but throw parse error", function(){
 59+  // assertEquals(parser.parse('=10e'), PARSE_ERROR);
 60+  // assertEquals(parser.parse('= SUM('), PARSE_ERROR);
 61+});
 62+
 63+test("Parse & operator", function(){
 64+  assertEquals(parser.parse('"hey"&" "&"there"'), "hey there");
 65+});
 66+
 67+test("Parse * operator", function(){
 68+  assertEquals(parser.parse('10 * 10'), 100);
 69+  assertEquals(parser.parse('10 * 0'), 0);
 70+  assertEquals(parser.parse('1 * 1'), 1);
 71+});
 72+
 73+test("Parse / operator", function(){
 74+  assertEquals(parser.parse('10 / 2'), 5);
 75+  assertEquals(parser.parse('10 / 1'), 10);
 76+  assertEquals(parser.parse('1 / 1'), 1);
 77+  assertEquals(parser.parse('0 / 1'), 0);
 78+  assertEquals(parser.parse('"1" / 1'), 1);
 79+  assertEquals(parser.parse('"500" / 1'), 500);
 80+  catchAndAssertEquals(function () {
 81+    parser.parse(' 10 / 0');
 82+  }, DIV_ZERO_ERROR);
 83+  catchAndAssertEquals(function () {
 84+    parser.parse('0 / 0')
 85+  }, DIV_ZERO_ERROR);
 86+  // assertEquals(parser.parse('P9 / 1'), 0);
 87+});
 88+
 89+test("Parse ^ operator", function(){
 90+  assertEquals(parser.parse('10 ^ 10'), 10000000000);
 91+  assertEquals(parser.parse('10 ^ 0'), 1);
 92+  assertEquals(parser.parse('1 ^ 1'), 1);
 93+  assertEquals(parser.parse('2 ^ 10'), 1024);
 94+});
 95+
 96+test("Parse equality operators", function(){
 97+  assertEquals(parser.parse('1 = 1'), true);
 98+  assertEquals(parser.parse('1 = 0'), false);
 99+  assertEquals(parser.parse('1 < 2'), true);
100+  assertEquals(parser.parse('1 < 0'), false);
101+  assertEquals(parser.parse('1 <= 1'), true);
102+  // assertEquals('= 1 <= 2', true); // TODO: Fails.
103+  assertEquals(parser.parse('1 >= 1'), true);
104+  assertEquals(parser.parse('2 >= 1'), true);
105+  assertEquals(parser.parse('1 >= 0'), true);
106+  assertEquals(parser.parse('1 >= 2'), false);
107+  assertEquals(parser.parse('1 <> 1'), false);
108+  assertEquals(parser.parse('1 <> 2'), true);
109+});
110+
111+test("Parse operators, order of operations", function(){
112+  assertEquals(parser.parse('10 + -10'), 0);
113+  assertEquals(parser.parse('10 + -10 = 0'), true);
114+  // assertEquals(parser.parse('10 + -10 = 0 & "str"'), false); // TODO should pass.
115+  assertEquals(parser.parse('-10%'), -0.1);
116+  assertEquals(parser.parse('10 + 10%'), 10.1);
117+  assertEquals(parser.parse('-10 + 10%'), -9.9);
118+  assertEquals(parser.parse('-10 - +10%'), -10.1);
119+  assertEquals(parser.parse('2^-10 + 10%'), 0.1009765625);
120+  assertEquals(parser.parse('4 * 5 / 2'), 10);
121+  assertEquals(parser.parse('4 / 5 * 4'), 3.2);
122+  assertEquals(parser.parse('2^2*5'), 20);
123+  assertEquals(parser.parse('2^(2*5)'), 1024);
124+});
125+
126+test("Parse and throw error literal", function () {
127+  // these pass, but strangely so.
128+  // assertEquals(parser.parse('#N/A'), NA_ERROR);
129+  // assertEquals(parser.parse('#NUM!'), NUM_ERROR);
130+  // assertEquals(parser.parse('#REF!'), REF_ERROR);
131+  // assertEquals(parser.parse('#NULL!'), NULL_ERROR);
132+  // assertEquals(parser.parse('#ERROR'), PARSE_ERROR);
133+  // assertEquals(parser.parse('#DIV/0!'), DIV_ZERO_ERROR);
134+  // assertEquals(parser.parse('#VALUE!'), VALUE_ERROR);
135+  // assertEquals(parser.parse('ISERROR(#N/A)'), true);
136+  // assertEquals(parser.parse('=ISERROR(#NUM!)'), true);
137+  // assertEquals(parser.parse('=ISERROR(#REF!)'), true);
138+  // assertEquals(parser.parse('=ISERROR(#NULL!)'), true);
139+  // assertEquals(parser.parse('=ISERROR(#ERROR)'), true);
140+  // assertEquals(parser.parse('=ISERROR(#DIV/0!)'), true);
141+  // assertEquals(parser.parse('=ISERROR(#VALUE!)'), true);
142+  // assertEquals(parser.parse('=IFERROR(#N/A, 10)'), 10);
143+  // assertEquals(parser.parse('=IFERROR(#NUM!, 10)'), 10);
144+  // assertEquals(parser.parse('=IFERROR(#REF!, 10)'), 10);
145+  // assertEquals(parser.parse('=IFERROR(#NULL!, 10)'), 10);
146+  // assertEquals(parser.parse('=IFERROR(#ERROR, 10)'), 10);
147+  // assertEquals(parser.parse('=IFERROR(#DIV/0!, 10)'), 10);
148+  // assertEquals(parser.parse('=IFERROR(#VALUE!, 10)'), 10);
149+});
150+
151+test("Parse plain numbers", function() {
152+  assertEquals(parser.parse('10'), 10);
153+  // assertEquals('=.1', 0.1); // TODO: Fails from parse error, but should pass
154+  // assertEquals(parser.parse('0.1'), 0.1); // TODO: Can't coerce to number?
155+  assertEquals(parser.parse('+1'), 1);
156+  assertEquals(parser.parse('-1'), -1);
157+  assertEquals(parser.parse('++1'), 1);
158+  assertEquals(parser.parse('--1'), 1);
159+  assertEquals(parser.parse('10e1'), 100);
160+  assertEquals(parser.parse('0e1'), 0);
161+  // assertEquals('=0.e1', 0); // TODO: Fails from parse error, but should pass
162+  assertEquals(parser.parse('-10e1'), -100);
163+  assertEquals(parser.parse('+10e1'), 100);
164+  assertEquals(parser.parse('++10e1'), 100);
165+  assertEquals(parser.parse('--10e1'), 100);
166+});
167+
168+test("Parse complex numbers and math", function(){
169+  assertEquals(parser.parse('"10" + 10'), 20);
170+  assertEquals(parser.parse('"10.111111" + 0'), 10.111111);
171+  assertEquals(parser.parse('10%'), 0.1);
172+  assertEquals(parser.parse('10% + 1'), 1.1);
173+  assertEquals(parser.parse('"10e1" + 0'), 100);
174+  assertEquals(parser.parse('10e1'), 100);
175+  assertEquals(parser.parse('10e-1'), 1);
176+  assertEquals(parser.parse('10e+1'), 100);
177+  assertEquals(parser.parse('10E1'), 100);
178+  assertEquals(parser.parse('10E-1'), 1);
179+  assertEquals(parser.parse('10E+1'), 100);
180+  assertEquals(parser.parse('"1,000,000"  + 0'), 1000000);
181+  assertEquals(parser.parse('"+$10.00" + 0'), 10);
182+  assertEquals(parser.parse('"-$10.00" + 0'), -10);
183+  assertEquals(parser.parse('"$+10.00" + 0'), 10);
184+  assertEquals(parser.parse('"$-10.00" + 0'), -10);
185+  assertEquals(parser.parse('"10" + 10'), 20);
186+  assertEquals(parser.parse('"10.111111" + 0'), 10.111111);
187+  assertEquals(parser.parse('10%'), 0.1);
188+  assertEquals(parser.parse('10% + 1'), 1.1);
189+  assertEquals(parser.parse('"10e1" + 0'), 100);
190+  assertEquals(parser.parse('10e1'), 100);
191+  assertEquals(parser.parse('10e-1'), 1);
192+  assertEquals(parser.parse('10e+1'), 100);
193+  assertEquals(parser.parse('10E1'), 100);
194+  assertEquals(parser.parse('10E-1'), 1);
195+  assertEquals(parser.parse('10E+1'), 100);
196+  assertEquals(parser.parse('"1,000,000"  + 0'), 1000000);
197+  catchAndAssertEquals(function () {
198+    parser.parse('"10e" + 10');
199+  }, VALUE_ERROR);
200+  assertEquals(parser.parse('"+$10.00" + 0'), 10);
201+  assertEquals(parser.parse('"-$10.00" + 0'), -10);
202+  assertEquals(parser.parse('"$+10.00" + 0'), 10);
203+  assertEquals(parser.parse('"$-10.00" + 0'), -10);
204+});
205+
206+test("Parse strings", function(){
207+  assertEquals(parser.parse('"str"'), "str");
208+  assertEquals(parser.parse('"str"&"str"'), "strstr");
209+  catchAndAssertEquals(function () {
210+    parser.parse('"str"+"str"');
211+  }, VALUE_ERROR);
212+  // assertEquals("='str'", PARSE_ERROR); // TODO: Parses, but it shouldn't.
213+});
214+
215+test("Parse boolean literals", function(){
216+  assertEquals(parser.parse('TRUE'), true);
217+  assertEquals(parser.parse('true'), true);
218+  assertEquals(parser.parse('FALSE'), false);
219+  assertEquals(parser.parse('false'), false);
220+});
221+
222+test("Parse boolean logic", function(){
223+  // assertEquals('=(1=1)', true); // TODO: Fails because we compute the value, rather than checking equality
224+  // assertEquals('=(1=2)', false); // TODO: Fails because we compute the value, rather than checking equality
225+  assertEquals(parser.parse('(1=1)+2'), 3);
226+
227+});
228+
229+
230+test("Parse range literal", function(){
231+  // assertEqualsArray('=[1, 2, 3]', [1, 2, 3]); // TODO: Fails because of low-level parser error
232+  // assertEqualsArray('=[]', []); // TODO: Fails because of low-level parser error
233+  // assertEqualsArray('=["str", "str"]', ["str", "str"]); // TODO: Fails because of low-level parser error
234+  // assertEqualsArray('=["str", [1, 2, 3], [1]]', ["str", [1, 2, 3], [1]]); // TODO: Fails because of low-level parser error
235+});
236+
237+
238+test("Parse range following comma", function(){
239+  // assertEquals('=SERIESSUM(1, 0, 1, [4, 5, 6])', 15);
240+  // assertEquals('=SERIESSUM([1], [0], [1], [4, 5, 6])', 15);
241+});
242+
243+