1 /*
  2  JessieCode Interpreter and Compiler
  3 
  4     Copyright 2011-2016
  5         Michael Gerhaeuser,
  6         Alfred Wassermann
  7 
  8     JessieCode is free software dual licensed under the GNU LGPL or MIT License.
  9 
 10     You can redistribute it and/or modify it under the terms of the
 11 
 12       * GNU Lesser General Public License as published by
 13         the Free Software Foundation, either version 3 of the License, or
 14         (at your option) any later version
 15       OR
 16       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 17 
 18     JessieCode is distributed in the hope that it will be useful,
 19     but WITHOUT ANY WARRANTY; without even the implied warranty of
 20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21     GNU Lesser General Public License for more details.
 22 
 23     You should have received a copy of the GNU Lesser General Public License and
 24     the MIT License along with JessieCode. If not, see <http://www.gnu.org/licenses/>
 25     and <http://opensource.org/licenses/MIT/>.
 26  */
 27 
 28 /*global JXG: true, define: true, window: true, console: true, self: true, document: true, parser: true*/
 29 /*jslint nomen: true, plusplus: true*/
 30 
 31 /* depends:
 32  jxg
 33  parser/geonext
 34  base/constants
 35  base/text
 36  math/math
 37  math/geometry
 38  math/statistics
 39  utils/type
 40  utils/uuid
 41  */
 42 
 43 /**
 44  * @fileoverview JessieCode is a scripting language designed to provide a simple scripting language to build constructions
 45  * with JSXGraph. It is similar to JavaScript, but prevents access to the DOM. Hence, it can be used in community driven
 46  * Math portals which want to use JSXGraph to display interactive math graphics.
 47  */
 48 
 49 define([
 50     'jxg', 'base/constants', 'base/text', 'math/math', 'math/geometry', 'math/statistics', 'utils/type', 'utils/uuid', 'utils/env'
 51 ], function (JXG, Const, Text, Mat, Geometry, Statistics, Type, UUID, Env) {
 52 
 53     ;
 54 
 55     // IE 6-8 compatibility
 56     if (!Object.create) {
 57         Object.create = function(o, properties) {
 58             if (typeof o !== 'object' && typeof o !== 'function') throw new TypeError('Object prototype may only be an Object: ' + o);
 59             else if (o === null) throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
 60 
 61             if (typeof properties != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
 62 
 63             function F() {}
 64 
 65             F.prototype = o;
 66 
 67             return new F();
 68         };
 69     }
 70 
 71     var priv = {
 72             modules: {
 73                 'math': Mat,
 74                 'math/geometry': Geometry,
 75                 'math/statistics': Statistics,
 76                 'math/numerics': Mat.Numerics
 77             }
 78         };
 79 
 80     /**
 81      * A JessieCode object provides an interface to the parser and stores all variables and objects used within a JessieCode script.
 82      * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance
 83      * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}.
 84      * @constructor
 85      * @param {String} [code] Code to parse.
 86      * @param {Boolean} [geonext=false] Geonext compatibility mode.
 87      */
 88     JXG.JessieCode = function (code, geonext) {
 89         // Control structures
 90 
 91         /**
 92          * The global scope.
 93          * @type {Object}
 94          */
 95         this.scope = {
 96             id: 0,
 97             hasChild: true,
 98             args: [],
 99             locals: {},
100             context: null,
101             previous: null
102         };
103 
104         /**
105          * Keeps track of all possible scopes every required.
106          * @type {Array}
107          */
108         this.scopes = [];
109         this.scopes.push(this.scope);
110 
111         /**
112          * A stack to store debug information (like line and column where it was defined) of a parameter
113          * @type Array
114          * @private
115          */
116         this.dpstack = [[]];
117 
118         /**
119          * Determines the parameter stack scope.
120          * @type Number
121          * @private
122          */
123         this.pscope = 0;
124 
125         /**
126          * Used to store the property-value definition while parsing an object literal.
127          * @type Array
128          * @private
129          */
130         this.propstack = [{}];
131 
132         /**
133          * The current scope of the object literal stack {@link JXG.JessieCode#propstack}.
134          * @type Number
135          * @private
136          */
137         this.propscope = 0;
138 
139         /**
140          * Store the left hand side of an assignment. If an element is constructed and no attributes are given, this is
141          * used as the element's name.
142          * @type Array
143          * @private
144          */
145         this.lhs = [];
146 
147         /**
148          * lhs flag, used by JXG.JessieCode#replaceNames
149          * @type Boolean
150          * @default false
151          */
152         this.isLHS = false;
153 
154         /**
155          * The id of an HTML node in which innerHTML all warnings are stored (if no <tt>console</tt> object is available).
156          * @type String
157          * @default 'jcwarn'
158          */
159         this.warnLog = 'jcwarn';
160 
161         /**
162          * Store $log messages in case there's no console.
163          * @type {Array}
164          */
165         this.$log = [];
166 
167         /**
168          * Built-in functions and constants
169          * @type Object
170          */
171         this.builtIn = this.defineBuiltIn();
172 
173         /**
174          * The board which currently is used to create and look up elements.
175          * @type JXG.Board
176          */
177         this.board = null;
178 
179         /**
180          * Keep track of which element is created in which line.
181          * @type Object
182          */
183         this.lineToElement = {};
184 
185         this.parCurLine = 1;
186         this.parCurColumn = 0;
187         this.line = 1;
188         this.col = 1;
189 
190         this.code = '';
191 
192         if (typeof code === 'string') {
193             this.parse(code, geonext);
194         }
195     };
196 
197 
198     JXG.extend(JXG.JessieCode.prototype, /** @lends JXG.JessieCode.prototype */ {
199         /**
200          * Create a new parse tree node.
201          * @param {String} type Type of node, e.g. node_op, node_var, or node_const
202          * @param value The nodes value, e.g. a variables value or a functions body.
203          * @param {Array} children Arbitrary number of child nodes.
204          */
205         node: function (type, value, children) {
206             return {
207                 type: type,
208                 value: value,
209                 children: children
210             };
211         },
212 
213         /**
214          * Create a new parse tree node. Basically the same as node(), but this builds
215          * the children part out of an arbitrary number of parameters, instead of one
216          * array parameter.
217          * @param {String} type Type of node, e.g. node_op, node_var, or node_const
218          * @param value The nodes value, e.g. a variables value or a functions body.
219          * @param children Arbitrary number of parameters; define the child nodes.
220          */
221         createNode: function (type, value, children) {
222             var n = this.node(type, value, []),
223                 i;
224 
225             for (i = 2; i < arguments.length; i++) {
226                 n.children.push(arguments[i]);
227             }
228 
229             n.line = this.parCurLine;
230             n.col = this.parCurColumn;
231 
232             return n;
233         },
234 
235         /**
236          * Create a new scope.
237          * @param {Array} args
238          * @returns {Object}
239          */
240         pushScope: function (args) {
241             var scope = {
242                     args: args,
243                     locals: {},
244                     context: null,
245                     previous: this.scope
246                 };
247 
248             this.scope.hasChild = true;
249             this.scope = scope;
250             scope.id = this.scopes.push(scope) - 1;
251 
252             return scope;
253         },
254 
255         /**
256          * Remove the current scope and reinstate the previous scope
257          * @returns {Object}
258          */
259         popScope: function () {
260             var s = this.scope.previous;
261 
262             // make sure the global scope is not lost
263             this.scope = s !== null ? s : this.scope;
264 
265             return this.scope;
266         },
267 
268         /**
269          * Looks up an {@link JXG.GeometryElement} by its id.
270          * @param {String} id
271          * @returns {JXG.GeometryElement}
272          */
273         getElementById: function (id) {
274             return this.board.objects[id];
275         },
276 
277         log: function () {
278             this.$log.push(arguments);
279 
280             if (typeof console === 'object' && console.log) {
281                 console.log.apply(console, arguments);
282             }
283         },
284 
285         /**
286          * Returns a element creator function which takes two parameters: the parents array and the attributes object.
287          * @param {String} vname The element type, e.g. 'point', 'line', 'midpoint'
288          * @returns {function}
289          */
290         creator: (function () {
291             // stores the already defined creators
292             var _ccache = {}, r;
293 
294             r = function (vname) {
295                 var f;
296 
297                 // _ccache is global, i.e. it is the same for ALL JessieCode instances.
298                 // That's why we need the board id here
299                 if (typeof _ccache[this.board.id + vname] === 'function') {
300                     f =  _ccache[this.board.id + vname];
301                 } else {
302                     f = (function (that) {
303                         return function (parameters, attributes) {
304                             var attr;
305 
306                             if (Type.exists(attributes)) {
307                                 attr = attributes;
308                             } else {
309                                 attr = {name: (that.lhs[that.scope] !== 0 ? that.lhs[that.scope] : '')};
310                             }
311                             return that.board.create(vname, parameters, attr);
312                         };
313                     }(this));
314 
315                     f.creator = true;
316                     _ccache[this.board.id + vname] = f;
317                 }
318 
319                 return f;
320             };
321 
322             r.clearCache = function () {
323                 _ccache = {};
324             };
325 
326             return r;
327         }()),
328 
329         /**
330          * Assigns a value to a variable in the current scope.
331          * @param {String} vname Variable name
332          * @param value Anything
333          * @see JXG.JessieCode#sstack
334          * @see JXG.JessieCode#scope
335          */
336         letvar: function (vname, value) {
337             if (this.builtIn[vname]) {
338                 this._warn('"' + vname + '" is a predefined value.');
339             }
340 
341             this.scope.locals[vname] = value;
342         },
343 
344         /**
345          * Checks if the given variable name can be found in the current scope chain.
346          * @param {String} vname
347          * @returns {Object} A reference to the scope object the variable can be found in or null if it can't be found.
348          */
349         isLocalVariable: function (vname) {
350             var s = this.scope;
351 
352             while (s !== null) {
353                 if (Type.exists(s.locals[vname])) {
354                     return s;
355                 }
356 
357                 s = s.previous;
358             }
359 
360             return null;
361         },
362 
363         /**
364          * Checks if the given variable name is a parameter in any scope from the current to the global scope.
365          * @param {String} vname
366          * @returns {Object} A reference to the scope object that contains the variable in its arg list.
367          */
368         isParameter: function (vname) {
369             var s = this.scope;
370 
371             while (s !== null) {
372                 if (Type.indexOf(s.args, vname) > -1) {
373                     return s;
374                 }
375 
376                 s = s.previous;
377             }
378 
379             return null;
380         },
381 
382         /**
383          * Checks if the given variable name is a valid creator method.
384          * @param {String} vname
385          * @returns {Boolean}
386          */
387         isCreator: function (vname) {
388             // check for an element with this name
389             return !!JXG.elements[vname];
390         },
391 
392         /**
393          * Checks if the given variable identifier is a valid member of the JavaScript Math Object.
394          * @param {String} vname
395          * @returns {Boolean}
396          */
397         isMathMethod: function (vname) {
398             return vname !== 'E' && !!Math[vname];
399         },
400 
401         /**
402          * Returns true if the given identifier is a builtIn variable/function.
403          * @param {String} vname
404          * @returns {Boolean}
405          */
406         isBuiltIn: function (vname) {
407             return !!this.builtIn[vname];
408         },
409 
410         /**
411          * Looks up the value of the given variable.
412          * @param {String} vname Name of the variable
413          * @param {Boolean} [local=false] Only look up the internal symbol table and don't look for
414          * the <tt>vname</tt> in Math or the element list.
415          */
416         getvar: function (vname, local) {
417             var s;
418 
419             local = Type.def(local, false);
420 
421             s = this.isLocalVariable(vname);
422             if (s !== null) {
423                 return s.locals[vname];
424             }
425 
426             // check for an element with this name
427             if (this.isCreator(vname)) {
428                 return this.creator(vname);
429             }
430 
431             if (this.isBuiltIn(vname)) {
432                 return this.builtIn[vname];
433             }
434 
435             if (this.isMathMethod(vname)) {
436                 return Math[vname];
437             }
438 
439             if (!local) {
440                 s = this.board.select(vname);
441                 if (s !== vname) {
442                     return s;
443                 }
444             }
445         },
446 
447         /**
448          * Look up the value of a local variable.
449          * @param {string} vname
450          * @returns {*}
451          */
452         resolve: function (vname) {
453             var s = this.scope;
454 
455             while (s !== null) {
456                 if (Type.exists(s.locals[vname])) {
457                     return s.locals[vname];
458                 }
459 
460                 s = s.previous;
461             }
462         },
463 
464         /**
465          * TODO this needs to be called from JS and should not generate JS code
466          * Looks up a variable identifier in various tables and generates JavaScript code that could be eval'd to get the value.
467          * @param {String} vname Identifier
468          * @param {Boolean} [local=false] Don't resolve ids and names of elements
469          * @param {Boolean} [withProps=false]
470          */
471         getvarJS: function (vname, local, withProps) {
472             var s, r = '';
473 
474             local = Type.def(local, false);
475             withProps = Type.def(withProps, false);
476 
477             s = this.isParameter(vname);
478             if (s !== null) {
479                 return vname;
480             }
481 
482             s = this.isLocalVariable(vname);
483             if (s !== null && !withProps) {
484                 return '$jc$.resolve(\'' + vname + '\')';
485             }
486 
487             // check for an element with this name
488             if (this.isCreator(vname)) {
489                 return '(function () { var a = Array.prototype.slice.call(arguments, 0), props = ' + (withProps ? 'a.pop()' : '{}') + '; return $jc$.board.create.apply($jc$.board, [\'' + vname + '\'].concat([a, props])); })';
490             }
491 
492             if (withProps) {
493                 this._error('Syntax error (attribute values are allowed with element creators only)');
494             }
495 
496             if (this.isBuiltIn(vname)) {
497                 // if src does not exist, it is a number. in that case, just return the value.
498                 return this.builtIn[vname].src || this.builtIn[vname];
499             }
500 
501             if (this.isMathMethod(vname)) {
502                 return 'Math.' + vname;
503             }
504 
505             if (!local) {
506                 if (Type.isId(this.board, vname)) {
507                     r = '$jc$.board.objects[\'' + vname + '\']';
508                 } else if (Type.isName(this.board, vname)) {
509                     r = '$jc$.board.elementsByName[\'' + vname + '\']';
510                 } else if (Type.isGroup(this.board, vname)) {
511                     r = '$jc$.board.groups[\'' + vname + '\']';
512                 }
513 
514                 return r;
515             }
516 
517             return '';
518         },
519 
520         /**
521          * Adds the property <tt>isMap</tt> to a function and sets it to true.
522          * @param {function} f
523          * @returns {function}
524          */
525         makeMap: function (f) {
526             f.isMap = true;
527 
528             return f;
529         },
530 
531         functionCodeJS: function (node) {
532             var p = node.children[0].join(', '),
533                 bo = '',
534                 bc = '';
535 
536             if (node.value === 'op_map') {
537                 bo = '{ return  ';
538                 bc = ' }';
539             }
540 
541             return 'function (' + p + ') {\n' +
542                     'var $oldscope$ = $jc$.scope;\n' +
543                     '$jc$.scope = $jc$.scopes[' + this.scope.id + '];\n' +
544                     'var r = (function () ' + bo + this.compile(node.children[1], true) + bc + ')();\n' +
545                     '$jc$.scope = $oldscope$;\n' +
546                     'return r;\n' +
547                 '}';
548         },
549 
550         /**
551          * Converts a node type <tt>node_op</tt> and value <tt>op_map</tt> or <tt>op_function</tt> into a executable
552          * function.
553          * @param {Object} node
554          * @returns {function}
555          */
556         defineFunction: function (node) {
557             var fun, i,
558                 list = node.children[0],
559                 scope = this.pushScope(list);
560 
561             if (this.board.options.jc.compile) {
562                 this.isLHS = false;
563 
564                 // we currently need to put the parameters into the local scope
565                 // until the compiled JS variable lookup code is fixed
566                 for (i = 0; i < list.length; i++) {
567                     scope.locals[list[i]] = list[i];
568                 }
569 
570                 this.replaceNames(node.children[1]);
571 
572                 fun = (function ($jc$) {
573                     var fun,
574                         str = 'var f = ' + $jc$.functionCodeJS(node) + '; f;';
575 
576                     try {
577                         // yeah, eval is evil, but we don't have much choice here.
578                         // the str is well defined and there is no user input in it that we didn't check before
579 
580                         /*jslint evil:true*/
581                         fun = eval(str);
582                         /*jslint evil:false*/
583 
584                         return fun;
585                     } catch (e) {
586                         $jc$._warn('error compiling function\n\n' + str + '\n\n' + e.toString());
587                         return function () {};
588                     }
589                 }(this));
590 
591                 // clean up scope
592                 this.popScope();
593             } else {
594                 fun = (function (_pstack, that, id) {
595                     return function () {
596                         var r, oldscope;
597 
598                         oldscope = that.scope;
599                         that.scope = that.scopes[id];
600 
601                         for (r = 0; r < _pstack.length; r++) {
602                             that.scope.locals[_pstack[r]] = arguments[r];
603                         }
604 
605                         r = that.execute(node.children[1]);
606                         that.scope = oldscope;
607 
608                         return r;
609                     };
610                 }(list, this, scope.id));
611             }
612 
613             fun.node = node;
614             fun.scope = scope;
615             fun.toJS = fun.toString;
616             fun.toString = (function (_that) {
617                 return function () {
618                     return _that.compile(_that.replaceIDs(Type.deepCopy(node)));
619                 };
620             }(this));
621 
622             fun.deps = {};
623             this.collectDependencies(node.children[1], fun.deps);
624 
625             return fun;
626         },
627 
628         /**
629          * Merge all atribute values given with an element creator into one object.
630          * @param {Object} o An arbitrary number of objects
631          * @returns {Object} All given objects merged into one. If properties appear in more (case sensitive) than one
632          * object the last value is taken.
633          */
634         mergeAttributes: function (o) {
635             var i, attr = {};
636 
637             for (i = 0; i < arguments.length; i++) {
638                 attr = Type.deepCopy(attr, arguments[i], true);
639             }
640 
641             return attr;
642         },
643 
644         /**
645          * Sets the property <tt>what</tt> of <tt>o</tt> to <tt>value</tt>
646          * @param {JXG.Point|JXG.Text} o
647          * @param {String} what
648          * @param value
649          */
650         setProp: function (o, what, value) {
651             var par = {}, x, y;
652 
653             if (o.elementClass === Const.OBJECT_CLASS_POINT && (what === 'X' || what === 'Y')) {
654                 // set coords
655 
656                 what = what.toLowerCase();
657 
658                 // we have to deal with three cases here:
659                 // o.isDraggable && typeof value === number:
660                 //   stay draggable, just set the new coords (e.g. via moveTo)
661                 // o.isDraggable && typeof value === function:
662                 //   convert to !o.isDraggable, set the new coords via o.addConstraint()
663                 // !o.isDraggable:
664                 //   stay !o.isDraggable, update the given coord by overwriting X/YEval
665 
666                 if (o.isDraggable && typeof value === 'number') {
667                     x = what === 'x' ? value : o.X();
668                     y = what === 'y' ? value : o.Y();
669 
670                     o.setPosition(Const.COORDS_BY_USER, [x, y]);
671                 } else if (o.isDraggable && (typeof value === 'function' || typeof value === 'string')) {
672                     x = what === 'x' ? value : o.coords.usrCoords[1];
673                     y = what === 'y' ? value : o.coords.usrCoords[2];
674 
675                     o.addConstraint([x, y]);
676                 } else if (!o.isDraggable) {
677                     x = what === 'x' ? value : o.XEval.origin;
678                     y = what === 'y' ? value : o.YEval.origin;
679 
680                     o.addConstraint([x, y]);
681                 }
682 
683                 this.board.update();
684             } else if (o.elementClass === Const.OBJECT_CLASS_TEXT && (what === 'X' || what === 'Y')) {
685                 if (typeof value === 'number') {
686                     o[what] = function () { return value; };
687                 } else if (typeof value === 'function') {
688                     o.isDraggable = false;
689                     o[what] = value;
690                 } else if (typeof value === 'string') {
691                     o.isDraggable = false;
692                     o[what] = Type.createFunction(value, this.board, null, true);
693                     o[what + 'jc'] = value;
694                 }
695 
696                 o[what].origin = value;
697 
698                 this.board.update();
699             } else if (o.type && o.elementClass && o.visProp) {
700                 if (Type.exists(o[o.methodMap[what]]) && typeof o[o.methodMap[what]] !== 'function') {
701                     o[o.methodMap[what]] = value;
702                 } else {
703                     par[what] = value;
704                     o.setAttribute(par);
705                 }
706             } else {
707                 o[what] = value;
708             }
709         },
710 
711         /**
712          * Parses JessieCode
713          * @param {String} code
714          * @param {Boolean} [geonext=false] Geonext compatibility mode.
715          * @param {Boolean} dontstore
716          */
717         parse: function (code, geonext, dontstore) {
718             var i, setTextBackup, ast, result,
719                 ccode = code.replace(/\r\n/g, '\n').split('\n'),
720                 cleaned = [];
721 
722             if (!dontstore) {
723                 this.code += code + '\n';
724             }
725 
726             if (Text) {
727                 setTextBackup = Text.Text.prototype.setText;
728                 Text.Text.prototype.setText = Text.Text.prototype.setTextJessieCode;
729             }
730 
731             try {
732                 if (!Type.exists(geonext)) {
733                     geonext = false;
734                 }
735 
736                 for (i = 0; i < ccode.length; i++) {
737                     if (geonext) {
738                         ccode[i] = JXG.GeonextParser.geonext2JS(ccode[i], this.board);
739                     }
740                     cleaned.push(ccode[i]);
741                 }
742 
743                 code = cleaned.join('\n');
744                 ast = parser.parse(code);
745                 result = this.execute(ast);
746             } catch (e) {  // catch is mandatory in old IEs
747             } finally {
748                 // make sure the original text method is back in place
749                 if (Text) {
750                     Text.Text.prototype.setText = setTextBackup;
751                 }
752             }
753 
754             return result;
755         },
756 
757         /**
758          * Parses a JessieCode snippet, e.g. "3+4", and wraps it into a function, if desired.
759          * @param {String} code A small snippet of JessieCode. Must not be an assignment.
760          * @param {Boolean} funwrap If true, the code is wrapped in a function.
761          * @param {String} varname Name of the parameter(s)
762          * @param {Boolean} [geonext=false] Geonext compatibility mode.
763          */
764         snippet: function (code, funwrap, varname, geonext) {
765             var c;
766 
767             funwrap = Type.def(funwrap, true);
768             varname = Type.def(varname, '');
769             geonext = Type.def(geonext, false);
770 
771             c = (funwrap ? ' function (' + varname + ') { return ' : '') + code + (funwrap ? '; }' : '') + ';';
772 
773             return this.parse(c, geonext, true);
774         },
775 
776         /**
777          * Traverses through the given subtree and changes all values of nodes with the replaced flag set by
778          * {@link JXG.JessieCode#replaceNames} to the name of the element (if not empty).
779          * @param {Object} node
780          */
781         replaceIDs: function (node) {
782             var i, v;
783 
784             if (node.replaced) {
785                 // these children exist, if node.replaced is set.
786                 v = this.board.objects[node.children[1][0].value];
787 
788                 if (Type.exists(v) && v.name !== "") {
789                     node.type = 'node_var';
790                     node.value = v.name;
791 
792                     // maybe it's not necessary, but just to be sure that everything is cleaned up we better delete all
793                     // children and the replaced flag
794                     node.children.length = 0;
795                     delete node.replaced;
796                 }
797             }
798 
799             if (node.children) {
800                 // assignments are first evaluated on the right hand side
801                 for (i = node.children.length; i > 0; i--) {
802                     if (Type.exists(node.children[i - 1])) {
803                         node.children[i - 1] = this.replaceIDs(node.children[i - 1]);
804                     }
805 
806                 }
807             }
808 
809             return node;
810         },
811 
812         /**
813          * Traverses through the given subtree and changes all elements referenced by names through referencing them by ID.
814          * An identifier is only replaced if it is not found in all scopes above the current scope and if it
815          * has not been blacklisted within the codeblock determined by the given subtree.
816          * @param {Object} node
817          */
818         replaceNames: function (node) {
819             var i, v;
820 
821             v = node.value;
822 
823             // we are interested only in nodes of type node_var and node_op > op_lhs.
824             // currently, we are not checking if the id is a local variable. in this case, we're stuck anyway.
825 
826             if (node.type === 'node_op' && v === 'op_lhs' && node.children.length === 1) {
827                 this.isLHS = true;
828             } else if (node.type === 'node_var') {
829                 if (this.isLHS) {
830                     this.letvar(v, true);
831                 } else if (!Type.exists(this.getvar(v, true)) && Type.exists(this.board.elementsByName[v])) {
832                     node = this.createReplacementNode(node);
833                 }
834             }
835 
836             if (node.children) {
837                 // assignments are first evaluated on the right hand side
838                 for (i = node.children.length; i > 0; i--) {
839                     if (Type.exists(node.children[i - 1])) {
840                         node.children[i - 1] = this.replaceNames(node.children[i - 1]);
841                     }
842                 }
843             }
844 
845             if (node.type === 'node_op' && node.value === 'op_lhs' && node.children.length === 1) {
846                 this.isLHS = false;
847             }
848 
849             return node;
850         },
851 
852         /**
853          * Replaces node_var nodes with node_op>op_execfun nodes, calling the internal $() function with the id of the
854          * element accessed by the node_var node.
855          * @param {Object} node
856          * @returns {Object} op_execfun node
857          */
858         createReplacementNode: function (node) {
859             var v = node.value,
860                 el = this.board.elementsByName[v];
861 
862             node = this.createNode('node_op', 'op_execfun',
863                 this.createNode('node_var', '$'),
864                 [this.createNode('node_str', el.id)]);
865 
866             node.replaced = true;
867 
868             return node;
869         },
870 
871         /**
872          * Search the parse tree below <tt>node</tt> for <em>stationary</em> dependencies, i.e. dependencies hard coded into
873          * the function.
874          * @param {Object} node
875          * @param {Object} result An object where the referenced elements will be stored. Access key is their id.
876          */
877         collectDependencies: function (node, result) {
878             var i, v, e;
879 
880             v = node.value;
881 
882             if (node.type === 'node_var') {
883                 e = this.getvar(v);
884                 if (e && e.visProp && e.type && e.elementClass && e.id) {
885                     result[e.id] = e;
886                 }
887             }
888 
889             // the $()-function-calls are special because their parameter is given as a string, not as a node_var.
890             if (node.type === 'node_op' && node.value === 'op_execfun' && node.children.length > 1 && node.children[0].value === '$' && node.children[1].length > 0) {
891                 e = node.children[1][0].value;
892                 result[e] = this.board.objects[e];
893             }
894 
895             if (node.children) {
896                 for (i = node.children.length; i > 0; i--) {
897                     if (Type.exists(node.children[i - 1])) {
898                         this.collectDependencies(node.children[i - 1], result);
899                     }
900 
901                 }
902             }
903         },
904 
905         resolveProperty: function (e, v, compile) {
906             compile = Type.def(compile, false);
907 
908             // is it a geometry element or a board?
909             if (e /*&& e.type && e.elementClass*/ && e.methodMap) {
910                 // yeah, it is. but what does the user want?
911                 if (Type.exists(e.subs) && Type.exists(e.subs[v])) {
912                     // a subelement it is, good sir.
913                     e = e.subs;
914                 } else if (Type.exists(e.methodMap[v])) {
915                     // the user wants to call a method
916                     v = e.methodMap[v];
917                 } else {
918                     // the user wants to change an attribute
919                     e = e.visProp;
920                     v = v.toLowerCase();
921                 }
922             }
923 
924             if (!Type.exists(e)) {
925                 this._error(e + ' is not an object');
926             }
927 
928             if (!Type.exists(e[v])) {
929                 this._error('unknown property ' + v);
930             }
931 
932             if (compile && typeof e[v] === 'function') {
933                 return function () { return e[v].apply(e, arguments); };
934             }
935 
936             return e[v];
937         },
938 
939         /**
940          * Resolves the lefthand side of an assignment operation
941          * @param node
942          * @returns {Object} An object with two properties. <strong>o</strong> which contains the object, and
943          * a string <strong>what</strong> which contains the property name.
944          */
945         getLHS: function (node) {
946             var res;
947 
948             if (node.type === 'node_var') {
949                 res = {
950                     o: this.scope.locals,
951                     what: node.value
952                 };
953             } else if (node.type === 'node_op' && node.value === 'op_property') {
954                 res = {
955                     o: this.execute(node.children[0]),
956                     what: node.children[1]
957                 };
958             } else if (node.type === 'node_op' && node.value === 'op_extvalue') {
959                 res = {
960                     o: this.execute(node.children[0]),
961                     what: this.execute(node.children[1])
962                 };
963             } else {
964                 throw new Error('Syntax error: Invalid left-hand side of assignment.');
965             }
966 
967             return res;
968         },
969 
970         getLHSCompiler: function (node, js) {
971             var res;
972 
973             if (node.type === 'node_var') {
974                 res = node.value;
975             } else if (node.type === 'node_op' && node.value === 'op_property') {
976                 res = [
977                     this.compile(node.children[0], js),
978                     "'" + node.children[1] + "'"
979                 ];
980             } else if (node.type === 'node_op' && node.value === 'op_extvalue') {
981                 res = [
982                     this.compile(node.children[0], js),
983                     node.children[1].type === 'node_const' ? node.children[1].value : this.compile(node.children[1], js)
984                 ];
985             } else {
986                 throw new Error('Syntax error: Invalid left-hand side of assignment.');
987             }
988 
989             return res;
990         },
991 
992         /**
993          * Executes a parse subtree.
994          * @param {Object} node
995          * @returns {Number|String|Object|Boolean} Something
996          * @private
997          */
998         execute: function (node) {
999             var ret, v, i, e, l, undef, list, ilist,
1000                 parents = [],
1001                 // exec fun
1002                 fun, attr, sc;
1003 
1004             ret = 0;
1005 
1006             if (!node) {
1007                 return ret;
1008             }
1009 
1010             this.line = node.line;
1011             this.col = node.col;
1012 
1013             switch (node.type) {
1014             case 'node_op':
1015                 switch (node.value) {
1016                 case 'op_none':
1017                     if (node.children[0]) {
1018                         this.execute(node.children[0]);
1019                     }
1020                     if (node.children[1]) {
1021                         ret = this.execute(node.children[1]);
1022                     }
1023                     break;
1024                 case 'op_assign':
1025                     v = this.getLHS(node.children[0]);
1026 
1027                     this.lhs[this.scope.id] = v[1];
1028 
1029                     if (v.o.type && v.o.elementClass && v.o.methodMap && v.what === 'label') {
1030                         this._error('Left-hand side of assignment is read-only.');
1031                     }
1032 
1033                     ret = this.execute(node.children[1]);
1034                     if (v.o !== this.scope.locals || (Type.isArray(v.o) && typeof v.what === 'number')) {
1035                         // it is either an array component being set or a property of an object.
1036                         this.setProp(v.o, v.what, ret);
1037                     } else {
1038                         // this is just a local variable inside JessieCode
1039                         this.letvar(v.what, ret);
1040                     }
1041 
1042                     this.lhs[this.scope.id] = 0;
1043                     break;
1044                 case 'op_if':
1045                     if (this.execute(node.children[0])) {
1046                         ret = this.execute(node.children[1]);
1047                     }
1048                     break;
1049                 case 'op_conditional':
1050                     // fall through
1051                 case 'op_if_else':
1052                     if (this.execute(node.children[0])) {
1053                         ret = this.execute(node.children[1]);
1054                     } else {
1055                         ret = this.execute(node.children[2]);
1056                     }
1057                     break;
1058                 case 'op_while':
1059                     while (this.execute(node.children[0])) {
1060                         this.execute(node.children[1]);
1061                     }
1062                     break;
1063                 case 'op_do':
1064                     do {
1065                         this.execute(node.children[0]);
1066                     } while (this.execute(node.children[1]));
1067                     break;
1068                 case 'op_for':
1069                     for (this.execute(node.children[0]); this.execute(node.children[1]); this.execute(node.children[2])) {
1070                         this.execute(node.children[3]);
1071                     }
1072                     break;
1073                 case 'op_proplst':
1074                     if (node.children[0]) {
1075                         this.execute(node.children[0]);
1076                     }
1077                     if (node.children[1]) {
1078                         this.execute(node.children[1]);
1079                     }
1080                     break;
1081                 case 'op_emptyobject':
1082                     ret = {};
1083                     break;
1084                 case 'op_proplst_val':
1085                     this.propstack.push({});
1086                     this.propscope++;
1087 
1088                     this.execute(node.children[0]);
1089                     ret = this.propstack[this.propscope];
1090 
1091                     this.propstack.pop();
1092                     this.propscope--;
1093                     break;
1094                 case 'op_prop':
1095                     // child 0: Identifier
1096                     // child 1: Value
1097                     this.propstack[this.propscope][node.children[0]] = this.execute(node.children[1]);
1098                     break;
1099                 case 'op_array':
1100                     ret = [];
1101                     l = node.children[0].length;
1102 
1103                     for (i = 0; i < l; i++) {
1104                         ret.push(this.execute(node.children[0][i]));
1105                     }
1106 
1107                     break;
1108                 case 'op_extvalue':
1109                     ret = this.execute(node.children[0]);
1110                     i = this.execute(node.children[1]);
1111 
1112                     if (typeof i === 'number' && Math.abs(Math.round(i) - i) < Mat.eps) {
1113                         ret = ret[i];
1114                     } else {
1115                         ret = undef;
1116                     }
1117                     break;
1118                 case 'op_return':
1119                     if (this.scope === 0) {
1120                         this._error('Unexpected return.');
1121                     } else {
1122                         return this.execute(node.children[0]);
1123                     }
1124                     break;
1125                 case 'op_map':
1126                     if (!node.children[1].isMath) {
1127                         this._error('In a map only function calls and mathematical expressions are allowed.');
1128                     }
1129 
1130                     fun = this.defineFunction(node);
1131                     fun.isMap = true;
1132 
1133                     ret = fun;
1134                     break;
1135                 case 'op_function':
1136                     // parse the parameter list
1137                     // after this, the parameters are in pstack
1138 
1139                     fun = this.defineFunction(node);
1140                     fun.isMap = false;
1141 
1142                     ret = fun;
1143                     break;
1144                 case 'op_execfun':
1145                     // node.children:
1146                     //   [0]: Name of the function
1147                     //   [1]: Parameter list as a parse subtree
1148                     //   [2]: Properties, only used in case of a create function
1149                     this.dpstack.push([]);
1150                     this.pscope++;
1151 
1152                     // parameter parsing is done below
1153                     list = node.children[1];
1154 
1155                     // parse the properties only if given
1156                     if (Type.exists(node.children[2])) {
1157                         if (node.children[3]) {
1158                             ilist = node.children[2];
1159                             attr = {};
1160 
1161                             for (i = 0; i < ilist.length; i++) {
1162                                 attr = Type.deepCopy(attr, this.execute(ilist[i]), true);
1163                             }
1164                         } else {
1165                             attr = this.execute(node.children[2]);
1166                         }
1167                     }
1168 
1169                     // look up the variables name in the variable table
1170                     fun = this.execute(node.children[0]);
1171 
1172                     // determine the scope the function wants to run in
1173                     if (fun && fun.sc) {
1174                         sc = fun.sc;
1175                     } else {
1176                         sc = this;
1177                     }
1178 
1179                     if (!fun.creator && Type.exists(node.children[2])) {
1180                         this._error('Unexpected value. Only element creators are allowed to have a value after the function call.');
1181                     }
1182 
1183                     // interpret ALL the parameters
1184                     for (i = 0; i < list.length; i++) {
1185                         parents[i] = this.execute(list[i]);
1186                         this.dpstack[this.pscope].push({
1187                             line: node.children[1][i].line,
1188                             // SketchBin currently works only if the last column of the
1189                             // parent position is taken. This is due to how I patched JS/CC
1190                             // to count the lines and columns. So, ecol will do for now
1191                             col: node.children[1][i].ecol
1192                         });
1193                     }
1194 
1195                     // check for the function in the variable table
1196                     if (typeof fun === 'function' && !fun.creator) {
1197                         ret = fun.apply(sc, parents);
1198                     } else if (typeof fun === 'function' && !!fun.creator) {
1199                         e = this.line;
1200 
1201                         // creator methods are the only ones that take properties, hence this special case
1202                         try {
1203                             ret = fun(parents, attr);
1204                             ret.jcLineStart = e;
1205                             ret.jcLineEnd = node.eline;
1206 
1207                             for (i = e; i <= node.line; i++) {
1208                                 this.lineToElement[i] = ret;
1209                             }
1210 
1211                             ret.debugParents = this.dpstack[this.pscope];
1212                         } catch (ex) {
1213                             this._error(ex.toString());
1214                         }
1215                     } else {
1216                         this._error('Function \'' + fun + '\' is undefined.');
1217                     }
1218 
1219                     // clear parameter stack
1220                     this.dpstack.pop();
1221                     this.pscope--;
1222                     break;
1223                 case 'op_property':
1224                     e = this.execute(node.children[0]);
1225                     v = node.children[1];
1226 
1227                     ret = this.resolveProperty(e, v, false);
1228 
1229                     // set the scope, in case this is a method the user wants to call
1230                     if (Type.exists(ret)) {
1231                         ret.sc = e;
1232                     }
1233 
1234                     break;
1235                 case 'op_use':
1236                     this._warn('Use of the \'use\' operator is deprecated.');
1237                     this.use(node.children[0].toString());
1238                     break;
1239                 case 'op_delete':
1240                     this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.');
1241                     v = this.getvar(node.children[0]);
1242                     ret = this.del(v);
1243                     break;
1244                 case 'op_equ':
1245                     // == is intentional
1246                     /*jslint eqeq:true*/
1247                     ret = this.execute(node.children[0]) == this.execute(node.children[1]);
1248                     /*jslint eqeq:false*/
1249                     break;
1250                 case 'op_neq':
1251                     // != is intentional
1252                     /*jslint eqeq:true*/
1253                     ret = this.execute(node.children[0]) != this.execute(node.children[1]);
1254                     /*jslint eqeq:true*/
1255                     break;
1256                 case 'op_approx':
1257                     ret = Math.abs(this.execute(node.children[0]) - this.execute(node.children[1])) < Mat.eps;
1258                     break;
1259                 case 'op_grt':
1260                     ret = this.execute(node.children[0]) > this.execute(node.children[1]);
1261                     break;
1262                 case 'op_lot':
1263                     ret = this.execute(node.children[0]) < this.execute(node.children[1]);
1264                     break;
1265                 case 'op_gre':
1266                     ret = this.execute(node.children[0]) >= this.execute(node.children[1]);
1267                     break;
1268                 case 'op_loe':
1269                     ret = this.execute(node.children[0]) <= this.execute(node.children[1]);
1270                     break;
1271                 case 'op_or':
1272                     ret = this.execute(node.children[0]) || this.execute(node.children[1]);
1273                     break;
1274                 case 'op_and':
1275                     ret = this.execute(node.children[0]) && this.execute(node.children[1]);
1276                     break;
1277                 case 'op_not':
1278                     ret = !this.execute(node.children[0]);
1279                     break;
1280                 case 'op_add':
1281                     ret = this.add(this.execute(node.children[0]), this.execute(node.children[1]));
1282                     break;
1283                 case 'op_sub':
1284                     ret = this.sub(this.execute(node.children[0]), this.execute(node.children[1]));
1285                     break;
1286                 case 'op_div':
1287                     ret = this.div(this.execute(node.children[0]), this.execute(node.children[1]));
1288                     break;
1289                 case 'op_mod':
1290                     // use mathematical modulo, JavaScript implements the symmetric modulo.
1291                     ret = this.mod(this.execute(node.children[0]), this.execute(node.children[1]), true);
1292                     break;
1293                 case 'op_mul':
1294                     ret = this.mul(this.execute(node.children[0]), this.execute(node.children[1]));
1295                     break;
1296                 case 'op_exp':
1297                     ret = this.pow(this.execute(node.children[0]),  this.execute(node.children[1]));
1298                     break;
1299                 case 'op_neg':
1300                     ret = this.execute(node.children[0]) * -1;
1301                     break;
1302                 }
1303                 break;
1304 
1305             case 'node_var':
1306                 ret = this.getvar(node.value);
1307                 break;
1308 
1309             case 'node_const':
1310                 ret = Number(node.value);
1311                 break;
1312 
1313             case 'node_const_bool':
1314                 ret = node.value;
1315                 break;
1316 
1317             case 'node_str':
1318                 //ret = node.value.replace(/\\'/, "'").replace(/\\"/, '"').replace(/\\\\/, '\\');
1319                 /*jslint regexp:true*/
1320                 ret = node.value.replace(/\\(.)/, '$1');
1321                 /*jslint regexp:false*/
1322                 break;
1323             }
1324 
1325             return ret;
1326         },
1327 
1328         /**
1329          * Compiles a parse tree back to JessieCode.
1330          * @param {Object} node
1331          * @param {Boolean} [js=false] Currently ignored. Compile either to JavaScript or back to JessieCode (required for the UI).
1332          * @returns Something
1333          * @private
1334          */
1335         compile: function (node, js) {
1336             var e, i, list, scope,
1337                 ret = '';
1338 
1339             if (!Type.exists(js)) {
1340                 js = false;
1341             }
1342 
1343             if (!node) {
1344                 return ret;
1345             }
1346 
1347             switch (node.type) {
1348             case 'node_op':
1349                 switch (node.value) {
1350                 case 'op_none':
1351                     if (node.children[0]) {
1352                         ret = this.compile(node.children[0], js);
1353                     }
1354                     if (node.children[1]) {
1355                         ret += this.compile(node.children[1], js);
1356                     }
1357                     break;
1358                 case 'op_assign':
1359                     //e = this.compile(node.children[0], js);
1360                     if (js) {
1361                         e = this.getLHSCompiler(node.children[0], js);
1362                         if (Type.isArray(e)) {
1363                             ret = '$jc$.setProp(' + e[0] + ', ' + e[1] + ', ' + this.compile(node.children[1], js) + ');\n';
1364                         } else {
1365                             if (this.isLocalVariable(e) !== this.scope) {
1366                                 this.scope.locals[e] = true;
1367                             }
1368                             ret = '$jc$.scopes[' + this.scope.id + '].locals[\'' + e + '\'] = ' + this.compile(node.children[1], js) + ';\n';
1369                         }
1370                     } else {
1371                         e = this.compile(node.children[0]);
1372                         ret = e + ' = ' + this.compile(node.children[1], js) + ';\n';
1373                     }
1374 
1375                     break;
1376                 case 'op_if':
1377                     ret = ' if (' + this.compile(node.children[0], js) + ') ' + this.compile(node.children[1], js);
1378                     break;
1379                 case 'op_if_else':
1380                     ret = ' if (' + this.compile(node.children[0], js) + ')' + this.compile(node.children[1], js);
1381                     ret += ' else ' + this.compile(node.children[2], js);
1382                     break;
1383                 case 'op_conditional':
1384                     ret = '((' + this.compile(node.children[0], js) + ')?(' + this.compile(node.children[1], js);
1385                     ret += '):(' + this.compile(node.children[2], js) + '))';
1386                     break;
1387                 case 'op_while':
1388                     ret = ' while (' + this.compile(node.children[0], js) + ') {\n' + this.compile(node.children[1], js) + '}\n';
1389                     break;
1390                 case 'op_do':
1391                     ret = ' do {\n' + this.compile(node.children[0], js) + '} while (' + this.compile(node.children[1], js) + ');\n';
1392                     break;
1393                 case 'op_for':
1394                     ret = ' for (' + this.compile(node.children[0], js) + '; ' + this.compile(node.children[1], js) + '; ' + this.compile(node.children[2], js) + ') {\n' + this.compile(node.children[3], js) + '\n}\n';
1395                     break;
1396                 case 'op_proplst':
1397                     if (node.children[0]) {
1398                         ret = this.compile(node.children[0], js) + ', ';
1399                     }
1400 
1401                     ret += this.compile(node.children[1], js);
1402                     break;
1403                 case 'op_prop':
1404                     // child 0: Identifier
1405                     // child 1: Value
1406                     ret = node.children[0] + ': ' + this.compile(node.children[1], js);
1407                     break;
1408                 case 'op_emptyobject':
1409                     ret = js ? '{}' : '<< >>';
1410                     break;
1411                 case 'op_proplst_val':
1412                     ret = this.compile(node.children[0], js);
1413                     break;
1414                 case 'op_array':
1415                     list = [];
1416                     for (i = 0; i < node.children[0].length; i++) {
1417                         list.push(this.compile(node.children[0][i], js));
1418                     }
1419                     ret = '[' + list.join(', ') + ']';
1420                     break;
1421                 case 'op_extvalue':
1422                     ret = this.compile(node.children[0], js) + '[' + this.compile(node.children[1], js) + ']';
1423                     break;
1424                 case 'op_return':
1425                     ret = ' return ' + this.compile(node.children[0], js) + ';\n';
1426                     break;
1427                 case 'op_map':
1428                     if (!node.children[1].isMath) {
1429                         this._error('In a map only function calls and mathematical expressions are allowed.');
1430                     }
1431 
1432                     list = node.children[0];
1433                     if (js) {
1434                         ret = ' $jc$.makeMap(function (' + list.join(', ') + ') { return ' + this.compile(node.children[1], js) + '; })';
1435                     } else {
1436                         ret = 'map (' + list.join(', ') + ') -> ' + this.compile(node.children[1], js);
1437                     }
1438                     break;
1439                 case 'op_function':
1440                     list = node.children[0];
1441                     scope = this.pushScope(list);
1442                     if (js) {
1443                         ret = this.functionCodeJS(node);
1444                     } else {
1445                         ret = ' function (' + list.join(', ') + ') ' + this.compile(node.children[1], js);
1446                     }
1447                     this.popScope();
1448                     break;
1449                 case 'op_execfunmath':
1450                     console.log('TODO');
1451                     ret = '-1';
1452                     break;
1453                 case 'op_execfun':
1454                     // parse the properties only if given
1455                     if (node.children[2]) {
1456                         list = [];
1457                         for (i = 0; i < node.children[2].length; i++) {
1458                             list.push(this.compile(node.children[2][i], js));
1459                         }
1460 
1461                         if (js) {
1462                             e = '$jc$.mergeAttributes(' + list.join(', ') + ')';
1463                         }
1464                     }
1465                     node.children[0].withProps = !!node.children[2];
1466                     list = [];
1467                     for (i = 0; i < node.children[1].length; i++) {
1468                         list.push(this.compile(node.children[1][i], js));
1469                     }
1470                     ret = this.compile(node.children[0], js) + '(' + list.join(', ') + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? e : '');
1471 
1472                     // save us a function call when compiled to javascript
1473                     if (js && node.children[0].value === '$') {
1474                         ret = '$jc$.board.objects[' + this.compile(node.children[1][0], js) + ']';
1475                     }
1476 
1477                     break;
1478                 case 'op_property':
1479                     if (js && node.children[1] !== 'X' && node.children[1] !== 'Y') {
1480                         ret = '$jc$.resolveProperty(' + this.compile(node.children[0], js) + ', \'' + node.children[1] + '\', true)';
1481                     } else {
1482                         ret = this.compile(node.children[0], js) + '.' + node.children[1];
1483                     }
1484                     break;
1485                 case 'op_use':
1486                     this._warn('Use of the \'use\' operator is deprecated.');
1487                     if (js) {
1488                         ret = '$jc$.use(\'';
1489                     } else {
1490                         ret = 'use(\'';
1491                     }
1492 
1493                     ret += node.children[0].toString() + '\');';
1494                     break;
1495                 case 'op_delete':
1496                     this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.');
1497                     if (js) {
1498                         ret = '$jc$.del(';
1499                     } else {
1500                         ret = 'remove(';
1501                     }
1502 
1503                     ret += this.compile(node.children[0], js) + ')';
1504                     break;
1505                 case 'op_equ':
1506                     ret = '(' + this.compile(node.children[0], js) + ' == ' + this.compile(node.children[1], js) + ')';
1507                     break;
1508                 case 'op_neq':
1509                     ret = '(' + this.compile(node.children[0], js) + ' != ' + this.compile(node.children[1], js) + ')';
1510                     break;
1511                 case 'op_approx':
1512                     ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')';
1513                     break;
1514                 case 'op_grt':
1515                     ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')';
1516                     break;
1517                 case 'op_lot':
1518                     ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')';
1519                     break;
1520                 case 'op_gre':
1521                     ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')';
1522                     break;
1523                 case 'op_loe':
1524                     ret = '(' + this.compile(node.children[0], js) + ' <= ' + this.compile(node.children[1], js) + ')';
1525                     break;
1526                 case 'op_or':
1527                     ret = '(' + this.compile(node.children[0], js) + ' || ' + this.compile(node.children[1], js) + ')';
1528                     break;
1529                 case 'op_and':
1530                     ret = '(' + this.compile(node.children[0], js) + ' && ' + this.compile(node.children[1], js) + ')';
1531                     break;
1532                 case 'op_not':
1533                     ret = '!(' + this.compile(node.children[0], js) + ')';
1534                     break;
1535                 case 'op_add':
1536                     if (js) {
1537                         ret = '$jc$.add(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
1538                     } else {
1539                         ret = '(' + this.compile(node.children[0], js) + ' + ' + this.compile(node.children[1], js) + ')';
1540                     }
1541                     break;
1542                 case 'op_sub':
1543                     if (js) {
1544                         ret = '$jc$.sub(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
1545                     } else {
1546                         ret = '(' + this.compile(node.children[0], js) + ' - ' + this.compile(node.children[1], js) + ')';
1547                     }
1548                     break;
1549                 case 'op_div':
1550                     if (js) {
1551                         ret = '$jc$.div(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
1552                     } else {
1553                         ret = '(' + this.compile(node.children[0], js) + ' / ' + this.compile(node.children[1], js) + ')';
1554                     }
1555                     break;
1556                 case 'op_mod':
1557                     if (js) {
1558                         ret = '$jc$.mod(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ', true)';
1559                     } else {
1560                         ret = '(' + this.compile(node.children[0], js) + ' % ' + this.compile(node.children[1], js) + ')';
1561                     }
1562                     break;
1563                 case 'op_mul':
1564                     if (js) {
1565                         ret = '$jc$.mul(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
1566                     } else {
1567                         ret = '(' + this.compile(node.children[0], js) + ' * ' + this.compile(node.children[1], js) + ')';
1568                     }
1569                     break;
1570                 case 'op_exp':
1571                     if (js) {
1572                         ret = '$jc$.pow(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';
1573                     } else {
1574                         ret = '(' + this.compile(node.children[0], js) + '^' + this.compile(node.children[1], js) + ')';
1575                     }
1576                     break;
1577                 case 'op_neg':
1578                     ret = '(-' + this.compile(node.children[0], js) + ')';
1579                     break;
1580                 }
1581                 break;
1582 
1583             case 'node_var':
1584                 if (js) {
1585                     ret = this.getvarJS(node.value, false, node.withProps);
1586                 } else {
1587                     ret = node.value;
1588                 }
1589                 break;
1590 
1591             case 'node_const':
1592                 ret = node.value;
1593                 break;
1594 
1595             case 'node_const_bool':
1596                 ret = node.value;
1597                 break;
1598 
1599             case 'node_str':
1600                 ret = '\'' + node.value + '\'';
1601                 break;
1602             }
1603 
1604             if (node.needsBrackets) {
1605                 ret = '{\n' + ret + '}\n';
1606             }
1607 
1608             return ret;
1609         },
1610 
1611         /**
1612          * This is used as the global X() function.
1613          * @param {JXG.Point|JXG.Text} e
1614          * @returns {Number}
1615          */
1616         X: function (e) {
1617             return e.X();
1618         },
1619 
1620         /**
1621          * This is used as the global Y() function.
1622          * @param {JXG.Point|JXG.Text} e
1623          * @returns {Number}
1624          */
1625         Y: function (e) {
1626             return e.Y();
1627         },
1628 
1629         /**
1630          * This is used as the global V() function.
1631          * @param {Glider|Slider} e
1632          * @returns {Number}
1633          */
1634         V: function (e) {
1635             return e.Value();
1636         },
1637 
1638         /**
1639          * This is used as the global L() function.
1640          * @param {JXG.Line} e
1641          * @returns {Number}
1642          */
1643         L: function (e) {
1644             return e.L();
1645         },
1646 
1647         /**
1648          * This is used as the global dist() function.
1649          * @param {JXG.Point} p1
1650          * @param {JXG.Point} p2
1651          * @returns {Number}
1652          */
1653         dist: function (p1, p2) {
1654             if (!Type.exists(p1) || !Type.exists(p1.Dist)) {
1655                 this._error('Error: Can\'t calculate distance.');
1656             }
1657 
1658             return p1.Dist(p2);
1659         },
1660 
1661         /**
1662          * + operator implementation
1663          * @param {Number|Array|JXG.Point} a
1664          * @param {Number|Array|JXG.Point} b
1665          * @returns {Number|Array}
1666          */
1667         add: function (a, b) {
1668             var i, len, res;
1669 
1670             a = Type.evalSlider(a);
1671             b = Type.evalSlider(b);
1672 
1673             if (Type.isArray(a) && Type.isArray(b)) {
1674                 len = Math.min(a.length, b.length);
1675                 res = [];
1676 
1677                 for (i = 0; i < len; i++) {
1678                     res[i] = a[i] + b[i];
1679                 }
1680             } else if (Type.isNumber(a) && Type.isNumber(b)) {
1681                 res = a + b;
1682             } else if (Type.isString(a) || Type.isString(b)) {
1683                 res = a.toString() + b.toString();
1684             } else {
1685                 this._error('Operation + not defined on operands ' + typeof a + ' and ' + typeof b);
1686             }
1687 
1688             return res;
1689         },
1690 
1691         /**
1692          * + operator implementation
1693          * @param {Number|Array|JXG.Point} a
1694          * @param {Number|Array|JXG.Point} b
1695          * @returns {Number|Array}
1696          */
1697         sub: function (a, b) {
1698             var i, len, res;
1699 
1700             a = Type.evalSlider(a);
1701             b = Type.evalSlider(b);
1702 
1703             if (Type.isArray(a) && Type.isArray(b)) {
1704                 len = Math.min(a.length, b.length);
1705                 res = [];
1706 
1707                 for (i = 0; i < len; i++) {
1708                     res[i] = a[i] - b[i];
1709                 }
1710             } else if (Type.isNumber(a) && Type.isNumber(b)) {
1711                 res = a - b;
1712             } else {
1713                 this._error('Operation - not defined on operands ' + typeof a + ' and ' + typeof b);
1714             }
1715 
1716             return res;
1717         },
1718 
1719         /**
1720          * Multiplication of vectors and numbers
1721          * @param {Number|Array} a
1722          * @param {Number|Array} b
1723          * @returns {Number|Array} (Inner) product of the given input values.
1724          */
1725         mul: function (a, b) {
1726             var i, len, res;
1727 
1728             a = Type.evalSlider(a);
1729             b = Type.evalSlider(b);
1730 
1731             if (Type.isArray(a) && Type.isNumber(b)) {
1732                 // swap b and a
1733                 i = a;
1734                 a = b;
1735                 b = a;
1736             }
1737 
1738             if (Type.isArray(a) && Type.isArray(b)) {
1739                 len = Math.min(a.length, b.length);
1740                 res = Mat.innerProduct(a, b, len);
1741             } else if (Type.isNumber(a) && Type.isArray(b)) {
1742                 len = b.length;
1743                 res = [];
1744 
1745                 for (i = 0; i < len; i++) {
1746                     res[i] = a * b[i];
1747                 }
1748             } else if (Type.isNumber(a) && Type.isNumber(b)) {
1749                 res = a * b;
1750             } else {
1751                 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);
1752             }
1753 
1754             return res;
1755         },
1756 
1757         /**
1758          * Implementation of the / operator.
1759          * @param {Number|Array} a
1760          * @param {Number} b
1761          * @returns {Number|Array}
1762          */
1763         div: function (a, b) {
1764             var i, len, res;
1765 
1766             a = Type.evalSlider(a);
1767             b = Type.evalSlider(b);
1768 
1769             if (Type.isArray(a) && Type.isNumber(b)) {
1770                 len = a.length;
1771                 res = [];
1772 
1773                 for (i = 0; i < len; i++) {
1774                     res[i] = a[i] / b;
1775                 }
1776             } else if (Type.isNumber(a) && Type.isNumber(b)) {
1777                 res = a / b;
1778             } else {
1779                 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);
1780             }
1781 
1782             return res;
1783         },
1784 
1785         /**
1786          * Implementation of the % operator.
1787          * @param {Number|Array} a
1788          * @param {Number} b
1789          * @returns {Number|Array}
1790          */
1791         mod: function (a, b) {
1792             var i, len, res;
1793 
1794             a = Type.evalSlider(a);
1795             b = Type.evalSlider(b);
1796 
1797             if (Type.isArray(a) && Type.isNumber(b)) {
1798                 len = a.length;
1799                 res = [];
1800 
1801                 for (i = 0; i < len; i++) {
1802                     res[i] = Mat.mod(a[i], b, true);
1803                 }
1804             } else if (Type.isNumber(a) && Type.isNumber(b)) {
1805                 res = Mat.mod(a, b, true);
1806             } else {
1807                 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);
1808             }
1809 
1810             return res;
1811         },
1812 
1813         /**
1814          * Pow function wrapper to allow direct usage of sliders.
1815          * @param {Number|Slider} a
1816          * @param {Number|Slider} b
1817          * @returns {Number}
1818          */
1819         pow: function (a, b) {
1820             a = Type.evalSlider(a);
1821             b = Type.evalSlider(b);
1822 
1823             return Math.pow(a, b);
1824         },
1825 
1826         /**
1827          * Implementation of the ?: operator
1828          * @param {Boolean} cond Condition
1829          * @param {*} v1
1830          * @param {*} v2
1831          * @returns {*} Either v1 or v2.
1832          */
1833         ifthen: function (cond, v1, v2) {
1834             if (cond) {
1835                 return v1;
1836             }
1837 
1838             return v2;
1839         },
1840 
1841         /**
1842          * Implementation of the delete() builtin function
1843          * @param {JXG.GeometryElement} element
1844          */
1845         del: function (element) {
1846             if (typeof element === 'object' && JXG.exists(element.type) && JXG.exists(element.elementClass)) {
1847                 this.board.removeObject(element);
1848             }
1849         },
1850 
1851         /**
1852          * Implementation of the use() builtin function
1853          * @param {String} board
1854          */
1855         use: function (board) {
1856             var b, ref,
1857                 found = false;
1858 
1859             if (typeof board === 'string') {
1860                 // search all the boards for the one with the appropriate container div
1861                 for (b in JXG.boards) {
1862                     if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === board) {
1863                         ref = JXG.boards[b];
1864                         found = true;
1865                         break;
1866                     }
1867                 }
1868             } else {
1869                 ref = board;
1870                 found = true;
1871             }
1872 
1873             if (found) {
1874                 this.board = ref;
1875                 this.builtIn.$board = ref;
1876                 this.builtIn.$board.src = '$jc$.board';
1877             } else {
1878                 this._error('Board \'' + board + '\' not found!');
1879             }
1880         },
1881 
1882         /**
1883          * Find the first symbol to the given value from the given scope upwards.
1884          * @param v Value
1885          * @param {Number} [scope=-1] The scope, default is to start with current scope (-1).
1886          * @returns {Array} An array containing the symbol and the scope if a symbol could be found,
1887          * an empty array otherwise;
1888          */
1889         findSymbol: function (v, scope) {
1890             var i, s;
1891 
1892             scope = Type.def(scope, -1);
1893 
1894             if (scope === -1) {
1895                 s = this.scope;
1896             } else {
1897                 s = this.scopes[scope];
1898             }
1899 
1900             while (s !== null) {
1901                 for (i in s.locals) {
1902                     if (s.locals.hasOwnProperty(i) && s.locals[i] === v) {
1903                         return [i, s];
1904                     }
1905                 }
1906 
1907                 s = s.previous;
1908             }
1909 
1910             return [];
1911         },
1912 
1913         /**
1914          * Import modules into a JessieCode script.
1915          * @param {String} module
1916          */
1917         importModule: function (module) {
1918             return priv.modules[module.toLowerCase()];
1919         },
1920 
1921         /**
1922          * Defines built in methods and constants.
1923          * @returns {Object} BuiltIn control object
1924          */
1925         defineBuiltIn: function () {
1926             var that = this,
1927                 builtIn = {
1928                     PI: Math.PI,
1929                     EULER: Math.E,
1930                     X: that.X,
1931                     Y: that.Y,
1932                     V: that.V,
1933                     L: that.L,
1934                     dist: that.dist,
1935                     rad: Geometry.rad,
1936                     deg: Geometry.trueAngle,
1937                     factorial: Mat.factorial,
1938                     trunc: Type.trunc,
1939                     log: Mat.log,
1940                     ln: Math.log,
1941                     log10: Mat.log10,
1942                     lg: Mat.log10,
1943                     log2: Mat.log2,
1944                     lb: Mat.log2,
1945                     ld: Mat.log2,
1946                     cosh: Mat.cosh,
1947                     sinh: Mat.sinh,
1948                     IfThen: that.ifthen,
1949                     'import': that.importModule,
1950                     'use': that.use,
1951                     'remove': that.del,
1952                     '$': that.getElementById,
1953                     '$board': that.board,
1954                     '$log': that.log
1955                 };
1956 
1957             // special scopes for factorial, deg, and rad
1958             builtIn.rad.sc = Geometry;
1959             builtIn.deg.sc = Geometry;
1960             builtIn.factorial.sc = Mat;
1961 
1962             // set the javascript equivalent for the builtIns
1963             // some of the anonymous functions should be replaced by global methods later on
1964             // EULER and PI don't get a source attribute - they will be lost anyways and apparently
1965             // some browser will throw an exception when a property is assigned to a primitive value.
1966             builtIn.X.src = '$jc$.X';
1967             builtIn.Y.src = '$jc$.Y';
1968             builtIn.V.src = '$jc$.V';
1969             builtIn.L.src = '$jc$.L';
1970             builtIn.dist.src = '$jc$.dist';
1971             builtIn.rad.src = 'JXG.Math.Geometry.rad';
1972             builtIn.deg.src = 'JXG.Math.Geometry.trueAngle';
1973             builtIn.factorial.src = 'JXG.Math.factorial';
1974             builtIn.trunc.src = 'JXG.trunc';
1975             builtIn.ln.src = 'Math.log';
1976             builtIn.log10.src = 'JXG.Math.log10';
1977             builtIn.lg.src = 'JXG.Math.log10';
1978             builtIn.log2.src = 'JXG.Math.log2';
1979             builtIn.lb.src = 'JXG.Math.log2';
1980             builtIn.ld.src = 'JXG.Math.log2';
1981             builtIn.cosh.src = 'JXG.Math.cosh';
1982             builtIn.sinh.src = 'JXG.Math.sinh';
1983             builtIn['import'].src = '$jc$.importModule';
1984             builtIn.use.src = '$jc$.use';
1985             builtIn.remove.src = '$jc$.del';
1986             builtIn.IfThen.src = '$jc$.ifthen';
1987             // usually unused, see node_op > op_execfun
1988             builtIn.$.src = '(function (n) { return $jc$.board.select(n); })';
1989             if (builtIn.$board) {
1990                 builtIn.$board.src = '$jc$.board';
1991             }
1992             builtIn.$log.src = '$jc$.log';
1993 
1994             return builtIn;
1995         },
1996 
1997         /**
1998          * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the
1999          * id "debug" and an innerHTML property is used.
2000          * @param {String} log
2001          * @private
2002          */
2003         _debug: function (log) {
2004             if (typeof console === 'object') {
2005                 console.log(log);
2006             } else if (Env.isBrowser && document && document.getElementById('debug') !== null) {
2007                 document.getElementById('debug').innerHTML += log + '<br />';
2008             }
2009         },
2010 
2011         /**
2012          * Throws an exception with the given error message.
2013          * @param {String} msg Error message
2014          */
2015         _error: function (msg) {
2016             var e = new Error('Error(' + this.line + '): ' + msg);
2017             e.line = this.line;
2018             throw e;
2019         },
2020 
2021         /**
2022          * Output a warning message using {@link JXG#debug} and precedes the message with "Warning: ".
2023          * @param {String} msg
2024          */
2025         _warn: function (msg) {
2026             if (typeof console === 'object') {
2027                 console.log('Warning(' + this.line + '): ' + msg);
2028             } else if (Env.isBrowser && document && document.getElementById(this.warnLog) !== null) {
2029                 document.getElementById(this.warnLog).innerHTML += 'Warning(' + this.line + '): ' + msg + '<br />';
2030             }
2031         },
2032 
2033         _log: function (msg) {
2034             if (typeof window !== 'object' && typeof self === 'object' && self.postMessage) {
2035                 self.postMessage({type: 'log', msg: 'Log: ' + msg.toString()});
2036             } else {
2037                 console.log('Log: ', arguments);
2038             }
2039         }
2040 
2041     });
2042 
2043 /* parser generated by jison 0.4.15 */
2044 /*
2045   Returns a Parser object of the following structure:
2046 
2047   Parser: {
2048     yy: {}
2049   }
2050 
2051   Parser.prototype: {
2052     yy: {},
2053     trace: function(),
2054     symbols_: {associative list: name ==> number},
2055     terminals_: {associative list: number ==> name},
2056     productions_: [...],
2057     performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
2058     table: [...],
2059     defaultActions: {...},
2060     parseError: function(str, hash),
2061     parse: function(input),
2062 
2063     lexer: {
2064         EOF: 1,
2065         parseError: function(str, hash),
2066         setInput: function(input),
2067         input: function(),
2068         unput: function(str),
2069         more: function(),
2070         less: function(n),
2071         pastInput: function(),
2072         upcomingInput: function(),
2073         showPosition: function(),
2074         test_match: function(regex_match_array, rule_index),
2075         next: function(),
2076         lex: function(),
2077         begin: function(condition),
2078         popState: function(),
2079         _currentRules: function(),
2080         topState: function(),
2081         pushState: function(condition),
2082 
2083         options: {
2084             ranges: boolean           (optional: true ==> token location info will include a .range[] member)
2085             flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
2086             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)
2087         },
2088 
2089         performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
2090         rules: [...],
2091         conditions: {associative list: name ==> set},
2092     }
2093   }
2094 
2095 
2096   token location info (@$, _$, etc.): {
2097     first_line: n,
2098     last_line: n,
2099     first_column: n,
2100     last_column: n,
2101     range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
2102   }
2103 
2104 
2105   the parseError function receives a 'hash' object with these members for lexer and parser errors: {
2106     text:        (matched text)
2107     token:       (the produced terminal token, if any)
2108     line:        (yylineno)
2109   }
2110   while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
2111     loc:         (yylloc)
2112     expected:    (string describing the set of expected tokens)
2113     recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
2114   }
2115 */
2116 var parser = (function(){
2117 var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,149],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,166],$VX=[10,86];
2118 var parser = {trace: function trace() { },
2119 yy: {},
2120 symbols_: {"error":2,"Program":3,"StatementList":4,"EOF":5,"IfStatement":6,"IF":7,"(":8,"Expression":9,")":10,"Statement":11,"ELSE":12,"LoopStatement":13,"WHILE":14,"FOR":15,";":16,"DO":17,"UnaryStatement":18,"USE":19,"IDENTIFIER":20,"DELETE":21,"ReturnStatement":22,"RETURN":23,"EmptyStatement":24,"StatementBlock":25,"{":26,"}":27,"ExpressionStatement":28,"AssignmentExpression":29,"ConditionalExpression":30,"LeftHandSideExpression":31,"=":32,"LogicalORExpression":33,"?":34,":":35,"LogicalANDExpression":36,"||":37,"EqualityExpression":38,"&&":39,"RelationalExpression":40,"==":41,"!=":42,"~=":43,"AdditiveExpression":44,"<":45,">":46,"<=":47,">=":48,"MultiplicativeExpression":49,"+":50,"-":51,"UnaryExpression":52,"*":53,"/":54,"%":55,"ExponentExpression":56,"^":57,"!":58,"MemberExpression":59,"CallExpression":60,"PrimaryExpression":61,"FunctionExpression":62,"MapExpression":63,".":64,"[":65,"]":66,"BasicLiteral":67,"ObjectLiteral":68,"ArrayLiteral":69,"NullLiteral":70,"BooleanLiteral":71,"StringLiteral":72,"NumberLiteral":73,"NULL":74,"TRUE":75,"FALSE":76,"STRING":77,"NUMBER":78,"NAN":79,"INFINITY":80,"ElementList":81,"<<":82,">>":83,"PropertyList":84,"Property":85,",":86,"PropertyName":87,"Arguments":88,"AttributeList":89,"Attribute":90,"FUNCTION":91,"ParameterDefinitionList":92,"MAP":93,"->":94,"$accept":0,"$end":1},
2121 terminals_: {2:"error",5:"EOF",7:"IF",8:"(",10:")",12:"ELSE",14:"WHILE",15:"FOR",16:";",17:"DO",19:"USE",20:"IDENTIFIER",21:"DELETE",23:"RETURN",26:"{",27:"}",32:"=",34:"?",35:":",37:"||",39:"&&",41:"==",42:"!=",43:"~=",45:"<",46:">",47:"<=",48:">=",50:"+",51:"-",53:"*",54:"/",55:"%",57:"^",58:"!",64:".",65:"[",66:"]",74:"NULL",75:"TRUE",76:"FALSE",77:"STRING",78:"NUMBER",79:"NAN",80:"INFINITY",82:"<<",83:">>",86:",",91:"FUNCTION",93:"MAP",94:"->"},
2122 productions_: [0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,6],[92,1],[92,3]],
2123 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
2124 /* this == yyval */
2125 
2126 var $0 = $$.length - 1;
2127 switch (yystate) {
2128 case 1:
2129  return $$[$0-1];
2130 break;
2131 case 2:
2132  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_if', $$[$0-2], $$[$0]);
2133 break;
2134 case 3:
2135  this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_if_else', $$[$0-4], $$[$0-2], $$[$0]);
2136 break;
2137 case 4:
2138  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_while', $$[$0-2], $$[$0]);
2139 break;
2140 case 5:
2141  this.$ = AST.createNode(lc(_$[$0-8]), 'node_op', 'op_for', $$[$0-6], $$[$0-4], $$[$0-2], $$[$0]);
2142 break;
2143 case 6:
2144  this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_do', $$[$0-5], $$[$0-2]);
2145 break;
2146 case 7:
2147  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_use', $$[$0]);
2148 break;
2149 case 8:
2150  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_delete', $$[$0]);
2151 break;
2152 case 9:
2153  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_return', undefined);
2154 break;
2155 case 10:
2156  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_return', $$[$0-1]);
2157 break;
2158 case 11: case 14:
2159  this.$ = AST.createNode(lc(_$[$0]), 'node_op', 'op_none');
2160 break;
2161 case 12:
2162  this.$ = $$[$0-1]; this.$.needsBrackets = true;
2163 break;
2164 case 13:
2165  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_none', $$[$0-1], $$[$0]);
2166 break;
2167 case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 23: case 24: case 26: case 28: case 30: case 32: case 36: case 41: case 44: case 48: case 50: case 52: case 54: case 55: case 56: case 58: case 62: case 81: case 84: case 85: case 86:
2168  this.$ = $$[$0];
2169 break;
2170 case 22: case 65: case 93:
2171  this.$ = $$[$0-1];
2172 break;
2173 case 25:
2174  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_assign', $$[$0-2], $$[$0]); this.$.isMath = false;
2175 break;
2176 case 27:
2177  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_conditional', $$[$0-4], $$[$0-2], $$[$0]); this.$.isMath = false;
2178 break;
2179 case 29:
2180  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_or', $$[$0-2], $$[$0]); this.$.isMath = false;
2181 break;
2182 case 31:
2183  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_and', $$[$0-2], $$[$0]); this.$.isMath = false;
2184 break;
2185 case 33:
2186  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_equ', $$[$0-2], $$[$0]); this.$.isMath = false;
2187 break;
2188 case 34:
2189  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_neq', $$[$0-2], $$[$0]); this.$.isMath = false;
2190 break;
2191 case 35:
2192  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_approx', $$[$0-2], $$[$0]); this.$.isMath = false;
2193 break;
2194 case 37:
2195  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lot', $$[$0-2], $$[$0]); this.$.isMath = false;
2196 break;
2197 case 38:
2198  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_grt', $$[$0-2], $$[$0]); this.$.isMath = false;
2199 break;
2200 case 39:
2201  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_loe', $$[$0-2], $$[$0]); this.$.isMath = false;
2202 break;
2203 case 40:
2204  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gre', $$[$0-2], $$[$0]); this.$.isMath = false;
2205 break;
2206 case 42:
2207  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_add', $$[$0-2], $$[$0]); this.$.isMath = true;
2208 break;
2209 case 43:
2210  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_sub', $$[$0-2], $$[$0]); this.$.isMath = true;
2211 break;
2212 case 45:
2213  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mul', $$[$0-2], $$[$0]); this.$.isMath = true;
2214 break;
2215 case 46:
2216  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_div', $$[$0-2], $$[$0]); this.$.isMath = true;
2217 break;
2218 case 47:
2219  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mod', $$[$0-2], $$[$0]); this.$.isMath = true;
2220 break;
2221 case 49:
2222  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_exp', $$[$0-2], $$[$0]); this.$.isMath = true;
2223 break;
2224 case 51:
2225  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_not', $$[$0]); this.$.isMath = false;
2226 break;
2227 case 53:
2228  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_neg', $$[$0]); this.$.isMath = true;
2229 break;
2230 case 57: case 63: case 64: case 66: case 67: case 68: case 97:
2231  this.$ = $$[$0]; this.$.isMath = false;
2232 break;
2233 case 59: case 91:
2234  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_property', $$[$0-2], $$[$0]); this.$.isMath = true;
2235 break;
2236 case 60: case 90:
2237  this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_extvalue', $$[$0-3], $$[$0-1]); this.$.isMath = true;
2238 break;
2239 case 61:
2240  this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]);
2241 break;
2242 case 69:
2243  this.$ = $$[$0]; this.$.isMath = true;
2244 break;
2245 case 70:
2246  this.$ = AST.createNode(lc(_$[$0]), 'node_const', null);
2247 break;
2248 case 71:
2249  this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', true);
2250 break;
2251 case 72:
2252  this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', false);
2253 break;
2254 case 73:
2255  this.$ = AST.createNode(lc(_$[$0]), 'node_str', $$[$0].substring(1, $$[$0].length - 1));
2256 break;
2257 case 74:
2258  this.$ = AST.createNode(lc(_$[$0]), 'node_const', parseFloat($$[$0]));
2259 break;
2260 case 75:
2261  this.$ = AST.createNode(lc(_$[$0]), 'node_const', NaN);
2262 break;
2263 case 76:
2264  this.$ = AST.createNode(lc(_$[$0]), 'node_const', Infinity);
2265 break;
2266 case 77:
2267  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_array', []);
2268 break;
2269 case 78:
2270  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_array', $$[$0-1]);
2271 break;
2272 case 79:
2273  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {});
2274 break;
2275 case 80:
2276  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]);
2277 break;
2278 case 82:
2279  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst', $$[$0-2], $$[$0]);
2280 break;
2281 case 83:
2282  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_prop', $$[$0-2], $$[$0]);
2283 break;
2284 case 87: case 89:
2285  this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_execfun', $$[$0-1], $$[$0]); this.$.isMath = true;
2286 break;
2287 case 88:
2288  this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_execfun', $$[$0-2], $$[$0-1], $$[$0], true); this.$.isMath = false;
2289 break;
2290 case 92:
2291  this.$ = [];
2292 break;
2293 case 94: case 98: case 103:
2294  this.$ = [$$[$0]];
2295 break;
2296 case 95: case 99: case 104:
2297  this.$ = $$[$0-2].concat($$[$0]);
2298 break;
2299 case 96:
2300  this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); this.$.isMath = true;
2301 break;
2302 case 100:
2303  this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_function', [], $$[$0]); this.$.isMath = false;
2304 break;
2305 case 101:
2306  this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_function', $$[$0-2], $$[$0]); this.$.isMath = false;
2307 break;
2308 case 102:
2309  this.$ = AST.createNode(lc(_$[$0-5]), 'node_op', 'op_map', $$[$0-3], $$[$0]);
2310 break;
2311 }
2312 },
2313 table: [o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{20:$VR,92:140},{8:$V2,20:$V8,31:109,44:141,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,145],86:[1,146]},o($VS,[2,81]),{35:[1,147]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,148],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:150,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:152,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,155]},{10:[1,156]},{16:[1,157]},{8:[1,158]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,159]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,160]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,161]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,162],86:$VT},{66:[1,163]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:164,26:$Vb},{10:[1,165],86:$VW},o($VX,[2,103]),{10:[1,167],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:168,87:96},{8:$V2,20:$V8,29:169,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:170,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:171,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:172,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:173,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:174,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:175,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),{20:$VQ,68:127,82:$Vn,90:176},o($VV,[2,93]),o($Vs,[2,90]),o($Vs,[2,100]),{25:177,26:$Vb},{20:[1,178]},{94:[1,179]},o($VS,[2,82]),o($VS,[2,83]),o($VU,[2,99]),o($Vq,[2,2],{12:[1,180]}),o($Vr,[2,4]),{16:[1,181]},{10:[1,182]},o($Vs,[2,27]),o($Vs,[2,95]),o($Vs,[2,101]),o($VX,[2,104]),{8:$V2,9:183,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:184,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:185,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,186]},o($Vs,[2,102]),o($Vr,[2,3]),{10:[1,187]},o($Vr,[2,6]),{6:6,7:$V1,8:$V2,9:20,11:188,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vr,[2,5])],
2314 defaultActions: {3:[2,1],97:[2,84],98:[2,85],99:[2,86]},
2315 parseError: function parseError(str, hash) {
2316     if (hash.recoverable) {
2317         this.trace(str);
2318     } else {
2319         throw new Error(str);
2320     }
2321 },
2322 parse: function parse(input) {
2323     var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
2324     var args = lstack.slice.call(arguments, 1);
2325     var lexer = Object.create(this.lexer);
2326     var sharedState = { yy: {} };
2327     for (var k in this.yy) {
2328         if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
2329             sharedState.yy[k] = this.yy[k];
2330         }
2331     }
2332     lexer.setInput(input, sharedState.yy);
2333     sharedState.yy.lexer = lexer;
2334     sharedState.yy.parser = this;
2335     if (typeof lexer.yylloc == 'undefined') {
2336         lexer.yylloc = {};
2337     }
2338     var yyloc = lexer.yylloc;
2339     lstack.push(yyloc);
2340     var ranges = lexer.options && lexer.options.ranges;
2341     if (typeof sharedState.yy.parseError === 'function') {
2342         this.parseError = sharedState.yy.parseError;
2343     } else {
2344         this.parseError = Object.getPrototypeOf(this).parseError;
2345     }
2346     function popStack(n) {
2347         stack.length = stack.length - 2 * n;
2348         vstack.length = vstack.length - n;
2349         lstack.length = lstack.length - n;
2350     }
2351     _token_stack:
2352         function lex() {
2353             var token;
2354             token = lexer.lex() || EOF;
2355             if (typeof token !== 'number') {
2356                 token = self.symbols_[token] || token;
2357             }
2358             return token;
2359         }
2360     var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
2361     while (true) {
2362         state = stack[stack.length - 1];
2363         if (this.defaultActions[state]) {
2364             action = this.defaultActions[state];
2365         } else {
2366             if (symbol === null || typeof symbol == 'undefined') {
2367                 symbol = lex();
2368             }
2369             action = table[state] && table[state][symbol];
2370         }
2371                     if (typeof action === 'undefined' || !action.length || !action[0]) {
2372                 var errStr = '';
2373                 expected = [];
2374                 for (p in table[state]) {
2375                     if (this.terminals_[p] && p > TERROR) {
2376                         expected.push('\'' + this.terminals_[p] + '\'');
2377                     }
2378                 }
2379                 if (lexer.showPosition) {
2380                     errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
2381                 } else {
2382                     errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
2383                 }
2384                 this.parseError(errStr, {
2385                     text: lexer.match,
2386                     token: this.terminals_[symbol] || symbol,
2387                     line: lexer.yylineno,
2388                     loc: yyloc,
2389                     expected: expected
2390                 });
2391             }
2392         if (action[0] instanceof Array && action.length > 1) {
2393             throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
2394         }
2395         switch (action[0]) {
2396         case 1:
2397             stack.push(symbol);
2398             vstack.push(lexer.yytext);
2399             lstack.push(lexer.yylloc);
2400             stack.push(action[1]);
2401             symbol = null;
2402             if (!preErrorSymbol) {
2403                 yyleng = lexer.yyleng;
2404                 yytext = lexer.yytext;
2405                 yylineno = lexer.yylineno;
2406                 yyloc = lexer.yylloc;
2407                 if (recovering > 0) {
2408                     recovering--;
2409                 }
2410             } else {
2411                 symbol = preErrorSymbol;
2412                 preErrorSymbol = null;
2413             }
2414             break;
2415         case 2:
2416             len = this.productions_[action[1]][1];
2417             yyval.$ = vstack[vstack.length - len];
2418             yyval._$ = {
2419                 first_line: lstack[lstack.length - (len || 1)].first_line,
2420                 last_line: lstack[lstack.length - 1].last_line,
2421                 first_column: lstack[lstack.length - (len || 1)].first_column,
2422                 last_column: lstack[lstack.length - 1].last_column
2423             };
2424             if (ranges) {
2425                 yyval._$.range = [
2426                     lstack[lstack.length - (len || 1)].range[0],
2427                     lstack[lstack.length - 1].range[1]
2428                 ];
2429             }
2430             r = this.performAction.apply(yyval, [
2431                 yytext,
2432                 yyleng,
2433                 yylineno,
2434                 sharedState.yy,
2435                 action[1],
2436                 vstack,
2437                 lstack
2438             ].concat(args));
2439             if (typeof r !== 'undefined') {
2440                 return r;
2441             }
2442             if (len) {
2443                 stack = stack.slice(0, -1 * len * 2);
2444                 vstack = vstack.slice(0, -1 * len);
2445                 lstack = lstack.slice(0, -1 * len);
2446             }
2447             stack.push(this.productions_[action[1]][0]);
2448             vstack.push(yyval.$);
2449             lstack.push(yyval._$);
2450             newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
2451             stack.push(newState);
2452             break;
2453         case 3:
2454             return true;
2455         }
2456     }
2457     return true;
2458 }};
2459 
2460 
2461     var AST = {
2462         node: function (type, value, children) {
2463             return {
2464                 type: type,
2465                 value: value,
2466                 children: children
2467             };
2468         },
2469 
2470         createNode: function (pos, type, value, children) {
2471             var i,
2472                 n = this.node(type, value, []);
2473 
2474             for (i = 3; i < arguments.length; i++) {
2475                 n.children.push(arguments[i]);
2476             }
2477 
2478             n.line = pos[0];
2479             n.col = pos[1];
2480             n.eline = pos[2];
2481             n.ecol = pos[3];
2482 
2483             return n;
2484         }
2485     };
2486 
2487     var lc = function (lc1) {
2488         return [lc1.first_line, lc1.first_column, lc1.last_line, lc1.last_column];
2489     };
2490 
2491 /* generated by jison-lex 0.3.4 */
2492 var lexer = (function(){
2493 var lexer = ({
2494 
2495 EOF:1,
2496 
2497 parseError:function parseError(str, hash) {
2498         if (this.yy.parser) {
2499             this.yy.parser.parseError(str, hash);
2500         } else {
2501             throw new Error(str);
2502         }
2503     },
2504 
2505 // resets the lexer, sets new input
2506 setInput:function (input, yy) {
2507         this.yy = yy || this.yy || {};
2508         this._input = input;
2509         this._more = this._backtrack = this.done = false;
2510         this.yylineno = this.yyleng = 0;
2511         this.yytext = this.matched = this.match = '';
2512         this.conditionStack = ['INITIAL'];
2513         this.yylloc = {
2514             first_line: 1,
2515             first_column: 0,
2516             last_line: 1,
2517             last_column: 0
2518         };
2519         if (this.options.ranges) {
2520             this.yylloc.range = [0,0];
2521         }
2522         this.offset = 0;
2523         return this;
2524     },
2525 
2526 // consumes and returns one char from the input
2527 input:function () {
2528         var ch = this._input[0];
2529         this.yytext += ch;
2530         this.yyleng++;
2531         this.offset++;
2532         this.match += ch;
2533         this.matched += ch;
2534         var lines = ch.match(/(?:\r\n?|\n).*/g);
2535         if (lines) {
2536             this.yylineno++;
2537             this.yylloc.last_line++;
2538         } else {
2539             this.yylloc.last_column++;
2540         }
2541         if (this.options.ranges) {
2542             this.yylloc.range[1]++;
2543         }
2544 
2545         this._input = this._input.slice(1);
2546         return ch;
2547     },
2548 
2549 // unshifts one char (or a string) into the input
2550 unput:function (ch) {
2551         var len = ch.length;
2552         var lines = ch.split(/(?:\r\n?|\n)/g);
2553 
2554         this._input = ch + this._input;
2555         this.yytext = this.yytext.substr(0, this.yytext.length - len);
2556         //this.yyleng -= len;
2557         this.offset -= len;
2558         var oldLines = this.match.split(/(?:\r\n?|\n)/g);
2559         this.match = this.match.substr(0, this.match.length - 1);
2560         this.matched = this.matched.substr(0, this.matched.length - 1);
2561 
2562         if (lines.length - 1) {
2563             this.yylineno -= lines.length - 1;
2564         }
2565         var r = this.yylloc.range;
2566 
2567         this.yylloc = {
2568             first_line: this.yylloc.first_line,
2569             last_line: this.yylineno + 1,
2570             first_column: this.yylloc.first_column,
2571             last_column: lines ?
2572                 (lines.length === oldLines.length ? this.yylloc.first_column : 0)
2573                  + oldLines[oldLines.length - lines.length].length - lines[0].length :
2574               this.yylloc.first_column - len
2575         };
2576 
2577         if (this.options.ranges) {
2578             this.yylloc.range = [r[0], r[0] + this.yyleng - len];
2579         }
2580         this.yyleng = this.yytext.length;
2581         return this;
2582     },
2583 
2584 // When called from action, caches matched text and appends it on next action
2585 more:function () {
2586         this._more = true;
2587         return this;
2588     },
2589 
2590 // 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.
2591 reject:function () {
2592         if (this.options.backtrack_lexer) {
2593             this._backtrack = true;
2594         } else {
2595             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(), {
2596                 text: "",
2597                 token: null,
2598                 line: this.yylineno
2599             });
2600 
2601         }
2602         return this;
2603     },
2604 
2605 // retain first n characters of the match
2606 less:function (n) {
2607         this.unput(this.match.slice(n));
2608     },
2609 
2610 // displays already matched input, i.e. for error messages
2611 pastInput:function () {
2612         var past = this.matched.substr(0, this.matched.length - this.match.length);
2613         return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
2614     },
2615 
2616 // displays upcoming input, i.e. for error messages
2617 upcomingInput:function () {
2618         var next = this.match;
2619         if (next.length < 20) {
2620             next += this._input.substr(0, 20-next.length);
2621         }
2622         return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
2623     },
2624 
2625 // displays the character position where the lexing error occurred, i.e. for error messages
2626 showPosition:function () {
2627         var pre = this.pastInput();
2628         var c = new Array(pre.length + 1).join("-");
2629         return pre + this.upcomingInput() + "\n" + c + "^";
2630     },
2631 
2632 // test the lexed token: return FALSE when not a match, otherwise return token
2633 test_match:function (match, indexed_rule) {
2634         var token,
2635             lines,
2636             backup;
2637 
2638         if (this.options.backtrack_lexer) {
2639             // save context
2640             backup = {
2641                 yylineno: this.yylineno,
2642                 yylloc: {
2643                     first_line: this.yylloc.first_line,
2644                     last_line: this.last_line,
2645                     first_column: this.yylloc.first_column,
2646                     last_column: this.yylloc.last_column
2647                 },
2648                 yytext: this.yytext,
2649                 match: this.match,
2650                 matches: this.matches,
2651                 matched: this.matched,
2652                 yyleng: this.yyleng,
2653                 offset: this.offset,
2654                 _more: this._more,
2655                 _input: this._input,
2656                 yy: this.yy,
2657                 conditionStack: this.conditionStack.slice(0),
2658                 done: this.done
2659             };
2660             if (this.options.ranges) {
2661                 backup.yylloc.range = this.yylloc.range.slice(0);
2662             }
2663         }
2664 
2665         lines = match[0].match(/(?:\r\n?|\n).*/g);
2666         if (lines) {
2667             this.yylineno += lines.length;
2668         }
2669         this.yylloc = {
2670             first_line: this.yylloc.last_line,
2671             last_line: this.yylineno + 1,
2672             first_column: this.yylloc.last_column,
2673             last_column: lines ?
2674                          lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
2675                          this.yylloc.last_column + match[0].length
2676         };
2677         this.yytext += match[0];
2678         this.match += match[0];
2679         this.matches = match;
2680         this.yyleng = this.yytext.length;
2681         if (this.options.ranges) {
2682             this.yylloc.range = [this.offset, this.offset += this.yyleng];
2683         }
2684         this._more = false;
2685         this._backtrack = false;
2686         this._input = this._input.slice(match[0].length);
2687         this.matched += match[0];
2688         token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
2689         if (this.done && this._input) {
2690             this.done = false;
2691         }
2692         if (token) {
2693             return token;
2694         } else if (this._backtrack) {
2695             // recover context
2696             for (var k in backup) {
2697                 this[k] = backup[k];
2698             }
2699             return false; // rule action called reject() implying the next rule should be tested instead.
2700         }
2701         return false;
2702     },
2703 
2704 // return next match in input
2705 next:function () {
2706         if (this.done) {
2707             return this.EOF;
2708         }
2709         if (!this._input) {
2710             this.done = true;
2711         }
2712 
2713         var token,
2714             match,
2715             tempMatch,
2716             index;
2717         if (!this._more) {
2718             this.yytext = '';
2719             this.match = '';
2720         }
2721         var rules = this._currentRules();
2722         for (var i = 0; i < rules.length; i++) {
2723             tempMatch = this._input.match(this.rules[rules[i]]);
2724             if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
2725                 match = tempMatch;
2726                 index = i;
2727                 if (this.options.backtrack_lexer) {
2728                     token = this.test_match(tempMatch, rules[i]);
2729                     if (token !== false) {
2730                         return token;
2731                     } else if (this._backtrack) {
2732                         match = false;
2733                         continue; // rule action called reject() implying a rule MISmatch.
2734                     } else {
2735                         // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
2736                         return false;
2737                     }
2738                 } else if (!this.options.flex) {
2739                     break;
2740                 }
2741             }
2742         }
2743         if (match) {
2744             token = this.test_match(match, rules[index]);
2745             if (token !== false) {
2746                 return token;
2747             }
2748             // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
2749             return false;
2750         }
2751         if (this._input === "") {
2752             return this.EOF;
2753         } else {
2754             return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
2755                 text: "",
2756                 token: null,
2757                 line: this.yylineno
2758             });
2759         }
2760     },
2761 
2762 // return next match that has a token
2763 lex:function lex() {
2764         var r = this.next();
2765         if (r) {
2766             return r;
2767         } else {
2768             return this.lex();
2769         }
2770     },
2771 
2772 // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
2773 begin:function begin(condition) {
2774         this.conditionStack.push(condition);
2775     },
2776 
2777 // pop the previously active lexer condition state off the condition stack
2778 popState:function popState() {
2779         var n = this.conditionStack.length - 1;
2780         if (n > 0) {
2781             return this.conditionStack.pop();
2782         } else {
2783             return this.conditionStack[0];
2784         }
2785     },
2786 
2787 // produce the lexer rule set which is active for the currently active lexer condition state
2788 _currentRules:function _currentRules() {
2789         if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
2790             return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
2791         } else {
2792             return this.conditions["INITIAL"].rules;
2793         }
2794     },
2795 
2796 // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
2797 topState:function topState(n) {
2798         n = this.conditionStack.length - 1 - Math.abs(n || 0);
2799         if (n >= 0) {
2800             return this.conditionStack[n];
2801         } else {
2802             return "INITIAL";
2803         }
2804     },
2805 
2806 // alias for begin(condition)
2807 pushState:function pushState(condition) {
2808         this.begin(condition);
2809     },
2810 
2811 // return the number of states currently on the stack
2812 stateStackSize:function stateStackSize() {
2813         return this.conditionStack.length;
2814     },
2815 options: {},
2816 performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
2817 var YYSTATE=YY_START;
2818 switch($avoiding_name_collisions) {
2819 case 0:/* ignore */
2820 break;
2821 case 1:return 78
2822 break;
2823 case 2:return 78
2824 break;
2825 case 3: return 77;
2826 break;
2827 case 4: return 77;
2828 break;
2829 case 5:/* ignore comment */
2830 break;
2831 case 6:/* ignore multiline comment */
2832 break;
2833 case 7:return 7
2834 break;
2835 case 8:return 12
2836 break;
2837 case 9:return 14
2838 break;
2839 case 10:return 17
2840 break;
2841 case 11:return 15
2842 break;
2843 case 12:return 91
2844 break;
2845 case 13:return 93
2846 break;
2847 case 14:return 19
2848 break;
2849 case 15:return 23
2850 break;
2851 case 16:return 21
2852 break;
2853 case 17:return 75
2854 break;
2855 case 18:return 76
2856 break;
2857 case 19:return 74
2858 break;
2859 case 20:return 80
2860 break;
2861 case 21:return 94
2862 break;
2863 case 22:return 82
2864 break;
2865 case 23:return 83
2866 break;
2867 case 24:return 26
2868 break;
2869 case 25:return 27
2870 break;
2871 case 26:return 16
2872 break;
2873 case 27:return '#'
2874 break;
2875 case 28:return 34
2876 break;
2877 case 29:return 35
2878 break;
2879 case 30:return 79
2880 break;
2881 case 31:return 64
2882 break;
2883 case 32:return 65
2884 break;
2885 case 33:return 66
2886 break;
2887 case 34:return 8
2888 break;
2889 case 35:return 10
2890 break;
2891 case 36:return 58
2892 break;
2893 case 37:return 57
2894 break;
2895 case 38:return 53
2896 break;
2897 case 39:return 54
2898 break;
2899 case 40:return 55
2900 break;
2901 case 41:return 50
2902 break;
2903 case 42:return 51
2904 break;
2905 case 43:return 47
2906 break;
2907 case 44:return 45
2908 break;
2909 case 45:return 48
2910 break;
2911 case 46:return 46
2912 break;
2913 case 47:return 41
2914 break;
2915 case 48:return 43
2916 break;
2917 case 49:return 42
2918 break;
2919 case 50:return 39
2920 break;
2921 case 51:return 37
2922 break;
2923 case 52:return 32
2924 break;
2925 case 53:return 86
2926 break;
2927 case 54:return 5
2928 break;
2929 case 55:return 20
2930 break;
2931 case 56:return 'INVALID'
2932 break;
2933 }
2934 },
2935 rules: [/^(?:\s+)/,/^(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+\b)/,/^(?:[0-9]+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:\/\/.*)/,/^(?:\/\*(.|\n|\r)*?\*\/)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:while\b)/,/^(?:do\b)/,/^(?:for\b)/,/^(?:function\b)/,/^(?:map\b)/,/^(?:use\b)/,/^(?:return\b)/,/^(?:delete\b)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:Infinity\b)/,/^(?:->)/,/^(?:<<)/,/^(?:>>)/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:#)/,/^(?:\?)/,/^(?::)/,/^(?:NaN\b)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:\()/,/^(?:\))/,/^(?:!)/,/^(?:\^)/,/^(?:\*)/,/^(?:\/)/,/^(?:%)/,/^(?:\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\$][A-Za-z0-9_]*)/,/^(?:.)/],
2936 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,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56],"inclusive":true}}
2937 });
2938 return lexer;
2939 })();
2940 parser.lexer = lexer;
2941 function Parser () {
2942   this.yy = {};
2943 }
2944 Parser.prototype = parser;parser.Parser = Parser;
2945 return new Parser;
2946 })();
2947 
2948 
2949 if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
2950 exports.parser = parser;
2951 exports.Parser = parser.Parser;
2952 exports.parse = function () { return parser.parse.apply(parser, arguments); };
2953 exports.main = function commonjsMain(args) {
2954     if (!args[1]) {
2955         console.log('Usage: '+args[0]+' FILE');
2956         process.exit(1);
2957     }
2958     var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
2959     return exports.parser.parse(source);
2960 };
2961 if (typeof module !== 'undefined' && require.main === module) {
2962   exports.main(process.argv.slice(1));
2963 }
2964 }
2965 
2966     // Work around an issue with browsers that don't support Object.getPrototypeOf()
2967     parser.yy.parseError = parser.parseError;
2968 
2969     return JXG.JessieCode;
2970 });
2971