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