commit
message
[Parser, Errors] work-in-progress on getting error-catching formulas working
author
Ben Vogt <[email protected]>
date
2017-09-04 18:54:13
stats
7 file(s) changed,
71 insertions(+),
37 deletions(-)
files
src/Errors.ts
src/Formulas.ts
src/Formulas/AllFormulas.ts
src/Parser/Parser.ts
src/Sheet.ts
tests/Formulas/InfoTest.ts
tests/SheetFormulaTest.ts
1diff --git a/src/Errors.ts b/src/Errors.ts
2index d84bb72..891b7c4 100644
3--- a/src/Errors.ts
4+++ b/src/Errors.ts
5@@ -5,6 +5,7 @@ let REF_ERROR = "#REF!";
6 let NAME_ERROR = "#NAME!";
7 let NUM_ERROR = "#NUM!";
8 let NA_ERROR = "#N/A";
9+let PARSE_ERROR = "#ERROR";
10
11 class NullError extends Error {
12 constructor(message: string) {
13@@ -55,6 +56,13 @@ class NAError extends Error {
14 }
15 }
16
17+class ParseError extends Error {
18+ constructor(message: string) {
19+ super(message);
20+ this.name = PARSE_ERROR;
21+ }
22+}
23+
24 export {
25 DIV_ZERO_ERROR,
26 NULL_ERROR,
27@@ -63,11 +71,13 @@ export {
28 NAME_ERROR,
29 NUM_ERROR,
30 NA_ERROR,
31+ PARSE_ERROR,
32 DivZeroError,
33 NullError,
34 ValueError,
35 RefError,
36 NameError,
37 NumError,
38- NAError
39+ NAError,
40+ ParseError
41 }
42\ No newline at end of file
43diff --git a/src/Formulas.ts b/src/Formulas.ts
44index ea0cdb9..79fd940 100644
45--- a/src/Formulas.ts
46+++ b/src/Formulas.ts
47@@ -1,4 +1,7 @@
48 import * as AllFormulas from "./Formulas/AllFormulas";
49+import {
50+ __TRY_CATCH_FORMULAS
51+} from "./Formulas/AllFormulas";
52
53 let Formulas = {
54 exists: function(fn: string) {
55@@ -11,6 +14,9 @@ let Formulas = {
56 if (fn in AllFormulas.__COMPLEX) {
57 return AllFormulas.__COMPLEX[fn];
58 }
59+ },
60+ isTryCatchFormula: function (fn: string) : boolean {
61+ return __TRY_CATCH_FORMULAS[fn] !== undefined;
62 }
63 };
64
65diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
66index 34966f8..017f049 100644
67--- a/src/Formulas/AllFormulas.ts
68+++ b/src/Formulas/AllFormulas.ts
69@@ -251,7 +251,7 @@ import {
70 } from "./Date"
71
72 // Using alias to bind dot-notation function names.
73-let __COMPLEX = {
74+const __COMPLEX = {
75 "F.DIST": FDIST$LEFTTAILED,
76 "NETWORKDAYS.INTL": NETWORKDAYS$INTL,
77 "WORKDAY.INTL": WORKDAY$INTL,
78@@ -263,8 +263,14 @@ let __COMPLEX = {
79 "RANK.EQ": RANK$EQ
80 };
81
82+const __TRY_CATCH_FORMULAS : Object = {
83+ "ERROR.TYPE": ERRORTYPE,
84+ "ERRORTYPE": ERRORTYPE,
85+};
86+
87 export {
88 __COMPLEX,
89+ __TRY_CATCH_FORMULAS,
90
91 ABS,
92 ACOS,
93diff --git a/src/Parser/Parser.ts b/src/Parser/Parser.ts
94index 03b3e29..a2e9121 100644
95--- a/src/Parser/Parser.ts
96+++ b/src/Parser/Parser.ts
97@@ -1,6 +1,7 @@
98 import {
99 ObjectFromPairs
100 } from "../Utilities/ObjectFromPairs";
101+import {ParseError} from "../Errors";
102
103 // Rules represent the Regular Expressions that will be used in sequence to match a given input to the Parser.
104 const WHITE_SPACE_RULE = /^(?:\s+)/; // rule 0
105@@ -1272,7 +1273,8 @@ let Parser = (function () {
106 },
107 p,
108 newState,
109- expected;
110+ expected,
111+ catchFailuresOn = false;
112 while (true) {
113 // retrieve state number from top of stack
114 state = stack[stack.length - 1];
115@@ -1353,7 +1355,7 @@ let Parser = (function () {
116 // just recovered from another error
117 if (recovering == 3) {
118 if (symbol === EOF || preErrorSymbol === EOF) {
119- throw new Error(errStr || 'Parsing halted while starting to recover from another error.');
120+ throw new ParseError(errStr || 'Parsing halted while starting to recover from another error.');
121 }
122
123 // discard current lookahead and grab another
124@@ -1366,7 +1368,7 @@ let Parser = (function () {
125
126 // try to recover from error
127 if (error_rule_depth === false) {
128- throw new Error(errStr || 'Parsing halted. No suitable error recovery rule available.');
129+ throw new ParseError(errStr || 'Parsing halted. No suitable error recovery rule available.');
130 }
131 popStack(error_rule_depth);
132
133@@ -1379,7 +1381,7 @@ let Parser = (function () {
134
135 // this shouldn't happen, unless resolve defaults are off
136 if (action[0] instanceof Array && action.length > 1) {
137- throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
138+ throw new ParseError('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
139 }
140
141 // LexActions are always:
142@@ -1463,7 +1465,7 @@ let Parser = (function () {
143 if (this.yy.parser) {
144 this.yy.parser.parseError(str, hash);
145 } else {
146- throw new Error(str);
147+ throw new ParseError(str);
148 }
149 },
150
151diff --git a/src/Sheet.ts b/src/Sheet.ts
152index 8e48590..b79db5b 100644
153--- a/src/Sheet.ts
154+++ b/src/Sheet.ts
155@@ -7,7 +7,7 @@ import {
156 import {
157 DivZeroError,
158 RefError,
159- NameError
160+ NameError, ParseError
161 } from "./Errors";
162 import {
163 Formulas
164@@ -55,11 +55,11 @@ let Sheet = (function () {
165 };
166
167 newParser.yy.parseError = function (str, hash) {
168- throw {
169+ throw new ParseError(JSON.stringify({
170 name: 'Parser error',
171 message: str,
172 prop: hash
173- }
174+ }));
175 };
176
177 newParser.yy.handler = handler;
178@@ -463,12 +463,9 @@ let Sheet = (function () {
179 },
180
181 cellValue: function (cellId) {
182- let value,
183- origin = this,
184+ let origin = this,
185 cell = instance.matrix.getCell(cellId);
186
187- // get value, defaulting to undefined
188- value = cell.isBlank() ? undefined : cell.getValue();
189 //update dependencies
190 instance.matrix.getCell(origin).updateDependencies([cellId]);
191 // check references error
192@@ -479,7 +476,7 @@ let Sheet = (function () {
193 }
194 // check if any error occurs
195 if (!cell.isBlank() && cell.getError()) {
196- throw cell.getError()
197+ throw cell.getError();
198 }
199 return cell;
200 },
201@@ -533,7 +530,7 @@ let Sheet = (function () {
202 instance.matrix.getCell(id).setError(new RefError("Reference does not exist"));
203 instance.matrix.getCell(id).clearValue();
204 });
205- throw new RefError("Reference does not exist.");
206+ error = new RefError("Reference does not exist.");
207 }
208 } catch (ex) {
209 error = ex;
210diff --git a/tests/Formulas/InfoTest.ts b/tests/Formulas/InfoTest.ts
211index ebeb050..b0e5c41 100644
212--- a/tests/Formulas/InfoTest.ts
213+++ b/tests/Formulas/InfoTest.ts
214@@ -141,7 +141,7 @@ test("ISREF", function(){
215 });
216
217 test("ERRORTYPE", function(){
218- var errorCell = new Cell("A1");
219+ let errorCell = new Cell("A1");
220 errorCell.setError(new NAError("error"));
221 assertEquals(ERRORTYPE(new NullError("error")), 1);
222 assertEquals(ERRORTYPE(new DivZeroError("error")), 2);
223@@ -173,7 +173,7 @@ test("ISBLANK", function(){
224
225
226 test("ISERR", function(){
227- var errorCell = new Cell("A1");
228+ let errorCell = new Cell("A1");
229 errorCell.setError(new DivZeroError("err"));
230 assertEquals(ISERR(errorCell), true);
231 assertEquals(ISERR(Cell.BuildFrom("A1", 10)), false);
232@@ -190,7 +190,7 @@ test("ISERR", function(){
233
234
235 test("ISERROR", function(){
236- var errorCell = new Cell("A1");
237+ let errorCell = new Cell("A1");
238 errorCell.setError(new DivZeroError("err"));
239 assertEquals(ISERROR(errorCell), true);
240 assertEquals(ISERROR(Cell.BuildFrom("A1", 10)), false);
241@@ -209,7 +209,7 @@ test("ISERROR", function(){
242
243
244 test("ISNA", function(){
245- var errorCell = new Cell("A1");
246+ let errorCell = new Cell("A1");
247 errorCell.setError(new NAError("err"));
248 assertEquals(ISNA(errorCell), true);
249 assertEquals(ISNA(Cell.BuildFrom("A1", 10)), false);
250@@ -228,7 +228,7 @@ test("ISNA", function(){
251
252
253 test("IFERROR", function(){
254- var errorCell = new Cell("A1");
255+ let errorCell = new Cell("A1");
256 errorCell.setError(new NAError("err"));
257 assertEquals(IFERROR(errorCell, 10), 10);
258 assertEquals(IFERROR(10), 10);
259@@ -246,7 +246,7 @@ test("TYPE", function(){
260 assertEquals(TYPE(false), 4);
261 assertEquals(TYPE(new NAError("err")), 16);
262 assertEquals(TYPE([1, 2, 3]), 64);
263- var errorCell = new Cell("A1");
264+ let errorCell = new Cell("A1");
265 errorCell.setError(new NAError("err"));
266 assertEquals(TYPE(errorCell), 16);
267 assertEquals(TYPE(Cell.BuildFrom("A1", 1)), 1);
268diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
269index 010ba10..8f5ccd9 100644
270--- a/tests/SheetFormulaTest.ts
271+++ b/tests/SheetFormulaTest.ts
272@@ -8,49 +8,49 @@ import {
273 import {
274 DIV_ZERO_ERROR,
275 VALUE_ERROR,
276- NA_ERROR
277+ NA_ERROR, PARSE_ERROR
278 } from "../src/Errors";
279
280 function assertFormulaEqualsError(formula: string, errorString: string) {
281- var sheet = new Sheet();
282+ let sheet = new Sheet();
283 sheet.setCell("A1", formula);
284- var cell = sheet.getCell("A1");
285+ let cell = sheet.getCell("A1");
286 assertEquals(cell.getError().name, errorString);
287 assertEquals(cell.getValue(), null);
288 }
289
290 function assertFormulaEquals(formula: string, expectation: any) {
291- var sheet = new Sheet();
292+ let sheet = new Sheet();
293 sheet.setCell("A1", formula);
294- var cell = sheet.getCell("A1");
295+ let cell = sheet.getCell("A1");
296 assertEquals(cell.getError(), null);
297 assertEquals(cell.getValue(), expectation);
298 }
299
300 function assertFormulaEqualsDependsOnReference(refId: string, value: any, formula: string, expectation: any) {
301- var sheet = new Sheet();
302+ let sheet = new Sheet();
303 sheet.setCell(refId, value);
304 sheet.setCell("A1", formula);
305- var cell = sheet.getCell("A1");
306+ let cell = sheet.getCell("A1");
307 assertEquals(cell.getError(), null);
308 assertEquals(cell.getValue(), expectation);
309 }
310
311 function assertFormulaResultsInType(formula: string, type: string) {
312- var sheet = new Sheet();
313+ let sheet = new Sheet();
314 sheet.setCell("A1", formula);
315- var cell = sheet.getCell("A1");
316+ let cell = sheet.getCell("A1");
317 assertEquals(cell.getError(), null);
318 assertEquals(typeof cell.getValue(), type);
319 }
320
321 function assertFormulaEqualsArray(formula: string, expectation: any) {
322- var sheet = new Sheet();
323+ let sheet = new Sheet();
324 sheet.setCell("A1", formula);
325- var cell = sheet.getCell("A1");
326+ let cell = sheet.getCell("A1");
327 assertEquals(null, cell.getError());
328- var values = cell.getValue();
329- for (var index in values) {
330+ let values = cell.getValue();
331+ for (let index in values) {
332 assertEquals(values[index], expectation[index]);
333 }
334 }
335@@ -967,6 +967,17 @@ test("Sheet TO_TEXT", function(){
336 assertFormulaEquals('=TO_TEXT(false)', "FALSE");
337 });
338
339+test("Sheet ERROR.TYPE", function(){
340+ let sheet = new Sheet();
341+ sheet.setCell("M1", "= 1/0");
342+ sheet.setCell("A1", "=ERROR.TYPE(M1)");
343+ assertEquals(sheet.getCell("A1").getValue(), 2);
344+});
345+
346+test("Sheet parsing error", function(){
347+ assertFormulaEqualsError('= 10e', PARSE_ERROR);
348+});
349+
350 test("Sheet *", function(){
351 assertFormulaEquals('= 10 * 10', 100);
352 assertFormulaEquals('= 10 * 0', 0);