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