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 tpye builtIn, Math.*, creator. 427 * 428 * @see JXG.JessieCode#resolveType 429 */ 430 getvar: function (vname, local, isFunctionName) { 431 var s; 432 433 local = Type.def(local, false); 434 435 // Local scope has always precedence 436 s = this.isLocalVariable(vname); 437 if (s !== null) { 438 return s.locals[vname]; 439 } 440 441 // Handle the - so far only - few constants by hard coding them. 442 if (vname === '$board' || vname === 'EULER' || vname === 'PI') { 443 return this.builtIn[vname]; 444 } 445 446 if (!!isFunctionName) { 447 if (this.isBuiltIn(vname)) { 448 return this.builtIn[vname]; 449 } 450 451 if (this.isMathMethod(vname)) { 452 return Math[vname]; 453 } 454 455 // check for an element with this name 456 if (this.isCreator(vname)) { 457 return this.creator(vname); 458 } 459 } 460 461 if (!local) { 462 s = this.board.select(vname); 463 if (s !== vname) { 464 return s; 465 } 466 } 467 }, 468 469 /** 470 * Look up the value of a local variable. 471 * @param {string} vname 472 * @returns {*} 473 */ 474 resolve: function (vname) { 475 var s = this.scope; 476 477 while (s !== null) { 478 if (Type.exists(s.locals[vname])) { 479 return s.locals[vname]; 480 } 481 482 s = s.previous; 483 } 484 }, 485 486 /** 487 * TODO this needs to be called from JS and should not generate JS code 488 * Looks up a variable identifier in various tables and generates JavaScript code that could be eval'd to get the value. 489 * @param {String} vname Identifier 490 * @param {Boolean} [local=false] Don't resolve ids and names of elements 491 * @param {Boolean} [withProps=false] 492 */ 493 getvarJS: function (vname, local, withProps) { 494 var s, r = '', re; 495 496 local = Type.def(local, false); 497 withProps = Type.def(withProps, false); 498 499 s = this.isParameter(vname); 500 if (s !== null) { 501 return vname; 502 } 503 504 s = this.isLocalVariable(vname); 505 if (s !== null && !withProps) { 506 return '$jc$.resolve(\'' + vname + '\')'; 507 } 508 509 // check for an element with this name 510 if (this.isCreator(vname)) { 511 return '(function () { var a = Array.prototype.slice.call(arguments, 0), props = ' + (withProps ? 'a.pop()' : '{}') + '; return $jc$.board.create.apply($jc$.board, [\'' + vname + '\'].concat([a, props])); })'; 512 } 513 514 if (withProps) { 515 this._error('Syntax error (attribute values are allowed with element creators only)'); 516 } 517 518 if (this.isBuiltIn(vname)) { 519 // If src does not exist, it is a number. In that case, just return the value. 520 r = this.builtIn[vname].src || this.builtIn[vname]; 521 522 // Get the "real" name of the function 523 if (Type.isNumber(r)) { 524 return r; 525 } 526 // Search a JSXGraph object in board 527 if (r.match(/board\.select/)) { 528 return r; 529 } 530 531 vname = r.split('.').pop(); 532 if (Type.exists(this.board.mathLib)) { 533 // Handle builtin case: ln(x) -> Math.log 534 re = new RegExp('^Math\.' + vname); 535 if (re.exec(r) !== null) { 536 return r.replace(re, '$jc$.board.mathLib.' + vname); 537 } 538 } 539 if (Type.exists(this.board.mathLibJXG)) { 540 // Handle builtin case: factorial(x) -> JXG.Math.factorial 541 re = new RegExp('^JXG\.Math\.'); 542 if (re.exec(r) !== null) { 543 return r.replace(re, '$jc$.board.mathLibJXG.'); 544 } 545 return r; 546 } 547 return r; 548 549 // return this.builtIn[vname].src || this.builtIn[vname]; 550 } 551 552 if (this.isMathMethod(vname)) { 553 return '$jc$.board.mathLib.' + vname; 554 // return 'Math.' + vname; 555 } 556 557 // if (!local) { 558 // if (Type.isId(this.board, vname)) { 559 // r = '$jc$.board.objects[\'' + vname + '\']'; 560 // } else if (Type.isName(this.board, vname)) { 561 // r = '$jc$.board.elementsByName[\'' + vname + '\']'; 562 // } else if (Type.isGroup(this.board, vname)) { 563 // r = '$jc$.board.groups[\'' + vname + '\']'; 564 // } 565 566 // return r; 567 // } 568 if (!local) { 569 if (Type.isId(this.board, vname)) { 570 r = '$jc$.board.objects[\'' + vname + '\']'; 571 if (this.board.objects[vname].elType === 'slider') { 572 r += '.Value()'; 573 } 574 } else if (Type.isName(this.board, vname)) { 575 r = '$jc$.board.elementsByName[\'' + vname + '\']'; 576 if (this.board.elementsByName[vname].elType === 'slider') { 577 r += '.Value()'; 578 } 579 } else if (Type.isGroup(this.board, vname)) { 580 r = '$jc$.board.groups[\'' + vname + '\']'; 581 } 582 583 return r; 584 } 585 586 return ''; 587 }, 588 589 /** 590 * Adds the property <tt>isMap</tt> to a function and sets it to true. 591 * @param {function} f 592 * @returns {function} 593 */ 594 makeMap: function (f) { 595 f.isMap = true; 596 597 return f; 598 }, 599 600 functionCodeJS: function (node) { 601 var p = node.children[0].join(', '), 602 bo = '', 603 bc = ''; 604 605 if (node.value === 'op_map') { 606 bo = '{ return '; 607 bc = ' }'; 608 } 609 610 return 'function (' + p + ') {\n' + 611 'var $oldscope$ = $jc$.scope;\n' + 612 '$jc$.scope = $jc$.scopes[' + this.scope.id + '];\n' + 613 'var r = (function () ' + bo + this.compile(node.children[1], true) + bc + ')();\n' + 614 '$jc$.scope = $oldscope$;\n' + 615 'return r;\n' + 616 '}'; 617 }, 618 619 /** 620 * Converts a node type <tt>node_op</tt> and value <tt>op_map</tt> or <tt>op_function</tt> into a executable 621 * function. Does a simple type inspection. 622 * @param {Object} node 623 * @returns {function} 624 * @see JXG.JessieCode#resolveType 625 */ 626 defineFunction: function (node) { 627 var fun, i, that = this, 628 list = node.children[0], 629 scope = this.pushScope(list); 630 631 if (this.board.options.jc.compile) { 632 this.isLHS = false; 633 634 // we currently need to put the parameters into the local scope 635 // until the compiled JS variable lookup code is fixed 636 for (i = 0; i < list.length; i++) { 637 scope.locals[list[i]] = list[i]; 638 } 639 640 this.replaceNames(node.children[1]); 641 642 /** @ignore */ 643 fun = (function (jc) { 644 var fun, 645 // str = 'var f = ' + $jc$.functionCodeJS(node) + '; f;'; 646 str = 'var f = function($jc$) { return ' + 647 jc.functionCodeJS(node) + 648 '}; f;'; 649 650 try { 651 // yeah, eval is evil, but we don't have much choice here. 652 // the str is well defined and there is no user input in it that we didn't check before 653 654 /*jslint evil:true*/ 655 // fun = eval(str); 656 fun = eval(str)(jc); 657 /*jslint evil:false*/ 658 659 scope.argtypes = []; 660 for (i = 0; i < list.length; i++) { 661 scope.argtypes.push(that.resolveType(list[i], node)); 662 } 663 664 return fun; 665 } catch (e) { 666 // $jc$._warn('error compiling function\n\n' + str + '\n\n' + e.toString()); 667 jc._warn("error compiling function\n\n" + str + "\n\n" + e.toString()); 668 return function () { }; 669 } 670 }(this)); 671 672 // clean up scope 673 this.popScope(); 674 } else { 675 /** @ignore */ 676 fun = (function (_pstack, that, id) { 677 return function () { 678 var r, oldscope; 679 680 oldscope = that.scope; 681 that.scope = that.scopes[id]; 682 683 for (r = 0; r < _pstack.length; r++) { 684 that.scope.locals[_pstack[r]] = arguments[r]; 685 } 686 687 r = that.execute(node.children[1]); 688 that.scope = oldscope; 689 690 return r; 691 }; 692 }(list, this, scope.id)); 693 } 694 695 fun.node = node; 696 fun.scope = scope; 697 fun.toJS = fun.toString; 698 fun.toString = (function (_that) { 699 return function () { 700 return _that.compile(_that.replaceIDs(Type.deepCopy(node))); 701 }; 702 }(this)); 703 704 fun.deps = {}; 705 this.collectDependencies(node.children[1], fun.deps); 706 707 return fun; 708 }, 709 710 /** 711 * Merge all attribute values given with an element creator into one object. 712 * @param {Object} o An arbitrary number of objects 713 * @returns {Object} All given objects merged into one. If properties appear in more (case sensitive) than one 714 * object the last value is taken. 715 */ 716 mergeAttributes: function (o) { 717 var i, attr = {}; 718 719 for (i = 0; i < arguments.length; i++) { 720 attr = Type.deepCopy(attr, arguments[i], true); 721 } 722 723 return attr; 724 }, 725 726 /** 727 * Sets the property <tt>what</tt> of <tt>o</tt> to <tt>value</tt> 728 * @param {JXG.Point|JXG.Text} o 729 * @param {String} what 730 * @param value 731 */ 732 setProp: function (o, what, value) { 733 var par = {}, x, y; 734 735 if (o.elementClass === Const.OBJECT_CLASS_POINT && (what === 'X' || what === 'Y')) { 736 // set coords 737 738 what = what.toLowerCase(); 739 740 // we have to deal with three cases here: 741 // o.isDraggable && typeof value === number: 742 // stay draggable, just set the new coords (e.g. via moveTo) 743 // o.isDraggable && typeof value === function: 744 // convert to !o.isDraggable, set the new coords via o.addConstraint() 745 // !o.isDraggable: 746 // stay !o.isDraggable, update the given coord by overwriting X/YEval 747 748 if (o.isDraggable && typeof value === 'number') { 749 x = what === 'x' ? value : o.X(); 750 y = what === 'y' ? value : o.Y(); 751 752 o.setPosition(Const.COORDS_BY_USER, [x, y]); 753 } else if (o.isDraggable && (typeof value === 'function' || typeof value === 'string')) { 754 x = what === 'x' ? value : o.coords.usrCoords[1]; 755 y = what === 'y' ? value : o.coords.usrCoords[2]; 756 757 o.addConstraint([x, y]); 758 } else if (!o.isDraggable) { 759 x = what === 'x' ? value : o.XEval.origin; 760 y = what === 'y' ? value : o.YEval.origin; 761 762 o.addConstraint([x, y]); 763 } 764 765 this.board.update(); 766 } else if (o.elementClass === Const.OBJECT_CLASS_TEXT && (what === 'X' || what === 'Y')) { 767 if (typeof value === 'number') { 768 o[what] = function () { return value; }; 769 } else if (typeof value === 'function') { 770 o.isDraggable = false; 771 o[what] = value; 772 } else if (typeof value === 'string') { 773 o.isDraggable = false; 774 o[what] = Type.createFunction(value, this.board, null, true); 775 o[what + 'jc'] = value; 776 } 777 778 o[what].origin = value; 779 780 this.board.update(); 781 } else if (o.type && o.elementClass && o.visProp) { 782 if (Type.exists(o[o.methodMap[what]]) && typeof o[o.methodMap[what]] !== 'function') { 783 o[o.methodMap[what]] = value; 784 } else { 785 par[what] = value; 786 o.setAttribute(par); 787 } 788 } else { 789 o[what] = value; 790 } 791 }, 792 793 /** 794 * Generic method to parse JessieCode. 795 * This consists of generating an AST with parser.parse, 796 * apply simplifying rules from CA and 797 * manipulate the AST according to the second parameter "cmd". 798 * @param {String} code JessieCode code to be parsed 799 * @param {String} cmd Type of manipulation to be done with AST 800 * @param {Boolean} [geonext=false] Geonext compatibility mode. 801 * @param {Boolean} dontstore If false, the code string is stored in this.code. 802 * @return {Object} Returns result of computation as directed in cmd. 803 */ 804 _genericParse: function (code, cmd, geonext, dontstore) { 805 var i, setTextBackup, ast, result, 806 ccode = code.replace(/\r\n/g, '\n').split('\n'), 807 cleaned = []; 808 809 if (!dontstore) { 810 this.code += code + '\n'; 811 } 812 813 if (Text) { 814 setTextBackup = Text.prototype.setText; 815 Text.prototype.setText = Text.prototype.setTextJessieCode; 816 } 817 818 try { 819 if (!Type.exists(geonext)) { 820 geonext = false; 821 } 822 823 for (i = 0; i < ccode.length; i++) { 824 if (geonext) { 825 ccode[i] = JXG.GeonextParser.geonext2JS(ccode[i], this.board); 826 } 827 cleaned.push(ccode[i]); 828 } 829 830 code = cleaned.join('\n'); 831 ast = parser.parse(code); 832 if (this.CA) { 833 ast = this.CA.expandDerivatives(ast, null, ast); 834 ast = this.CA.removeTrivialNodes(ast); 835 } 836 switch (cmd) { 837 case 'parse': 838 result = this.execute(ast); 839 break; 840 case 'manipulate': 841 result = this.compile(ast); 842 break; 843 case 'getAst': 844 result = ast; 845 break; 846 default: 847 result = false; 848 } 849 } catch (e) { // catch is mandatory in old IEs 850 // console.log(e); 851 // We throw the error again, 852 // so the user can catch it. 853 throw e; 854 } finally { 855 // make sure the original text method is back in place 856 if (Text) { 857 Text.prototype.setText = setTextBackup; 858 } 859 } 860 861 return result; 862 }, 863 864 /** 865 * Parses JessieCode. 866 * This consists of generating an AST with parser.parse, apply simplifying rules 867 * from CA and executing the ast by calling this.execute(ast). 868 * 869 * @param {String} code JessieCode code to be parsed 870 * @param {Boolean} [geonext=false] Geonext compatibility mode. 871 * @param {Boolean} dontstore If false, the code string is stored in this.code. 872 * @return {Object} Parse JessieCode code and execute it. 873 */ 874 parse: function (code, geonext, dontstore) { 875 return this._genericParse(code, 'parse', geonext, dontstore); 876 }, 877 878 /** 879 * Manipulate JessieCode. 880 * This consists of generating an AST with parser.parse, 881 * apply simlifying rules from CA 882 * and compile the AST back to JessieCode. 883 * 884 * @param {String} code JessieCode code to be parsed 885 * @param {Boolean} [geonext=false] Geonext compatibility mode. 886 * @param {Boolean} dontstore If false, the code string is stored in this.code. 887 * @return {String} Simplified JessieCode code 888 */ 889 manipulate: function (code, geonext, dontstore) { 890 return this._genericParse(code, 'manipulate', geonext, dontstore); 891 }, 892 893 /** 894 * Get abstract syntax tree (AST) from JessieCode code. 895 * This consists of generating an AST with parser.parse. 896 * 897 * @param {String} code 898 * @param {Boolean} [geonext=false] Geonext compatibility mode. 899 * @param {Boolean} dontstore 900 * @return {Node} AST 901 */ 902 getAST: function (code, geonext, dontstore) { 903 return this._genericParse(code, 'getAst', geonext, dontstore); 904 }, 905 906 /** 907 * Parses a JessieCode snippet, e.g. "3+4", and wraps it into a function, if desired. 908 * @param {String} code A small snippet of JessieCode. Must not be an assignment. 909 * @param {Boolean} funwrap If true, the code is wrapped in a function. 910 * @param {String} varname Name of the parameter(s) 911 * @param {Boolean} [geonext=false] Geonext compatibility mode. 912 */ 913 snippet: function (code, funwrap, varname, geonext) { 914 var c; 915 916 funwrap = Type.def(funwrap, true); 917 varname = Type.def(varname, ''); 918 geonext = Type.def(geonext, false); 919 920 c = (funwrap ? ' function (' + varname + ') { return ' : '') + code + (funwrap ? '; }' : '') + ';'; 921 922 return this.parse(c, geonext, true); 923 }, 924 925 /** 926 * Traverses through the given subtree and changes all values of nodes with the replaced flag set by 927 * {@link JXG.JessieCode#replaceNames} to the name of the element (if not empty). 928 * @param {Object} node 929 */ 930 replaceIDs: function (node) { 931 var i, v; 932 933 if (node.replaced) { 934 // These children exist, if node.replaced is set. 935 v = this.board.objects[node.children[1][0].value]; 936 937 if (Type.exists(v) && v.name !== "") { 938 node.type = 'node_var'; 939 node.value = v.name; 940 941 // Maybe it's not necessary, but just to be sure that everything is cleaned up we better delete all 942 // children and the replaced flag 943 node.children.length = 0; 944 delete node.replaced; 945 } 946 } 947 948 if (Type.isArray(node)) { 949 for (i = 0; i < node.length; i++) { 950 node[i] = this.replaceIDs(node[i]); 951 } 952 } 953 954 if (node.children) { 955 // assignments are first evaluated on the right hand side 956 for (i = node.children.length; i > 0; i--) { 957 if (Type.exists(node.children[i - 1])) { 958 node.children[i - 1] = this.replaceIDs(node.children[i - 1]); 959 } 960 961 } 962 } 963 964 return node; 965 }, 966 967 /** 968 * Traverses through the given subtree and changes all elements referenced by names through referencing them by ID. 969 * An identifier is only replaced if it is not found in all scopes above the current scope and if it 970 * has not been blacklisted within the codeblock determined by the given subtree. 971 * @param {Object} node 972 */ 973 replaceNames: function (node) { 974 var i, v; 975 976 v = node.value; 977 978 // We are interested only in nodes of type node_var and node_op > op_lhs. 979 // Currently, we are not checking if the id is a local variable. in this case, we're stuck anyway. 980 981 if (node.type === 'node_op' && v === 'op_lhs' && node.children.length === 1) { 982 this.isLHS = true; 983 } else if (node.type === 'node_var') { 984 if (this.isLHS) { 985 this.letvar(v, true); 986 } else if (!Type.exists(this.getvar(v, true)) && Type.exists(this.board.elementsByName[v])) { 987 node = this.createReplacementNode(node); 988 } 989 } 990 991 if (Type.isArray(node)) { 992 for (i = 0; i < node.length; i++) { 993 node[i] = this.replaceNames(node[i]); 994 } 995 } 996 997 if (node.children) { 998 // Assignments are first evaluated on the right hand side 999 for (i = node.children.length; i > 0; i--) { 1000 if (Type.exists(node.children[i - 1])) { 1001 node.children[i - 1] = this.replaceNames(node.children[i - 1]); 1002 } 1003 } 1004 } 1005 1006 if (node.type === 'node_op' && node.value === 'op_lhs' && node.children.length === 1) { 1007 this.isLHS = false; 1008 } 1009 1010 return node; 1011 }, 1012 1013 /** 1014 * Replaces node_var nodes with node_op>op_execfun nodes, calling the internal $() function with the id of the 1015 * element accessed by the node_var node. 1016 * @param {Object} node 1017 * @returns {Object} op_execfun node 1018 */ 1019 createReplacementNode: function (node) { 1020 var v = node.value, 1021 el = this.board.elementsByName[v]; 1022 1023 node = this.createNode('node_op', 'op_execfun', 1024 this.createNode('node_var', '$'), 1025 [this.createNode('node_str', el.id)]); 1026 1027 node.replaced = true; 1028 1029 return node; 1030 }, 1031 1032 /** 1033 * Search the parse tree below <tt>node</tt> for <em>stationary</em> dependencies, i.e. dependencies hard coded into 1034 * the function. 1035 * @param {Object} node 1036 * @param {Object} result An object where the referenced elements will be stored. Access key is their id. 1037 */ 1038 collectDependencies: function (node, result) { 1039 var i, v, e, le; 1040 1041 if (Type.isArray(node)) { 1042 le = node.length; 1043 for (i = 0; i < le; i++) { 1044 this.collectDependencies(node[i], result); 1045 } 1046 return; 1047 } 1048 1049 v = node.value; 1050 1051 if (node.type === 'node_var') { 1052 e = this.getvar(v); 1053 if (e && e.visProp && e.type && e.elementClass && e.id) { 1054 result[e.id] = e; 1055 } 1056 } 1057 1058 // The $()-function-calls are special because their parameter is given as a string, not as a node_var. 1059 if (node.type === 'node_op' && node.value === 'op_execfun' && 1060 node.children.length > 1 && node.children[0].value === '$' && 1061 node.children[1].length > 0) { 1062 1063 e = node.children[1][0].value; 1064 result[e] = this.board.objects[e]; 1065 } 1066 1067 if (node.children) { 1068 for (i = node.children.length; i > 0; i--) { 1069 if (Type.exists(node.children[i - 1])) { 1070 this.collectDependencies(node.children[i - 1], result); 1071 } 1072 1073 } 1074 } 1075 }, 1076 1077 resolveProperty: function (e, v, compile) { 1078 compile = Type.def(compile, false); 1079 1080 // is it a geometry element or a board? 1081 if (e /*&& e.type && e.elementClass*/ && e.methodMap) { 1082 // yeah, it is. but what does the user want? 1083 if (Type.exists(e.subs) && Type.exists(e.subs[v])) { 1084 // a subelement it is, good sir. 1085 e = e.subs; 1086 } else if (Type.exists(e.methodMap[v])) { 1087 // the user wants to call a method 1088 v = e.methodMap[v]; 1089 } else { 1090 // the user wants to change an attribute 1091 e = e.visProp; 1092 v = v.toLowerCase(); 1093 } 1094 } 1095 1096 if (Type.isFunction(e)) { 1097 this._error('Accessing function properties is not allowed.'); 1098 } 1099 1100 if (!Type.exists(e)) { 1101 this._error(e + ' is not an object'); 1102 } 1103 1104 if (!Type.exists(e[v])) { 1105 this._error('unknown property ' + v); 1106 } 1107 1108 if (compile && typeof e[v] === 'function') { 1109 return function () { return e[v].apply(e, arguments); }; 1110 } 1111 1112 return e[v]; 1113 }, 1114 1115 /** 1116 * Type inspection: check if the string vname appears as function name in the 1117 * AST node. Used in "op_execfun". This allows the JessieCode exmples below. 1118 * 1119 * @private 1120 * @param {String} vname 1121 * @param {Object} node 1122 * @returns 'any' or 'function' 1123 * @see JXG.JessieCode#execute 1124 * @see JXG.JessieCode#getvar 1125 * 1126 * @example 1127 * var p = board.create('point', [2, 0], {name: 'X'}); 1128 * var txt = 'X(X)'; 1129 * console.log(board.jc.parse(txt)); 1130 * 1131 * @example 1132 * var p = board.create('point', [2, 0], {name: 'X'}); 1133 * var txt = 'f = function(el, X) { return X(el); }; f(X, X);'; 1134 * console.log(board.jc.parse(txt)); 1135 * 1136 * @example 1137 * var p = board.create('point', [2, 0], {name: 'point'}); 1138 * var txt = 'B = point(1,3); X(point);'; 1139 * console.log(board.jc.parse(txt)); 1140 * 1141 * @example 1142 * var p = board.create('point', [2, 0], {name: 'A'}); 1143 * var q = board.create('point', [-2, 0], {name: 'X'}); 1144 * var txt = 'getCoord=function(p, f){ return f(p); }; getCoord(A, X);'; 1145 * console.log(board.jc.parse(txt)); 1146 */ 1147 resolveType: function (vname, node) { 1148 var i, t, 1149 type = 'any'; // Possible values: 'function', 'any' 1150 1151 if (Type.isArray(node)) { 1152 // node contains the parameters of a function call or function declaration 1153 for (i = 0; i < node.length; i++) { 1154 t = this.resolveType(vname, node[i]); 1155 if (t !== 'any') { 1156 type = t; 1157 return type; 1158 } 1159 } 1160 } 1161 1162 if (node.type === 'node_op' && node.value === 'op_execfun' && 1163 node.children[0].type === 'node_var' && node.children[0].value === vname) { 1164 return 'function'; 1165 } 1166 1167 if (node.type === 'node_op') { 1168 for (i = 0; i < node.children.length; i++) { 1169 if (node.children[0].type === 'node_var' && node.children[0].value === vname && 1170 (node.value === 'op_add' || node.value === 'op_sub' || node.value === 'op_mul' || 1171 node.value === 'op_div' || node.value === 'op_mod' || node.value === 'op_exp' || 1172 node.value === 'op_neg')) { 1173 return 'any'; 1174 } 1175 } 1176 1177 for (i = 0; i < node.children.length; i++) { 1178 t = this.resolveType(vname, node.children[i]); 1179 if (t !== 'any') { 1180 type = t; 1181 return type; 1182 } 1183 } 1184 } 1185 1186 return 'any'; 1187 }, 1188 1189 /** 1190 * Resolves the lefthand side of an assignment operation 1191 * @param node 1192 * @returns {Object} An object with two properties. <strong>o</strong> which contains the object, and 1193 * a string <strong>what</strong> which contains the property name. 1194 */ 1195 getLHS: function (node) { 1196 var res; 1197 1198 if (node.type === 'node_var') { 1199 res = { 1200 o: this.scope.locals, 1201 what: node.value 1202 }; 1203 } else if (node.type === 'node_op' && node.value === 'op_property') { 1204 res = { 1205 o: this.execute(node.children[0]), 1206 what: node.children[1] 1207 }; 1208 } else if (node.type === 'node_op' && node.value === 'op_extvalue') { 1209 res = { 1210 o: this.execute(node.children[0]), 1211 what: this.execute(node.children[1]) 1212 }; 1213 } else { 1214 throw new Error('Syntax error: Invalid left-hand side of assignment.'); 1215 } 1216 1217 return res; 1218 }, 1219 1220 getLHSCompiler: function (node, js) { 1221 var res; 1222 1223 if (node.type === 'node_var') { 1224 res = node.value; 1225 } else if (node.type === 'node_op' && node.value === 'op_property') { 1226 res = [ 1227 this.compile(node.children[0], js), 1228 "'" + node.children[1] + "'" 1229 ]; 1230 } else if (node.type === 'node_op' && node.value === 'op_extvalue') { 1231 res = [ 1232 this.compile(node.children[0], js), 1233 node.children[1].type === 'node_const' ? node.children[1].value : this.compile(node.children[1], js) 1234 ]; 1235 } else { 1236 throw new Error('Syntax error: Invalid left-hand side of assignment.'); 1237 } 1238 1239 return res; 1240 }, 1241 1242 /** 1243 * Executes a parse subtree. 1244 * @param {Object} node 1245 * @returns {Number|String|Object|Boolean} Something 1246 * @private 1247 */ 1248 execute: function (node) { 1249 var ret, v, i, e, l, undef, list, ilist, 1250 parents = [], 1251 // exec fun 1252 fun, attr, sc; 1253 1254 ret = 0; 1255 1256 if (!node) { 1257 return ret; 1258 } 1259 1260 this.line = node.line; 1261 this.col = node.col; 1262 1263 switch (node.type) { 1264 case 'node_op': 1265 switch (node.value) { 1266 case 'op_none': 1267 if (node.children[0]) { 1268 this.execute(node.children[0]); 1269 } 1270 if (node.children[1]) { 1271 ret = this.execute(node.children[1]); 1272 } 1273 break; 1274 case 'op_assign': 1275 v = this.getLHS(node.children[0]); 1276 this.lhs[this.scope.id] = v.what; 1277 1278 if (v.o.type && v.o.elementClass && v.o.methodMap && v.what === 'label') { 1279 this._error('Left-hand side of assignment is read-only.'); 1280 } 1281 1282 ret = this.execute(node.children[1]); 1283 if (v.o !== this.scope.locals || (Type.isArray(v.o) && typeof v.what === 'number')) { 1284 // it is either an array component being set or a property of an object. 1285 this.setProp(v.o, v.what, ret); 1286 } else { 1287 // this is just a local variable inside JessieCode 1288 this.letvar(v.what, ret); 1289 } 1290 this.lhs[this.scope.id] = 0; 1291 break; 1292 case 'op_if': 1293 if (this.execute(node.children[0])) { 1294 ret = this.execute(node.children[1]); 1295 } 1296 break; 1297 case 'op_conditional': 1298 // fall through 1299 case 'op_if_else': 1300 if (this.execute(node.children[0])) { 1301 ret = this.execute(node.children[1]); 1302 } else { 1303 ret = this.execute(node.children[2]); 1304 } 1305 break; 1306 case 'op_while': 1307 while (this.execute(node.children[0])) { 1308 this.execute(node.children[1]); 1309 } 1310 break; 1311 case 'op_do': 1312 do { 1313 this.execute(node.children[0]); 1314 } while (this.execute(node.children[1])); 1315 break; 1316 case 'op_for': 1317 for (this.execute(node.children[0]); this.execute(node.children[1]); this.execute(node.children[2])) { 1318 this.execute(node.children[3]); 1319 } 1320 break; 1321 case 'op_proplst': 1322 if (node.children[0]) { 1323 this.execute(node.children[0]); 1324 } 1325 if (node.children[1]) { 1326 this.execute(node.children[1]); 1327 } 1328 break; 1329 case 'op_emptyobject': 1330 ret = {}; 1331 break; 1332 case 'op_proplst_val': 1333 this.propstack.push({}); 1334 this.propscope++; 1335 1336 this.execute(node.children[0]); 1337 ret = this.propstack[this.propscope]; 1338 1339 this.propstack.pop(); 1340 this.propscope--; 1341 break; 1342 case 'op_prop': 1343 // child 0: Identifier 1344 // child 1: Value 1345 this.propstack[this.propscope][node.children[0]] = this.execute(node.children[1]); 1346 break; 1347 case 'op_array': 1348 ret = []; 1349 l = node.children[0].length; 1350 1351 for (i = 0; i < l; i++) { 1352 ret.push(this.execute(node.children[0][i])); 1353 } 1354 1355 break; 1356 case 'op_extvalue': 1357 ret = this.execute(node.children[0]); 1358 i = this.execute(node.children[1]); 1359 1360 if (typeof i === 'number' && Math.abs(Math.round(i) - i) < Mat.eps) { 1361 ret = ret[i]; 1362 } else { 1363 ret = undef; 1364 } 1365 break; 1366 case 'op_return': 1367 if (this.scope === 0) { 1368 this._error('Unexpected return.'); 1369 } else { 1370 return this.execute(node.children[0]); 1371 } 1372 break; 1373 case 'op_map': 1374 if (!node.children[1].isMath && node.children[1].type !== 'node_var') { 1375 this._error('execute: In a map only function calls and mathematical expressions are allowed.'); 1376 } 1377 1378 /** @ignore */ 1379 fun = this.defineFunction(node); 1380 fun.isMap = true; 1381 1382 ret = fun; 1383 break; 1384 case 'op_function': 1385 // parse the parameter list 1386 // after this, the parameters are in pstack 1387 1388 /** @ignore */ 1389 fun = this.defineFunction(node); 1390 fun.isMap = false; 1391 1392 ret = fun; 1393 break; 1394 case 'op_execfun': 1395 // node.children: 1396 // [0]: Name of the function 1397 // [1]: Parameter list as a parse subtree 1398 // [2]: Properties, only used in case of a create function 1399 this.dpstack.push([]); 1400 this.pscope++; 1401 1402 // parameter parsing is done below 1403 list = node.children[1]; 1404 1405 // parse the properties only if given 1406 if (Type.exists(node.children[2])) { 1407 if (node.children[3]) { 1408 ilist = node.children[2]; 1409 attr = {}; 1410 1411 for (i = 0; i < ilist.length; i++) { 1412 attr = Type.deepCopy(attr, this.execute(ilist[i]), true); 1413 } 1414 } else { 1415 attr = this.execute(node.children[2]); 1416 } 1417 } 1418 1419 // look up the variables name in the variable table 1420 node.children[0]._isFunctionName = true; 1421 fun = this.execute(node.children[0]); 1422 delete node.children[0]._isFunctionName; 1423 1424 // determine the scope the function wants to run in 1425 if (fun && fun.sc) { 1426 sc = fun.sc; 1427 } else { 1428 sc = this; 1429 } 1430 1431 if (!fun.creator && Type.exists(node.children[2])) { 1432 this._error('Unexpected value. Only element creators are allowed to have a value after the function call.'); 1433 } 1434 1435 // interpret ALL the parameters 1436 for (i = 0; i < list.length; i++) { 1437 if (Type.exists(fun.scope) && Type.exists(fun.scope.argtypes) && fun.scope.argtypes[i] === 'function') { 1438 // Type inspection 1439 list[i]._isFunctionName = true; 1440 parents[i] = this.execute(list[i]); 1441 delete list[i]._isFunctionName; 1442 } else { 1443 parents[i] = this.execute(list[i]); 1444 } 1445 //parents[i] = Type.evalSlider(this.execute(list[i])); 1446 this.dpstack[this.pscope].push({ 1447 line: node.children[1][i].line, 1448 // SketchBin currently works only if the last column of the 1449 // parent position is taken. This is due to how I patched JS/CC 1450 // to count the lines and columns. So, ecol will do for now 1451 col: node.children[1][i].ecol 1452 }); 1453 } 1454 1455 // check for the function in the variable table 1456 if (typeof fun === 'function' && !fun.creator) { 1457 ret = fun.apply(sc, parents); 1458 } else if (typeof fun === 'function' && !!fun.creator) { 1459 e = this.line; 1460 1461 // creator methods are the only ones that take properties, hence this special case 1462 try { 1463 ret = fun(parents, attr); 1464 ret.jcLineStart = e; 1465 ret.jcLineEnd = node.eline; 1466 1467 for (i = e; i <= node.line; i++) { 1468 this.lineToElement[i] = ret; 1469 } 1470 1471 ret.debugParents = this.dpstack[this.pscope]; 1472 } catch (ex) { 1473 this._error(ex.toString()); 1474 } 1475 } else { 1476 this._error('Function \'' + fun + '\' is undefined.'); 1477 } 1478 1479 // clear parameter stack 1480 this.dpstack.pop(); 1481 this.pscope--; 1482 break; 1483 case 'op_property': 1484 e = this.execute(node.children[0]); 1485 v = node.children[1]; 1486 1487 ret = this.resolveProperty(e, v, false); 1488 1489 // set the scope, in case this is a method the user wants to call 1490 if (Type.exists(ret)) { 1491 ret.sc = e; 1492 } 1493 1494 break; 1495 case 'op_use': 1496 this._warn('Use of the \'use\' operator is deprecated.'); 1497 this.use(node.children[0].toString()); 1498 break; 1499 case 'op_delete': 1500 this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.'); 1501 v = this.getvar(node.children[0]); 1502 ret = this.del(v); 1503 break; 1504 case 'op_eq': 1505 // == is intentional 1506 /*jslint eqeq:true*/ 1507 ret = this.execute(node.children[0]) == this.execute(node.children[1]); 1508 /*jslint eqeq:false*/ 1509 break; 1510 case 'op_neq': 1511 // != is intentional 1512 /*jslint eqeq:true*/ 1513 ret = this.execute(node.children[0]) != this.execute(node.children[1]); 1514 /*jslint eqeq:true*/ 1515 break; 1516 case 'op_approx': 1517 ret = Math.abs(this.execute(node.children[0]) - this.execute(node.children[1])) < Mat.eps; 1518 break; 1519 case 'op_gt': 1520 ret = this.execute(node.children[0]) > this.execute(node.children[1]); 1521 break; 1522 case 'op_lt': 1523 ret = this.execute(node.children[0]) < this.execute(node.children[1]); 1524 break; 1525 case 'op_geq': 1526 ret = this.execute(node.children[0]) >= this.execute(node.children[1]); 1527 break; 1528 case 'op_leq': 1529 ret = this.execute(node.children[0]) <= this.execute(node.children[1]); 1530 break; 1531 case 'op_or': 1532 ret = this.execute(node.children[0]) || this.execute(node.children[1]); 1533 break; 1534 case 'op_and': 1535 ret = this.execute(node.children[0]) && this.execute(node.children[1]); 1536 break; 1537 case 'op_not': 1538 ret = !this.execute(node.children[0]); 1539 break; 1540 case 'op_add': 1541 ret = this.add(this.execute(node.children[0]), this.execute(node.children[1])); 1542 break; 1543 case 'op_sub': 1544 ret = this.sub(this.execute(node.children[0]), this.execute(node.children[1])); 1545 break; 1546 case 'op_div': 1547 ret = this.div(this.execute(node.children[0]), this.execute(node.children[1])); 1548 break; 1549 case 'op_mod': 1550 // use mathematical modulo, JavaScript implements the symmetric modulo. 1551 ret = this.mod(this.execute(node.children[0]), this.execute(node.children[1]), true); 1552 break; 1553 case 'op_mul': 1554 ret = this.mul(this.execute(node.children[0]), this.execute(node.children[1])); 1555 break; 1556 case 'op_exp': 1557 ret = this.pow(this.execute(node.children[0]), this.execute(node.children[1])); 1558 break; 1559 case 'op_neg': 1560 ret = this.neg(this.execute(node.children[0])); 1561 break; 1562 } 1563 break; 1564 1565 case 'node_var': 1566 // node._isFunctionName is set in execute: at op_execfun. 1567 ret = this.getvar(node.value, false, node._isFunctionName); 1568 break; 1569 1570 case 'node_const': 1571 if (node.value === null) { 1572 ret = null; 1573 } else { 1574 ret = Number(node.value); 1575 } 1576 break; 1577 1578 case 'node_const_bool': 1579 ret = node.value; 1580 break; 1581 1582 case 'node_str': 1583 //ret = node.value.replace(/\\'/, "'").replace(/\\"/, '"').replace(/\\\\/, '\\'); 1584 /*jslint regexp:true*/ 1585 ret = node.value.replace(/\\(.)/g, '$1'); // Remove backslash, important in JessieCode tags 1586 /*jslint regexp:false*/ 1587 break; 1588 } 1589 1590 return ret; 1591 }, 1592 1593 /** 1594 * Compiles a parse tree back to JessieCode. 1595 * @param {Object} node 1596 * @param {Boolean} [js=false] Compile either to JavaScript or back to JessieCode (required for the UI). 1597 * @returns Something 1598 * @private 1599 */ 1600 compile: function (node, js) { 1601 var e, i, list, scope, 1602 ret = ''; 1603 1604 if (!Type.exists(js)) { 1605 js = false; 1606 } 1607 1608 if (!node) { 1609 return ret; 1610 } 1611 1612 switch (node.type) { 1613 case 'node_op': 1614 switch (node.value) { 1615 case 'op_none': 1616 if (node.children[0]) { 1617 ret = this.compile(node.children[0], js); 1618 } 1619 if (node.children[1]) { 1620 ret += this.compile(node.children[1], js); 1621 } 1622 break; 1623 case 'op_assign': 1624 //e = this.compile(node.children[0], js); 1625 if (js) { 1626 e = this.getLHSCompiler(node.children[0], js); 1627 if (Type.isArray(e)) { 1628 ret = '$jc$.setProp(' + e[0] + ', ' + e[1] + ', ' + this.compile(node.children[1], js) + ');\n'; 1629 } else { 1630 if (this.isLocalVariable(e) !== this.scope) { 1631 this.scope.locals[e] = true; 1632 } 1633 ret = '$jc$.scopes[' + this.scope.id + '].locals[\'' + e + '\'] = ' + this.compile(node.children[1], js) + ';\n'; 1634 } 1635 } else { 1636 e = this.compile(node.children[0]); 1637 ret = e + ' = ' + this.compile(node.children[1], js) + ';\n'; 1638 } 1639 break; 1640 case 'op_if': 1641 ret = ' if (' + this.compile(node.children[0], js) + ') ' + this.compile(node.children[1], js); 1642 break; 1643 case 'op_if_else': 1644 ret = ' if (' + this.compile(node.children[0], js) + ')' + this.compile(node.children[1], js); 1645 ret += ' else ' + this.compile(node.children[2], js); 1646 break; 1647 case 'op_conditional': 1648 ret = '((' + this.compile(node.children[0], js) + ')?(' + this.compile(node.children[1], js); 1649 ret += '):(' + this.compile(node.children[2], js) + '))'; 1650 break; 1651 case 'op_while': 1652 ret = ' while (' + this.compile(node.children[0], js) + ') {\n' + this.compile(node.children[1], js) + '}\n'; 1653 break; 1654 case 'op_do': 1655 ret = ' do {\n' + this.compile(node.children[0], js) + '} while (' + this.compile(node.children[1], js) + ');\n'; 1656 break; 1657 case 'op_for': 1658 //ret = ' for (' + this.compile(node.children[0], js) + '; ' + this.compile(node.children[1], js) + '; ' + this.compile(node.children[2], js) + ') {\n' + this.compile(node.children[3], js) + '\n}\n'; 1659 ret = ' for (' + this.compile(node.children[0], js) + // Assignment ends with ";" 1660 this.compile(node.children[1], js) + '; ' + // Logical test comes without ";" 1661 this.compile(node.children[2], js).slice(0, -2) + // Counting comes with ";" which has to be removed 1662 ') {\n' + this.compile(node.children[3], js) + '\n}\n'; 1663 break; 1664 case 'op_proplst': 1665 if (node.children[0]) { 1666 ret = this.compile(node.children[0], js) + ', '; 1667 } 1668 1669 ret += this.compile(node.children[1], js); 1670 break; 1671 case 'op_prop': 1672 // child 0: Identifier 1673 // child 1: Value 1674 ret = node.children[0] + ': ' + this.compile(node.children[1], js); 1675 break; 1676 case 'op_emptyobject': 1677 ret = js ? '{}' : '<< >>'; 1678 break; 1679 case 'op_proplst_val': 1680 ret = this.compile(node.children[0], js); 1681 break; 1682 case 'op_array': 1683 list = []; 1684 for (i = 0; i < node.children[0].length; i++) { 1685 list.push(this.compile(node.children[0][i], js)); 1686 } 1687 ret = '[' + list.join(', ') + ']'; 1688 break; 1689 case 'op_extvalue': 1690 ret = this.compile(node.children[0], js) + '[' + this.compile(node.children[1], js) + ']'; 1691 break; 1692 case 'op_return': 1693 ret = ' return ' + this.compile(node.children[0], js) + ';\n'; 1694 break; 1695 case 'op_map': 1696 if (!node.children[1].isMath && node.children[1].type !== 'node_var') { 1697 this._error('compile: In a map only function calls and mathematical expressions are allowed.'); 1698 } 1699 1700 list = node.children[0]; 1701 if (js) { 1702 ret = ' $jc$.makeMap(function (' + list.join(', ') + ') { return ' + this.compile(node.children[1], js) + '; })'; 1703 } else { 1704 ret = 'map (' + list.join(', ') + ') -> ' + this.compile(node.children[1], js); 1705 } 1706 1707 break; 1708 case 'op_function': 1709 list = node.children[0]; 1710 scope = this.pushScope(list); 1711 if (js) { 1712 ret = this.functionCodeJS(node); 1713 } else { 1714 ret = ' function (' + list.join(', ') + ') ' + this.compile(node.children[1], js); 1715 } 1716 this.popScope(); 1717 break; 1718 case 'op_execfunmath': 1719 console.log('op_execfunmath: TODO'); 1720 ret = '-1'; 1721 break; 1722 case 'op_execfun': 1723 // parse the properties only if given 1724 if (node.children[2]) { 1725 list = []; 1726 for (i = 0; i < node.children[2].length; i++) { 1727 list.push(this.compile(node.children[2][i], js)); 1728 } 1729 1730 if (js) { 1731 e = '$jc$.mergeAttributes(' + list.join(', ') + ')'; 1732 } else { 1733 e = list.join(', '); 1734 } 1735 } 1736 node.children[0].withProps = !!node.children[2]; 1737 list = []; 1738 for (i = 0; i < node.children[1].length; i++) { 1739 list.push(this.compile(node.children[1][i], js)); 1740 } 1741 ret = this.compile(node.children[0], js) + '(' + list.join(', ') + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? ' ' + e : ''); 1742 if (js) { 1743 // Inserting a newline here allows simulataneously 1744 // - procedural calls like Q.moveTo(...); and 1745 // - function calls in expressions like log(x) + 1; 1746 // Problem: procedural calls will not be ended by a semicolon. 1747 ret += '\n'; 1748 } 1749 1750 // save us a function call when compiled to javascript 1751 if (js && node.children[0].value === '$') { 1752 ret = '$jc$.board.objects[' + this.compile(node.children[1][0], js) + ']'; 1753 } 1754 break; 1755 case 'op_property': 1756 if (js && node.children[1] !== 'X' && node.children[1] !== 'Y') { 1757 ret = '$jc$.resolveProperty(' + this.compile(node.children[0], js) + ', \'' + node.children[1] + '\', true)'; 1758 } else { 1759 ret = this.compile(node.children[0], js) + '.' + node.children[1]; 1760 } 1761 break; 1762 case 'op_use': 1763 this._warn('Use of the \'use\' operator is deprecated.'); 1764 if (js) { 1765 ret = '$jc$.use(\''; 1766 } else { 1767 ret = 'use(\''; 1768 } 1769 1770 ret += node.children[0].toString() + '\');'; 1771 break; 1772 case 'op_delete': 1773 this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.'); 1774 if (js) { 1775 ret = '$jc$.del('; 1776 } else { 1777 ret = 'remove('; 1778 } 1779 1780 ret += this.compile(node.children[0], js) + ')'; 1781 break; 1782 case 'op_eq': 1783 ret = '(' + this.compile(node.children[0], js) + ' === ' + this.compile(node.children[1], js) + ')'; 1784 break; 1785 case 'op_neq': 1786 ret = '(' + this.compile(node.children[0], js) + ' !== ' + this.compile(node.children[1], js) + ')'; 1787 break; 1788 case 'op_approx': 1789 ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')'; 1790 break; 1791 case 'op_gt': 1792 if (js) { 1793 ret = '$jc$.gt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1794 } else { 1795 ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')'; 1796 } 1797 break; 1798 case 'op_lt': 1799 if (js) { 1800 ret = '$jc$.lt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1801 } else { 1802 ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')'; 1803 } 1804 break; 1805 case 'op_geq': 1806 if (js) { 1807 ret = '$jc$.geq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1808 } else { 1809 ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')'; 1810 } 1811 break; 1812 case 'op_leq': 1813 if (js) { 1814 ret = '$jc$.leq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1815 } else { 1816 ret = '(' + this.compile(node.children[0], js) + ' <= ' + this.compile(node.children[1], js) + ')'; 1817 } 1818 break; 1819 case 'op_or': 1820 ret = '(' + this.compile(node.children[0], js) + ' || ' + this.compile(node.children[1], js) + ')'; 1821 break; 1822 case 'op_and': 1823 ret = '(' + this.compile(node.children[0], js) + ' && ' + this.compile(node.children[1], js) + ')'; 1824 break; 1825 case 'op_not': 1826 ret = '!(' + this.compile(node.children[0], js) + ')'; 1827 break; 1828 case 'op_add': 1829 if (js) { 1830 ret = '$jc$.add(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1831 } else { 1832 ret = '(' + this.compile(node.children[0], js) + ' + ' + this.compile(node.children[1], js) + ')'; 1833 } 1834 break; 1835 case 'op_sub': 1836 if (js) { 1837 ret = '$jc$.sub(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1838 } else { 1839 ret = '(' + this.compile(node.children[0], js) + ' - ' + this.compile(node.children[1], js) + ')'; 1840 } 1841 break; 1842 case 'op_div': 1843 if (js) { 1844 ret = '$jc$.div(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1845 } else { 1846 ret = '(' + this.compile(node.children[0], js) + ' / ' + this.compile(node.children[1], js) + ')'; 1847 } 1848 break; 1849 case 'op_mod': 1850 if (js) { 1851 ret = '$jc$.mod(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ', true)'; 1852 } else { 1853 ret = '(' + this.compile(node.children[0], js) + ' % ' + this.compile(node.children[1], js) + ')'; 1854 } 1855 break; 1856 case 'op_mul': 1857 if (js) { 1858 ret = '$jc$.mul(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1859 } else { 1860 ret = '(' + this.compile(node.children[0], js) + ' * ' + this.compile(node.children[1], js) + ')'; 1861 } 1862 break; 1863 case 'op_exp': 1864 if (js) { 1865 ret = '$jc$.pow(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1866 } else { 1867 ret = '(' + this.compile(node.children[0], js) + '^' + this.compile(node.children[1], js) + ')'; 1868 } 1869 break; 1870 case 'op_neg': 1871 if (js) { 1872 ret = '$jc$.neg(' + this.compile(node.children[0], js) + ')'; 1873 } else { 1874 ret = '(-' + this.compile(node.children[0], js) + ')'; 1875 } 1876 break; 1877 } 1878 break; 1879 1880 case 'node_var': 1881 if (js) { 1882 ret = this.getvarJS(node.value, false, node.withProps); 1883 } else { 1884 ret = node.value; 1885 } 1886 break; 1887 1888 case 'node_const': 1889 ret = node.value; 1890 break; 1891 1892 case 'node_const_bool': 1893 ret = node.value; 1894 break; 1895 1896 case 'node_str': 1897 ret = '\'' + node.value + '\''; 1898 break; 1899 } 1900 1901 if (node.needsBrackets) { 1902 if (js) { 1903 ret = '{\n' + ret + '\n}\n'; 1904 } else { 1905 ret = '<< ' + ret + ' >>'; 1906 } 1907 } 1908 1909 return ret; 1910 }, 1911 1912 /** 1913 * This is used as the global getName() function. 1914 * @param {JXG.GeometryElement} obj 1915 * @param {Boolean} useId 1916 * @returns {String} 1917 */ 1918 getName: function (obj, useId) { 1919 var name = ''; 1920 1921 if (Type.exists(obj) && Type.exists(obj.getName)) { 1922 name = obj.getName(); 1923 if ((!Type.exists(name) || name === '') && !!useId) { 1924 name = obj.id; 1925 } 1926 } else if (!!useId) { 1927 name = obj.id; 1928 } 1929 1930 return name; 1931 }, 1932 1933 /** 1934 * This is used as the global X() function. 1935 * @param {JXG.Point|JXG.Text} e 1936 * @returns {Number} 1937 */ 1938 X: function (e) { 1939 return e.X(); 1940 }, 1941 1942 /** 1943 * This is used as the global Y() function. 1944 * @param {JXG.Point|JXG.Text} e 1945 * @returns {Number} 1946 */ 1947 Y: function (e) { 1948 return e.Y(); 1949 }, 1950 1951 /** 1952 * This is used as the global V() function. 1953 * @param {Glider|Slider} e 1954 * @returns {Number} 1955 */ 1956 V: function (e) { 1957 return e.Value(); 1958 }, 1959 1960 /** 1961 * This is used as the global L() function. 1962 * @param {JXG.Line} e 1963 * @returns {Number} 1964 */ 1965 L: function (e) { 1966 return e.L(); 1967 }, 1968 1969 /** 1970 * This is used as the global area() function. 1971 * @param {JXG.Circle|JXG.Polygon} obj 1972 * @returns {Number} 1973 */ 1974 area: function (obj) { 1975 if (!Type.exists(obj) || !Type.exists(obj.Area)) { 1976 this._error('Error: Can\'t calculate area.'); 1977 } 1978 1979 return obj.Area(); 1980 }, 1981 1982 /** 1983 * This is used as the global dist() function. 1984 * @param {JXG.Point} p1 1985 * @param {JXG.Point} p2 1986 * @returns {Number} 1987 */ 1988 dist: function (p1, p2) { 1989 if (!Type.exists(p1) || !Type.exists(p1.Dist)) { 1990 this._error('Error: Can\'t calculate distance.'); 1991 } 1992 1993 return p1.Dist(p2); 1994 }, 1995 1996 /** 1997 * This is used as the global radius() function. 1998 * @param {JXG.Circle|Sector} obj 1999 * @returns {Number} 2000 */ 2001 radius: function (obj) { 2002 if (!Type.exists(obj) || !Type.exists(obj.Radius)) { 2003 this._error('Error: Can\'t calculate radius.'); 2004 } 2005 2006 return obj.Radius(); 2007 }, 2008 2009 /** 2010 * + operator implementation 2011 * @param {Number|Array|JXG.Point} a 2012 * @param {Number|Array|JXG.Point} b 2013 * @returns {Number|Array} 2014 */ 2015 add: function (a, b) { 2016 var i, len, res; 2017 2018 a = Type.evalSlider(a); 2019 b = Type.evalSlider(b); 2020 2021 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2022 res = Interval.add(a, b); 2023 } else if (Type.isArray(a) && Type.isArray(b)) { 2024 len = Math.min(a.length, b.length); 2025 res = []; 2026 2027 for (i = 0; i < len; i++) { 2028 res[i] = a[i] + b[i]; 2029 } 2030 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2031 res = a + b; 2032 } else if (Type.isString(a) || Type.isString(b)) { 2033 res = a.toString() + b.toString(); 2034 } else { 2035 this._error('Operation + not defined on operands ' + typeof a + ' and ' + typeof b); 2036 } 2037 2038 return res; 2039 }, 2040 2041 /** 2042 * - operator implementation 2043 * @param {Number|Array|JXG.Point} a 2044 * @param {Number|Array|JXG.Point} b 2045 * @returns {Number|Array} 2046 */ 2047 sub: function (a, b) { 2048 var i, len, res; 2049 2050 a = Type.evalSlider(a); 2051 b = Type.evalSlider(b); 2052 2053 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2054 res = Interval.sub(a, b); 2055 } else if (Type.isArray(a) && Type.isArray(b)) { 2056 len = Math.min(a.length, b.length); 2057 res = []; 2058 2059 for (i = 0; i < len; i++) { 2060 res[i] = a[i] - b[i]; 2061 } 2062 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2063 res = a - b; 2064 } else { 2065 this._error('Operation - not defined on operands ' + typeof a + ' and ' + typeof b); 2066 } 2067 2068 return res; 2069 }, 2070 2071 /** 2072 * unary - operator implementation 2073 * @param {Number|Array|JXG.Point} a 2074 * @returns {Number|Array} 2075 */ 2076 neg: function (a) { 2077 var i, len, res; 2078 2079 a = Type.evalSlider(a); 2080 2081 if (Interval.isInterval(a)) { 2082 res = Interval.negative(a); 2083 } else if (Type.isArray(a)) { 2084 len = a.length; 2085 res = []; 2086 2087 for (i = 0; i < len; i++) { 2088 res[i] = -a[i]; 2089 } 2090 } else if (Type.isNumber(a)) { 2091 res = -a; 2092 } else { 2093 this._error('Unary operation - not defined on operand ' + typeof a); 2094 } 2095 2096 return res; 2097 }, 2098 2099 /** 2100 * Multiplication of vectors and numbers 2101 * @param {Number|Array} a 2102 * @param {Number|Array} b 2103 * @returns {Number|Array} (Inner) product of the given input values. 2104 */ 2105 mul: function (a, b) { 2106 var i, len, res; 2107 2108 a = Type.evalSlider(a); 2109 b = Type.evalSlider(b); 2110 2111 if (Type.isArray(a) && Type.isNumber(b)) { 2112 // swap b and a 2113 i = a; 2114 a = b; 2115 b = a; 2116 } 2117 2118 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2119 res = Interval.mul(a, b); 2120 } else if (Type.isArray(a) && Type.isArray(b)) { 2121 len = Math.min(a.length, b.length); 2122 res = Mat.innerProduct(a, b, len); 2123 } else if (Type.isNumber(a) && Type.isArray(b)) { 2124 len = b.length; 2125 res = []; 2126 2127 for (i = 0; i < len; i++) { 2128 res[i] = a * b[i]; 2129 } 2130 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2131 res = a * b; 2132 } else { 2133 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b); 2134 } 2135 2136 return res; 2137 }, 2138 2139 /** 2140 * Implementation of the / operator. 2141 * @param {Number|Array} a 2142 * @param {Number} b 2143 * @returns {Number|Array} 2144 */ 2145 div: function (a, b) { 2146 var i, len, res; 2147 2148 a = Type.evalSlider(a); 2149 b = Type.evalSlider(b); 2150 2151 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2152 res = Interval.div(a, b); 2153 } else if (Type.isArray(a) && Type.isNumber(b)) { 2154 len = a.length; 2155 res = []; 2156 2157 for (i = 0; i < len; i++) { 2158 res[i] = a[i] / b; 2159 } 2160 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2161 res = a / b; 2162 } else { 2163 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b); 2164 } 2165 2166 return res; 2167 }, 2168 2169 /** 2170 * Implementation of the % operator. 2171 * @param {Number|Array} a 2172 * @param {Number} b 2173 * @returns {Number|Array} 2174 */ 2175 mod: function (a, b) { 2176 var i, len, res; 2177 2178 a = Type.evalSlider(a); 2179 b = Type.evalSlider(b); 2180 2181 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2182 return Interval.fmod(a, b); 2183 } else if (Type.isArray(a) && Type.isNumber(b)) { 2184 len = a.length; 2185 res = []; 2186 2187 for (i = 0; i < len; i++) { 2188 res[i] = Mat.mod(a[i], b, true); 2189 } 2190 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2191 res = Mat.mod(a, b, true); 2192 } else { 2193 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b); 2194 } 2195 2196 return res; 2197 }, 2198 2199 /** 2200 * Pow function wrapper to allow direct usage of sliders. 2201 * @param {Number|Slider} a 2202 * @param {Number|Slider} b 2203 * @returns {Number} 2204 */ 2205 pow: function (a, b) { 2206 a = Type.evalSlider(a); 2207 b = Type.evalSlider(b); 2208 2209 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2210 return Interval.pow(a, b); 2211 } 2212 return Mat.pow(a, b); 2213 }, 2214 2215 lt: function (a, b) { 2216 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2217 return Interval.lt(a, b); 2218 } 2219 return a < b; 2220 }, 2221 leq: function (a, b) { 2222 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2223 return Interval.leq(a, b); 2224 } 2225 return a <= b; 2226 }, 2227 gt: function (a, b) { 2228 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2229 return Interval.gt(a, b); 2230 } 2231 return a > b; 2232 }, 2233 geq: function (a, b) { 2234 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2235 return Intervalt.geq(a, b); 2236 } 2237 return a >= b; 2238 }, 2239 2240 randint: function (min, max, step) { 2241 if (!Type.exists(step)) { 2242 step = 1; 2243 } 2244 return Math.round(Math.random() * (max - min) / step) * step + min; 2245 }, 2246 2247 DDD: function (f) { 2248 console.log('Dummy derivative function. This should never appear!'); 2249 }, 2250 2251 /** 2252 * Implementation of the ?: operator 2253 * @param {Boolean} cond Condition 2254 * @param {*} v1 2255 * @param {*} v2 2256 * @returns {*} Either v1 or v2. 2257 */ 2258 ifthen: function (cond, v1, v2) { 2259 if (cond) { 2260 return v1; 2261 } 2262 2263 return v2; 2264 }, 2265 2266 /** 2267 * Implementation of the delete() builtin function 2268 * @param {JXG.GeometryElement} element 2269 */ 2270 del: function (element) { 2271 if (typeof element === 'object' && JXG.exists(element.type) && JXG.exists(element.elementClass)) { 2272 this.board.removeObject(element); 2273 } 2274 }, 2275 2276 /** 2277 * Implementation of the use() builtin function 2278 * @param {String} board 2279 */ 2280 use: function (board) { 2281 var b, ref, 2282 found = false; 2283 2284 if (typeof board === 'string') { 2285 // search all the boards for the one with the appropriate container div 2286 for (b in JXG.boards) { 2287 if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === board) { 2288 ref = JXG.boards[b]; 2289 found = true; 2290 break; 2291 } 2292 } 2293 } else { 2294 ref = board; 2295 found = true; 2296 } 2297 2298 if (found) { 2299 this.board = ref; 2300 this.builtIn.$board = ref; 2301 this.builtIn.$board.src = '$jc$.board'; 2302 } else { 2303 this._error('Board \'' + board + '\' not found!'); 2304 } 2305 }, 2306 2307 /** 2308 * Find the first symbol to the given value from the given scope upwards. 2309 * @param v Value 2310 * @param {Number} [scope=-1] The scope, default is to start with current scope (-1). 2311 * @returns {Array} An array containing the symbol and the scope if a symbol could be found, 2312 * an empty array otherwise; 2313 */ 2314 findSymbol: function (v, scope) { 2315 var i, s; 2316 2317 scope = Type.def(scope, -1); 2318 2319 if (scope === -1) { 2320 s = this.scope; 2321 } else { 2322 s = this.scopes[scope]; 2323 } 2324 2325 while (s !== null) { 2326 for (i in s.locals) { 2327 if (s.locals.hasOwnProperty(i) && s.locals[i] === v) { 2328 return [i, s]; 2329 } 2330 } 2331 2332 s = s.previous; 2333 } 2334 2335 return []; 2336 }, 2337 2338 /** 2339 * Import modules into a JessieCode script. 2340 * @param {String} module 2341 */ 2342 importModule: function (module) { 2343 return priv.modules[module.toLowerCase()]; 2344 }, 2345 2346 /** 2347 * Defines built in methods and constants. 2348 * @returns {Object} BuiltIn control object 2349 */ 2350 defineBuiltIn: function () { 2351 var that = this, 2352 builtIn = { 2353 PI: Math.PI, 2354 EULER: Math.E, 2355 D: that.DDD, 2356 X: that.X, 2357 Y: that.Y, 2358 V: that.V, 2359 L: that.L, 2360 2361 acosh: Mat.acosh, 2362 acot: Mat.acot, 2363 asinh: Mat.asinh, 2364 binomial: Mat.binomial, 2365 cbrt: Mat.cbrt, 2366 cosh: Mat.cosh, 2367 cot: Mat.cot, 2368 deg: Geometry.trueAngle, 2369 A: that.area, 2370 area: that.area, 2371 dist: that.dist, 2372 R: that.radius, 2373 radius: that.radius, 2374 erf: Mat.erf, 2375 erfc: Mat.erfc, 2376 erfi: Mat.erfi, 2377 factorial: Mat.factorial, 2378 gcd: Mat.gcd, 2379 lb: Mat.log2, 2380 lcm: Mat.lcm, 2381 ld: Mat.log2, 2382 lg: Mat.log10, 2383 ln: Math.log, 2384 log: Mat.log, 2385 log10: Mat.log10, 2386 log2: Mat.log2, 2387 ndtr: Mat.ndtr, 2388 ndtri: Mat.ndtri, 2389 nthroot: Mat.nthroot, 2390 pow: Mat.pow, 2391 rad: Geometry.rad, 2392 ratpow: Mat.ratpow, 2393 trunc: Type.trunc, 2394 sinh: Mat.sinh, 2395 2396 randint: that.randint, 2397 2398 IfThen: that.ifthen, 2399 'import': that.importModule, 2400 'use': that.use, 2401 'remove': that.del, 2402 '$': that.getElementById, 2403 getName: that.getName, 2404 name: that.getName, 2405 '$board': that.board, 2406 '$log': that.log 2407 }; 2408 2409 // special scopes for factorial, deg, and rad 2410 builtIn.rad.sc = Geometry; 2411 builtIn.deg.sc = Geometry; 2412 builtIn.factorial.sc = Mat; 2413 2414 // set the javascript equivalent for the builtIns 2415 // some of the anonymous functions should be replaced by global methods later on 2416 // EULER and PI don't get a source attribute - they will be lost anyways and apparently 2417 // some browser will throw an exception when a property is assigned to a primitive value. 2418 builtIn.X.src = '$jc$.X'; 2419 builtIn.Y.src = '$jc$.Y'; 2420 builtIn.V.src = '$jc$.V'; 2421 builtIn.L.src = '$jc$.L'; 2422 2423 builtIn.acosh.src = 'JXG.Math.acosh'; 2424 builtIn.acot.src = 'JXG.Math.acot'; 2425 builtIn.asinh.src = 'JXG.Math.asinh'; 2426 builtIn.binomial.src = 'JXG.Math.binomial'; 2427 builtIn.cbrt.src = 'JXG.Math.cbrt'; 2428 builtIn.cot.src = 'JXG.Math.cot'; 2429 builtIn.cosh.src = 'JXG.Math.cosh'; 2430 builtIn.deg.src = 'JXG.Math.Geometry.trueAngle'; 2431 builtIn.erf.src = 'JXG.Math.erf'; 2432 builtIn.erfc.src = 'JXG.Math.erfc'; 2433 builtIn.erfi.src = 'JXG.Math.erfi'; 2434 builtIn.A.src = '$jc$.area'; 2435 builtIn.area.src = '$jc$.area'; 2436 builtIn.dist.src = '$jc$.dist'; 2437 builtIn.R.src = '$jc$.radius'; 2438 builtIn.radius.src = '$jc$.radius'; 2439 builtIn.factorial.src = 'JXG.Math.factorial'; 2440 builtIn.gcd.src = 'JXG.Math.gcd'; 2441 builtIn.lb.src = 'JXG.Math.log2'; 2442 builtIn.lcm.src = 'JXG.Math.lcm'; 2443 builtIn.ld.src = 'JXG.Math.log2'; 2444 builtIn.lg.src = 'JXG.Math.log10'; 2445 builtIn.ln.src = 'Math.log'; 2446 builtIn.log.src = 'JXG.Math.log'; 2447 builtIn.log10.src = 'JXG.Math.log10'; 2448 builtIn.log2.src = 'JXG.Math.log2'; 2449 builtIn.ndtr.src = 'JXG.Math.ndtr'; 2450 builtIn.ndtri.src = 'JXG.Math.ndtri'; 2451 builtIn.nthroot.src = 'JXG.Math.nthroot'; 2452 builtIn.pow.src = 'JXG.Math.pow'; 2453 builtIn.rad.src = 'JXG.Math.Geometry.rad'; 2454 builtIn.ratpow.src = 'JXG.Math.ratpow'; 2455 builtIn.trunc.src = 'JXG.trunc'; 2456 builtIn.sinh.src = 'JXG.Math.sinh'; 2457 2458 builtIn.randint.src = '$jc$.randint'; 2459 2460 builtIn['import'].src = '$jc$.importModule'; 2461 builtIn.use.src = '$jc$.use'; 2462 builtIn.remove.src = '$jc$.del'; 2463 builtIn.IfThen.src = '$jc$.ifthen'; 2464 // usually unused, see node_op > op_execfun 2465 builtIn.$.src = '(function (n) { return $jc$.board.select(n); })'; 2466 builtIn.getName.src = '$jc$.getName'; 2467 builtIn.name.src = '$jc$.getName'; 2468 if (builtIn.$board) { 2469 builtIn.$board.src = '$jc$.board'; 2470 } 2471 builtIn.$log.src = '$jc$.log'; 2472 2473 return builtIn; 2474 }, 2475 2476 /** 2477 * Returns information about the possible functions and constants. 2478 * @returns {Object} 2479 */ 2480 getPossibleOperands: function () { 2481 var FORBIDDEN = ['E'], 2482 jessiecode = this.defineBuiltIn(), 2483 math = Math, 2484 jc, ma, merge, 2485 i, j, p, len, e, 2486 funcs, funcsJC, consts, operands, 2487 sort, pack; 2488 2489 sort = function (a, b) { 2490 return a.toLowerCase().localeCompare(b.toLowerCase()); 2491 }; 2492 2493 pack = function (name, origin) { 2494 var that = null; 2495 2496 if (origin === 'jc') that = jessiecode[name]; 2497 else if (origin === 'Math') that = math[name]; 2498 else return; 2499 2500 if (FORBIDDEN.indexOf(name) >= 0) { 2501 return; 2502 } else if (JXG.isFunction(that)) { 2503 return { 2504 name: name, 2505 type: 'function', 2506 numParams: that.length, 2507 origin: origin, 2508 }; 2509 } else if (JXG.isNumber(that)) { 2510 return { 2511 name: name, 2512 type: 'constant', 2513 value: that, 2514 origin: origin, 2515 }; 2516 } else if (that !== undefined) { 2517 console.error('undefined type', that); 2518 } 2519 }; 2520 2521 jc = Object.getOwnPropertyNames(jessiecode).sort(sort); 2522 ma = Object.getOwnPropertyNames(math).sort(sort); 2523 merge = []; 2524 i = 0; 2525 j = 0; 2526 2527 while (i < jc.length || j < ma.length) { 2528 if (jc[i] === ma[j]) { 2529 p = pack(ma[j], 'Math'); 2530 if (JXG.exists(p)) merge.push(p); 2531 i++; 2532 j++; 2533 } else if (!JXG.exists(ma[j]) || jc[i].toLowerCase().localeCompare(ma[j].toLowerCase()) < 0) { 2534 p = pack(jc[i], 'jc'); 2535 if (JXG.exists(p)) merge.push(p); 2536 i++; 2537 } else { 2538 p = pack(ma[j], 'Math'); 2539 if (JXG.exists(p)) merge.push(p); 2540 j++; 2541 } 2542 } 2543 2544 funcs = []; 2545 funcsJC = []; 2546 consts = []; 2547 operands = {}; 2548 len = merge.length; 2549 for (i = 0; i < len; i++) { 2550 e = merge[i]; 2551 switch (e.type) { 2552 case 'function': 2553 funcs.push(e.name); 2554 if (e.origin === 'jc') 2555 funcsJC.push(e.name); 2556 break; 2557 case 'constant': 2558 consts.push(e.name); 2559 break; 2560 } 2561 operands[e.name] = e; 2562 } 2563 2564 return { 2565 all: operands, 2566 list: merge, 2567 functions: funcs, 2568 functions_jessiecode: funcsJC, 2569 constants: consts, 2570 }; 2571 }, 2572 2573 /** 2574 * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the 2575 * id "debug" and an innerHTML property is used. 2576 * @param {String} log 2577 * @private 2578 */ 2579 _debug: function (log) { 2580 if (typeof console === 'object') { 2581 console.log(log); 2582 } else if (Env.isBrowser && document && document.getElementById('debug') !== null) { 2583 document.getElementById('debug').innerHTML += log + '<br />'; 2584 } 2585 }, 2586 2587 /** 2588 * Throws an exception with the given error message. 2589 * @param {String} msg Error message 2590 */ 2591 _error: function (msg) { 2592 var e = new Error('Error(' + this.line + '): ' + msg); 2593 e.line = this.line; 2594 throw e; 2595 }, 2596 2597 /** 2598 * Output a warning message using {@link JXG#debug} and precedes the message with "Warning: ". 2599 * @param {String} msg 2600 */ 2601 _warn: function (msg) { 2602 if (typeof console === 'object') { 2603 console.log('Warning(' + this.line + '): ' + msg); 2604 } else if (Env.isBrowser && document && document.getElementById(this.warnLog) !== null) { 2605 document.getElementById(this.warnLog).innerHTML += 'Warning(' + this.line + '): ' + msg + '<br />'; 2606 } 2607 }, 2608 2609 _log: function (msg) { 2610 if (typeof window !== 'object' && typeof self === 'object' && self.postMessage) { 2611 self.postMessage({ type: 'log', msg: 'Log: ' + msg.toString() }); 2612 } else { 2613 console.log('Log: ', arguments); 2614 } 2615 } 2616 2617 }); 2618 2619 /* parser generated by jison 0.4.18 */ 2620 /* 2621 Returns a Parser object of the following structure: 2622 2623 Parser: { 2624 yy: {} 2625 } 2626 2627 Parser.prototype: { 2628 yy: {}, 2629 trace: function(), 2630 symbols_: {associative list: name ==> number}, 2631 terminals_: {associative list: number ==> name}, 2632 productions_: [...], 2633 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), 2634 table: [...], 2635 defaultActions: {...}, 2636 parseError: function(str, hash), 2637 parse: function(input), 2638 2639 lexer: { 2640 EOF: 1, 2641 parseError: function(str, hash), 2642 setInput: function(input), 2643 input: function(), 2644 unput: function(str), 2645 more: function(), 2646 less: function(n), 2647 pastInput: function(), 2648 upcomingInput: function(), 2649 showPosition: function(), 2650 test_match: function(regex_match_array, rule_index), 2651 next: function(), 2652 lex: function(), 2653 begin: function(condition), 2654 popState: function(), 2655 _currentRules: function(), 2656 topState: function(), 2657 pushState: function(condition), 2658 2659 options: { 2660 ranges: boolean (optional: true ==> token location info will include a .range[] member) 2661 flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) 2662 backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) 2663 }, 2664 2665 performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), 2666 rules: [...], 2667 conditions: {associative list: name ==> set}, 2668 } 2669 } 2670 2671 2672 token location info (@$, _$, etc.): { 2673 first_line: n, 2674 last_line: n, 2675 first_column: n, 2676 last_column: n, 2677 range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) 2678 } 2679 2680 2681 the parseError function receives a 'hash' object with these members for lexer and parser errors: { 2682 text: (matched text) 2683 token: (the produced terminal token, if any) 2684 line: (yylineno) 2685 } 2686 while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { 2687 loc: (yylloc) 2688 expected: (string describing the set of expected tokens) 2689 recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) 2690 } 2691 */ 2692 var parser = (function(){ 2693 var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,150],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,167],$VX=[10,86]; 2694 var parser = {trace: function trace () { }, 2695 yy: {}, 2696 symbols_: {"error":2,"Program":3,"StatementList":4,"EOF":5,"IfStatement":6,"IF":7,"(":8,"Expression":9,")":10,"Statement":11,"ELSE":12,"LoopStatement":13,"WHILE":14,"FOR":15,";":16,"DO":17,"UnaryStatement":18,"USE":19,"IDENTIFIER":20,"DELETE":21,"ReturnStatement":22,"RETURN":23,"EmptyStatement":24,"StatementBlock":25,"{":26,"}":27,"ExpressionStatement":28,"AssignmentExpression":29,"ConditionalExpression":30,"LeftHandSideExpression":31,"=":32,"LogicalORExpression":33,"?":34,":":35,"LogicalANDExpression":36,"||":37,"EqualityExpression":38,"&&":39,"RelationalExpression":40,"==":41,"!=":42,"~=":43,"AdditiveExpression":44,"<":45,">":46,"<=":47,">=":48,"MultiplicativeExpression":49,"+":50,"-":51,"UnaryExpression":52,"*":53,"/":54,"%":55,"ExponentExpression":56,"^":57,"!":58,"MemberExpression":59,"CallExpression":60,"PrimaryExpression":61,"FunctionExpression":62,"MapExpression":63,".":64,"[":65,"]":66,"BasicLiteral":67,"ObjectLiteral":68,"ArrayLiteral":69,"NullLiteral":70,"BooleanLiteral":71,"StringLiteral":72,"NumberLiteral":73,"NULL":74,"TRUE":75,"FALSE":76,"STRING":77,"NUMBER":78,"NAN":79,"INFINITY":80,"ElementList":81,"<<":82,">>":83,"PropertyList":84,"Property":85,",":86,"PropertyName":87,"Arguments":88,"AttributeList":89,"Attribute":90,"FUNCTION":91,"ParameterDefinitionList":92,"MAP":93,"->":94,"$accept":0,"$end":1}, 2697 terminals_: {2:"error",5:"EOF",7:"IF",8:"(",10:")",12:"ELSE",14:"WHILE",15:"FOR",16:";",17:"DO",19:"USE",20:"IDENTIFIER",21:"DELETE",23:"RETURN",26:"{",27:"}",32:"=",34:"?",35:":",37:"||",39:"&&",41:"==",42:"!=",43:"~=",45:"<",46:">",47:"<=",48:">=",50:"+",51:"-",53:"*",54:"/",55:"%",57:"^",58:"!",64:".",65:"[",66:"]",74:"NULL",75:"TRUE",76:"FALSE",77:"STRING",78:"NUMBER",79:"NAN",80:"INFINITY",82:"<<",83:">>",86:",",91:"FUNCTION",93:"MAP",94:"->"}, 2698 productions_: [0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,5],[63,6],[92,1],[92,3]], 2699 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { 2700 /* this == yyval */ 2701 2702 var $0 = $$.length - 1; 2703 switch (yystate) { 2704 case 1: 2705 return $$[$0-1]; 2706 break; 2707 case 2: 2708 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_if', $$[$0-2], $$[$0]); 2709 break; 2710 case 3: 2711 this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_if_else', $$[$0-4], $$[$0-2], $$[$0]); 2712 break; 2713 case 4: 2714 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_while', $$[$0-2], $$[$0]); 2715 break; 2716 case 5: 2717 this.$ = AST.createNode(lc(_$[$0-8]), 'node_op', 'op_for', $$[$0-6], $$[$0-4], $$[$0-2], $$[$0]); 2718 break; 2719 case 6: 2720 this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_do', $$[$0-5], $$[$0-2]); 2721 break; 2722 case 7: 2723 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_use', $$[$0]); 2724 break; 2725 case 8: 2726 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_delete', $$[$0]); 2727 break; 2728 case 9: 2729 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_return', undefined); 2730 break; 2731 case 10: 2732 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_return', $$[$0-1]); 2733 break; 2734 case 11: case 14: 2735 this.$ = AST.createNode(lc(_$[$0]), 'node_op', 'op_none'); 2736 break; 2737 case 12: 2738 this.$ = $$[$0-1]; this.$.needsBrackets = true; 2739 break; 2740 case 13: 2741 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_none', $$[$0-1], $$[$0]); 2742 break; 2743 case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 23: case 24: case 26: case 28: case 30: case 32: case 36: case 41: case 44: case 48: case 50: case 52: case 54: case 55: case 56: case 58: case 62: case 81: case 84: case 85: case 86: 2744 this.$ = $$[$0]; 2745 break; 2746 case 22: case 65: case 93: 2747 this.$ = $$[$0-1]; 2748 break; 2749 case 25: 2750 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_assign', $$[$0-2], $$[$0]); this.$.isMath = false; 2751 break; 2752 case 27: 2753 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_conditional', $$[$0-4], $$[$0-2], $$[$0]); this.$.isMath = false; 2754 break; 2755 case 29: 2756 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_or', $$[$0-2], $$[$0]); this.$.isMath = false; 2757 break; 2758 case 31: 2759 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_and', $$[$0-2], $$[$0]); this.$.isMath = false; 2760 break; 2761 case 33: 2762 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_eq', $$[$0-2], $$[$0]); this.$.isMath = false; 2763 break; 2764 case 34: 2765 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_neq', $$[$0-2], $$[$0]); this.$.isMath = false; 2766 break; 2767 case 35: 2768 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_approx', $$[$0-2], $$[$0]); this.$.isMath = false; 2769 break; 2770 case 37: 2771 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lt', $$[$0-2], $$[$0]); this.$.isMath = false; 2772 break; 2773 case 38: 2774 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gt', $$[$0-2], $$[$0]); this.$.isMath = false; 2775 break; 2776 case 39: 2777 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_leq', $$[$0-2], $$[$0]); this.$.isMath = false; 2778 break; 2779 case 40: 2780 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_geq', $$[$0-2], $$[$0]); this.$.isMath = false; 2781 break; 2782 case 42: 2783 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_add', $$[$0-2], $$[$0]); this.$.isMath = true; 2784 break; 2785 case 43: 2786 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_sub', $$[$0-2], $$[$0]); this.$.isMath = true; 2787 break; 2788 case 45: 2789 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mul', $$[$0-2], $$[$0]); this.$.isMath = true; 2790 break; 2791 case 46: 2792 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_div', $$[$0-2], $$[$0]); this.$.isMath = true; 2793 break; 2794 case 47: 2795 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mod', $$[$0-2], $$[$0]); this.$.isMath = true; 2796 break; 2797 case 49: 2798 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_exp', $$[$0-2], $$[$0]); this.$.isMath = true; 2799 break; 2800 case 51: 2801 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_not', $$[$0]); this.$.isMath = false; 2802 break; 2803 case 53: 2804 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_neg', $$[$0]); this.$.isMath = true; 2805 break; 2806 case 57: case 63: case 64: case 66: case 67: case 68: case 97: 2807 this.$ = $$[$0]; this.$.isMath = false; 2808 break; 2809 case 59: case 91: 2810 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_property', $$[$0-2], $$[$0]); this.$.isMath = true; 2811 break; 2812 case 60: case 90: 2813 this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_extvalue', $$[$0-3], $$[$0-1]); this.$.isMath = true; 2814 break; 2815 case 61: 2816 this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); 2817 break; 2818 case 69: 2819 this.$ = $$[$0]; this.$.isMath = true; 2820 break; 2821 case 70: 2822 this.$ = AST.createNode(lc(_$[$0]), 'node_const', null); 2823 break; 2824 case 71: 2825 this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', true); 2826 break; 2827 case 72: 2828 this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', false); 2829 break; 2830 case 73: 2831 this.$ = AST.createNode(lc(_$[$0]), 'node_str', $$[$0].substring(1, $$[$0].length - 1)); 2832 break; 2833 case 74: 2834 this.$ = AST.createNode(lc(_$[$0]), 'node_const', parseFloat($$[$0])); 2835 break; 2836 case 75: 2837 this.$ = AST.createNode(lc(_$[$0]), 'node_const', NaN); 2838 break; 2839 case 76: 2840 this.$ = AST.createNode(lc(_$[$0]), 'node_const', Infinity); 2841 break; 2842 case 77: 2843 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_array', []); 2844 break; 2845 case 78: 2846 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_array', $$[$0-1]); 2847 break; 2848 case 79: 2849 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {}); this.$.needsBrackets = true; 2850 break; 2851 case 80: 2852 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]); this.$.needsBrackets = true; 2853 break; 2854 case 82: 2855 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst', $$[$0-2], $$[$0]); 2856 break; 2857 case 83: 2858 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_prop', $$[$0-2], $$[$0]); 2859 break; 2860 case 87: case 89: 2861 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_execfun', $$[$0-1], $$[$0]); this.$.isMath = true; 2862 break; 2863 case 88: 2864 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_execfun', $$[$0-2], $$[$0-1], $$[$0], true); this.$.isMath = false; 2865 break; 2866 case 92: 2867 this.$ = []; 2868 break; 2869 case 94: case 98: case 104: 2870 this.$ = [$$[$0]]; 2871 break; 2872 case 95: case 99: case 105: 2873 this.$ = $$[$0-2].concat($$[$0]); 2874 break; 2875 case 96: 2876 this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); this.$.isMath = true; 2877 break; 2878 case 100: 2879 this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_function', [], $$[$0]); this.$.isMath = false; 2880 break; 2881 case 101: 2882 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_function', $$[$0-2], $$[$0]); this.$.isMath = false; 2883 break; 2884 case 102: 2885 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_map', [], $$[$0]); 2886 break; 2887 case 103: 2888 this.$ = AST.createNode(lc(_$[$0-5]), 'node_op', 'op_map', $$[$0-3], $$[$0]); 2889 break; 2890 } 2891 }, 2892 table: [o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{10:[1,140],20:$VR,92:141},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:145,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,146],86:[1,147]},o($VS,[2,81]),{35:[1,148]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,149],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:152,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:155,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,156]},{10:[1,157]},{16:[1,158]},{8:[1,159]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,160]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,161]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,162]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,163],86:$VT},{66:[1,164]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:165,26:$Vb},{10:[1,166],86:$VW},o($VX,[2,104]),{94:[1,168]},{10:[1,169],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:170,87:96},{8:$V2,20:$V8,29:171,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:172,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:173,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:174,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:175,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:176,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:177,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),