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: