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