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