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