commit
message
[errors] refactoring errors
author
Ben Vogt <[email protected]>
date
2017-04-02 20:29:59
stats
12 file(s) changed,
208 insertions(+),
166 deletions(-)
files
README.md
src/Errors.ts
src/RawFormulas/Date.ts
src/RawFormulas/Engineering.ts
src/RawFormulas/Financial.ts
src/RawFormulas/Logical.ts
src/RawFormulas/Math.ts
src/RawFormulas/Statistical.ts
src/RawFormulas/Text.ts
src/RawFormulas/Utils.ts
tests/DateFormulasTest.ts
tests/FormulasTest.ts
1diff --git a/README.md b/README.md
2index 1694a13..5b95a00 100644
3--- a/README.md
4+++ b/README.md
5@@ -16,9 +16,6 @@ And the same for MAX, MAXA, COUNT, COUNTA, etc. Look these over.
6 * COVARIANCES
7 * ...etc.
8
9-### Refactor the way we construct and throw errors
10-For example, the mis-matched argument length errors are all generated the same way.
11-
12 ### Refactor the way tests are organized.
13 Group by error type and have some useful functions that will call with 0, N, N+1 args to test the args
14 checker. Also, test for *all possible* errors that could be thrown, and *all possible types* that could be passed in.
15@@ -41,9 +38,6 @@ Like dollars, dates are special types, but can be compared as if they're primati
16 valid inside a cell: `=DATE(1992, 6, 6) > =DATE(1992, 6, 10)`. We should check types and and have Date-to-number
17 conversion inside parser.js.
18
19-* Organize tests in a way that makes sense.
20-Annotate them, and standardize the error checking for errors like REF, NA, NUM, VALUE, etc.
21-
22 * Test all ExcelDate functions
23 Right now we're just using the number of days since 1900, but we should check the other functions.
24
25diff --git a/src/Errors.ts b/src/Errors.ts
26index 13238c9..9398717 100644
27--- a/src/Errors.ts
28+++ b/src/Errors.ts
29@@ -1,13 +1,3 @@
30-class CellError extends Error {
31- public message: string;
32- public text: string;
33- constructor(message: string, text: string) {
34- super(message);
35- this.message = message;
36- this.text = text;
37- }
38-}
39-
40 var NULL_ERROR = "#NULL!";
41 var DIV_ZERO_ERROR = "#DIV/0!";
42 var VALUE_ERROR = "#VALUE!";
43@@ -44,14 +34,70 @@ var Errors = {
44 }
45 };
46
47+
48+class NullError extends Error {
49+ constructor(message: string) {
50+ super(message);
51+ this.name = NULL_ERROR;
52+ }
53+}
54+
55+class DivZeroError extends Error {
56+ constructor(message: string) {
57+ super(message);
58+ this.name = DIV_ZERO_ERROR;
59+ }
60+}
61+
62+class ValueError extends Error {
63+ constructor(message: string) {
64+ super(message);
65+ this.name = VALUE_ERROR;
66+ }
67+}
68+
69+class RefError extends Error {
70+ constructor(message: string) {
71+ super(message);
72+ this.name = REF_ERROR;
73+ }
74+}
75+
76+class NameError extends Error {
77+ constructor(message: string) {
78+ super(message);
79+ this.name = NAME_ERROR;
80+ }
81+}
82+
83+class NumError extends Error {
84+ constructor(message: string) {
85+ super(message);
86+ this.name = NUM_ERROR;
87+ }
88+}
89+
90+class NAError extends Error {
91+ constructor(message: string) {
92+ super(message);
93+ this.name = NA_ERROR;
94+ }
95+}
96+
97 export {
98 Errors,
99- CellError,
100 DIV_ZERO_ERROR,
101 NULL_ERROR,
102 VALUE_ERROR,
103 REF_ERROR,
104 NAME_ERROR,
105 NUM_ERROR,
106- NA_ERROR
107+ NA_ERROR,
108+ DivZeroError,
109+ NullError,
110+ ValueError,
111+ RefError,
112+ NameError,
113+ NumError,
114+ NAError
115 }
116\ No newline at end of file
117diff --git a/src/RawFormulas/Date.ts b/src/RawFormulas/Date.ts
118index a782a89..587cc82 100644
119--- a/src/RawFormulas/Date.ts
120+++ b/src/RawFormulas/Date.ts
121@@ -3,13 +3,10 @@ import * as moment from "moment";
122 import * as Formula from "formulajs"
123 import {
124 ArgsChecker,
125- DateRegExBuilder,
126 TypeCaster
127 } from "./Utils";
128 import {
129- NUM_ERROR,
130- VALUE_ERROR,
131- CellError
132+ NumError, ValueError
133 } from "../Errors";
134 import {
135 ExcelDate,
136@@ -37,7 +34,7 @@ var DATE = function (...values) : ExcelDate {
137 .add(day, 'days');
138 var excelDate = new ExcelDate(m);
139 if (excelDate.toNumber() < 0) {
140- throw new CellError(NUM_ERROR, "DATE evaluates to an out of range value " + excelDate.toNumber()
141+ throw new NumError("DATE evaluates to an out of range value " + excelDate.toNumber()
142 + ". It should be greater than or equal to 0.");
143 }
144 return excelDate;
145@@ -58,7 +55,7 @@ var DATEVALUE = function (...values) : number {
146 try {
147 date = TypeCaster.stringToExcelDate(dateString);
148 } catch (e) {
149- throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
150+ throw new ValueError("DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
151 }
152
153 // If we've not been able to parse the date by now, then we cannot parse it at all.
154diff --git a/src/RawFormulas/Engineering.ts b/src/RawFormulas/Engineering.ts
155index 576f392..72bbea5 100644
156--- a/src/RawFormulas/Engineering.ts
157+++ b/src/RawFormulas/Engineering.ts
158@@ -2,8 +2,10 @@ import {
159 ArgsChecker,
160 TypeCaster
161 } from "./Utils";
162-import { CellError } from "../Errors"
163-import * as ERRORS from "../Errors"
164+import {
165+ ValueError,
166+ NumError
167+} from "../Errors"
168
169 /**
170 * Converts a signed binary number to decimal format.
171@@ -16,11 +18,11 @@ import * as ERRORS from "../Errors"
172 var BIN2DEC = function (...values) : number {
173 ArgsChecker.checkLength(values, 1);
174 if (typeof TypeCaster.firstValue(values[0]) === "boolean") {
175- throw new CellError(ERRORS.VALUE_ERROR, "Function BIN2DEC parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
176+ throw new ValueError("Function BIN2DEC parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
177 }
178 var n = TypeCaster.firstValueAsString(values[0]);
179 if (!(/^[01]{1,10}$/).test(n)) {
180- throw new CellError(ERRORS.NUM_ERROR, "Input for BIN2DEC ('"+n+"') is not a valid binary representation.");
181+ throw new NumError("Input for BIN2DEC ('" + n + "') is not a valid binary representation.");
182 }
183
184 if (n.length === 10 && n.substring(0, 1) === '1') {
185@@ -42,7 +44,7 @@ var BIN2DEC = function (...values) : number {
186 var BIN2HEX = function (...values) : string {
187 ArgsChecker.checkLengthWithin(values, 1, 2);
188 if (typeof TypeCaster.firstValue(values[0]) === "boolean") {
189- throw new CellError(ERRORS.VALUE_ERROR, "Function BIN2HEX parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
190+ throw new ValueError("Function BIN2HEX parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
191 }
192 var n = TypeCaster.firstValueAsString(values[0]);
193 var p = 10;
194@@ -50,7 +52,7 @@ var BIN2HEX = function (...values) : string {
195 p = TypeCaster.firstValueAsNumber(values[1]);
196 }
197 if (!(/^[01]{1,10}$/).test(n)) {
198- throw new CellError(ERRORS.NUM_ERROR, "Input for BIN2HEX ('"+n+"') is not a valid binary representation.");
199+ throw new NumError("Input for BIN2HEX ('"+n+"') is not a valid binary representation.");
200 }
201
202 if (n.length === 10 && n.substring(0, 1) === '1') {
203@@ -58,7 +60,7 @@ var BIN2HEX = function (...values) : string {
204 }
205
206 if (p < 1 || p > 10) {
207- throw new CellError(ERRORS.NUM_ERROR, "Function BIN2HEX parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
208+ throw new NumError("Function BIN2HEX parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
209 }
210 p = Math.floor(p);
211 // Convert decimal number to hexadecimal
212@@ -88,7 +90,7 @@ var BIN2HEX = function (...values) : string {
213 var BIN2OCT = function (...values) : string {
214 ArgsChecker.checkLengthWithin(values, 1, 2);
215 if (typeof TypeCaster.firstValue(values[0]) === "boolean") {
216- throw new CellError(ERRORS.VALUE_ERROR, "Function BIN2OCT parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
217+ throw new ValueError("Function BIN2OCT parameter 1 expects text values. But '" + values[0] + "' is a boolean and cannot be coerced to a text.");
218 }
219 var n = TypeCaster.firstValueAsString(values[0]);
220 var p = 10;
221@@ -96,7 +98,7 @@ var BIN2OCT = function (...values) : string {
222 p = TypeCaster.firstValueAsNumber(values[1]);
223 }
224 if (!(/^[01]{1,10}$/).test(n)) {
225- throw new CellError(ERRORS.NUM_ERROR, "Input for BIN2OCT ('"+n+"') is not a valid binary representation.");
226+ throw new NumError("Input for BIN2OCT ('"+n+"') is not a valid binary representation.");
227 }
228
229 if (n.length === 10 && n.substring(0, 1) === '1') {
230@@ -104,7 +106,7 @@ var BIN2OCT = function (...values) : string {
231 }
232
233 if (p < 1 || p > 10) {
234- throw new CellError(ERRORS.NUM_ERROR, "Function BIN2OCT parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
235+ throw new NumError("Function BIN2OCT parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
236 }
237 p = Math.floor(p);
238 var result = parseInt(n.toString(), 2).toString(8);
239@@ -146,10 +148,10 @@ var DEC2OCT = function (...values) : string {
240 placesPresent = true;
241 }
242 if (n < -53687092 || n > 536870911) {
243- throw new CellError(ERRORS.NUM_ERROR, "Function DEC2OCT parameter 1 value is " + n + ". Valid values are between -53687092 and 536870911 inclusive.");
244+ throw new NumError("Function DEC2OCT parameter 1 value is " + n + ". Valid values are between -53687092 and 536870911 inclusive.");
245 }
246 if (p < 1 || p > 10) {
247- throw new CellError(ERRORS.NUM_ERROR, "Function DEC2OCT parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
248+ throw new NumError("Function DEC2OCT parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
249 }
250 if (n < 0) {
251 return (1073741824 + n).toString(8).toUpperCase();
252@@ -194,10 +196,10 @@ var DEC2HEX = function (...values) : string {
253 placesPresent = true;
254 }
255 if (n < -549755813888 || n > 549755813887) {
256- throw new CellError(ERRORS.NUM_ERROR, "Function DEC2HEX parameter 1 value is " + n + ". Valid values are between -549755813888 and 549755813887 inclusive.");
257+ throw new NumError("Function DEC2HEX parameter 1 value is " + n + ". Valid values are between -549755813888 and 549755813887 inclusive.");
258 }
259 if (p < 1 || p > 10) {
260- throw new CellError(ERRORS.NUM_ERROR, "Function DEC2HEX parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
261+ throw new NumError("Function DEC2HEX parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
262 }
263 // Ignore places and return a 10-character hexadecimal number if number is negative
264 if (n < 0) {
265@@ -246,10 +248,10 @@ var DEC2BIN = function (...values) : string {
266 }
267
268 if (n < -512 || n > 511) {
269- throw new CellError(ERRORS.NUM_ERROR, "Function DEC2BIN parameter 1 value is " + n + ". Valid values are between -512 and 511 inclusive.");
270+ throw new NumError("Function DEC2BIN parameter 1 value is " + n + ". Valid values are between -512 and 511 inclusive.");
271 }
272 if (p < 1 || p > 10) {
273- throw new CellError(ERRORS.NUM_ERROR, "Function DEC2BIN parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
274+ throw new NumError("Function DEC2BIN parameter 2 value is " + p + ". Valid values are between 1 and 10 inclusive.");
275 }
276
277 // Ignore places and return a 10-character binary number if number is negative
278diff --git a/src/RawFormulas/Financial.ts b/src/RawFormulas/Financial.ts
279index 7dae7f2..af38ac7 100644
280--- a/src/RawFormulas/Financial.ts
281+++ b/src/RawFormulas/Financial.ts
282@@ -4,9 +4,9 @@ import {
283 checkForDevideByZero
284 } from "./Utils";
285 import {
286- CellError
287+ NumError,
288+ DivZeroError
289 } from "../Errors"
290-import * as ERRORS from "../Errors"
291
292 /**
293 * Calculates the depreciation of an asset for a specified period using the double-declining balance method.
294@@ -27,23 +27,23 @@ var DDB = function (...values) : number {
295 var factor = values.length === 5 ? TypeCaster.firstValueAsNumber(values[4]) : 2;
296
297 if (cost < 0) {
298- throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 1 value is "
299+ throw new NumError("Function DDB parameter 1 value is "
300 + cost + ". It should be greater than or equal to 0.");
301 }
302 if (salvage < 0) {
303- throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 2 value is "
304+ throw new NumError("Function DDB parameter 2 value is "
305 + salvage + ". It should be greater than or equal to 0.");
306 }
307 if (life < 0) {
308- throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 3 value is "
309+ throw new NumError("Function DDB parameter 3 value is "
310 + life + ". It should be greater than or equal to 0.");
311 }
312 if (period < 0) {
313- throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 4 value is "
314+ throw new NumError("Function DDB parameter 4 value is "
315 + period + ". It should be greater than or equal to 0.");
316 }
317 if (period > life) {
318- throw new CellError(ERRORS.NUM_ERROR, "Function DDB parameter 4 value is "
319+ throw new NumError("Function DDB parameter 4 value is "
320 + life + ". It should be less than or equal to value of Function DB parameter 3 with "+ period +".");
321 }
322 if (salvage >= cost) {
323@@ -78,34 +78,34 @@ var DB = function (...values) : number {
324 var period = TypeCaster.firstValueAsNumber(values[3]);
325 var month = values.length === 5 ? Math.floor(TypeCaster.firstValueAsNumber(values[4])) : 12;
326 if (cost < 0) {
327- throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 1 value is "
328+ throw new NumError("Function DB parameter 1 value is "
329 + cost + ". It should be greater than or equal to 0.");
330 }
331 if (salvage < 0) {
332- throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 2 value is "
333+ throw new NumError("Function DB parameter 2 value is "
334 + salvage + ". It should be greater than or equal to 0.");
335 }
336 if (life < 0) {
337- throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 3 value is "
338+ throw new NumError("Function DB parameter 3 value is "
339 + life + ". It should be greater than or equal to 0.");
340 }
341 if (period < 0) {
342- throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 4 value is "
343+ throw new NumError("Function DB parameter 4 value is "
344 + period + ". It should be greater than or equal to 0.");
345 }
346 if (month > 12 || month < 1) {
347- throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 5 value is "
348+ throw new NumError("Function DB parameter 5 value is "
349 + month + ". Valid values are between 1 and 12 inclusive.");
350 }
351 if (period > life) {
352- throw new CellError(ERRORS.NUM_ERROR, "Function DB parameter 4 value is "
353+ throw new NumError("Function DB parameter 4 value is "
354 + life + ". It should be less than or equal to value of Function DB parameter 3 with "+ period +".");
355 }
356 if (salvage >= cost) {
357 return 0;
358 }
359 if (cost === 0 && salvage !== 0) {
360- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function DB cause a divide by zero error.")
361+ throw new DivZeroError("Evaluation of function DB cause a divide by zero error.")
362 }
363 var rate = (1 - Math.pow(salvage / cost, 1 / life));
364 var initial = cost * rate * month / 12;
365@@ -149,7 +149,7 @@ var DOLLAR = function (...values) : number {
366 var divisor = sign * (Math.floor(Math.abs(v) * Math.pow(10, places)));
367 var pow = Math.pow(10, places);
368 if (pow === 0 && divisor !== 0) {
369- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function DOLLAR cause a divide by zero error.")
370+ throw new DivZeroError("Evaluation of function DOLLAR cause a divide by zero error.")
371 }
372 return divisor / pow;
373 };
374@@ -167,13 +167,13 @@ var DOLLARDE = function (...values) : number {
375 var dollar = TypeCaster.firstValueAsNumber(values[0]);
376 var fraction = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
377 if (fraction === 0) {
378- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function DOLLARDE parameter 2 cannot be zero.");
379+ throw new DivZeroError("Function DOLLARDE parameter 2 cannot be zero.");
380 }
381 var result = parseInt(dollar.toString(), 10);
382 result += (dollar % 1) * Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN10)) / fraction;
383 var power = Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN2) + 1);
384 if (power === 0) {
385- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function DOLLARDE caused a divide by zero error.");
386+ throw new DivZeroError("Evaluation of function DOLLARDE cause a divide by zero error.")
387 }
388 result = Math.round(result * power) / power;
389 return result;
390@@ -192,7 +192,7 @@ var DOLLARFR = function (...values) : number {
391 var dollar = TypeCaster.firstValueAsNumber(values[0]);
392 var unit = Math.floor(TypeCaster.firstValueAsNumber(values[1]));
393 if (unit === 0) {
394- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function DOLLARFR parameter 2 cannot be zero.");
395+ throw new DivZeroError("Function DOLLARFR parameter 2 cannot be zero.");
396 }
397 var result = parseInt(dollar.toString(), 10);
398 result += (dollar % 1) * Math.pow(10, -Math.ceil(Math.log(unit) / Math.LN10)) * unit;
399@@ -212,10 +212,10 @@ var EFFECT = function (...values) : number {
400 var rate = TypeCaster.firstValueAsNumber(values[0]);
401 var periods = TypeCaster.firstValueAsNumber(values[1]);
402 if (rate <= 0) {
403- throw new CellError(ERRORS.NUM_ERROR, "Function EFFECT parameter 1 value is " + rate + ". It should be greater than to 0");
404+ throw new NumError("Function EFFECT parameter 1 value is " + rate + ". It should be greater than to 0");
405 }
406 if (periods < 1) {
407- throw new CellError(ERRORS.NUM_ERROR, "Function EFFECT parameter 2 value is " + periods + ". It should be greater than or equal to 1");
408+ throw new NumError("Function EFFECT parameter 2 value is " + periods + ". It should be greater than or equal to 1");
409 }
410 periods = Math.floor(periods);
411 return Math.pow(1 + rate / periods, periods) - 1;
412@@ -274,14 +274,14 @@ var CUMPRINC = function (...values) : number {
413 var value = TypeCaster.firstValueAsNumber(values[2]);
414 var start = TypeCaster.firstValueAsNumber(values[3]);
415 if (start < 1) {
416- throw new CellError(ERRORS.NUM_ERROR, "Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
417+ throw new NumError("Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
418 }
419 var end = TypeCaster.firstValueAsNumber(values[4]);
420 if (end < 1) {
421- throw new CellError(ERRORS.NUM_ERROR, "Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
422+ throw new NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
423 }
424 if (end < start) {
425- throw new CellError(ERRORS.NUM_ERROR, "Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
426+ throw new NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
427 }
428 var type = TypeCaster.firstValueAsBoolean(values[5]);
429
430@@ -326,14 +326,14 @@ var CUMIPMT = function (...values) : number {
431 var value = TypeCaster.firstValueAsNumber(values[2]);
432 var start = TypeCaster.firstValueAsNumber(values[3]);
433 if (start < 1) {
434- throw new CellError(ERRORS.NUM_ERROR, "Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
435+ throw new NumError("Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
436 }
437 var end = TypeCaster.firstValueAsNumber(values[4]);
438 if (end < 1) {
439- throw new CellError(ERRORS.NUM_ERROR, "Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
440+ throw new NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
441 }
442 if (end < start) {
443- throw new CellError(ERRORS.NUM_ERROR, "Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
444+ throw new NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
445 }
446 var type = TypeCaster.firstValueAsBoolean(values[5]);
447
448diff --git a/src/RawFormulas/Logical.ts b/src/RawFormulas/Logical.ts
449index 28b2b5d..747acf8 100644
450--- a/src/RawFormulas/Logical.ts
451+++ b/src/RawFormulas/Logical.ts
452@@ -1,6 +1,5 @@
453 import { ArgsChecker, TypeCaster } from "./Utils"
454-import { CellError } from "../Errors"
455-import * as ERRORS from "../Errors"
456+import { ValueError, RefError } from "../Errors"
457
458 /**
459 * Returns true if all of the provided arguments are logically true, and false if any of the provided arguments are logically false.
460@@ -13,7 +12,7 @@ var AND = function (...values) {
461 var result = true;
462 for (var i = 0; i < values.length; i++) {
463 if (typeof values[i] === "string") {
464- throw new CellError(ERRORS.VALUE_ERROR, "AND expects boolean values. But '" + values[i] + "' is a text and cannot be coerced to a boolean.")
465+ throw new ValueError("AND expects boolean values. But '" + values[i] + "' is a text and cannot be coerced to a boolean.")
466 } else if (values[i] instanceof Array) {
467 if (!AND.apply(this, values[i])) {
468 result = false;
469@@ -40,12 +39,12 @@ var EXACT = function (...values) {
470 var two = values[1];
471 if (one instanceof Array) {
472 if (one.length === 0) {
473- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
474+ throw new RefError("Reference does not exist.");
475 }
476 }
477 if (two instanceof Array) {
478 if (two.length === 0) {
479- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
480+ throw new RefError("Reference does not exist.");
481 }
482 }
483 one = TypeCaster.valueToString(one);
484@@ -87,14 +86,14 @@ var NOT = function (...values) : boolean {
485 if (X === "") {
486 return true;
487 }
488- throw new CellError(ERRORS.VALUE_ERROR, "Function NOT parameter 1 expects boolean values. But '" + X + "' is a text and cannot be coerced to a boolean.")
489+ throw new ValueError("Function NOT parameter 1 expects boolean values. But '" + X + "' is a text and cannot be coerced to a boolean.")
490 }
491 if (typeof(X) === "number") {
492 return X === 0;
493 }
494 if (X instanceof Array) {
495 if (X.length === 0) {
496- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
497+ throw new RefError("Reference does not exist.");
498 }
499 return NOT(X[0]);
500 }
501@@ -112,7 +111,7 @@ var OR = function (...values) {
502 for (var i = 0; i < values.length; i++) {
503 if (values[i] instanceof Array) {
504 if (values[i].length === 0) {
505- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
506+ throw new RefError("Reference does not exist.");
507 }
508 if (OR.apply(this, values[i])) {
509 return true;
510@@ -136,7 +135,7 @@ var XOR = function (...values) {
511 for (var i = 0; i < values.length; i++) {
512 if (values[i] instanceof Array) {
513 if (values[i].length === 0) {
514- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
515+ throw new RefError("Reference does not exist.");
516 }
517 if (XOR.apply(this, values[i])) {
518 if (alreadyTruthy) {
519diff --git a/src/RawFormulas/Math.ts b/src/RawFormulas/Math.ts
520index 9915b86..f01ef1a 100644
521--- a/src/RawFormulas/Math.ts
522+++ b/src/RawFormulas/Math.ts
523@@ -6,9 +6,8 @@ import {
524 TypeCaster
525 } from "./Utils";
526 import {
527- CellError
528+ NumError, DivZeroError, RefError, ValueError, NAError
529 } from "../Errors";
530-import * as ERRORS from "../Errors";
531
532 /**
533 * Returns the absolute value of a number.
534@@ -34,7 +33,7 @@ var ACOS = function (value?) {
535 if (value === -1) {
536 return Math.PI;
537 } else if (value > 1 || value < -1) {
538- throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
539+ throw new NumError("Function ACOS parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
540 }
541 return Math.acos(value);
542 };
543@@ -49,7 +48,7 @@ var ACOSH = function (value?) {
544 ArgsChecker.checkLength(arguments, 1);
545 value = TypeCaster.valueToNumber(value);
546 if (value < 1) {
547- throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". It should be greater than or equal to 1.");
548+ throw new NumError("Function ACOSH parameter 1 value is " + value + ". It should be greater than or equal to 1.");
549 }
550 return Math.log(value + Math.sqrt(value * value - 1));
551 };
552@@ -64,7 +63,7 @@ var ACOTH = function (value?) {
553 ArgsChecker.checkLength(arguments, 1);
554 value = TypeCaster.valueToNumber(value);
555 if (value <= 1 && value >= -1) {
556- throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". Valid values cannot be between -1 and 1 inclusive.")
557+ throw new NumError("Function ACOTH parameter 1 value is " + value + ". Valid values cannot be between -1 and 1 inclusive.")
558 }
559 return 0.5 * Math.log((value + 1) / (value - 1));
560 };
561@@ -81,7 +80,7 @@ var ASIN = function (value?) {
562 if (value === -1) {
563 return Math.PI;
564 } else if (value > 1 || value < -1) {
565- throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
566+ throw new NumError("Function ASIN parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
567 }
568 return Math.asin(value);
569 };
570@@ -111,7 +110,7 @@ var ATAN = function (value?) {
571 if (value === -1) {
572 return Math.PI;
573 } else if (value > 1 || value < -1) {
574- throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
575+ throw new NumError("Function ATAN parameter 1 value is " + value + ". Valid values are between -1 and 1 inclusive.");
576 }
577 return Math.atan(value);
578 };
579@@ -129,7 +128,7 @@ var ATAN2 = function (x, y) {
580 x = TypeCaster.valueToNumber(x);
581 y = TypeCaster.valueToNumber(y);
582 if (x === 0 && y === 0) {
583- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function ATAN2 caused a divide by zero error.");
584+ throw new DivZeroError("Evaluation of function ATAN2 caused a divide by zero error.");
585 }
586 return Math.atan2(y, x);
587 };
588@@ -145,7 +144,7 @@ var ATANH = function (value?) : number {
589 ArgsChecker.checkLength(arguments, 1);
590 value = TypeCaster.valueToNumber(value);
591 if (value >= 1 || value <= -1) {
592- throw new CellError(ERRORS.NUM_ERROR, "Function ATANH parameter 1 value is " + value + ". Valid values are between -1 and 1 exclusive.");
593+ throw new NumError("Function ATANH parameter 1 value is " + value + ". Valid values are between -1 and 1 exclusive.");
594 }
595 if (Math.abs(value) < 1) {
596
597@@ -163,7 +162,7 @@ var EVEN = function (...values) : number {
598 ArgsChecker.checkLength(values, 1);
599 if (values[0] instanceof Array) {
600 if (values[0].length === 0) {
601- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
602+ throw new RefError("Reference does not exist.");
603 }
604 return EVEN(values[0][0]);
605 }
606@@ -183,7 +182,7 @@ var MOD = function (...values) : number {
607 var oneN = TypeCaster.valueToNumber(values[0]);
608 var twoN = TypeCaster.valueToNumber(values[1]);
609 if (twoN === 0) {
610- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function MOD parameter 2 cannot be zero.");
611+ throw new DivZeroError("Function MOD parameter 2 cannot be zero.");
612 }
613 return oneN % twoN;
614 };
615@@ -199,7 +198,7 @@ var ODD = function (...values) : number {
616 ArgsChecker.checkLength(values, 1);
617 if (values[0] instanceof Array) {
618 if (values[0].length === 0) {
619- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
620+ throw new RefError("Reference does not exist.");
621 }
622 return ODD(values[0][0]);
623 }
624@@ -235,7 +234,7 @@ var SUM = function (...values) : number {
625 result = result + SUM.apply(this, values[i]);
626 } else {
627 if (values[i] === "") {
628- throw new CellError(ERRORS.VALUE_ERROR, "Function SUM parameter "+i+" expects number values. But '"+values[i]+"' is a text and cannot be coerced to a number.");
629+ throw new ValueError("Function SUM parameter "+i+" expects number values. But '"+values[i]+"' is a text and cannot be coerced to a number.");
630 }
631 result = result + TypeCaster.valueToNumber(values[i]);
632 }
633@@ -253,7 +252,7 @@ var SQRT = function (...values) : number {
634 ArgsChecker.checkLength(values, 1);
635 var x = TypeCaster.firstValueAsNumber(values[0]);
636 if (x < 0) {
637- throw new CellError(ERRORS.VALUE_ERROR, "Function SQRT parameter 1 expects number values. But '" + values[0] + "' is a text and cannot be coerced to a number.");
638+ throw new ValueError("Function SQRT parameter 1 expects number values. But '" + values[0] + "' is a text and cannot be coerced to a number.");
639 }
640 return Math.sqrt(x);
641 };
642@@ -268,7 +267,7 @@ var SQRTPI = function (...values) : number{
643 ArgsChecker.checkLength(values, 1);
644 var n = TypeCaster.firstValueAsNumber(values[0]);
645 if (n < 0) {
646- throw new CellError(ERRORS.NUM_ERROR, "Function SQRTPI parameter 1 value is " + n + ". It should be greater than or equal to 0.");
647+ throw new NumError("Function SQRTPI parameter 1 value is " + n + ". It should be greater than or equal to 0.");
648 }
649 return Math.sqrt(n * Math.PI);
650 };
651@@ -307,7 +306,7 @@ var COT = function (...values) : number {
652 ArgsChecker.checkLength(values, 1);
653 var x = TypeCaster.firstValueAsNumber(values[0]);
654 if (x === 0) {
655- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COT caused a divide by zero error.");
656+ throw new DivZeroError("Evaluation of function COT caused a divide by zero error.");
657 }
658 return 1 / Math.tan(x);
659 };
660@@ -322,7 +321,7 @@ var COTH = function (...values) : number {
661 ArgsChecker.checkLength(values, 1);
662 var x = TypeCaster.firstValueAsNumber(values[0]);
663 if (x === 0) {
664- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COTH caused a divide by zero error.");
665+ throw new DivZeroError("Evaluation of function COTH caused a divide by zero error.");
666 }
667 return 1 / Math["tanh"](x);
668 };
669@@ -349,7 +348,7 @@ var INT = function (...values) : number {
670 var ISEVEN = function (...values) : boolean {
671 ArgsChecker.checkLength(values, 1);
672 if (values[0] === "") {
673- throw new CellError(ERRORS.VALUE_ERROR, "Function ISEVEN parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
674+ throw new ValueError("Function ISEVEN parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
675 }
676 var x = TypeCaster.firstValueAsNumber(values[0]);
677 return Math.floor(x) % 2 === 0;
678@@ -365,7 +364,7 @@ var ISEVEN = function (...values) : boolean {
679 var ISODD = function (...values) : boolean {
680 ArgsChecker.checkLength(values, 1);
681 if (values[0] === "") {
682- throw new CellError(ERRORS.VALUE_ERROR, "Function ISODD parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
683+ throw new ValueError("Function ISODD parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
684 }
685 var x = TypeCaster.firstValueAsNumber(values[0]);
686 return Math.floor(x) % 2 === 1;
687@@ -414,7 +413,7 @@ var LOG10 = function (...values) : number {
688 ArgsChecker.checkLength(values, 1);
689 var n = TypeCaster.firstValueAsNumber(values[0]);
690 if (n < 1) {
691- throw new CellError(ERRORS.NUM_ERROR, "Function LOG10 parameter 1 value is " + n + ". It should be greater than 0.");
692+ throw new NumError("Function LOG10 parameter 1 value is " + n + ". It should be greater than 0.");
693 }
694 var ln = Math.log(n);
695 var lb = Math.log(10);
696@@ -435,16 +434,16 @@ var LOG = function (...values) : number {
697 if (values.length > 1) {
698 b = TypeCaster.firstValueAsNumber(values[1]);
699 if (b < 1) {
700- throw new CellError(ERRORS.NUM_ERROR, "Function LOG parameter 2 value is " + b + ". It should be greater than 0.");
701+ throw new NumError("Function LOG parameter 2 value is " + b + ". It should be greater than 0.");
702 }
703 }
704 if (b < 2) {
705- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function LOG caused a divide by zero error.");
706+ throw new DivZeroError("Evaluation of function LOG caused a divide by zero error.");
707 }
708 var ln = Math.log(n);
709 var lb = Math.log(b);
710 if (lb === 0) {
711- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function LOG caused a divide by zero error.");
712+ throw new DivZeroError("Evaluation of function LOG caused a divide by zero error.");
713 }
714 return ln / lb;
715 };
716@@ -459,7 +458,7 @@ var LN = function (...values) : number {
717 ArgsChecker.checkLength(values, 1);
718 var n = TypeCaster.firstValueAsNumber(values[0]);
719 if (n < 1) {
720- throw new CellError(ERRORS.NUM_ERROR, "Function LN parameter 1 value is " + n + ". It should be greater than 0.");
721+ throw new NumError("Function LN parameter 1 value is " + n + ". It should be greater than 0.");
722 }
723 return Math.log(n);
724 };
725@@ -503,7 +502,7 @@ var CEILING = function (...values) : number {
726 }
727 var significance = TypeCaster.firstValueAsNumber(values[1]);
728 if (significance === 0) {
729- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function CEILING parameter 2 cannot be zero.");
730+ throw new DivZeroError("Function CEILING parameter 2 cannot be zero.");
731 }
732 var precision = -Math.floor(Math.log(significance) / Math.log(10));
733 if (num >= 0) {
734@@ -528,7 +527,7 @@ var FLOOR = function (...values) : number {
735 }
736 var significance = TypeCaster.firstValueAsNumber(values[1]);
737 if (significance === 0) {
738- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function FLOOR parameter 2 cannot be zero.");
739+ throw new DivZeroError("Function FLOOR parameter 2 cannot be zero.");
740 }
741 significance = significance ? Math.abs(significance) : 1;
742 var precision = -Math.floor(Math.log(significance) / Math.log(10));
743@@ -550,7 +549,7 @@ var IF = function (...values) : any {
744 ArgsChecker.checkLength(values, 3);
745 if (values[0] instanceof Array) {
746 if (values[0].length === 0) {
747- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
748+ throw new RefError("Reference does not exist.");
749 }
750 return IF(values[0][0], values[1], values[2]);
751 } else if (values[0] === "") {
752@@ -614,7 +613,7 @@ var COUNTIFS = function (...values) {
753 var otherCriteriaEvaluationSuccessfulSoFar = true;
754 for (var x = 0; x < values.length; x += 2) {
755 if (values[x].length < values[0].length) {
756- throw new CellError(ERRORS.VALUE_ERROR, "Array arguments to COUNTIFS are of different size.");
757+ throw new ValueError("Array arguments to COUNTIFS are of different size.");
758 }
759 var criteriaEvaluation = criteriaEvaluationFunctions[x+1];
760 if (otherCriteriaEvaluationSuccessfulSoFar) {
761@@ -732,7 +731,7 @@ var SUMSQ = function (...values) {
762 for (var i = 0; i < values.length; i++) {
763 if (values[i] instanceof Array) {
764 if (values[i].length === 0) {
765- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
766+ throw new RefError("Reference does not exist.");
767 }
768 result = result + SUMSQ.apply(this, Filter.filterOutNonNumberValues(values[i]));
769 } else {
770@@ -871,7 +870,7 @@ var SUMX2PY2 = function (...values) : number {
771 var arrOne = Filter.flattenAndThrow(values[0]);
772 var arrTwo = Filter.flattenAndThrow(values[1]);
773 if (arrOne.length !== arrTwo.length) {
774- throw new CellError(ERRORS.NA_ERROR, "Array arguments to SUMX2PY2 are of different size.");
775+ throw new NAError("Array arguments to SUMX2PY2 are of different size.");
776 }
777 var result = 0;
778 for (var i = 0; i < arrOne.length; i++) {
779@@ -897,7 +896,7 @@ var SUMX2MY2 = function (...values) : number {
780 var arrOne = Filter.flattenAndThrow(values[0]);
781 var arrTwo = Filter.flattenAndThrow(values[1]);
782 if (arrOne.length !== arrTwo.length) {
783- throw new CellError(ERRORS.NA_ERROR, "Array arguments to SUMX2MY2 are of different size.");
784+ throw new NAError("Array arguments to SUMX2MY2 are of different size.");
785 }
786 var result = 0;
787 for (var i = 0; i < arrOne.length; i++) {
788@@ -966,7 +965,7 @@ var SUMPRODUCT = function (...values) : number {
789 for (var x = 1; x < values.length; x++) {
790 flattenedValues.push(Filter.flattenAndThrow(values[x]));
791 if (flattenedValues[x].length !== flattenedValues[0].length) {
792- throw new CellError(ERRORS.VALUE_ERROR, "SUMPRODUCT has mismatched range sizes. Expected count: "
793+ throw new ValueError("SUMPRODUCT has mismatched range sizes. Expected count: "
794 + flattenedValues[0].length + ". Actual count: " + flattenedValues[0].length + ".");
795 }
796 }
797@@ -1008,14 +1007,14 @@ var COMBIN = function (...values) : number {
798 var n = TypeCaster.firstValueAsNumber(values[0]);
799 var c = TypeCaster.firstValueAsNumber(values[1]);
800 if (n < c) {
801- throw new CellError(ERRORS.NUM_ERROR, "Function COMBIN parameter 2 value is "
802+ throw new NumError("Function COMBIN parameter 2 value is "
803 + c + ". It should be less than or equal to value of Function COMBIN parameter 1 with " + n + ".");
804 }
805 n = Math.floor(n);
806 c = Math.floor(c);
807 var div = fact(c) * fact(n - c);
808 if (div === 0) {
809- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COMBIN caused a divide by zero error.");
810+ throw new DivZeroError("Evaluation of function COMBIN caused a divide by zero error.");
811 }
812 return fact(n) / div;
813 };
814diff --git a/src/RawFormulas/Statistical.ts b/src/RawFormulas/Statistical.ts
815index 742244f..e1aeb88 100644
816--- a/src/RawFormulas/Statistical.ts
817+++ b/src/RawFormulas/Statistical.ts
818@@ -5,13 +5,12 @@ import {
819 TypeCaster
820 } from "./Utils";
821 import {
822- CellError
823+ RefError, NumError, DivZeroError, NAError
824 } from "../Errors";
825 import {
826 SUM,
827 ABS
828 } from "./Math"
829-import * as ERRORS from "../Errors";
830
831
832 /**
833@@ -49,7 +48,7 @@ var MEDIAN = function (...values) : number {
834 values.forEach(function (currentValue) {
835 if (currentValue instanceof Array) {
836 if (currentValue.length === 0) {
837- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
838+ throw new RefError("Reference does not exist.");
839 }
840 var filtered = Filter.filterOutStringValues(currentValue);
841 sortedArray = sortedArray.concat(filtered);
842@@ -66,7 +65,7 @@ var MEDIAN = function (...values) : number {
843 return TypeCaster.valueToNumber(sortedArray[0]);
844 }
845 if (sortedArray.length === 0) {
846- throw new CellError(ERRORS.NUM_ERROR, "MEDIAN has no valid input data.");
847+ throw new NumError("MEDIAN has no valid input data.");
848 }
849 // even number of values
850 if (sortedArray.length % 2 === 0) {
851@@ -95,7 +94,7 @@ var AVERAGE = function (...values) : number {
852 for (var i = 0; i < values.length; i++) {
853 if (values[i] instanceof Array) {
854 if (values[i].length === 0) {
855- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
856+ throw new RefError("Reference does not exist.");
857 }
858 var filtered = Filter.filterOutStringValues(values[i]);
859 result = result + SUM.apply(this, filtered);
860@@ -124,7 +123,7 @@ var AVEDEV = function (...values) {
861 var X = values[i];
862 if (X instanceof Array) {
863 if (X.length === 0) {
864- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
865+ throw new RefError("Reference does not exist.");
866 }
867 arrayValues.push(X);
868 } else {
869@@ -145,7 +144,7 @@ var AVEDEV = function (...values) {
870 count++;
871 }
872 if (count === 0) {
873- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function AVEDEV caused a devide by zero error.");
874+ throw new DivZeroError("Evaluation of function AVEDEV caused a devide by zero error.");
875 }
876 var mean = result / count;
877
878@@ -168,7 +167,7 @@ var AVERAGEA = function (...values) {
879 for (var i = 0; i < values.length; i++) {
880 if (values[i] instanceof Array) {
881 if (values[i].length === 0) {
882- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
883+ throw new RefError("Reference does not exist.");
884 }
885 var filtered = Filter.stringValuesToZeros(values[i]);
886 result = result + SUM.apply(this, filtered);
887@@ -179,7 +178,7 @@ var AVERAGEA = function (...values) {
888 }
889 }
890 if (count === 0) {
891- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function AVEDEV caused a devide by zero error.");
892+ throw new DivZeroError("Evaluation of function AVEDEV caused a devide by zero error.");
893 }
894 return result / count;
895 };
896@@ -198,7 +197,7 @@ var CORREL = function (...values) : number {
897 }
898 function variance(arr, flag) {
899 if ((arr.length - (flag ? 1 : 0)) === 0) {
900- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
901+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
902 }
903 return sumsqerr(arr) / (arr.length - (flag ? 1 : 0));
904 }
905@@ -212,7 +211,7 @@ var CORREL = function (...values) : number {
906 }
907 function mean(arr) {
908 if (arr.length === 0) {
909- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
910+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
911 }
912 return sum(arr) / arr.length;
913 }
914@@ -236,7 +235,7 @@ var CORREL = function (...values) : number {
915 sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);
916 }
917 if ((arr1Len - 1) === 0) {
918- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
919+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
920 }
921 return sum(sq_dev) / (arr1Len - 1);
922 }
923@@ -248,14 +247,14 @@ var CORREL = function (...values) : number {
924 values[1] = [values[1]];
925 }
926 if (values[0].length !== values[1].length) {
927- throw new CellError(ERRORS.NA_ERROR, "CORREL has mismatched argument count " + values[0] + " vs " + values[1] + ".");
928+ throw new NAError("CORREL has mismatched argument count " + values[0] + " vs " + values[1] + ".");
929 }
930 var arr1 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(values[0]));
931 var arr2 = Filter.filterOutNonNumberValues(Filter.flattenAndThrow(values[1]));
932 var stdevArr1 = stdev(arr1, 1);
933 var stdevArr2 = stdev(arr2, 1);
934 if (stdevArr1 === 0 || stdevArr2 === 0) {
935- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function CORREL caused a divide by zero error.");
936+ throw new DivZeroError("Evaluation of function CORREL caused a divide by zero error.");
937 }
938 return covariance(arr1, arr2) / stdevArr1 / stdevArr2;
939 };
940@@ -453,7 +452,7 @@ var FDIST$LEFTTAILED = function (...values) : number|undefined|boolean {
941 ArgsChecker.checkLength(values, 4);
942 var x = TypeCaster.firstValueAsNumber(values[0]);
943 if (x < 0) {
944- throw new CellError(ERRORS.NUM_ERROR, "Function F.DIST parameter 1 value is " + x + ". It should be greater than or equal to 0.");
945+ throw new NumError("Function F.DIST parameter 1 value is " + x + ". It should be greater than or equal to 0.");
946 }
947 var d1 = TypeCaster.firstValueAsNumber(values[1]);
948 var d2 = TypeCaster.firstValueAsNumber(values[2]);
949@@ -619,7 +618,7 @@ var FISHER = function (...values) : number {
950 ArgsChecker.checkLength(values, 1);
951 var x = TypeCaster.firstValueAsNumber(values[0]);
952 if (x <= -1 || x >= 1) {
953- throw new CellError(ERRORS.NUM_ERROR, "Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
954+ throw new NumError("Function FISHER parameter 1 value is " + x + ". Valid values are between -1 and 1 exclusive.");
955 }
956 return Math.log((1 + x) / (1 - x)) / 2;
957 };
958@@ -649,7 +648,7 @@ var MAX = function (...values) {
959 for (var i = 0; i < values.length; i++) {
960 if (values[i] instanceof Array) {
961 if (values[i].length === 0) {
962- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
963+ throw new RefError("Reference does not exist.");
964 }
965 var filtered = Filter.filterOutStringValues(values[i]);
966 if (filtered.length !== 0) {
967@@ -685,7 +684,7 @@ var MIN = function (...values) {
968 for (var i = 0; i < values.length; i++) {
969 if (values[i] instanceof Array) {
970 if (values[i].length === 0) {
971- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
972+ throw new RefError("Reference does not exist.");
973 }
974 var filtered = Filter.filterOutStringValues(values[i]);
975 if (filtered.length !== 0) {
976@@ -736,7 +735,7 @@ var AVERAGEIF = function (...values) {
977 }
978 }
979 if (count === 0) {
980- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function AVERAGEIF caused a divide by zero error.");
981+ throw new DivZeroError("Evaluation of function AVERAGEIF caused a divide by zero error.");
982 }
983 return result / count;
984 };
985diff --git a/src/RawFormulas/Text.ts b/src/RawFormulas/Text.ts
986index e18bd8a..999ffe4 100644
987--- a/src/RawFormulas/Text.ts
988+++ b/src/RawFormulas/Text.ts
989@@ -3,9 +3,8 @@ import {
990 TypeCaster
991 } from "./Utils";
992 import {
993- CellError
994+ ValueError, NumError, RefError
995 } from "../Errors";
996-import * as ERRORS from "../Errors";
997
998 /**
999 * Computes the value of a Roman numeral.
1000@@ -16,7 +15,7 @@ import * as ERRORS from "../Errors";
1001 var ARABIC = function (text?) {
1002 ArgsChecker.checkLength(arguments, 1);
1003 if (typeof text !== "string") {
1004- throw new CellError(ERRORS.VALUE_ERROR, 'Invalid roman numeral in ARABIC evaluation.');
1005+ throw new ValueError('Invalid roman numeral in ARABIC evaluation.');
1006 }
1007 var negative = false;
1008 if (text[0] === "-") {
1009@@ -25,7 +24,7 @@ var ARABIC = function (text?) {
1010 }
1011 // Credits: Rafa? Kukawski
1012 if (!/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/.test(text)) {
1013- throw new CellError(ERRORS.VALUE_ERROR, 'Invalid roman numeral in ARABIC evaluation.');
1014+ throw new ValueError('Invalid roman numeral in ARABIC evaluation.');
1015 }
1016 var r = 0;
1017 text.replace(/[MDLV]|C[MD]?|X[CL]?|I[XV]?/g, function (i) {
1018@@ -47,7 +46,7 @@ var CHAR = function (...values) : string {
1019 ArgsChecker.checkLength(values, 1);
1020 var n = TypeCaster.firstValueAsNumber(values[0]);
1021 if (n < 1 || n > 1114112) { //limit
1022- throw new CellError(ERRORS.NUM_ERROR, "Function CHAR parameter 1 value " + n + " is out of range.");
1023+ throw new NumError("Function CHAR parameter 1 value " + n + " is out of range.");
1024 }
1025 return String.fromCharCode(n);
1026 };
1027@@ -62,7 +61,7 @@ var CODE = function (...values) : number {
1028 ArgsChecker.checkLength(values, 1);
1029 var text = TypeCaster.firstValueAsString(values[0]);
1030 if (text === "") {
1031- throw new CellError(ERRORS.VALUE_ERROR, "Function CODE parameter 1 value should be non-empty.");
1032+ throw new ValueError("Function CODE parameter 1 value should be non-empty.");
1033 }
1034 return text.charCodeAt(0);
1035 };
1036@@ -115,7 +114,7 @@ var CONCATENATE = function (...values) : string {
1037 for (var i = 0; i < values.length; i++) {
1038 if (values[i] instanceof Array) {
1039 if (values[i].length === 0) {
1040- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1041+ throw new RefError("Reference does not exist.");
1042 }
1043 string += CONCATENATE.apply(this, arguments[i]);
1044 } else {
1045diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
1046index 51712a4..2be95f1 100644
1047--- a/src/RawFormulas/Utils.ts
1048+++ b/src/RawFormulas/Utils.ts
1049@@ -1,8 +1,7 @@
1050 /// <reference path="../../node_modules/moment/moment.d.ts"/>
1051 import * as moment from "moment";
1052-import {CellError, VALUE_ERROR} from "../Errors"
1053-import * as ERRORS from "../Errors"
1054-import {ExcelDate} from "../ExcelDate";
1055+import { ValueError, RefError, NAError, DivZeroError } from "../Errors"
1056+import { ExcelDate } from "../ExcelDate";
1057
1058 /**
1059 * Converts wild-card style expressions (in which * matches zero or more characters, and ? matches exactly one character)
1060@@ -576,7 +575,7 @@ class TypeCaster {
1061 }
1062 }
1063 if (m === undefined || !m.isValid()) {
1064- throw new CellError(VALUE_ERROR, "DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
1065+ throw new ValueError("DATEVALUE parameter '" + dateString + "' cannot be parsed to date/time.");
1066 }
1067 return new ExcelDate(m);
1068 }
1069@@ -596,13 +595,13 @@ class TypeCaster {
1070 if (value.indexOf(".") > -1) {
1071 var fl = parseFloat(value.replace("$", ""));
1072 if (isNaN(fl)) {
1073- throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1074+ throw new ValueError("Function ____ expects number values, but is text and cannot be coerced to a number.");
1075 }
1076 return fl;
1077 }
1078 var fl = parseInt(value.replace("$", ""));
1079 if (isNaN(fl)) {
1080- throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1081+ throw new ValueError("Function ____ expects number values, but is text and cannot be coerced to a number.");
1082 }
1083 return fl;
1084 } else if (typeof value === "boolean") {
1085@@ -633,7 +632,7 @@ class TypeCaster {
1086 if (typeof value === "number") {
1087 return value !== 0;
1088 } else if (typeof value === "string") {
1089- throw new CellError(ERRORS.VALUE_ERROR, "___ expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.")
1090+ throw new ValueError("___ expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.")
1091 } else if (typeof value === "boolean") {
1092 return value;
1093 }
1094@@ -683,7 +682,7 @@ class TypeCaster {
1095 static firstValueAsNumber(input: any) : number {
1096 if (input instanceof Array) {
1097 if (input.length === 0) {
1098- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1099+ throw new RefError("Reference does not exist.");
1100 }
1101 return TypeCaster.firstValueAsNumber(input[0]);
1102 }
1103@@ -698,7 +697,7 @@ class TypeCaster {
1104 static firstValueAsString(input: any) : string {
1105 if (input instanceof Array) {
1106 if (input.length === 0) {
1107- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1108+ throw new RefError("Reference does not exist.");
1109 }
1110 return TypeCaster.firstValueAsString(input[0]);
1111 }
1112@@ -708,7 +707,7 @@ class TypeCaster {
1113 static firstValue(input: any) : any {
1114 if (input instanceof Array) {
1115 if (input.length === 0) {
1116- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1117+ throw new RefError("Reference does not exist.");
1118 }
1119 return TypeCaster.firstValue(input[0]);
1120 }
1121@@ -723,7 +722,7 @@ class TypeCaster {
1122 static firstValueAsBoolean(input: any): boolean {
1123 if (input instanceof Array) {
1124 if (input.length === 0) {
1125- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1126+ throw new RefError("Reference does not exist.");
1127 }
1128 return TypeCaster.firstValueAsBoolean(input[0]);
1129 }
1130@@ -738,7 +737,7 @@ class TypeCaster {
1131 static firstValueAsExcelDate(input: any) : ExcelDate {
1132 if (input instanceof Array) {
1133 if (input.length === 0) {
1134- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1135+ throw new RefError("Reference does not exist.");
1136 }
1137 return TypeCaster.firstValueAsExcelDate(input[0]);
1138 }
1139@@ -762,10 +761,10 @@ class TypeCaster {
1140 if (TypeCaster.canCoerceToNumber(value)) {
1141 return new ExcelDate(TypeCaster.valueToNumber(value));
1142 }
1143- throw new CellError(ERRORS.VALUE_ERROR, "___ expects date values. But '" + value + "' is a text and cannot be coerced to a date.")
1144+ throw new ValueError("___ expects date values. But '" + value + "' is a text and cannot be coerced to a date.")
1145 }
1146 } else if (typeof value === "boolean") {
1147- throw new CellError(ERRORS.VALUE_ERROR, "___ expects date values. But '" + value + "' is a text and cannot be coerced to a date.")
1148+ throw new ValueError("___ expects date values. But '" + value + "' is a text and cannot be coerced to a date.")
1149 }
1150 }
1151 }
1152@@ -810,7 +809,7 @@ class Filter {
1153 static flattenAndThrow(values: Array<any>) : Array<any> {
1154 return values.reduce(function (flat, toFlatten) {
1155 if (Array.isArray(toFlatten) && toFlatten.length === 0) {
1156- throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1157+ throw new RefError("Reference does not exist.");
1158 }
1159 return flat.concat(Array.isArray(toFlatten) ? Filter.flattenAndThrow(toFlatten) : toFlatten);
1160 }, []);
1161@@ -858,7 +857,7 @@ class ArgsChecker {
1162 */
1163 static checkLength(args: any, length: number) {
1164 if (args.length !== length) {
1165- throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1166+ throw new NAError("Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1167 }
1168 }
1169
1170@@ -869,7 +868,7 @@ class ArgsChecker {
1171 */
1172 static checkAtLeastLength(args: any, length: number) {
1173 if (args.length < length) {
1174- throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1175+ throw new NAError("Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1176 }
1177 }
1178
1179@@ -881,7 +880,7 @@ class ArgsChecker {
1180 */
1181 static checkLengthWithin(args: any, low: number, high: number) {
1182 if (args.length > high || args.length < low) {
1183- throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1184+ throw new NAError("Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1185 }
1186 }
1187 }
1188@@ -904,7 +903,7 @@ class Serializer {
1189 var checkForDevideByZero = function(n : number) : number {
1190 n = +n; // Coerce to number.
1191 if (!n) { // Matches +0, -0, NaN
1192- throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function caused a divide by zero error.");
1193+ throw new DivZeroError("Evaluation of function caused a divide by zero error.");
1194 }
1195 return n;
1196 };
1197diff --git a/tests/DateFormulasTest.ts b/tests/DateFormulasTest.ts
1198index be9d600..d1f5635 100644
1199--- a/tests/DateFormulasTest.ts
1200+++ b/tests/DateFormulasTest.ts
1201@@ -10,15 +10,14 @@ function catchAndAssertEquals(toExecute, expected) {
1202 toExecute();
1203 toThrow = true;
1204 } catch (actualError) {
1205- if (actualError.message != expected) {
1206- console.log(expected, "not equal to", actualError.message);
1207+ if (actualError.name != expected) {
1208+ console.log(expected, "not equal to", actualError.name);
1209 }
1210 }
1211 if (toThrow) {
1212 throw new Error("expected error: " + expected);
1213 }
1214 }
1215-
1216 // Test EDATE
1217 assertEquals(EDATE(DATE(1992, 6, 24), 1), DATE(1992, 7, 24));
1218 assertEquals(EDATE(DATE(1992, 5, 24), 2), DATE(1992, 7, 24));
1219diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
1220index 6c65bf3..620ea18 100644
1221--- a/tests/FormulasTest.ts
1222+++ b/tests/FormulasTest.ts
1223@@ -17,8 +17,8 @@ function catchAndAssertEquals(toExecute, expected) {
1224 toExecute();
1225 toThrow = true;
1226 } catch (actualError) {
1227- if (actualError.message != expected) {
1228- console.log(expected, "not equal to", actualError.message);
1229+ if (actualError.name != expected) {
1230+ console.log(expected, "not equal to", actualError.name);
1231 }
1232 }
1233 if (toThrow) {