commit
message
ts.html and ts/sheet.ts working
author
Ben Vogt <[email protected]>
date
2016-12-26 18:06:42
stats
7 file(s) changed,
2348 insertions(+),
15 deletions(-)
files
js/TSParser.d.ts
js/sheet.ts
ts.html
ts/parser.js
ts/sheet.js
ts/sheet.ts
tsconfig.json
1diff --git a/js/TSParser.d.ts b/js/TSParser.d.ts
2deleted file mode 100644
3index ebf4c90..0000000
4--- a/js/TSParser.d.ts
5+++ /dev/null
6@@ -1,12 +0,0 @@
7-interface P {
8- yy: any;
9- lexer: any;
10- parse: any;
11- parseError: any;
12-}
13-
14-declare var Parser: P;
15-
16-export {
17- Parser
18-}
19\ No newline at end of file
20diff --git a/js/sheet.ts b/js/sheet.ts
21deleted file mode 100644
22index 2791be5..0000000
23--- a/js/sheet.ts
24+++ /dev/null
25@@ -1,3 +0,0 @@
26-import * as Formula from "../lib/formulajs"
27-/// <reference path="TSParser.d.ts"/>
28-import { Parser } from "./TSParser";
29diff --git a/ts.html b/ts.html
30new file mode 100644
31index 0000000..8a4b80b
32--- /dev/null
33+++ b/ts.html
34@@ -0,0 +1,158 @@
35+<!doctype html>
36+<html>
37+<head>
38+ <meta charset='utf-8'>
39+ <title>RuleJS - Like excel library to parse formulas.</title>
40+
41+ <!-- Latest compiled and minified CSS -->
42+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
43+
44+ <script src="lib/lodash/lodash.js"></script>
45+ <script src="lib/underscore.string/underscore.string.js"></script>
46+ <script src="lib/moment/moment.js"></script>
47+ <script src="lib/numeral/numeral.js"></script>
48+ <script src="lib/numericjs/numeric.js"></script>
49+ <script src="lib/js-md5/md5.js"></script>
50+ <script src="lib/jstat/jstat.js"></script>
51+ <script src="lib/formulajs/formula.js"></script>
52+
53+ <script src="ts/parser.js"></script>
54+ <script src="ts/sheet.js"></script>
55+ <style>
56+ .table input[type=text] {
57+ width: 50px;
58+ }
59+ #suportedList ul {
60+ -webkit-column-count: 4; -webkit-column-gap:20px;
61+ -moz-column-count:4; -moz-column-gap:20px;
62+ -o-column-count:4; -o-column-gap:20px;
63+ column-count:4; column-gap:20px;
64+ }
65+ </style>
66+</head>
67+<body>
68+<div class="col-xs-12">
69+ <section>
70+ <h1 class="page-header">RuleJS</h1>
71+ <section>
72+ <h1 class="page-header">Demo</h1>
73+ <p>Try to parse the formula by typing ex. <code>AND(1,0)</code> into input below and press <kbd>Parse</kbd> button.</p>
74+
75+ <div class="col-xs-12" style="padding: 0px;" id="mine">
76+
77+ <input type="text" id="X1" placeholder="ex. AND(1,0)"><button>Parse</button>
78+
79+ <p class="bg-info" style="display: none">result: <span id="result"></span></p>
80+ <p class="bg-danger" style="display: none">error: <span id="error"></span></p>
81+ <p class="clearfix"></p>
82+
83+ <p>Try to insert formula into input field by typing ex. <code>=A1</code>. It's possible to edit formula by double clicked on input field.</p>
84+ <table class="table table-bordered">
85+ <thead>
86+ <tr>
87+ <td></td>
88+ <td>A</td>
89+ <td>B</td>
90+ <td>C</td>
91+ <td>D</td>
92+ <td>E</td>
93+ <td>F</td>
94+ <td>G</td>
95+ <td>H</td>
96+ <td>I</td>
97+ <td>J</td>
98+ <td colspan="2" class="text-center">fn(x)</td>
99+ </tr>
100+ </thead>
101+ <tbody>
102+ <tr>
103+ <td>1</td>
104+ <td><input type="text" id="A1" value="1"></td>
105+ <td><input type="text" id="B1" value="2"></td>
106+ <td><input type="text" id="C1" value="3"></td>
107+ <td><input type="text" id="D1" value="4"></td>
108+ <td><input type="text" id="E1" value="5"></td>
109+ <td><input type="text" id="F1" value="6"></td>
110+ <td><input type="text" id="G1" value="7"></td>
111+ <td><input type="text" id="H1" value="8"></td>
112+ <td><input type="text" id="I1" value="9"></td>
113+ <td><input type="text" id="J1" value="10"></td>
114+ <td>SUM(A1:D1, H1)</td>
115+ <td><span id="K1" data-formula="SUM(A1:D1, H1)"></span></td>
116+ </tr>
117+ <tr>
118+ <td>2</td>
119+ <td><input type="text" id="A2" value="-1"></td>
120+ <td><input type="text" id="B2" value="-10"></td>
121+ <td><input type="text" id="C2" value="2"></td>
122+ <td><input type="text" id="D2" value="4"></td>
123+ <td><input type="text" id="E2" value="100"></td>
124+ <td><input type="text" id="F2" value="1"></td>
125+ <td><input type="text" id="G2" value="50"></td>
126+ <td><input type="text" id="H2" value="20"></td>
127+ <td><input type="text" id="I2" value="200"></td>
128+ <td><input type="text" id="J2" value="-100"></td>
129+ <td>MAX(A2:J2)</td>
130+ <td><span id="K2" data-formula="MAX(A2:J2)"></span></td>
131+ </tr>
132+ <tr>
133+ <td>3</td>
134+ <td><input type="text" id="A3" value="-1"></td>
135+ <td><input type="text" id="B3" value="-40"></td>
136+ <td><input type="text" id="C3" value="-53"></td>
137+ <td><input type="text" id="D3" value="1"></td>
138+ <td><input type="text" id="E3" value="10"></td>
139+ <td><input type="text" id="F3" value="30"></td>
140+ <td><input type="text" id="G3" value="10"></td>
141+ <td><input type="text" id="H3" value="301"></td>
142+ <td><input type="text" id="I3" value="-1"></td>
143+ <td><input type="text" id="J3" value="-20"></td>
144+ <td>MIN(A3:J3)</td>
145+ <td><span id="K3" data-formula="MIN(A3:J3)"></span></td>
146+ </tr>
147+ <tr>
148+ <td>4</td>
149+ <td><input type="text" id="A4" value="20"></td>
150+ <td><input type="text" id="B4" value="50"></td>
151+ <td><input type="text" id="C4" value="100"></td>
152+ <td><input type="text" id="D4" value="20"></td>
153+ <td><input type="text" id="E4" value="1"></td>
154+ <td><input type="text" id="F4" value="5"></td>
155+ <td><input type="text" id="G4" value="15"></td>
156+ <td><input type="text" id="H4" value="25"></td>
157+ <td><input type="text" id="I4" value="45"></td>
158+ <td><input type="text" id="J4" value="23"></td>
159+ <td>AVERAGE(A4:J4):</td>
160+ <td><span id="K4" data-formula="AVERAGE(A4:J4)"></span></td>
161+ </tr>
162+ <tr>
163+ <td>5</td>
164+ <td><input type="text" id="A5" value="0"></td>
165+ <td><input type="text" id="B5" value="10"></td>
166+ <td><input type="text" id="C5" value="1"></td>
167+ <td><input type="text" id="D5" value="10"></td>
168+ <td><input type="text" id="E5" value="2"></td>
169+ <td><input type="text" id="F5" value="10"></td>
170+ <td><input type="text" id="G5" value="3"></td>
171+ <td><input type="text" id="H5" value="10"></td>
172+ <td><input type="text" id="I5" value="4"></td>
173+ <td><input type="text" id="J5" value="10"></td>
174+ <td>SUMIF(A5:J5,'>5')</td>
175+ <td><span id="K5" data-formula="SUMIF(A5:J5,'>5')"></span></td>
176+ </tr>
177+ </tbody>
178+ </table>
179+ </div>
180+
181+
182+
183+ </section>
184+ </section>
185+</div>
186+
187+<script>
188+ var m = new mine('mine');
189+ m.init();
190+</script>
191+</body>
192+</html>
193diff --git a/ts/parser.js b/ts/parser.js
194new file mode 100644
195index 0000000..f1f27a2
196--- /dev/null
197+++ b/ts/parser.js
198@@ -0,0 +1,965 @@
199+/* parser generated by jison 0.4.15 */
200+/*
201+ Returns a Parser object of the following structure:
202+
203+ Parser: {
204+ yy: {}
205+ }
206+
207+ Parser.prototype: {
208+ yy: {},
209+ trace: function(),
210+ symbols_: {associative list: name ==> number},
211+ terminals_: {associative list: number ==> name},
212+ productions_: [...],
213+ performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
214+ table: [...],
215+ defaultActions: {...},
216+ parseError: function(str, hash),
217+ parse: function(input),
218+
219+ lexer: {
220+ EOF: 1,
221+ parseError: function(str, hash),
222+ setInput: function(input),
223+ input: function(),
224+ unput: function(str),
225+ more: function(),
226+ less: function(n),
227+ pastInput: function(),
228+ upcomingInput: function(),
229+ showPosition: function(),
230+ test_match: function(regex_match_array, rule_index),
231+ next: function(),
232+ lex: function(),
233+ begin: function(condition),
234+ popState: function(),
235+ _currentRules: function(),
236+ topState: function(),
237+ pushState: function(condition),
238+
239+ options: {
240+ ranges: boolean (optional: true ==> token location info will include a .range[] member)
241+ flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
242+ backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
243+ },
244+
245+ performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
246+ rules: [...],
247+ conditions: {associative list: name ==> set},
248+ }
249+ }
250+
251+
252+ token location info (@$, _$, etc.): {
253+ first_line: n,
254+ last_line: n,
255+ first_column: n,
256+ last_column: n,
257+ range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
258+ }
259+
260+
261+ the parseError function receives a 'hash' object with these members for lexer and parser errors: {
262+ text: (matched text)
263+ token: (the produced terminal token, if any)
264+ line: (yylineno)
265+ }
266+ while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
267+ loc: (yylloc)
268+ expected: (string describing the set of expected tokens)
269+ recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
270+ }
271+ */
272+var Parser = (function(){
273+ var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,4],$V1=[1,5],$V2=[1,7],$V3=[1,10],$V4=[1,8],$V5=[1,9],$V6=[1,11],$V7=[1,16],$V8=[1,17],$V9=[1,14],$Va=[1,15],$Vb=[1,18],$Vc=[1,20],$Vd=[1,21],$Ve=[1,22],$Vf=[1,23],$Vg=[1,24],$Vh=[1,25],$Vi=[1,26],$Vj=[1,27],$Vk=[1,28],$Vl=[1,29],$Vm=[5,11,12,13,15,16,17,18,19,20,21,22,30,31],$Vn=[5,11,12,13,15,16,17,18,19,20,21,22,30,31,33],$Vo=[1,38],$Vp=[5,11,12,13,15,16,17,18,19,20,21,22,30,31,35],$Vq=[5,12,13,15,16,17,18,19,30,31],$Vr=[5,12,15,16,17,18,30,31],$Vs=[5,12,13,15,16,17,18,19,20,21,30,31],$Vt=[15,30,31],$Vu=[5,11,12,13,15,16,17,18,19,20,21,22,30,31,32,36];
274+ var parser = {trace: function trace() { },
275+ yy: {},
276+ symbols_: {"error":2,"expressions":3,"expression":4,"EOF":5,"variableSequence":6,"TIME_AMPM":7,"TIME_24":8,"number":9,"STRING":10,"&":11,"=":12,"+":13,"(":14,")":15,"<":16,">":17,"NOT":18,"-":19,"*":20,"/":21,"^":22,"FUNCTION":23,"expseq":24,"cell":25,"FIXEDCELL":26,":":27,"CELL":28,"ARRAY":29,";":30,",":31,"VARIABLE":32,"DECIMAL":33,"NUMBER":34,"%":35,"#":36,"!":37,"$accept":0,"$end":1},
277+ terminals_: {5:"EOF",7:"TIME_AMPM",8:"TIME_24",10:"STRING",11:"&",12:"=",13:"+",14:"(",15:")",16:"<",17:">",18:"NOT",19:"-",20:"*",21:"/",22:"^",23:"FUNCTION",26:"FIXEDCELL",27:":",28:"CELL",29:"ARRAY",30:";",31:",",32:"VARIABLE",33:"DECIMAL",34:"NUMBER",35:"%",36:"#",37:"!"},
278+ productions_: [0,[3,2],[4,1],[4,1],[4,1],[4,1],[4,1],[4,3],[4,3],[4,3],[4,3],[4,4],[4,4],[4,4],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,2],[4,2],[4,3],[4,4],[4,1],[4,1],[4,2],[25,1],[25,3],[25,1],[25,3],[24,1],[24,1],[24,3],[24,3],[6,1],[6,3],[9,1],[9,3],[9,2],[2,3],[2,4]],
279+ performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
280+ /* this == yyval */
281+
282+ var $0 = $$.length - 1;
283+ switch (yystate) {
284+ case 1:
285+
286+ return $$[$0-1];
287+
288+ break;
289+ case 2:
290+
291+ this.$ = yy.handler.helper.callVariable.call(this, $$[$0]);
292+
293+ break;
294+ case 3:
295+
296+ this.$ = yy.handler.time.call(yy.obj, $$[$0], true);
297+
298+ break;
299+ case 4:
300+
301+ this.$ = yy.handler.time.call(yy.obj, $$[$0]);
302+
303+ break;
304+ case 5:
305+
306+ this.$ = yy.handler.helper.number($$[$0]);
307+
308+ break;
309+ case 6:
310+
311+ this.$ = yy.handler.helper.string($$[$0]);
312+
313+ break;
314+ case 7:
315+
316+ this.$ = yy.handler.helper.specialMatch('&', $$[$0-2], $$[$0]);
317+
318+ break;
319+ case 8:
320+
321+ this.$ = yy.handler.helper.logicMatch('=', $$[$0-2], $$[$0]);
322+
323+ break;
324+ case 9:
325+
326+ this.$ = yy.handler.helper.mathMatch('+', $$[$0-2], $$[$0]);
327+
328+ break;
329+ case 10:
330+
331+ this.$ = yy.handler.helper.number($$[$0-1]);
332+
333+ break;
334+ case 11:
335+
336+ this.$ = yy.handler.helper.logicMatch('<=', $$[$0-3], $$[$0]);
337+
338+ break;
339+ case 12:
340+
341+ this.$ = yy.handler.helper.logicMatch('>=', $$[$0-3], $$[$0]);
342+
343+ break;
344+ case 13:
345+
346+ this.$ = yy.handler.helper.logicMatch('<>', $$[$0-3], $$[$0]);
347+
348+ break;
349+ case 14:
350+
351+ this.$ = yy.handler.helper.logicMatch('NOT', $$[$0-2], $$[$0]);
352+
353+ break;
354+ case 15:
355+
356+ this.$ = yy.handler.helper.logicMatch('>', $$[$0-2], $$[$0]);
357+
358+ break;
359+ case 16:
360+
361+ this.$ = yy.handler.helper.logicMatch('<', $$[$0-2], $$[$0]);
362+
363+ break;
364+ case 17:
365+
366+ this.$ = yy.handler.helper.mathMatch('-', $$[$0-2], $$[$0]);
367+
368+ break;
369+ case 18:
370+
371+ this.$ = yy.handler.helper.mathMatch('*', $$[$0-2], $$[$0]);
372+
373+ break;
374+ case 19:
375+
376+ this.$ = yy.handler.helper.mathMatch('/', $$[$0-2], $$[$0]);
377+
378+ break;
379+ case 20:
380+
381+ this.$ = yy.handler.helper.mathMatch('^', $$[$0-2], $$[$0]);
382+
383+ break;
384+ case 21:
385+
386+ var n1 = yy.handler.helper.numberInverted($$[$0]);
387+ this.$ = n1;
388+ if (isNaN(this.$)) {
389+ this.$ = 0;
390+ }
391+
392+ break;
393+ case 22:
394+
395+ var n1 = yy.handler.helper.number($$[$0]);
396+ this.$ = n1;
397+ if (isNaN(this.$)) {
398+ this.$ = 0;
399+ }
400+
401+ break;
402+ case 23:
403+
404+ this.$ = yy.handler.helper.callFunction.call(this, $$[$0-2], '');
405+
406+ break;
407+ case 24:
408+
409+ this.$ = yy.handler.helper.callFunction.call(this, $$[$0-3], $$[$0-1]);
410+
411+ break;
412+ case 28:
413+
414+ this.$ = yy.handler.helper.fixedCellValue.call(yy.obj, $$[$0]);
415+
416+ break;
417+ case 29:
418+
419+ this.$ = yy.handler.helper.fixedCellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
420+
421+ break;
422+ case 30:
423+
424+ this.$ = yy.handler.helper.cellValue.call(yy.obj, $$[$0]);
425+
426+ break;
427+ case 31:
428+
429+ this.$ = yy.handler.helper.cellRangeValue.call(yy.obj, $$[$0-2], $$[$0]);
430+
431+ break;
432+ case 32:
433+
434+ if (yy.handler.utils.isArray($$[$0])) {
435+ this.$ = $$[$0];
436+ } else {
437+ this.$ = [$$[$0]];
438+ }
439+
440+ break;
441+ case 33:
442+
443+ var result = [],
444+ arr = eval("[" + yytext + "]");
445+
446+ arr.forEach(function (item) {
447+ result.push(item);
448+ });
449+
450+ this.$ = result;
451+
452+ break;
453+ case 34: case 35:
454+
455+ $$[$0-2].push($$[$0]);
456+ this.$ = $$[$0-2];
457+
458+ break;
459+ case 36:
460+
461+ this.$ = [$$[$0]];
462+
463+ break;
464+ case 37:
465+
466+ this.$ = (yy.handler.utils.isArray($$[$0-2]) ? $$[$0-2] : [$$[$0-2]]);
467+ this.$.push($$[$0]);
468+
469+ break;
470+ case 38:
471+
472+ this.$ = $$[$0];
473+
474+ break;
475+ case 39:
476+
477+ this.$ = ($$[$0-2] + '.' + $$[$0]) * 1;
478+
479+ break;
480+ case 40:
481+
482+ this.$ = $$[$0-1] * 0.01;
483+
484+ break;
485+ case 41: case 42:
486+
487+ this.$ = $$[$0-2] + $$[$0-1] + $$[$0];
488+
489+ break;
490+ }
491+ },
492+ table: [{2:13,3:1,4:2,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{1:[3]},{5:[1,19],11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl},o($Vm,[2,2],{33:[1,30]}),o($Vm,[2,3]),o($Vm,[2,4]),o($Vm,[2,5],{35:[1,31]}),o($Vm,[2,6]),{2:13,4:32,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:33,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:34,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{14:[1,35]},o($Vm,[2,25]),o($Vm,[2,26],{2:36,32:[1,37],36:$Vb}),o($Vn,[2,36],{36:$Vo}),o($Vp,[2,38],{33:[1,39]}),o($Vm,[2,28],{27:[1,40]}),o($Vm,[2,30],{27:[1,41]}),{32:[1,42]},{1:[2,1]},{2:13,4:43,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:44,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:45,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:48,6:3,7:$V0,8:$V1,9:6,10:$V2,12:[1,46],13:$V3,14:$V4,17:[1,47],19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:50,6:3,7:$V0,8:$V1,9:6,10:$V2,12:[1,49],13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:51,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:52,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:53,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:54,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:55,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{32:[1,56]},o($Vp,[2,40]),{11:$Vc,12:$Vd,13:$Ve,15:[1,57],16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl},o($Vq,[2,21],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),o($Vq,[2,22],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),{2:13,4:60,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,15:[1,58],19:$V5,23:$V6,24:59,25:12,26:$V7,28:$V8,29:[1,61],32:$V9,34:$Va,36:$Vb},o($Vm,[2,27]),{36:$Vo},{32:[1,62]},{34:[1,63]},{26:[1,64]},{28:[1,65]},{37:[1,66]},o($Vm,[2,7]),o([5,12,15,30,31],[2,8],{11:$Vc,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vq,[2,9],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),{2:13,4:67,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:68,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},o($Vr,[2,16],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),{2:13,4:69,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},o($Vr,[2,15],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o([5,12,15,18,30,31],[2,14],{11:$Vc,13:$Ve,16:$Vf,17:$Vg,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vq,[2,17],{11:$Vc,20:$Vj,21:$Vk,22:$Vl}),o($Vs,[2,18],{11:$Vc,22:$Vl}),o($Vs,[2,19],{11:$Vc,22:$Vl}),o([5,12,13,15,16,17,18,19,20,21,22,30,31],[2,20],{11:$Vc}),o($Vn,[2,37]),o($Vm,[2,10]),o($Vm,[2,23]),{15:[1,70],30:[1,71],31:[1,72]},o($Vt,[2,32],{11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vt,[2,33]),{37:[1,73]},o($Vp,[2,39]),o($Vm,[2,29]),o($Vm,[2,31]),o($Vu,[2,41]),o($Vr,[2,11],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vr,[2,13],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vr,[2,12],{11:$Vc,13:$Ve,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vm,[2,24]),{2:13,4:74,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},{2:13,4:75,6:3,7:$V0,8:$V1,9:6,10:$V2,13:$V3,14:$V4,19:$V5,23:$V6,25:12,26:$V7,28:$V8,32:$V9,34:$Va,36:$Vb},o($Vu,[2,42]),o($Vt,[2,34],{11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl}),o($Vt,[2,35],{11:$Vc,12:$Vd,13:$Ve,16:$Vf,17:$Vg,18:$Vh,19:$Vi,20:$Vj,21:$Vk,22:$Vl})],
493+ defaultActions: {19:[2,1]},
494+ parseError: function parseError(str, hash) {
495+ if (hash.recoverable) {
496+ this.trace(str);
497+ } else {
498+ throw new Error(str);
499+ }
500+ },
501+ parse: function parse(input) {
502+ var self = this,
503+ stack = [0],
504+ tstack = [], // token stack
505+ vstack = [null], // semantic value stack
506+ lstack = [], // location stack
507+ table = this.table,
508+ yytext = '',
509+ yylineno = 0,
510+ yyleng = 0,
511+ recovering = 0,
512+ TERROR = 2,
513+ EOF = 1;
514+
515+ var args = lstack.slice.call(arguments, 1);
516+
517+ //this.reductionCount = this.shiftCount = 0;
518+
519+ var lexer = Object.create(this.lexer);
520+ var sharedState = { yy: {} };
521+ // copy state
522+ for (var k in this.yy) {
523+ if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
524+ sharedState.yy[k] = this.yy[k];
525+ }
526+ }
527+
528+ lexer.setInput(input, sharedState.yy);
529+ sharedState.yy.lexer = lexer;
530+ sharedState.yy.parser = this;
531+ if (typeof lexer.yylloc == 'undefined') {
532+ lexer.yylloc = {};
533+ }
534+ var yyloc = lexer.yylloc;
535+ lstack.push(yyloc);
536+
537+ var ranges = lexer.options && lexer.options.ranges;
538+
539+ if (typeof sharedState.yy.parseError === 'function') {
540+ this.parseError = sharedState.yy.parseError;
541+ } else {
542+ this.parseError = Object.getPrototypeOf(this).parseError;
543+ }
544+
545+ function popStack (n) {
546+ stack.length = stack.length - 2 * n;
547+ vstack.length = vstack.length - n;
548+ lstack.length = lstack.length - n;
549+ }
550+
551+ _token_stack:
552+ function lex() {
553+ var token;
554+ token = lexer.lex() || EOF;
555+ // if token isn't its numeric value, convert
556+ if (typeof token !== 'number') {
557+ token = self.symbols_[token] || token;
558+ }
559+ return token;
560+ }
561+
562+ var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
563+ while (true) {
564+ // retreive state number from top of stack
565+ state = stack[stack.length - 1];
566+
567+ // use default actions if available
568+ if (this.defaultActions[state]) {
569+ action = this.defaultActions[state];
570+ } else {
571+ if (symbol === null || typeof symbol == 'undefined') {
572+ symbol = lex();
573+ }
574+ // read action for current state and first input
575+ action = table[state] && table[state][symbol];
576+ }
577+
578+ _handle_error:
579+ // handle parse error
580+ if (typeof action === 'undefined' || !action.length || !action[0]) {
581+ var error_rule_depth;
582+ var errStr = '';
583+
584+ // Return the rule stack depth where the nearest error rule can be found.
585+ // Return FALSE when no error recovery rule was found.
586+ function locateNearestErrorRecoveryRule(state) {
587+ var stack_probe = stack.length - 1;
588+ var depth = 0;
589+
590+ // try to recover from error
591+ for(;;) {
592+ // check for error recovery rule in this state
593+ if ((TERROR.toString()) in table[state]) {
594+ return depth;
595+ }
596+ if (state === 0 || stack_probe < 2) {
597+ return false; // No suitable error recovery rule available.
598+ }
599+ stack_probe -= 2; // popStack(1): [symbol, action]
600+ state = stack[stack_probe];
601+ ++depth;
602+ }
603+ }
604+
605+ if (!recovering) {
606+ // first see if there's any chance at hitting an error recovery rule:
607+ error_rule_depth = locateNearestErrorRecoveryRule(state);
608+
609+ // Report error
610+ expected = [];
611+ for (p in table[state]) {
612+ if (this.terminals_[p] && p > TERROR) {
613+ expected.push("'"+this.terminals_[p]+"'");
614+ }
615+ }
616+ if (lexer.showPosition) {
617+ errStr = 'Parse error on line '+(yylineno+1)+":\n"+lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol)+ "'";
618+ } else {
619+ errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
620+ (symbol == EOF ? "end of input" :
621+ ("'"+(this.terminals_[symbol] || symbol)+"'"));
622+ }
623+ this.parseError(errStr, {
624+ text: lexer.match,
625+ token: this.terminals_[symbol] || symbol,
626+ line: lexer.yylineno,
627+ loc: yyloc,
628+ expected: expected,
629+ recoverable: (error_rule_depth !== false)
630+ });
631+ } else if (preErrorSymbol !== EOF) {
632+ error_rule_depth = locateNearestErrorRecoveryRule(state);
633+ }
634+
635+ // just recovered from another error
636+ if (recovering == 3) {
637+ if (symbol === EOF || preErrorSymbol === EOF) {
638+ throw new Error(errStr || 'Parsing halted while starting to recover from another error.');
639+ }
640+
641+ // discard current lookahead and grab another
642+ yyleng = lexer.yyleng;
643+ yytext = lexer.yytext;
644+ yylineno = lexer.yylineno;
645+ yyloc = lexer.yylloc;
646+ symbol = lex();
647+ }
648+
649+ // try to recover from error
650+ if (error_rule_depth === false) {
651+ throw new Error(errStr || 'Parsing halted. No suitable error recovery rule available.');
652+ }
653+ popStack(error_rule_depth);
654+
655+ preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token
656+ symbol = TERROR; // insert generic error symbol as new lookahead
657+ state = stack[stack.length-1];
658+ action = table[state] && table[state][TERROR];
659+ recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
660+ }
661+
662+ // this shouldn't happen, unless resolve defaults are off
663+ if (action[0] instanceof Array && action.length > 1) {
664+ throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
665+ }
666+
667+ switch (action[0]) {
668+ case 1: // shift
669+ //this.shiftCount++;
670+
671+ stack.push(symbol);
672+ vstack.push(lexer.yytext);
673+ lstack.push(lexer.yylloc);
674+ stack.push(action[1]); // push state
675+ symbol = null;
676+ if (!preErrorSymbol) { // normal execution/no error
677+ yyleng = lexer.yyleng;
678+ yytext = lexer.yytext;
679+ yylineno = lexer.yylineno;
680+ yyloc = lexer.yylloc;
681+ if (recovering > 0) {
682+ recovering--;
683+ }
684+ } else {
685+ // error just occurred, resume old lookahead f/ before error
686+ symbol = preErrorSymbol;
687+ preErrorSymbol = null;
688+ }
689+ break;
690+
691+ case 2:
692+ // reduce
693+ //this.reductionCount++;
694+
695+ len = this.productions_[action[1]][1];
696+
697+ // perform semantic action
698+ yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
699+ // default location, uses first token for firsts, last for lasts
700+ yyval._$ = {
701+ first_line: lstack[lstack.length-(len||1)].first_line,
702+ last_line: lstack[lstack.length-1].last_line,
703+ first_column: lstack[lstack.length-(len||1)].first_column,
704+ last_column: lstack[lstack.length-1].last_column
705+ };
706+ if (ranges) {
707+ yyval._$.range = [lstack[lstack.length-(len||1)].range[0], lstack[lstack.length-1].range[1]];
708+ }
709+ r = this.performAction.apply(yyval, [yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack].concat(args));
710+
711+ if (typeof r !== 'undefined') {
712+ return r;
713+ }
714+
715+ // pop off stack
716+ if (len) {
717+ stack = stack.slice(0,-1*len*2);
718+ vstack = vstack.slice(0, -1*len);
719+ lstack = lstack.slice(0, -1*len);
720+ }
721+
722+ stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
723+ vstack.push(yyval.$);
724+ lstack.push(yyval._$);
725+ // goto new state = table[STATE][NONTERMINAL]
726+ newState = table[stack[stack.length-2]][stack[stack.length-1]];
727+ stack.push(newState);
728+ break;
729+
730+ case 3:
731+ // accept
732+ return true;
733+ }
734+
735+ }
736+
737+ return true;
738+ }};
739+
740+ /* generated by jison-lex 0.3.4 */
741+ var lexer = (function(){
742+ var lexer = ({
743+
744+ EOF:1,
745+
746+ parseError:function parseError(str, hash) {
747+ if (this.yy.parser) {
748+ this.yy.parser.parseError(str, hash);
749+ } else {
750+ throw new Error(str);
751+ }
752+ },
753+
754+// resets the lexer, sets new input
755+ setInput:function (input, yy) {
756+ this.yy = yy || this.yy || {};
757+ this._input = input;
758+ this._more = this._backtrack = this.done = false;
759+ this.yylineno = this.yyleng = 0;
760+ this.yytext = this.matched = this.match = '';
761+ this.conditionStack = ['INITIAL'];
762+ this.yylloc = {
763+ first_line: 1,
764+ first_column: 0,
765+ last_line: 1,
766+ last_column: 0
767+ };
768+ if (this.options.ranges) {
769+ this.yylloc.range = [0,0];
770+ }
771+ this.offset = 0;
772+ return this;
773+ },
774+
775+// consumes and returns one char from the input
776+ input:function () {
777+ var ch = this._input[0];
778+ this.yytext += ch;
779+ this.yyleng++;
780+ this.offset++;
781+ this.match += ch;
782+ this.matched += ch;
783+ var lines = ch.match(/(?:\r\n?|\n).*/g);
784+ if (lines) {
785+ this.yylineno++;
786+ this.yylloc.last_line++;
787+ } else {
788+ this.yylloc.last_column++;
789+ }
790+ if (this.options.ranges) {
791+ this.yylloc.range[1]++;
792+ }
793+
794+ this._input = this._input.slice(1);
795+ return ch;
796+ },
797+
798+// unshifts one char (or a string) into the input
799+ unput:function (ch) {
800+ var len = ch.length;
801+ var lines = ch.split(/(?:\r\n?|\n)/g);
802+
803+ this._input = ch + this._input;
804+ this.yytext = this.yytext.substr(0, this.yytext.length - len);
805+ //this.yyleng -= len;
806+ this.offset -= len;
807+ var oldLines = this.match.split(/(?:\r\n?|\n)/g);
808+ this.match = this.match.substr(0, this.match.length - 1);
809+ this.matched = this.matched.substr(0, this.matched.length - 1);
810+
811+ if (lines.length - 1) {
812+ this.yylineno -= lines.length - 1;
813+ }
814+ var r = this.yylloc.range;
815+
816+ this.yylloc = {
817+ first_line: this.yylloc.first_line,
818+ last_line: this.yylineno + 1,
819+ first_column: this.yylloc.first_column,
820+ last_column: lines ?
821+ (lines.length === oldLines.length ? this.yylloc.first_column : 0)
822+ + oldLines[oldLines.length - lines.length].length - lines[0].length :
823+ this.yylloc.first_column - len
824+ };
825+
826+ if (this.options.ranges) {
827+ this.yylloc.range = [r[0], r[0] + this.yyleng - len];
828+ }
829+ this.yyleng = this.yytext.length;
830+ return this;
831+ },
832+
833+// When called from action, caches matched text and appends it on next action
834+ more:function () {
835+ this._more = true;
836+ return this;
837+ },
838+
839+// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
840+ reject:function () {
841+ if (this.options.backtrack_lexer) {
842+ this._backtrack = true;
843+ } else {
844+ return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
845+ text: "",
846+ token: null,
847+ line: this.yylineno
848+ });
849+
850+ }
851+ return this;
852+ },
853+
854+// retain first n characters of the match
855+ less:function (n) {
856+ this.unput(this.match.slice(n));
857+ },
858+
859+// displays already matched input, i.e. for error messages
860+ pastInput:function () {
861+ var past = this.matched.substr(0, this.matched.length - this.match.length);
862+ return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
863+ },
864+
865+// displays upcoming input, i.e. for error messages
866+ upcomingInput:function () {
867+ var next = this.match;
868+ if (next.length < 20) {
869+ next += this._input.substr(0, 20-next.length);
870+ }
871+ return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
872+ },
873+
874+// displays the character position where the lexing error occurred, i.e. for error messages
875+ showPosition:function () {
876+ var pre = this.pastInput();
877+ var c = new Array(pre.length + 1).join("-");
878+ return pre + this.upcomingInput() + "\n" + c + "^";
879+ },
880+
881+// test the lexed token: return FALSE when not a match, otherwise return token
882+ test_match:function (match, indexed_rule) {
883+ var token,
884+ lines,
885+ backup;
886+
887+ if (this.options.backtrack_lexer) {
888+ // save context
889+ backup = {
890+ yylineno: this.yylineno,
891+ yylloc: {
892+ first_line: this.yylloc.first_line,
893+ last_line: this.last_line,
894+ first_column: this.yylloc.first_column,
895+ last_column: this.yylloc.last_column
896+ },
897+ yytext: this.yytext,
898+ match: this.match,
899+ matches: this.matches,
900+ matched: this.matched,
901+ yyleng: this.yyleng,
902+ offset: this.offset,
903+ _more: this._more,
904+ _input: this._input,
905+ yy: this.yy,
906+ conditionStack: this.conditionStack.slice(0),
907+ done: this.done
908+ };
909+ if (this.options.ranges) {
910+ backup.yylloc.range = this.yylloc.range.slice(0);
911+ }
912+ }
913+
914+ lines = match[0].match(/(?:\r\n?|\n).*/g);
915+ if (lines) {
916+ this.yylineno += lines.length;
917+ }
918+ this.yylloc = {
919+ first_line: this.yylloc.last_line,
920+ last_line: this.yylineno + 1,
921+ first_column: this.yylloc.last_column,
922+ last_column: lines ?
923+ lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
924+ this.yylloc.last_column + match[0].length
925+ };
926+ this.yytext += match[0];
927+ this.match += match[0];
928+ this.matches = match;
929+ this.yyleng = this.yytext.length;
930+ if (this.options.ranges) {
931+ this.yylloc.range = [this.offset, this.offset += this.yyleng];
932+ }
933+ this._more = false;
934+ this._backtrack = false;
935+ this._input = this._input.slice(match[0].length);
936+ this.matched += match[0];
937+ token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
938+ if (this.done && this._input) {
939+ this.done = false;
940+ }
941+ if (token) {
942+ return token;
943+ } else if (this._backtrack) {
944+ // recover context
945+ for (var k in backup) {
946+ this[k] = backup[k];
947+ }
948+ return false; // rule action called reject() implying the next rule should be tested instead.
949+ }
950+ return false;
951+ },
952+
953+// return next match in input
954+ next:function () {
955+ if (this.done) {
956+ return this.EOF;
957+ }
958+ if (!this._input) {
959+ this.done = true;
960+ }
961+
962+ var token,
963+ match,
964+ tempMatch,
965+ index;
966+ if (!this._more) {
967+ this.yytext = '';
968+ this.match = '';
969+ }
970+ var rules = this._currentRules();
971+ for (var i = 0; i < rules.length; i++) {
972+ tempMatch = this._input.match(this.rules[rules[i]]);
973+ if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
974+ match = tempMatch;
975+ index = i;
976+ if (this.options.backtrack_lexer) {
977+ token = this.test_match(tempMatch, rules[i]);
978+ if (token !== false) {
979+ return token;
980+ } else if (this._backtrack) {
981+ match = false;
982+ continue; // rule action called reject() implying a rule MISmatch.
983+ } else {
984+ // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
985+ return false;
986+ }
987+ } else if (!this.options.flex) {
988+ break;
989+ }
990+ }
991+ }
992+ if (match) {
993+ token = this.test_match(match, rules[index]);
994+ if (token !== false) {
995+ return token;
996+ }
997+ // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
998+ return false;
999+ }
1000+ if (this._input === "") {
1001+ return this.EOF;
1002+ } else {
1003+ return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
1004+ text: "",
1005+ token: null,
1006+ line: this.yylineno
1007+ });
1008+ }
1009+ },
1010+
1011+// return next match that has a token
1012+ lex:function lex() {
1013+ var r = this.next();
1014+ if (r) {
1015+ return r;
1016+ } else {
1017+ return this.lex();
1018+ }
1019+ },
1020+
1021+// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
1022+ begin:function begin(condition) {
1023+ this.conditionStack.push(condition);
1024+ },
1025+
1026+// pop the previously active lexer condition state off the condition stack
1027+ popState:function popState() {
1028+ var n = this.conditionStack.length - 1;
1029+ if (n > 0) {
1030+ return this.conditionStack.pop();
1031+ } else {
1032+ return this.conditionStack[0];
1033+ }
1034+ },
1035+
1036+// produce the lexer rule set which is active for the currently active lexer condition state
1037+ _currentRules:function _currentRules() {
1038+ if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
1039+ return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
1040+ } else {
1041+ return this.conditions["INITIAL"].rules;
1042+ }
1043+ },
1044+
1045+// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
1046+ topState:function topState(n) {
1047+ n = this.conditionStack.length - 1 - Math.abs(n || 0);
1048+ if (n >= 0) {
1049+ return this.conditionStack[n];
1050+ } else {
1051+ return "INITIAL";
1052+ }
1053+ },
1054+
1055+// alias for begin(condition)
1056+ pushState:function pushState(condition) {
1057+ this.begin(condition);
1058+ },
1059+
1060+// return the number of states currently on the stack
1061+ stateStackSize:function stateStackSize() {
1062+ return this.conditionStack.length;
1063+ },
1064+ options: {},
1065+ performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
1066+ var YYSTATE=YY_START;
1067+ switch($avoiding_name_collisions) {
1068+ case 0:/* skip whitespace */
1069+ break;
1070+ case 1:return 10;
1071+ break;
1072+ case 2:return 10;
1073+ break;
1074+ case 3:return 23;
1075+ break;
1076+ case 4:return 7;
1077+ break;
1078+ case 5:return 8;
1079+ break;
1080+ case 6:
1081+ //if (yy.obj.type == 'cell') return 26;
1082+ //return 32;
1083+ return 26
1084+
1085+ break;
1086+ case 7:
1087+ //if (yy.obj.type == 'cell') return 28;
1088+ //return 32;
1089+ return 28;
1090+
1091+ break;
1092+ case 8:return 23;
1093+ break;
1094+ case 9:return 32;
1095+ break;
1096+ case 10:return 32;
1097+ break;
1098+ case 11:return 34;
1099+ break;
1100+ case 12:return 29;
1101+ break;
1102+ case 13:/* skip whitespace */
1103+ break;
1104+ case 14:return 11;
1105+ break;
1106+ case 15:return ' ';
1107+ break;
1108+ case 16:return 33;
1109+ break;
1110+ case 17:return 27;
1111+ break;
1112+ case 18:return 30;
1113+ break;
1114+ case 19:return 31;
1115+ break;
1116+ case 20:return 20;
1117+ break;
1118+ case 21:return 21;
1119+ break;
1120+ case 22:return 19;
1121+ break;
1122+ case 23:return 13;
1123+ break;
1124+ case 24:return 22;
1125+ break;
1126+ case 25:return 14;
1127+ break;
1128+ case 26:return 15;
1129+ break;
1130+ case 27:return 17;
1131+ break;
1132+ case 28:return 16;
1133+ break;
1134+ case 29:return 18;
1135+ break;
1136+ case 30:return '"';
1137+ break;
1138+ case 31:return "'";
1139+ break;
1140+ case 32:return "!";
1141+ break;
1142+ case 33:return 12;
1143+ break;
1144+ case 34:return 35;
1145+ break;
1146+ case 35:return 36;
1147+ break;
1148+ case 36:return 5;
1149+ break;
1150+ }
1151+ },
1152+ rules: [/^(?:\s+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:[A-Za-z]{1,}[A-Za-z_0-9]+(?=[(]))/,/^(?:([0]?[1-9]|1[0-2])[:][0-5][0-9]([:][0-5][0-9])?[ ]?(AM|am|aM|Am|PM|pm|pM|Pm))/,/^(?:([0]?[0-9]|1[0-9]|2[0-3])[:][0-5][0-9]([:][0-5][0-9])?)/,/^(?:\$[A-Za-z]+\$[0-9]+)/,/^(?:[A-Za-z]+[0-9]+)/,/^(?:[A-Za-z]+(?=[(]))/,/^(?:[A-Za-z]{1,}[A-Za-z_0-9]+)/,/^(?:[A-Za-z_]+)/,/^(?:[0-9]+)/,/^(?:\[(.*)?\])/,/^(?:\$)/,/^(?:&)/,/^(?: )/,/^(?:[.])/,/^(?::)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\/)/,/^(?:-)/,/^(?:\+)/,/^(?:\^)/,/^(?:\()/,/^(?:\))/,/^(?:>)/,/^(?:<)/,/^(?:NOT\b)/,/^(?:")/,/^(?:')/,/^(?:!)/,/^(?:=)/,/^(?:%)/,/^(?:[#])/,/^(?:$)/],
1153+ conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],"inclusive":true}}
1154+ });
1155+ return lexer;
1156+ })();
1157+ parser.lexer = lexer;
1158+ function Parser () {
1159+ this.yy = {};
1160+ }
1161+ Parser.prototype = parser;parser.Parser = Parser;
1162+ return new Parser;
1163+})();
1164\ No newline at end of file
1165diff --git a/ts/sheet.js b/ts/sheet.js
1166new file mode 100644
1167index 0000000..d6e9408
1168--- /dev/null
1169+++ b/ts/sheet.js
1170@@ -0,0 +1,535 @@
1171+var mine = (function () {
1172+ 'use strict';
1173+ var instance = this;
1174+ var parser = {
1175+ setObj: function (thing) {
1176+ },
1177+ parse: function (thing) {
1178+ }
1179+ };
1180+ var FormulaParser = function (handler) {
1181+ var formulaLexer = function () { };
1182+ formulaLexer.prototype = Parser.lexer;
1183+ var formulaParser = function () {
1184+ this.lexer = new formulaLexer();
1185+ this.yy = {};
1186+ };
1187+ formulaParser.prototype = Parser;
1188+ var newParser = new formulaParser;
1189+ newParser.setObj = function (obj) {
1190+ newParser.yy.obj = obj;
1191+ };
1192+ newParser.yy.parseError = function (str, hash) {
1193+ throw {
1194+ name: 'Parser error',
1195+ message: str,
1196+ prop: hash
1197+ };
1198+ };
1199+ newParser.yy.handler = handler;
1200+ return newParser;
1201+ };
1202+ var Exception = {
1203+ errors: [
1204+ { type: 'NULL', output: '#NULL' },
1205+ { type: 'DIV_ZERO', output: '#DIV/0!' },
1206+ { type: 'VALUE', output: '#VALUE!' },
1207+ { type: 'REF', output: '#REF!' },
1208+ { type: 'NAME', output: '#NAME?' },
1209+ { type: 'NUM', output: '#NUM!' },
1210+ { type: 'NOT_AVAILABLE', output: '#N/A!' },
1211+ { type: 'ERROR', output: '#ERROR' }
1212+ ],
1213+ get: function (type) {
1214+ var error = Exception.errors.filter(function (item) {
1215+ return item.type === type || item.output === type;
1216+ })[0];
1217+ return error ? error.output : null;
1218+ }
1219+ };
1220+ var Matrix = function () {
1221+ // var item = {
1222+ // id: '',
1223+ // formula: '',
1224+ // value: '',
1225+ // error: '',
1226+ // deps: [],
1227+ // formulaEdit: false
1228+ // };
1229+ this.data = [];
1230+ this.getItem = function (id) {
1231+ return instance.matrix.data.filter(function (item) {
1232+ return item.id === id;
1233+ })[0];
1234+ };
1235+ this.removeItem = function (id) {
1236+ instance.matrix.data = instance.matrix.data.filter(function (item) {
1237+ return item.id !== id;
1238+ });
1239+ };
1240+ this.updateItem = function (item, props) {
1241+ if (instance.utils.isString(item)) {
1242+ item = instance.matrix.getItem(item);
1243+ }
1244+ if (item && props) {
1245+ for (var p in props) {
1246+ if (item[p] && instance.utils.isArray(item[p])) {
1247+ if (instance.utils.isArray(props[p])) {
1248+ props[p].forEach(function (i) {
1249+ if (item[p].indexOf(i) === -1) {
1250+ item[p].push(i);
1251+ }
1252+ });
1253+ }
1254+ else {
1255+ if (item[p].indexOf(props[p]) === -1) {
1256+ item[p].push(props[p]);
1257+ }
1258+ }
1259+ }
1260+ else {
1261+ item[p] = props[p];
1262+ }
1263+ }
1264+ }
1265+ };
1266+ this.addItem = function (item) {
1267+ var cellId = item.id, coords = instance.utils.cellCoords(cellId);
1268+ item.row = coords.row;
1269+ item.col = coords.col;
1270+ var cellExist = instance.matrix.data.filter(function (cell) {
1271+ return cell.id === cellId;
1272+ })[0];
1273+ if (!cellExist) {
1274+ instance.matrix.data.push(item);
1275+ }
1276+ else {
1277+ instance.matrix.updateItem(cellExist, item);
1278+ }
1279+ return instance.matrix.getItem(cellId);
1280+ };
1281+ this.updateCellItem = function (id, props) {
1282+ var item = instance.matrix.getItem(id);
1283+ instance.matrix.updateItem(item, props);
1284+ };
1285+ this.getDependencies = function (id) {
1286+ var getDependencies = function (id) {
1287+ var filtered = instance.matrix.data.filter(function (cell) {
1288+ if (cell.deps) {
1289+ return cell.deps.indexOf(id) > -1;
1290+ }
1291+ });
1292+ var deps = [];
1293+ filtered.forEach(function (cell) {
1294+ if (deps.indexOf(cell.id) === -1) {
1295+ deps.push(cell.id);
1296+ }
1297+ });
1298+ return deps;
1299+ };
1300+ var allDependencies = [];
1301+ var getTotalDependencies = function (id) {
1302+ var deps = getDependencies(id);
1303+ if (deps.length) {
1304+ deps.forEach(function (refId) {
1305+ if (allDependencies.indexOf(refId) === -1) {
1306+ allDependencies.push(refId);
1307+ var item = instance.matrix.getItem(refId);
1308+ if (item.deps.length) {
1309+ getTotalDependencies(refId);
1310+ }
1311+ }
1312+ });
1313+ }
1314+ };
1315+ getTotalDependencies(id);
1316+ return allDependencies;
1317+ };
1318+ this.getCellDependencies = function (cell) {
1319+ return instance.matrix.getDependencies(cell.id);
1320+ };
1321+ var recalculateCellDependencies = function (cell) {
1322+ var allDependencies = instance.matrix.getCellDependencies(cell);
1323+ allDependencies.forEach(function (refId) {
1324+ var currentCell = instance.matrix.getItem(refId);
1325+ if (currentCell && currentCell.formula) {
1326+ calculateCellFormula(currentCell.formula, currentCell.id);
1327+ }
1328+ });
1329+ };
1330+ var calculateCellFormula = function (formula, id) {
1331+ // to avoid double translate formulas, update item data in parser
1332+ var parsed = parse(formula, id), value = parsed.result, error = parsed.error;
1333+ instance.matrix.updateCellItem(id, { value: value, error: error });
1334+ return parsed;
1335+ };
1336+ var registerCellInMatrix = function (cell) {
1337+ instance.matrix.addItem(cell);
1338+ calculateCellFormula(cell.formula, cell.id);
1339+ };
1340+ this.scan = function () {
1341+ var input = [
1342+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
1343+ [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
1344+ [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
1345+ [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
1346+ [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
1347+ ];
1348+ for (var y = 0; y < input.length; y++) {
1349+ for (var x = 0; x < input[0].length; x++) {
1350+ // set the cell here
1351+ var id = utils.XYtoA1(x, y);
1352+ var cell = {
1353+ id: id,
1354+ formula: input[y][x].toString()
1355+ };
1356+ registerCellInMatrix(cell);
1357+ recalculateCellDependencies(cell);
1358+ }
1359+ }
1360+ console.log(this.data);
1361+ };
1362+ };
1363+ var utils = {
1364+ isArray: function (value) {
1365+ return Object.prototype.toString.call(value) === '[object Array]';
1366+ },
1367+ isNumber: function (value) {
1368+ return Object.prototype.toString.call(value) === '[object Number]';
1369+ },
1370+ isString: function (value) {
1371+ return Object.prototype.toString.call(value) === '[object String]';
1372+ },
1373+ isFunction: function (value) {
1374+ return Object.prototype.toString.call(value) === '[object Function]';
1375+ },
1376+ isUndefined: function (value) {
1377+ return Object.prototype.toString.call(value) === '[object Undefined]';
1378+ },
1379+ isNull: function (value) {
1380+ return Object.prototype.toString.call(value) === '[object Null]';
1381+ },
1382+ isSet: function (value) {
1383+ return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
1384+ },
1385+ getCellAlphaNum: function (cell) {
1386+ var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
1387+ return {
1388+ alpha: alpha,
1389+ num: parseInt(num[0], 10)
1390+ };
1391+ },
1392+ toNum: function (chr) {
1393+ chr = instance.utils.clearFormula(chr);
1394+ var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
1395+ for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
1396+ result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
1397+ }
1398+ if (result) {
1399+ --result;
1400+ }
1401+ return result;
1402+ },
1403+ toChar: function (num) {
1404+ var s = '';
1405+ while (num >= 0) {
1406+ s = String.fromCharCode(num % 26 + 97) + s;
1407+ num = Math.floor(num / 26) - 1;
1408+ }
1409+ return s.toUpperCase();
1410+ },
1411+ XYtoA1: function (x, y) {
1412+ function numberToLetters(num) {
1413+ var mod = num % 26, pow = num / 26 | 0, out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
1414+ return pow ? numberToLetters(pow) + out : out;
1415+ }
1416+ return numberToLetters(x + 1) + (y + 1).toString();
1417+ },
1418+ cellCoords: function (cell) {
1419+ var num = cell.match(/\d+$/), alpha = cell.replace(num, '');
1420+ return {
1421+ row: parseInt(num[0], 10) - 1,
1422+ col: instance.utils.toNum(alpha)
1423+ };
1424+ },
1425+ clearFormula: function (formula) {
1426+ return formula.replace(/\$/g, '');
1427+ },
1428+ translateCellCoords: function (coords) {
1429+ return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
1430+ },
1431+ iterateCells: function (startCell, endCell, callback) {
1432+ var result = {
1433+ index: [],
1434+ value: [] // list of cell value
1435+ };
1436+ var cols = {
1437+ start: 0,
1438+ end: 0
1439+ };
1440+ if (endCell.col >= startCell.col) {
1441+ cols = {
1442+ start: startCell.col,
1443+ end: endCell.col
1444+ };
1445+ }
1446+ else {
1447+ cols = {
1448+ start: endCell.col,
1449+ end: startCell.col
1450+ };
1451+ }
1452+ var rows = {
1453+ start: 0,
1454+ end: 0
1455+ };
1456+ if (endCell.row >= startCell.row) {
1457+ rows = {
1458+ start: startCell.row,
1459+ end: endCell.row
1460+ };
1461+ }
1462+ else {
1463+ rows = {
1464+ start: endCell.row,
1465+ end: startCell.row
1466+ };
1467+ }
1468+ for (var column = cols.start; column <= cols.end; column++) {
1469+ for (var row = rows.start; row <= rows.end; row++) {
1470+ var cellIndex = instance.utils.toChar(column) + (row + 1), cellValue = instance.helper.cellValue.call(this, cellIndex);
1471+ result.index.push(cellIndex);
1472+ result.value.push(cellValue);
1473+ }
1474+ }
1475+ if (instance.utils.isFunction(callback)) {
1476+ return callback.apply(callback, [result]);
1477+ }
1478+ else {
1479+ return result;
1480+ }
1481+ },
1482+ sort: function (rev) {
1483+ return function (a, b) {
1484+ return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
1485+ };
1486+ }
1487+ };
1488+ var helper = {
1489+ SUPPORTED_FORMULAS: [
1490+ 'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
1491+ 'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
1492+ 'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
1493+ 'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
1494+ 'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
1495+ 'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
1496+ 'IF', 'INT', 'ISEVEN', 'ISODD',
1497+ 'LN', 'LOG', 'LOG10',
1498+ 'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
1499+ 'NOT',
1500+ 'ODD', 'OR',
1501+ 'PI', 'POWER',
1502+ 'ROUND', 'ROUNDDOWN', 'ROUNDUP',
1503+ 'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
1504+ 'TAN', 'TANH', 'TRUE', 'TRUNC',
1505+ 'XOR'
1506+ ],
1507+ number: function (num) {
1508+ switch (typeof num) {
1509+ case 'number':
1510+ return num;
1511+ case 'string':
1512+ if (!isNaN(num)) {
1513+ return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
1514+ }
1515+ }
1516+ return num;
1517+ },
1518+ string: function (str) {
1519+ return str.substring(1, str.length - 1);
1520+ },
1521+ numberInverted: function (num) {
1522+ return this.number(num) * (-1);
1523+ },
1524+ specialMatch: function (type, exp1, exp2) {
1525+ var result;
1526+ switch (type) {
1527+ case '&':
1528+ result = exp1.toString() + exp2.toString();
1529+ break;
1530+ }
1531+ return result;
1532+ },
1533+ logicMatch: function (type, exp1, exp2) {
1534+ var result;
1535+ switch (type) {
1536+ case '=':
1537+ result = (exp1 === exp2);
1538+ break;
1539+ case '>':
1540+ result = (exp1 > exp2);
1541+ break;
1542+ case '<':
1543+ result = (exp1 < exp2);
1544+ break;
1545+ case '>=':
1546+ result = (exp1 >= exp2);
1547+ break;
1548+ case '<=':
1549+ result = (exp1 === exp2);
1550+ break;
1551+ case '<>':
1552+ result = (exp1 != exp2);
1553+ break;
1554+ case 'NOT':
1555+ result = (exp1 != exp2);
1556+ break;
1557+ }
1558+ return result;
1559+ },
1560+ mathMatch: function (type, number1, number2) {
1561+ var result;
1562+ number1 = helper.number(number1);
1563+ number2 = helper.number(number2);
1564+ if (isNaN(number1) || isNaN(number2)) {
1565+ throw Error('VALUE');
1566+ }
1567+ switch (type) {
1568+ case '+':
1569+ result = number1 + number2;
1570+ break;
1571+ case '-':
1572+ result = number1 - number2;
1573+ break;
1574+ case '/':
1575+ result = number1 / number2;
1576+ if (result == Infinity) {
1577+ throw Error('DIV_ZERO');
1578+ }
1579+ else if (isNaN(result)) {
1580+ throw Error('VALUE');
1581+ }
1582+ break;
1583+ case '*':
1584+ result = number1 * number2;
1585+ break;
1586+ case '^':
1587+ result = Math.pow(number1, number2);
1588+ break;
1589+ }
1590+ return result;
1591+ },
1592+ callFunction: function (fn, args) {
1593+ fn = fn.toUpperCase();
1594+ args = args || [];
1595+ if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
1596+ if (instance.formulas[fn]) {
1597+ return instance.formulas[fn].apply(this, args);
1598+ }
1599+ }
1600+ throw Error('NAME');
1601+ },
1602+ callVariable: function (args) {
1603+ args = args || [];
1604+ var str = args[0];
1605+ if (str) {
1606+ str = str.toUpperCase();
1607+ if (instance.formulas[str]) {
1608+ return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
1609+ }
1610+ }
1611+ throw Error('NAME');
1612+ },
1613+ cellValue: function (cell) {
1614+ var value, element = this, item = instance.matrix.getItem(cell);
1615+ // get value
1616+ value = item ? item.value : "0"; // TODO: fix this, it's sloppy.
1617+ //update dependencies
1618+ instance.matrix.updateCellItem(element, { deps: [cell] });
1619+ // check references error
1620+ if (item && item.deps) {
1621+ if (item.deps.indexOf(cell) !== -1) {
1622+ throw Error('REF');
1623+ }
1624+ }
1625+ // check if any error occurs
1626+ if (item && item.error) {
1627+ throw Error(item.error);
1628+ }
1629+ // return value if is set
1630+ if (instance.utils.isSet(value)) {
1631+ var result = instance.helper.number(value);
1632+ return !isNaN(result) ? result : value;
1633+ }
1634+ // cell is not available
1635+ throw Error('NOT_AVAILABLE');
1636+ },
1637+ cellRangeValue: function (start, end) {
1638+ var coordsStart = instance.utils.cellCoords(start), coordsEnd = instance.utils.cellCoords(end), element = this;
1639+ // iterate cells to get values and indexes
1640+ var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd), result = [];
1641+ //update dependencies
1642+ instance.matrix.updateCellItem(element, { deps: cells.index });
1643+ result.push(cells.value);
1644+ return result;
1645+ },
1646+ fixedCellValue: function (id) {
1647+ id = id.replace(/\$/g, '');
1648+ return instance.helper.cellValue.call(this, id);
1649+ },
1650+ fixedCellRangeValue: function (start, end) {
1651+ start = start.replace(/\$/g, '');
1652+ end = end.replace(/\$/g, '');
1653+ return instance.helper.cellRangeValue.call(this, start, end);
1654+ }
1655+ };
1656+ var parse = function (formula, element) {
1657+ var result = null, error = null;
1658+ try {
1659+ parser.setObj(element);
1660+ result = parser.parse(formula);
1661+ var id;
1662+ if (element instanceof HTMLElement) {
1663+ id = element.getAttribute('id');
1664+ }
1665+ else if (element && element.id) {
1666+ id = element.id;
1667+ }
1668+ var deps = instance.matrix.getDependencies(id);
1669+ if (deps.indexOf(id) !== -1) {
1670+ result = null;
1671+ deps.forEach(function (id) {
1672+ instance.matrix.updateItem(id, { value: null, error: Exception.get('REF') });
1673+ });
1674+ throw Error('REF');
1675+ }
1676+ }
1677+ catch (ex) {
1678+ var message = Exception.get(ex.message);
1679+ if (message) {
1680+ error = message;
1681+ }
1682+ else {
1683+ error = Exception.get('ERROR');
1684+ }
1685+ }
1686+ return {
1687+ error: error,
1688+ result: result
1689+ };
1690+ };
1691+ var init = function () {
1692+ instance = this;
1693+ parser = FormulaParser(instance);
1694+ instance.formulas = Formula;
1695+ instance.matrix = new Matrix();
1696+ instance.custom = {};
1697+ instance.matrix.scan();
1698+ };
1699+ return {
1700+ init: init,
1701+ utils: utils,
1702+ helper: helper,
1703+ parse: parse
1704+ };
1705+});
1706diff --git a/ts/sheet.ts b/ts/sheet.ts
1707new file mode 100644
1708index 0000000..d0611dc
1709--- /dev/null
1710+++ b/ts/sheet.ts
1711@@ -0,0 +1,679 @@
1712+interface P {
1713+ yy: any;
1714+ lexer: any;
1715+ parse: any;
1716+ parseError: any;
1717+}
1718+
1719+declare var Parser: P;
1720+declare var Formula: any;
1721+
1722+var mine = (function () {
1723+ 'use strict';
1724+ var instance = this;
1725+
1726+ var parser = {
1727+ setObj: function (thing: any) {
1728+
1729+ },
1730+ parse: function (thing: any) {
1731+
1732+ }
1733+ };
1734+
1735+ var FormulaParser = function(handler) {
1736+ var formulaLexer = function () {};
1737+ formulaLexer.prototype = Parser.lexer;
1738+
1739+ var formulaParser = function () {
1740+ this.lexer = new formulaLexer();
1741+ this.yy = {};
1742+ };
1743+
1744+ formulaParser.prototype = Parser;
1745+ var newParser = new formulaParser;
1746+ newParser.setObj = function(obj) {
1747+ newParser.yy.obj = obj;
1748+ };
1749+
1750+ newParser.yy.parseError = function (str, hash) {
1751+ throw {
1752+ name: 'Parser error',
1753+ message: str,
1754+ prop: hash
1755+ }
1756+ };
1757+
1758+ newParser.yy.handler = handler;
1759+
1760+ return newParser;
1761+ };
1762+
1763+ var Exception = {
1764+ errors: [
1765+ {type: 'NULL', output: '#NULL'},
1766+ {type: 'DIV_ZERO', output: '#DIV/0!'},
1767+ {type: 'VALUE', output: '#VALUE!'},
1768+ {type: 'REF', output: '#REF!'},
1769+ {type: 'NAME', output: '#NAME?'},
1770+ {type: 'NUM', output: '#NUM!'},
1771+ {type: 'NOT_AVAILABLE', output: '#N/A!'},
1772+ {type: 'ERROR', output: '#ERROR'}
1773+ ],
1774+ get: function (type) {
1775+ var error = Exception.errors.filter(function (item) {
1776+ return item.type === type || item.output === type;
1777+ })[0];
1778+
1779+ return error ? error.output : null;
1780+ }
1781+ };
1782+
1783+ var Matrix = function () {
1784+
1785+ // var item = {
1786+ // id: '',
1787+ // formula: '',
1788+ // value: '',
1789+ // error: '',
1790+ // deps: [],
1791+ // formulaEdit: false
1792+ // };
1793+
1794+ this.data = [];
1795+
1796+ this.getItem = function (id) {
1797+ return instance.matrix.data.filter(function (item) {
1798+ return item.id === id;
1799+ })[0];
1800+ };
1801+
1802+ this.removeItem = function (id) {
1803+ instance.matrix.data = instance.matrix.data.filter(function (item) {
1804+ return item.id !== id;
1805+ });
1806+ };
1807+
1808+ this.updateItem = function (item, props) {
1809+ if (instance.utils.isString(item)) {
1810+ item = instance.matrix.getItem(item);
1811+ }
1812+
1813+ if (item && props) {
1814+ for (var p in props) {
1815+ if (item[p] && instance.utils.isArray(item[p])) {
1816+ if (instance.utils.isArray(props[p])) {
1817+ props[p].forEach(function (i) {
1818+ if (item[p].indexOf(i) === -1) {
1819+ item[p].push(i);
1820+ }
1821+ });
1822+ } else {
1823+
1824+ if (item[p].indexOf(props[p]) === -1) {
1825+ item[p].push(props[p]);
1826+ }
1827+ }
1828+ } else {
1829+ item[p] = props[p];
1830+ }
1831+ }
1832+ }
1833+ };
1834+
1835+ this.addItem = function (item) {
1836+ var cellId = item.id,
1837+ coords = instance.utils.cellCoords(cellId);
1838+
1839+ item.row = coords.row;
1840+ item.col = coords.col;
1841+
1842+ var cellExist = instance.matrix.data.filter(function (cell) {
1843+ return cell.id === cellId;
1844+ })[0];
1845+
1846+ if (!cellExist) {
1847+ instance.matrix.data.push(item);
1848+ } else {
1849+ instance.matrix.updateItem(cellExist, item);
1850+ }
1851+
1852+ return instance.matrix.getItem(cellId);
1853+ };
1854+
1855+
1856+ this.updateCellItem = function (id, props) {
1857+ var item = instance.matrix.getItem(id);
1858+
1859+ instance.matrix.updateItem(item, props);
1860+ };
1861+
1862+ this.getDependencies = function (id) {
1863+ var getDependencies = function (id) {
1864+ var filtered = instance.matrix.data.filter(function (cell) {
1865+ if (cell.deps) {
1866+ return cell.deps.indexOf(id) > -1;
1867+ }
1868+ });
1869+
1870+ var deps = [];
1871+ filtered.forEach(function (cell) {
1872+ if (deps.indexOf(cell.id) === -1) {
1873+ deps.push(cell.id);
1874+ }
1875+ });
1876+
1877+ return deps;
1878+ };
1879+
1880+ var allDependencies = [];
1881+
1882+ var getTotalDependencies = function (id) {
1883+ var deps = getDependencies(id);
1884+
1885+ if (deps.length) {
1886+ deps.forEach(function (refId) {
1887+ if (allDependencies.indexOf(refId) === -1) {
1888+ allDependencies.push(refId);
1889+
1890+ var item = instance.matrix.getItem(refId);
1891+ if (item.deps.length) {
1892+ getTotalDependencies(refId);
1893+ }
1894+ }
1895+ });
1896+ }
1897+ };
1898+
1899+ getTotalDependencies(id);
1900+
1901+ return allDependencies;
1902+ };
1903+
1904+ this.getCellDependencies = function (cell) {
1905+ return instance.matrix.getDependencies(cell.id);
1906+ };
1907+
1908+ var recalculateCellDependencies = function (cell) {
1909+ var allDependencies = instance.matrix.getCellDependencies(cell);
1910+
1911+ allDependencies.forEach(function (refId) {
1912+ var currentCell = instance.matrix.getItem(refId);
1913+ if (currentCell && currentCell.formula) {
1914+ calculateCellFormula(currentCell.formula, currentCell.id);
1915+ }
1916+ });
1917+ };
1918+
1919+ var calculateCellFormula = function (formula, id) {
1920+ // to avoid double translate formulas, update item data in parser
1921+ var parsed = parse(formula, id),
1922+ value = parsed.result,
1923+ error = parsed.error;
1924+
1925+ instance.matrix.updateCellItem(id, {value: value, error: error});
1926+
1927+ return parsed;
1928+ };
1929+
1930+ var registerCellInMatrix = function (cell) {
1931+ instance.matrix.addItem(cell);
1932+ calculateCellFormula(cell.formula, cell.id);
1933+ };
1934+
1935+ this.scan = function () {
1936+ var input = [
1937+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "SUM(A1:D1, H1)"],
1938+ [-1, -10, 2, 4, 100, 1, 50, 20, 200, -100, "MAX(A2:J2)"],
1939+ [-1, -40, -53, 1, 10, 30, 10, 301, -1, -20, "MIN(A3:J3)"],
1940+ [20, 50, 100, 20, 1, 5, 15, 25, 45, 23, "AVERAGE(A4:J4)"],
1941+ [0, 10, 1, 10, 2, 10, 3, 10, 4, 10, "SUMIF(A5:J5,'>5')"]
1942+ ];
1943+ for (var y = 0; y < input.length; y++) {
1944+ for (var x = 0; x < input[0].length; x++) {
1945+ // set the cell here
1946+ var id = utils.XYtoA1(x, y);
1947+ var cell = {
1948+ id: id,
1949+ formula: input[y][x].toString()
1950+ };
1951+ registerCellInMatrix(cell);
1952+ recalculateCellDependencies(cell);
1953+ }
1954+ }
1955+ console.log(this.data);
1956+ };
1957+ };
1958+
1959+ var utils = {
1960+ isArray: function (value) {
1961+ return Object.prototype.toString.call(value) === '[object Array]';
1962+ },
1963+
1964+ isNumber: function (value) {
1965+ return Object.prototype.toString.call(value) === '[object Number]';
1966+ },
1967+
1968+ isString: function (value) {
1969+ return Object.prototype.toString.call(value) === '[object String]';
1970+ },
1971+
1972+ isFunction: function (value) {
1973+ return Object.prototype.toString.call(value) === '[object Function]';
1974+ },
1975+
1976+ isUndefined: function (value) {
1977+ return Object.prototype.toString.call(value) === '[object Undefined]';
1978+ },
1979+
1980+ isNull: function (value) {
1981+ return Object.prototype.toString.call(value) === '[object Null]';
1982+ },
1983+
1984+ isSet: function (value) {
1985+ return !instance.utils.isUndefined(value) && !instance.utils.isNull(value);
1986+ },
1987+
1988+ getCellAlphaNum: function (cell) {
1989+ var num = cell.match(/\d+$/),
1990+ alpha = cell.replace(num, '');
1991+
1992+ return {
1993+ alpha: alpha,
1994+ num: parseInt(num[0], 10)
1995+ }
1996+ },
1997+
1998+ toNum: function (chr) {
1999+ chr = instance.utils.clearFormula(chr);
2000+ var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
2001+
2002+ for (i = 0, j = chr.length - 1; i < chr.length; i += 1, j -= 1) {
2003+ result += Math.pow(base.length, j) * (base.indexOf(chr[i]) + 1);
2004+ }
2005+
2006+ if (result) {
2007+ --result;
2008+ }
2009+
2010+ return result;
2011+ },
2012+
2013+ toChar: function (num) {
2014+ var s = '';
2015+
2016+ while (num >= 0) {
2017+ s = String.fromCharCode(num % 26 + 97) + s;
2018+ num = Math.floor(num / 26) - 1;
2019+ }
2020+
2021+ return s.toUpperCase();
2022+ },
2023+ XYtoA1: function (x, y) {
2024+ function numberToLetters(num) {
2025+ var mod = num % 26,
2026+ pow = num / 26 | 0,
2027+ out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
2028+ return pow ? numberToLetters(pow) + out : out;
2029+ }
2030+ return numberToLetters(x+1) + (y+1).toString();
2031+ },
2032+ cellCoords: function (cell) {
2033+ var num = cell.match(/\d+$/),
2034+ alpha = cell.replace(num, '');
2035+
2036+ return {
2037+ row: parseInt(num[0], 10) - 1,
2038+ col: instance.utils.toNum(alpha)
2039+ };
2040+ },
2041+
2042+ clearFormula: function (formula) {
2043+ return formula.replace(/\$/g, '');
2044+ },
2045+
2046+ translateCellCoords: function (coords) {
2047+ return instance.utils.toChar(coords.col) + '' + parseInt(coords.row + 1, 10);
2048+ },
2049+
2050+ iterateCells: function (startCell, endCell, callback) {
2051+ var result = {
2052+ index: [], // list of cell index: A1, A2, A3
2053+ value: [] // list of cell value
2054+ };
2055+
2056+ var cols = {
2057+ start: 0,
2058+ end: 0
2059+ };
2060+
2061+ if (endCell.col >= startCell.col) {
2062+ cols = {
2063+ start: startCell.col,
2064+ end: endCell.col
2065+ };
2066+ } else {
2067+ cols = {
2068+ start: endCell.col,
2069+ end: startCell.col
2070+ };
2071+ }
2072+
2073+ var rows = {
2074+ start: 0,
2075+ end: 0
2076+ };
2077+
2078+ if (endCell.row >= startCell.row) {
2079+ rows = {
2080+ start: startCell.row,
2081+ end: endCell.row
2082+ };
2083+ } else {
2084+ rows = {
2085+ start: endCell.row,
2086+ end: startCell.row
2087+ };
2088+ }
2089+
2090+ for (var column = cols.start; column <= cols.end; column++) {
2091+ for (var row = rows.start; row <= rows.end; row++) {
2092+ var cellIndex = instance.utils.toChar(column) + (row + 1),
2093+ cellValue = instance.helper.cellValue.call(this, cellIndex);
2094+
2095+ result.index.push(cellIndex);
2096+ result.value.push(cellValue);
2097+ }
2098+ }
2099+
2100+ if (instance.utils.isFunction(callback)) {
2101+ return callback.apply(callback, [result]);
2102+ } else {
2103+ return result;
2104+ }
2105+ },
2106+
2107+ sort: function (rev) {
2108+ return function (a, b) {
2109+ return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
2110+ }
2111+ }
2112+ };
2113+
2114+ var helper = {
2115+ SUPPORTED_FORMULAS: [
2116+ 'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
2117+ 'BASE', 'BESSELI', 'BESSELJ', 'BESSELK', 'BESSELY', 'BETADIST', 'BETAINV', 'BIN2DEC', 'BIN2HEX', 'BIN2OCT', 'BINOMDIST', 'BINOMDISTRANGE', 'BINOMINV', 'BITAND', 'BITLSHIFT', 'BITOR', 'BITRSHIFT', 'BITXOR',
2118+ 'CEILING', 'CEILINGMATH', 'CEILINGPRECISE', 'CHAR', 'CHISQDIST', 'CHISQINV', 'CODE', 'COMBIN', 'COMBINA', 'COMPLEX', 'CONCATENATE', 'CONFIDENCENORM', 'CONFIDENCET', 'CONVERT', 'CORREL', 'COS', 'COSH', 'COT', 'COTH', 'COUNT', 'COUNTA', 'COUNTBLANK', 'COUNTIF', 'COUNTIFS', 'COUNTIN', 'COUNTUNIQUE', 'COVARIANCEP', 'COVARIANCES', 'CSC', 'CSCH', 'CUMIPMT', 'CUMPRINC',
2119+ 'DATE', 'DATEVALUE', 'DAY', 'DAYS', 'DAYS360', 'DB', 'DDB', 'DEC2BIN', 'DEC2HEX', 'DEC2OCT', 'DECIMAL', 'DEGREES', 'DELTA', 'DEVSQ', 'DOLLAR', 'DOLLARDE', 'DOLLARFR',
2120+ 'E', 'EDATE', 'EFFECT', 'EOMONTH', 'ERF', 'ERFC', 'EVEN', 'EXACT', 'EXPONDIST',
2121+ 'FALSE', 'FDIST', 'FINV', 'FISHER', 'FISHERINV',
2122+ 'IF', 'INT', 'ISEVEN', 'ISODD',
2123+ 'LN', 'LOG', 'LOG10',
2124+ 'MAX', 'MAXA', 'MEDIAN', 'MIN', 'MINA', 'MOD',
2125+ 'NOT',
2126+ 'ODD', 'OR',
2127+ 'PI', 'POWER',
2128+ 'ROUND', 'ROUNDDOWN', 'ROUNDUP',
2129+ 'SIN', 'SINH', 'SPLIT', 'SQRT', 'SQRTPI', 'SUM', 'SUMIF', 'SUMIFS', 'SUMPRODUCT', 'SUMSQ', 'SUMX2MY2', 'SUMX2PY2', 'SUMXMY2',
2130+ 'TAN', 'TANH', 'TRUE', 'TRUNC',
2131+ 'XOR'
2132+ ],
2133+
2134+ number: function (num) {
2135+ switch (typeof num) {
2136+ case 'number':
2137+ return num;
2138+ case 'string':
2139+ if (!isNaN(num)) {
2140+ return num.indexOf('.') > -1 ? parseFloat(num) : parseInt(num, 10);
2141+ }
2142+ }
2143+
2144+ return num;
2145+ },
2146+
2147+ string: function (str) {
2148+ return str.substring(1, str.length - 1);
2149+ },
2150+
2151+ numberInverted: function (num) {
2152+ return this.number(num) * (-1);
2153+ },
2154+
2155+ specialMatch: function (type, exp1, exp2) {
2156+ var result;
2157+
2158+ switch (type) {
2159+ case '&':
2160+ result = exp1.toString() + exp2.toString();
2161+ break;
2162+ }
2163+ return result;
2164+ },
2165+
2166+ logicMatch: function (type, exp1, exp2) {
2167+ var result;
2168+
2169+ switch (type) {
2170+ case '=':
2171+ result = (exp1 === exp2);
2172+ break;
2173+
2174+ case '>':
2175+ result = (exp1 > exp2);
2176+ break;
2177+
2178+ case '<':
2179+ result = (exp1 < exp2);
2180+ break;
2181+
2182+ case '>=':
2183+ result = (exp1 >= exp2);
2184+ break;
2185+
2186+ case '<=':
2187+ result = (exp1 === exp2);
2188+ break;
2189+
2190+ case '<>':
2191+ result = (exp1 != exp2);
2192+ break;
2193+
2194+ case 'NOT':
2195+ result = (exp1 != exp2);
2196+ break;
2197+ }
2198+
2199+ return result;
2200+ },
2201+
2202+ mathMatch: function (type, number1, number2) {
2203+ var result;
2204+
2205+ number1 = helper.number(number1);
2206+ number2 = helper.number(number2);
2207+
2208+ if (isNaN(number1) || isNaN(number2)) {
2209+ throw Error('VALUE');
2210+ }
2211+
2212+ switch (type) {
2213+ case '+':
2214+ result = number1 + number2;
2215+ break;
2216+ case '-':
2217+ result = number1 - number2;
2218+ break;
2219+ case '/':
2220+ result = number1 / number2;
2221+ if (result == Infinity) {
2222+ throw Error('DIV_ZERO');
2223+ } else if (isNaN(result)) {
2224+ throw Error('VALUE');
2225+ }
2226+ break;
2227+ case '*':
2228+ result = number1 * number2;
2229+ break;
2230+ case '^':
2231+ result = Math.pow(number1, number2);
2232+ break;
2233+ }
2234+
2235+ return result;
2236+ },
2237+
2238+ callFunction: function (fn, args) {
2239+ fn = fn.toUpperCase();
2240+ args = args || [];
2241+
2242+ if (instance.helper.SUPPORTED_FORMULAS.indexOf(fn) > -1) {
2243+ if (instance.formulas[fn]) {
2244+ return instance.formulas[fn].apply(this, args);
2245+ }
2246+ }
2247+
2248+ throw Error('NAME');
2249+ },
2250+
2251+ callVariable: function (args) {
2252+ args = args || [];
2253+ var str = args[0];
2254+
2255+ if (str) {
2256+ str = str.toUpperCase();
2257+ if (instance.formulas[str]) {
2258+ return ((typeof instance.formulas[str] === 'function') ? instance.formulas[str].apply(this, args) : instance.formulas[str]);
2259+ }
2260+ }
2261+
2262+ throw Error('NAME');
2263+ },
2264+
2265+ cellValue: function (cell) {
2266+ var value,
2267+ element = this,
2268+ item = instance.matrix.getItem(cell);
2269+ // get value
2270+ value = item ? item.value : "0"; // TODO: fix this, it's sloppy.
2271+ //update dependencies
2272+ instance.matrix.updateCellItem(element, {deps: [cell]});
2273+ // check references error
2274+ if (item && item.deps) {
2275+ if (item.deps.indexOf(cell) !== -1) {
2276+ throw Error('REF');
2277+ }
2278+ }
2279+
2280+ // check if any error occurs
2281+ if (item && item.error) {
2282+ throw Error(item.error);
2283+ }
2284+
2285+ // return value if is set
2286+ if (instance.utils.isSet(value)) {
2287+ var result = instance.helper.number(value);
2288+
2289+ return !isNaN(result) ? result : value;
2290+ }
2291+
2292+ // cell is not available
2293+ throw Error('NOT_AVAILABLE');
2294+ },
2295+
2296+ cellRangeValue: function (start, end) {
2297+ var coordsStart = instance.utils.cellCoords(start),
2298+ coordsEnd = instance.utils.cellCoords(end),
2299+ element = this;
2300+
2301+ // iterate cells to get values and indexes
2302+ var cells = instance.utils.iterateCells.call(this, coordsStart, coordsEnd),
2303+ result = [];
2304+ //update dependencies
2305+ instance.matrix.updateCellItem(element, {deps: cells.index});
2306+
2307+ result.push(cells.value);
2308+ return result;
2309+ },
2310+
2311+ fixedCellValue: function (id) {
2312+ id = id.replace(/\$/g, '');
2313+ return instance.helper.cellValue.call(this, id);
2314+ },
2315+
2316+ fixedCellRangeValue: function (start, end) {
2317+ start = start.replace(/\$/g, '');
2318+ end = end.replace(/\$/g, '');
2319+
2320+ return instance.helper.cellRangeValue.call(this, start, end);
2321+ }
2322+ };
2323+
2324+ var parse = function (formula, element) {
2325+ var result = null,
2326+ error = null;
2327+
2328+ try {
2329+
2330+ parser.setObj(element);
2331+ result = parser.parse(formula);
2332+
2333+ var id;
2334+
2335+ if (element instanceof HTMLElement) {
2336+ id = element.getAttribute('id');
2337+ } else if (element && element.id) {
2338+ id = element.id;
2339+ }
2340+
2341+ var deps = instance.matrix.getDependencies(id);
2342+
2343+ if (deps.indexOf(id) !== -1) {
2344+ result = null;
2345+
2346+ deps.forEach(function (id) {
2347+ instance.matrix.updateItem(id, {value: null, error: Exception.get('REF')});
2348+ });
2349+
2350+ throw Error('REF');
2351+ }
2352+
2353+ } catch (ex) {
2354+
2355+ var message = Exception.get(ex.message);
2356+
2357+ if (message) {
2358+ error = message;
2359+ } else {
2360+ error = Exception.get('ERROR');
2361+ }
2362+ }
2363+
2364+ return {
2365+ error: error,
2366+ result: result
2367+ }
2368+ };
2369+
2370+ var init = function () {
2371+ instance = this;
2372+
2373+ parser = FormulaParser(instance);
2374+
2375+ instance.formulas = Formula;
2376+ instance.matrix = new Matrix();
2377+
2378+ instance.custom = {};
2379+
2380+ instance.matrix.scan();
2381+ };
2382+
2383+ return {
2384+ init: init,
2385+ utils: utils,
2386+ helper: helper,
2387+ parse: parse
2388+ };
2389+
2390+});
2391diff --git a/tsconfig.json b/tsconfig.json
2392new file mode 100644
2393index 0000000..39a290d
2394--- /dev/null
2395+++ b/tsconfig.json
2396@@ -0,0 +1,11 @@
2397+{
2398+ "compilerOptions": {
2399+ "allowJs": true,
2400+ "allowUnreachableCode": true,
2401+ "allowUnusedLabels": true,
2402+ "outDir": "ts"
2403+ },
2404+ "files": [
2405+ "ts/sheet.ts"
2406+ ]
2407+}