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