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