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