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 } else { 1736 e = list.join(', '); 1737 } 1738 } 1739 node.children[0].withProps = !!node.children[2]; 1740 list = []; 1741 for (i = 0; i < node.children[1].length; i++) { 1742 list.push(this.compile(node.children[1][i], js)); 1743 } 1744 ret = this.compile(node.children[0], js) + '(' + list.join(', ') + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? ' ' + e : ''); 1745 if (js) { 1746 // Inserting a newline here allows simulataneously 1747 // - procedural calls like Q.moveTo(...); and 1748 // - function calls in expressions like log(x) + 1; 1749 // Problem: procedural calls will not be ended by a semicolon. 1750 ret += '\n'; 1751 } 1752 1753 // save us a function call when compiled to javascript 1754 if (js && node.children[0].value === '$') { 1755 ret = '$jc$.board.objects[' + this.compile(node.children[1][0], js) + ']'; 1756 } 1757 break; 1758 case 'op_property': 1759 if (js && node.children[1] !== 'X' && node.children[1] !== 'Y') { 1760 ret = '$jc$.resolveProperty(' + this.compile(node.children[0], js) + ', \'' + node.children[1] + '\', true)'; 1761 } else { 1762 ret = this.compile(node.children[0], js) + '.' + node.children[1]; 1763 } 1764 break; 1765 case 'op_use': 1766 this._warn('Use of the \'use\' operator is deprecated.'); 1767 if (js) { 1768 ret = '$jc$.use(\''; 1769 } else { 1770 ret = 'use(\''; 1771 } 1772 1773 ret += node.children[0].toString() + '\');'; 1774 break; 1775 case 'op_delete': 1776 this._warn('Use of the \'delete\' operator is deprecated. Please use the remove() function.'); 1777 if (js) { 1778 ret = '$jc$.del('; 1779 } else { 1780 ret = 'remove('; 1781 } 1782 1783 ret += this.compile(node.children[0], js) + ')'; 1784 break; 1785 case 'op_eq': 1786 ret = '(' + this.compile(node.children[0], js) + ' === ' + this.compile(node.children[1], js) + ')'; 1787 break; 1788 case 'op_neq': 1789 ret = '(' + this.compile(node.children[0], js) + ' !== ' + this.compile(node.children[1], js) + ')'; 1790 break; 1791 case 'op_approx': 1792 ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')'; 1793 break; 1794 case 'op_gt': 1795 if (js) { 1796 ret = '$jc$.gt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1797 } else { 1798 ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')'; 1799 } 1800 break; 1801 case 'op_lt': 1802 if (js) { 1803 ret = '$jc$.lt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1804 } else { 1805 ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')'; 1806 } 1807 break; 1808 case 'op_geq': 1809 if (js) { 1810 ret = '$jc$.geq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1811 } else { 1812 ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')'; 1813 } 1814 break; 1815 case 'op_leq': 1816 if (js) { 1817 ret = '$jc$.leq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1818 } else { 1819 ret = '(' + this.compile(node.children[0], js) + ' <= ' + this.compile(node.children[1], js) + ')'; 1820 } 1821 break; 1822 case 'op_or': 1823 ret = '(' + this.compile(node.children[0], js) + ' || ' + this.compile(node.children[1], js) + ')'; 1824 break; 1825 case 'op_and': 1826 ret = '(' + this.compile(node.children[0], js) + ' && ' + this.compile(node.children[1], js) + ')'; 1827 break; 1828 case 'op_not': 1829 ret = '!(' + this.compile(node.children[0], js) + ')'; 1830 break; 1831 case 'op_add': 1832 if (js) { 1833 ret = '$jc$.add(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1834 } else { 1835 ret = '(' + this.compile(node.children[0], js) + ' + ' + this.compile(node.children[1], js) + ')'; 1836 } 1837 break; 1838 case 'op_sub': 1839 if (js) { 1840 ret = '$jc$.sub(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1841 } else { 1842 ret = '(' + this.compile(node.children[0], js) + ' - ' + this.compile(node.children[1], js) + ')'; 1843 } 1844 break; 1845 case 'op_div': 1846 if (js) { 1847 ret = '$jc$.div(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1848 } else { 1849 ret = '(' + this.compile(node.children[0], js) + ' / ' + this.compile(node.children[1], js) + ')'; 1850 } 1851 break; 1852 case 'op_mod': 1853 if (js) { 1854 ret = '$jc$.mod(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ', true)'; 1855 } else { 1856 ret = '(' + this.compile(node.children[0], js) + ' % ' + this.compile(node.children[1], js) + ')'; 1857 } 1858 break; 1859 case 'op_mul': 1860 if (js) { 1861 ret = '$jc$.mul(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1862 } else { 1863 ret = '(' + this.compile(node.children[0], js) + ' * ' + this.compile(node.children[1], js) + ')'; 1864 } 1865 break; 1866 case 'op_exp': 1867 if (js) { 1868 ret = '$jc$.pow(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; 1869 } else { 1870 ret = '(' + this.compile(node.children[0], js) + '^' + this.compile(node.children[1], js) + ')'; 1871 } 1872 break; 1873 case 'op_neg': 1874 if (js) { 1875 ret = '$jc$.neg(' + this.compile(node.children[0], js) + ')'; 1876 } else { 1877 ret = '(-' + this.compile(node.children[0], js) + ')'; 1878 } 1879 break; 1880 } 1881 break; 1882 1883 case 'node_var': 1884 if (js) { 1885 ret = this.getvarJS(node.value, false, node.withProps); 1886 } else { 1887 ret = node.value; 1888 } 1889 break; 1890 1891 case 'node_const': 1892 ret = node.value; 1893 break; 1894 1895 case 'node_const_bool': 1896 ret = node.value; 1897 break; 1898 1899 case 'node_str': 1900 ret = '\'' + node.value + '\''; 1901 break; 1902 } 1903 1904 if (node.needsBrackets) { 1905 if (js) { 1906 ret = '{\n' + ret + '\n}\n'; 1907 } else { 1908 ret = '<< ' + ret + ' >>'; 1909 } 1910 } 1911 1912 return ret; 1913 }, 1914 1915 /** 1916 * This is used as the global getName() function. 1917 * @param {JXG.GeometryElement} obj 1918 * @param {Boolean} useId 1919 * @returns {String} 1920 */ 1921 getName: function (obj,useId) { 1922 var name = ''; 1923 1924 if (Type.exists(obj) && Type.exists(obj.getName)) { 1925 name = obj.getName(); 1926 if ((!Type.exists(name) || name === '') && !!useId) { 1927 name = obj.id; 1928 } 1929 } else if (!!useId) { 1930 name = obj.id; 1931 } 1932 1933 return name; 1934 }, 1935 1936 /** 1937 * This is used as the global X() function. 1938 * @param {JXG.Point|JXG.Text} e 1939 * @returns {Number} 1940 */ 1941 X: function (e) { 1942 return e.X(); 1943 }, 1944 1945 /** 1946 * This is used as the global Y() function. 1947 * @param {JXG.Point|JXG.Text} e 1948 * @returns {Number} 1949 */ 1950 Y: function (e) { 1951 return e.Y(); 1952 }, 1953 1954 /** 1955 * This is used as the global V() function. 1956 * @param {Glider|Slider} e 1957 * @returns {Number} 1958 */ 1959 V: function (e) { 1960 return e.Value(); 1961 }, 1962 1963 /** 1964 * This is used as the global L() function. 1965 * @param {JXG.Line} e 1966 * @returns {Number} 1967 */ 1968 L: function (e) { 1969 return e.L(); 1970 }, 1971 1972 /** 1973 * This is used as the global area() function. 1974 * @param {JXG.Circle|JXG.Polygon} obj 1975 * @returns {Number} 1976 */ 1977 area: function (obj) { 1978 if (!Type.exists(obj) || !Type.exists(obj.Area)) { 1979 this._error('Error: Can\'t calculate area.'); 1980 } 1981 1982 return obj.Area(); 1983 }, 1984 1985 /** 1986 * This is used as the global dist() function. 1987 * @param {JXG.Point} p1 1988 * @param {JXG.Point} p2 1989 * @returns {Number} 1990 */ 1991 dist: function (p1, p2) { 1992 if (!Type.exists(p1) || !Type.exists(p1.Dist)) { 1993 this._error('Error: Can\'t calculate distance.'); 1994 } 1995 1996 return p1.Dist(p2); 1997 }, 1998 1999 /** 2000 * This is used as the global radius() function. 2001 * @param {JXG.Circle|Sector} obj 2002 * @returns {Number} 2003 */ 2004 radius: function (obj) { 2005 if (!Type.exists(obj) || !Type.exists(obj.Radius)) { 2006 this._error('Error: Can\'t calculate radius.'); 2007 } 2008 2009 return obj.Radius(); 2010 }, 2011 2012 /** 2013 * + operator implementation 2014 * @param {Number|Array|JXG.Point} a 2015 * @param {Number|Array|JXG.Point} b 2016 * @returns {Number|Array} 2017 */ 2018 add: function (a, b) { 2019 var i, len, res; 2020 2021 a = Type.evalSlider(a); 2022 b = Type.evalSlider(b); 2023 2024 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2025 res = Interval.add(a, b); 2026 } else if (Type.isArray(a) && Type.isArray(b)) { 2027 len = Math.min(a.length, b.length); 2028 res = []; 2029 2030 for (i = 0; i < len; i++) { 2031 res[i] = a[i] + b[i]; 2032 } 2033 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2034 res = a + b; 2035 } else if (Type.isString(a) || Type.isString(b)) { 2036 res = a.toString() + b.toString(); 2037 } else { 2038 this._error('Operation + not defined on operands ' + typeof a + ' and ' + typeof b); 2039 } 2040 2041 return res; 2042 }, 2043 2044 /** 2045 * - operator implementation 2046 * @param {Number|Array|JXG.Point} a 2047 * @param {Number|Array|JXG.Point} b 2048 * @returns {Number|Array} 2049 */ 2050 sub: function (a, b) { 2051 var i, len, res; 2052 2053 a = Type.evalSlider(a); 2054 b = Type.evalSlider(b); 2055 2056 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2057 res = Interval.sub(a, b); 2058 } else if (Type.isArray(a) && Type.isArray(b)) { 2059 len = Math.min(a.length, b.length); 2060 res = []; 2061 2062 for (i = 0; i < len; i++) { 2063 res[i] = a[i] - b[i]; 2064 } 2065 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2066 res = a - b; 2067 } else { 2068 this._error('Operation - not defined on operands ' + typeof a + ' and ' + typeof b); 2069 } 2070 2071 return res; 2072 }, 2073 2074 /** 2075 * unary - operator implementation 2076 * @param {Number|Array|JXG.Point} a 2077 * @returns {Number|Array} 2078 */ 2079 neg: function (a) { 2080 var i, len, res; 2081 2082 a = Type.evalSlider(a); 2083 2084 if (Interval.isInterval(a)) { 2085 res = Interval.negative(a); 2086 } else if (Type.isArray(a)) { 2087 len = a.length; 2088 res = []; 2089 2090 for (i = 0; i < len; i++) { 2091 res[i] = -a[i]; 2092 } 2093 } else if (Type.isNumber(a)) { 2094 res = -a; 2095 } else { 2096 this._error('Unary operation - not defined on operand ' + typeof a); 2097 } 2098 2099 return res; 2100 }, 2101 2102 /** 2103 * Multiplication of vectors and numbers 2104 * @param {Number|Array} a 2105 * @param {Number|Array} b 2106 * @returns {Number|Array} (Inner) product of the given input values. 2107 */ 2108 mul: function (a, b) { 2109 var i, len, res; 2110 2111 a = Type.evalSlider(a); 2112 b = Type.evalSlider(b); 2113 2114 if (Type.isArray(a) && Type.isNumber(b)) { 2115 // swap b and a 2116 i = a; 2117 a = b; 2118 b = a; 2119 } 2120 2121 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2122 res = Interval.mul(a, b); 2123 } else if (Type.isArray(a) && Type.isArray(b)) { 2124 len = Math.min(a.length, b.length); 2125 res = Mat.innerProduct(a, b, len); 2126 } else if (Type.isNumber(a) && Type.isArray(b)) { 2127 len = b.length; 2128 res = []; 2129 2130 for (i = 0; i < len; i++) { 2131 res[i] = a * b[i]; 2132 } 2133 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2134 res = a * b; 2135 } else { 2136 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b); 2137 } 2138 2139 return res; 2140 }, 2141 2142 /** 2143 * Implementation of the / operator. 2144 * @param {Number|Array} a 2145 * @param {Number} b 2146 * @returns {Number|Array} 2147 */ 2148 div: function (a, b) { 2149 var i, len, res; 2150 2151 a = Type.evalSlider(a); 2152 b = Type.evalSlider(b); 2153 2154 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2155 res = Interval.div(a, b); 2156 } else if (Type.isArray(a) && Type.isNumber(b)) { 2157 len = a.length; 2158 res = []; 2159 2160 for (i = 0; i < len; i++) { 2161 res[i] = a[i] / b; 2162 } 2163 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2164 res = a / b; 2165 } else { 2166 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b); 2167 } 2168 2169 return res; 2170 }, 2171 2172 /** 2173 * Implementation of the % operator. 2174 * @param {Number|Array} a 2175 * @param {Number} b 2176 * @returns {Number|Array} 2177 */ 2178 mod: function (a, b) { 2179 var i, len, res; 2180 2181 a = Type.evalSlider(a); 2182 b = Type.evalSlider(b); 2183 2184 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2185 return Interval.fmod(a, b); 2186 } else if (Type.isArray(a) && Type.isNumber(b)) { 2187 len = a.length; 2188 res = []; 2189 2190 for (i = 0; i < len; i++) { 2191 res[i] = Mat.mod(a[i], b, true); 2192 } 2193 } else if (Type.isNumber(a) && Type.isNumber(b)) { 2194 res = Mat.mod(a, b, true); 2195 } else { 2196 this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b); 2197 } 2198 2199 return res; 2200 }, 2201 2202 /** 2203 * Pow function wrapper to allow direct usage of sliders. 2204 * @param {Number|Slider} a 2205 * @param {Number|Slider} b 2206 * @returns {Number} 2207 */ 2208 pow: function (a, b) { 2209 a = Type.evalSlider(a); 2210 b = Type.evalSlider(b); 2211 2212 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2213 return Interval.pow(a, b); 2214 } 2215 return Mat.pow(a, b); 2216 }, 2217 2218 lt: function (a, b) { 2219 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2220 return Interval.lt(a, b); 2221 } 2222 return a < b; 2223 }, 2224 leq: function (a, b) { 2225 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2226 return Interval.leq(a, b); 2227 } 2228 return a <= b; 2229 }, 2230 gt: function (a, b) { 2231 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2232 return Interval.gt(a, b); 2233 } 2234 return a > b; 2235 }, 2236 geq: function (a, b) { 2237 if (Interval.isInterval(a) || Interval.isInterval(b)) { 2238 return Intervalt.geq(a, b); 2239 } 2240 return a >= b; 2241 }, 2242 2243 randint: function (min, max, step) { 2244 if (!Type.exists(step)) { 2245 step = 1; 2246 } 2247 return Math.round(Math.random() * (max - min) / step) * step + min; 2248 }, 2249 2250 DDD: function (f) { 2251 console.log('Dummy derivative function. This should never appear!'); 2252 }, 2253 2254 /** 2255 * Implementation of the ?: operator 2256 * @param {Boolean} cond Condition 2257 * @param {*} v1 2258 * @param {*} v2 2259 * @returns {*} Either v1 or v2. 2260 */ 2261 ifthen: function (cond, v1, v2) { 2262 if (cond) { 2263 return v1; 2264 } 2265 2266 return v2; 2267 }, 2268 2269 /** 2270 * Implementation of the delete() builtin function 2271 * @param {JXG.GeometryElement} element 2272 */ 2273 del: function (element) { 2274 if (typeof element === 'object' && JXG.exists(element.type) && JXG.exists(element.elementClass)) { 2275 this.board.removeObject(element); 2276 } 2277 }, 2278 2279 /** 2280 * Implementation of the use() builtin function 2281 * @param {String} board 2282 */ 2283 use: function (board) { 2284 var b, ref, 2285 found = false; 2286 2287 if (typeof board === 'string') { 2288 // search all the boards for the one with the appropriate container div 2289 for (b in JXG.boards) { 2290 if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === board) { 2291 ref = JXG.boards[b]; 2292 found = true; 2293 break; 2294 } 2295 } 2296 } else { 2297 ref = board; 2298 found = true; 2299 } 2300 2301 if (found) { 2302 this.board = ref; 2303 this.builtIn.$board = ref; 2304 this.builtIn.$board.src = '$jc$.board'; 2305 } else { 2306 this._error('Board \'' + board + '\' not found!'); 2307 } 2308 }, 2309 2310 /** 2311 * Find the first symbol to the given value from the given scope upwards. 2312 * @param v Value 2313 * @param {Number} [scope=-1] The scope, default is to start with current scope (-1). 2314 * @returns {Array} An array containing the symbol and the scope if a symbol could be found, 2315 * an empty array otherwise; 2316 */ 2317 findSymbol: function (v, scope) { 2318 var i, s; 2319 2320 scope = Type.def(scope, -1); 2321 2322 if (scope === -1) { 2323 s = this.scope; 2324 } else { 2325 s = this.scopes[scope]; 2326 } 2327 2328 while (s !== null) { 2329 for (i in s.locals) { 2330 if (s.locals.hasOwnProperty(i) && s.locals[i] === v) { 2331 return [i, s]; 2332 } 2333 } 2334 2335 s = s.previous; 2336 } 2337 2338 return []; 2339 }, 2340 2341 /** 2342 * Import modules into a JessieCode script. 2343 * @param {String} module 2344 */ 2345 importModule: function (module) { 2346 return priv.modules[module.toLowerCase()]; 2347 }, 2348 2349 /** 2350 * Defines built in methods and constants. 2351 * @returns {Object} BuiltIn control object 2352 */ 2353 defineBuiltIn: function () { 2354 var that = this, 2355 builtIn = { 2356 PI: Math.PI, 2357 EULER: Math.E, 2358 D: that.DDD, 2359 X: that.X, 2360 Y: that.Y, 2361 V: that.V, 2362 L: that.L, 2363 2364 acosh: Mat.acosh, 2365 acot: Mat.acot, 2366 asinh: Mat.asinh, 2367 binomial: Mat.binomial, 2368 cbrt: Mat.cbrt, 2369 cosh: Mat.cosh, 2370 cot: Mat.cot, 2371 deg: Geometry.trueAngle, 2372 A: that.area, 2373 area: that.area, 2374 dist: that.dist, 2375 R: that.radius, 2376 radius: that.radius, 2377 erf: Mat.erf, 2378 erfc: Mat.erfc, 2379 erfi: Mat.erfi, 2380 factorial: Mat.factorial, 2381 gcd: Mat.gcd, 2382 lb: Mat.log2, 2383 lcm: Mat.lcm, 2384 ld: Mat.log2, 2385 lg: Mat.log10, 2386 ln: Math.log, 2387 log: Mat.log, 2388 log10: Mat.log10, 2389 log2: Mat.log2, 2390 ndtr: Mat.ndtr, 2391 ndtri: Mat.ndtri, 2392 nthroot: Mat.nthroot, 2393 pow: Mat.pow, 2394 rad: Geometry.rad, 2395 ratpow: Mat.ratpow, 2396 trunc: Type.trunc, 2397 sinh: Mat.sinh, 2398 2399 randint: that.randint, 2400 2401 IfThen: that.ifthen, 2402 'import': that.importModule, 2403 'use': that.use, 2404 'remove': that.del, 2405 '$': that.getElementById, 2406 getName: that.getName, 2407 name: that.getName, 2408 '$board': that.board, 2409 '$log': that.log 2410 }; 2411 2412 // special scopes for factorial, deg, and rad 2413 builtIn.rad.sc = Geometry; 2414 builtIn.deg.sc = Geometry; 2415 builtIn.factorial.sc = Mat; 2416 2417 // set the javascript equivalent for the builtIns 2418 // some of the anonymous functions should be replaced by global methods later on 2419 // EULER and PI don't get a source attribute - they will be lost anyways and apparently 2420 // some browser will throw an exception when a property is assigned to a primitive value. 2421 builtIn.X.src = '$jc$.X'; 2422 builtIn.Y.src = '$jc$.Y'; 2423 builtIn.V.src = '$jc$.V'; 2424 builtIn.L.src = '$jc$.L'; 2425 2426 builtIn.acosh.src = 'JXG.Math.acosh'; 2427 builtIn.acot.src = 'JXG.Math.acot'; 2428 builtIn.asinh.src = 'JXG.Math.asinh'; 2429 builtIn.binomial.src = 'JXG.Math.binomial'; 2430 builtIn.cbrt.src = 'JXG.Math.cbrt'; 2431 builtIn.cot.src = 'JXG.Math.cot'; 2432 builtIn.cosh.src = 'JXG.Math.cosh'; 2433 builtIn.deg.src = 'JXG.Math.Geometry.trueAngle'; 2434 builtIn.erf.src = 'JXG.Math.erf'; 2435 builtIn.erfc.src = 'JXG.Math.erfc'; 2436 builtIn.erfi.src = 'JXG.Math.erfi'; 2437 builtIn.A.src = '$jc$.area'; 2438 builtIn.area.src = '$jc$.area'; 2439 builtIn.dist.src = '$jc$.dist'; 2440 builtIn.R.src = '$jc$.radius'; 2441 builtIn.radius.src = '$jc$.radius'; 2442 builtIn.factorial.src = 'JXG.Math.factorial'; 2443 builtIn.gcd.src = 'JXG.Math.gcd'; 2444 builtIn.lb.src = 'JXG.Math.log2'; 2445 builtIn.lcm.src = 'JXG.Math.lcm'; 2446 builtIn.ld.src = 'JXG.Math.log2'; 2447 builtIn.lg.src = 'JXG.Math.log10'; 2448 builtIn.ln.src = 'Math.log'; 2449 builtIn.log.src = 'JXG.Math.log'; 2450 builtIn.log10.src = 'JXG.Math.log10'; 2451 builtIn.log2.src = 'JXG.Math.log2'; 2452 builtIn.ndtr.src = 'JXG.Math.ndtr'; 2453 builtIn.ndtri.src = 'JXG.Math.ndtri'; 2454 builtIn.nthroot.src = 'JXG.Math.nthroot'; 2455 builtIn.pow.src = 'JXG.Math.pow'; 2456 builtIn.rad.src = 'JXG.Math.Geometry.rad'; 2457 builtIn.ratpow.src = 'JXG.Math.ratpow'; 2458 builtIn.trunc.src = 'JXG.trunc'; 2459 builtIn.sinh.src = 'JXG.Math.sinh'; 2460 2461 builtIn.randint.src = '$jc$.randint'; 2462 2463 builtIn['import'].src = '$jc$.importModule'; 2464 builtIn.use.src = '$jc$.use'; 2465 builtIn.remove.src = '$jc$.del'; 2466 builtIn.IfThen.src = '$jc$.ifthen'; 2467 // usually unused, see node_op > op_execfun 2468 builtIn.$.src = '(function (n) { return $jc$.board.select(n); })'; 2469 builtIn.getName.src = '$jc$.getName'; 2470 builtIn.name.src = '$jc$.getName'; 2471 if (builtIn.$board) { 2472 builtIn.$board.src = '$jc$.board'; 2473 } 2474 builtIn.$log.src = '$jc$.log'; 2475 2476 return builtIn; 2477 }, 2478 2479 /** 2480 * Returns information about the possible functions and constants. 2481 * @returns {Object} 2482 */ 2483 getPossibleOperands: function () { 2484 var FORBIDDEN = ['E'], 2485 jessiecode = this.defineBuiltIn(), 2486 math = Math, 2487 jc, ma, merge, 2488 i, j, p, len, e, 2489 funcs, funcsJC, consts, operands, 2490 sort, pack; 2491 2492 sort = function (a, b) { 2493 return a.toLowerCase().localeCompare(b.toLowerCase()); 2494 }; 2495 2496 pack = function (name, origin) { 2497 var that = null; 2498 2499 if (origin === 'jc') that = jessiecode[name]; 2500 else if (origin === 'Math') that = math[name]; 2501 else return; 2502 2503 if (FORBIDDEN.includes(name)) { 2504 return; 2505 } else if (JXG.isFunction(that)) { 2506 return { 2507 name: name, 2508 type: 'function', 2509 numParams: that.length, 2510 origin: origin, 2511 }; 2512 } else if (JXG.isNumber(that)) { 2513 return { 2514 name: name, 2515 type: 'constant', 2516 value: that, 2517 origin: origin, 2518 }; 2519 } else if (that !== undefined) { 2520 console.error('undefined type', that); 2521 } 2522 }; 2523 2524 jc = Object.getOwnPropertyNames(jessiecode).sort(sort); 2525 ma = Object.getOwnPropertyNames(math).sort(sort); 2526 merge = []; 2527 i = 0; 2528 j = 0; 2529 2530 while (i < jc.length || j < ma.length) { 2531 if (jc[i] === ma[j]) { 2532 p = pack(ma[j], 'Math'); 2533 if (JXG.exists(p)) merge.push(p); 2534 i++; 2535 j++; 2536 } else if (!JXG.exists(ma[j]) || jc[i].toLowerCase().localeCompare(ma[j].toLowerCase()) < 0) { 2537 p = pack(jc[i], 'jc'); 2538 if (JXG.exists(p)) merge.push(p); 2539 i++; 2540 } else { 2541 p = pack(ma[j], 'Math'); 2542 if (JXG.exists(p)) merge.push(p); 2543 j++; 2544 } 2545 } 2546 2547 funcs = []; 2548 funcsJC = []; 2549 consts = []; 2550 operands = {}; 2551 len = merge.length; 2552 for (i = 0; i < len; i++) { 2553 e = merge[i]; 2554 switch (e.type) { 2555 case 'function': 2556 funcs.push(e.name); 2557 if (e.origin === 'jc') 2558 funcsJC.push(e.name); 2559 break; 2560 case 'constant': 2561 consts.push(e.name); 2562 break; 2563 } 2564 operands[e.name] = e; 2565 } 2566 2567 return { 2568 all: operands, 2569 list: merge, 2570 functions: funcs, 2571 functions_jessiecode: funcsJC, 2572 constants: consts, 2573 }; 2574 }, 2575 2576 /** 2577 * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the 2578 * id "debug" and an innerHTML property is used. 2579 * @param {String} log 2580 * @private 2581 */ 2582 _debug: function (log) { 2583 if (typeof console === 'object') { 2584 console.log(log); 2585 } else if (Env.isBrowser && document && document.getElementById('debug') !== null) { 2586 document.getElementById('debug').innerHTML += log + '<br />'; 2587 } 2588 }, 2589 2590 /** 2591 * Throws an exception with the given error message. 2592 * @param {String} msg Error message 2593 */ 2594 _error: function (msg) { 2595 var e = new Error('Error(' + this.line + '): ' + msg); 2596 e.line = this.line; 2597 throw e; 2598 }, 2599 2600 /** 2601 * Output a warning message using {@link JXG#debug} and precedes the message with "Warning: ". 2602 * @param {String} msg 2603 */ 2604 _warn: function (msg) { 2605 if (typeof console === 'object') { 2606 console.log('Warning(' + this.line + '): ' + msg); 2607 } else if (Env.isBrowser && document && document.getElementById(this.warnLog) !== null) { 2608 document.getElementById(this.warnLog).innerHTML += 'Warning(' + this.line + '): ' + msg + '<br />'; 2609 } 2610 }, 2611 2612 _log: function (msg) { 2613 if (typeof window !== 'object' && typeof self === 'object' && self.postMessage) { 2614 self.postMessage({type: 'log', msg: 'Log: ' + msg.toString()}); 2615 } else { 2616 console.log('Log: ', arguments); 2617 } 2618 } 2619 2620 }); 2621 2622 /* parser generated by jison 0.4.18 */ 2623 /* 2624 Returns a Parser object of the following structure: 2625 2626 Parser: { 2627 yy: {} 2628 } 2629 2630 Parser.prototype: { 2631 yy: {}, 2632 trace: function(), 2633 symbols_: {associative list: name ==> number}, 2634 terminals_: {associative list: number ==> name}, 2635 productions_: [...], 2636 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), 2637 table: [...], 2638 defaultActions: {...}, 2639 parseError: function(str, hash), 2640 parse: function(input), 2641 2642 lexer: { 2643 EOF: 1, 2644 parseError: function(str, hash), 2645 setInput: function(input), 2646 input: function(), 2647 unput: function(str), 2648 more: function(), 2649 less: function(n), 2650 pastInput: function(), 2651 upcomingInput: function(), 2652 showPosition: function(), 2653 test_match: function(regex_match_array, rule_index), 2654 next: function(), 2655 lex: function(), 2656 begin: function(condition), 2657 popState: function(), 2658 _currentRules: function(), 2659 topState: function(), 2660 pushState: function(condition), 2661 2662 options: { 2663 ranges: boolean (optional: true ==> token location info will include a .range[] member) 2664 flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) 2665 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) 2666 }, 2667 2668 performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), 2669 rules: [...], 2670 conditions: {associative list: name ==> set}, 2671 } 2672 } 2673 2674 2675 token location info (@$, _$, etc.): { 2676 first_line: n, 2677 last_line: n, 2678 first_column: n, 2679 last_column: n, 2680 range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) 2681 } 2682 2683 2684 the parseError function receives a 'hash' object with these members for lexer and parser errors: { 2685 text: (matched text) 2686 token: (the produced terminal token, if any) 2687 line: (yylineno) 2688 } 2689 while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { 2690 loc: (yylloc) 2691 expected: (string describing the set of expected tokens) 2692 recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) 2693 } 2694 */ 2695 var parser = (function(){ 2696 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]; 2697 var parser = {trace: function trace () { }, 2698 yy: {}, 2699 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}, 2700 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:"->"}, 2701 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]], 2702 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { 2703 /* this == yyval */ 2704 2705 var $0 = $$.length - 1; 2706 switch (yystate) { 2707 case 1: 2708 return $$[$0-1]; 2709 break; 2710 case 2: 2711 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_if', $$[$0-2], $$[$0]); 2712 break; 2713 case 3: 2714 this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_if_else', $$[$0-4], $$[$0-2], $$[$0]); 2715 break; 2716 case 4: 2717 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_while', $$[$0-2], $$[$0]); 2718 break; 2719 case 5: 2720 this.$ = AST.createNode(lc(_$[$0-8]), 'node_op', 'op_for', $$[$0-6], $$[$0-4], $$[$0-2], $$[$0]); 2721 break; 2722 case 6: 2723 this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_do', $$[$0-5], $$[$0-2]); 2724 break; 2725 case 7: 2726 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_use', $$[$0]); 2727 break; 2728 case 8: 2729 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_delete', $$[$0]); 2730 break; 2731 case 9: 2732 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_return', undefined); 2733 break; 2734 case 10: 2735 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_return', $$[$0-1]); 2736 break; 2737 case 11: case 14: 2738 this.$ = AST.createNode(lc(_$[$0]), 'node_op', 'op_none'); 2739 break; 2740 case 12: 2741 this.$ = $$[$0-1]; this.$.needsBrackets = true; 2742 break; 2743 case 13: 2744 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_none', $$[$0-1], $$[$0]); 2745 break; 2746 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: 2747 this.$ = $$[$0]; 2748 break; 2749 case 22: case 65: case 93: 2750 this.$ = $$[$0-1]; 2751 break; 2752 case 25: 2753 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_assign', $$[$0-2], $$[$0]); this.$.isMath = false; 2754 break; 2755 case 27: 2756 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_conditional', $$[$0-4], $$[$0-2], $$[$0]); this.$.isMath = false; 2757 break; 2758 case 29: 2759 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_or', $$[$0-2], $$[$0]); this.$.isMath = false; 2760 break; 2761 case 31: 2762 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_and', $$[$0-2], $$[$0]); this.$.isMath = false; 2763 break; 2764 case 33: 2765 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_eq', $$[$0-2], $$[$0]); this.$.isMath = false; 2766 break; 2767 case 34: 2768 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_neq', $$[$0-2], $$[$0]); this.$.isMath = false; 2769 break; 2770 case 35: 2771 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_approx', $$[$0-2], $$[$0]); this.$.isMath = false; 2772 break; 2773 case 37: 2774 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lt', $$[$0-2], $$[$0]); this.$.isMath = false; 2775 break; 2776 case 38: 2777 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gt', $$[$0-2], $$[$0]); this.$.isMath = false; 2778 break; 2779 case 39: 2780 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_leq', $$[$0-2], $$[$0]); this.$.isMath = false; 2781 break; 2782 case 40: 2783 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_geq', $$[$0-2], $$[$0]); this.$.isMath = false; 2784 break; 2785 case 42: 2786 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_add', $$[$0-2], $$[$0]); this.$.isMath = true; 2787 break; 2788 case 43: 2789 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_sub', $$[$0-2], $$[$0]); this.$.isMath = true; 2790 break; 2791 case 45: 2792 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mul', $$[$0-2], $$[$0]); this.$.isMath = true; 2793 break; 2794 case 46: 2795 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_div', $$[$0-2], $$[$0]); this.$.isMath = true; 2796 break; 2797 case 47: 2798 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mod', $$[$0-2], $$[$0]); this.$.isMath = true; 2799 break; 2800 case 49: 2801 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_exp', $$[$0-2], $$[$0]); this.$.isMath = true; 2802 break; 2803 case 51: 2804 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_not', $$[$0]); this.$.isMath = false; 2805 break; 2806 case 53: 2807 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_neg', $$[$0]); this.$.isMath = true; 2808 break; 2809 case 57: case 63: case 64: case 66: case 67: case 68: case 97: 2810 this.$ = $$[$0]; this.$.isMath = false; 2811 break; 2812 case 59: case 91: 2813 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_property', $$[$0-2], $$[$0]); this.$.isMath = true; 2814 break; 2815 case 60: case 90: 2816 this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_extvalue', $$[$0-3], $$[$0-1]); this.$.isMath = true; 2817 break; 2818 case 61: 2819 this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); 2820 break; 2821 case 69: 2822 this.$ = $$[$0]; this.$.isMath = true; 2823 break; 2824 case 70: 2825 this.$ = AST.createNode(lc(_$[$0]), 'node_const', null); 2826 break; 2827 case 71: 2828 this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', true); 2829 break; 2830 case 72: 2831 this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', false); 2832 break; 2833 case 73: 2834 this.$ = AST.createNode(lc(_$[$0]), 'node_str', $$[$0].substring(1, $$[$0].length - 1)); 2835 break; 2836 case 74: 2837 this.$ = AST.createNode(lc(_$[$0]), 'node_const', parseFloat($$[$0])); 2838 break; 2839 case 75: 2840 this.$ = AST.createNode(lc(_$[$0]), 'node_const', NaN); 2841 break; 2842 case 76: 2843 this.$ = AST.createNode(lc(_$[$0]), 'node_const', Infinity); 2844 break; 2845 case 77: 2846 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_array', []); 2847 break; 2848 case 78: 2849 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_array', $$[$0-1]); 2850 break; 2851 case 79: 2852 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {}); this.$.needsBrackets = true; 2853 break; 2854 case 80: 2855 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]); this.$.needsBrackets = true; 2856 break; 2857 case 82: 2858 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst', $$[$0-2], $$[$0]); 2859 break; 2860 case 83: 2861 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_prop', $$[$0-2], $$[$0]); 2862 break; 2863 case 87: case 89: 2864 this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_execfun', $$[$0-1], $$[$0]); this.$.isMath = true; 2865 break; 2866 case 88: 2867 this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_execfun', $$[$0-2], $$[$0-1], $$[$0], true); this.$.isMath = false; 2868 break; 2869 case 92: 2870 this.$ = []; 2871 break; 2872 case 94: case 98: case 104: 2873 this.$ = [$$[$0]]; 2874 break; 2875 case 95: case 99: case 105: 2876 this.$ = $$[$0-2].concat($$[$0]); 2877 break; 2878 case 96: 2879 this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); this.$.isMath = true; 2880 break; 2881 case 100: 2882 this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_function', [], $$[$0]); this.$.isMath = false; 2883 break; 2884 case 101: 2885 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_function', $$[$0-2], $$[$0]); this.$.isMath = false; 2886 break; 2887 case 102: 2888 this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_map', [], $$[$0]); 2889 break; 2890 case 103: 2891 this.$ = AST.createNode(lc(_$[$0-5]), 'node_op', 'op_map', $$[$0-3], $$[$0]); 2892 break; 2893 } 2894 }, 2895 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])], 2896 defaultActions: {3:[2,1],97:[2,84],98:[2,85],99:[2,86]}, 2897 parseError: function parseError (str, hash) { 2898 if (hash.recoverable) { 2899 this.trace(str); 2900 } else { 2901 var error = new Error(str); 2902 error.hash = hash; 2903 throw error; 2904 } 2905 }, 2906 parse: function parse(input) { 2907 var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; 2908 var args = lstack.slice.call(arguments, 1); 2909 var lexer = Object.create(this.lexer); 2910 var sharedState = { yy: {} }; 2911 for (var k in this.yy) { 2912 if (Object.prototype.hasOwnProperty.call(this.yy, k)) { 2913 sharedState.yy[k] = this.yy[k]; 2914 } 2915 } 2916 lexer.setInput(input, sharedState.yy); 2917 sharedState.yy.lexer = lexer; 2918 sharedState.yy.parser = this; 2919 if (typeof lexer.yylloc == 'undefined') { 2920 lexer.yylloc = {}; 2921 } 2922 var yyloc = lexer.yylloc; 2923 lstack.push(yyloc); 2924 var ranges = lexer.options && lexer.options.ranges; 2925 if (typeof sharedState.yy.parseError === 'function') { 2926 this.parseError = sharedState.yy.parseError; 2927 } else { 2928 this.parseError = Object.getPrototypeOf(this).parseError; 2929 } 2930 function popStack(n) { 2931 stack.length = stack.length - 2 * n; 2932 vstack.length = vstack.length - n; 2933 lstack.length = lstack.length - n; 2934 } 2935 _token_stack: 2936 var lex = function () { 2937 var token; 2938 token = lexer.lex() || EOF; 2939 if (typeof token !== 'number') { 2940 token = self.symbols_[token] || token; 2941 } 2942 return token; 2943 }; 2944 var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; 2945 while (true) { 2946 state = stack[stack.length - 1]; 2947 if (this.defaultActions[state]) { 2948 action = this.defaultActions[state]; 2949 } else { 2950 if (symbol === null || typeof symbol == 'undefined') { 2951 symbol = lex(); 2952 } 2953 action = table[state] && table[state][symbol]; 2954 } 2955 if (typeof action === 'undefined' || !action.length || !action[0]) { 2956 var errStr = ''; 2957 expected = []; 2958 for (p in table[state]) { 2959 if (this.terminals_[p] && p > TERROR) { 2960 expected.push('\'' + this.terminals_[p] + '\''); 2961 } 2962 } 2963 if (lexer.showPosition) { 2964 errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; 2965 } else { 2966 errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); 2967 } 2968 this.parseError(errStr, { 2969 text: lexer.match, 2970 token: this.terminals_[symbol] || symbol, 2971 line: lexer.yylineno, 2972 loc: yyloc, 2973 expected: expected 2974 }); 2975 } 2976 if (action[0] instanceof Array && action.length > 1) { 2977 throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); 2978 } 2979 switch (action[0]) { 2980 case 1: 2981 stack.push(symbol); 2982 vstack.push(lexer.yytext); 2983 lstack.push(lexer.yylloc); 2984 stack.push(action[1]); 2985 symbol = null; 2986 if (!preErrorSymbol) { 2987 yyleng = lexer.yyleng; 2988 yytext = lexer.yytext; 2989 yylineno = lexer.yylineno; 2990 yyloc = lexer.yylloc; 2991 if (recovering > 0) { 2992 recovering--; 2993 } 2994 } else { 2995 symbol = preErrorSymbol; 2996 preErrorSymbol = null; 2997 } 2998 break; 2999 case 2: 3000 len = this.productions_[action[1]][1]; 3001 yyval.$ = vstack[vstack.length - len]; 3002 yyval._$ = { 3003 first_line: lstack[lstack.length - (len || 1)].first_line, 3004 last_line: lstack[lstack.length - 1].last_line, 3005 first_column: lstack[lstack.length - (len || 1)].first_column, 3006 last_column: lstack[lstack.length - 1].last_column 3007 }; 3008 if (ranges) { 3009 yyval._$.range = [ 3010 lstack[lstack.length - (len || 1)].range[0], 3011 lstack[lstack.length - 1].range[1] 3012 ]; 3013 } 3014 r = this.performAction.apply(yyval, [ 3015 yytext, 3016 yyleng, 3017 yylineno, 3018 sharedState.yy, 3019 action[1], 3020 vstack, 3021 lstack 3022 ].concat(args)); 3023 if (typeof r !== 'undefined') { 3024 return r; 3025 } 3026 if (len) { 3027 stack = stack.slice(0, -1 * len * 2); 3028 vstack = vstack.slice(0, -1 * len); 3029 lstack = lstack.slice(0, -1 * len); 3030 } 3031 stack.push(this.productions_[action[1]][0]); 3032 vstack.push(yyval.$); 3033 lstack.push(yyval._$); 3034 newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; 3035 stack.push(newState); 3036 break; 3037 case 3: 3038 return true; 3039 } 3040 } 3041 return true; 3042 }}; 3043 3044 3045 var AST = { 3046 node: function (type, value, children) { 3047 return { 3048 type: type, 3049 value: value, 3050 children: children 3051 }; 3052 }, 3053 3054 createNode: function (pos, type, value, children) { 3055 var i, 3056 n = this.node(type, value, []); 3057 3058 for (i = 3; i < arguments.length; i++) { 3059 n.children.push(arguments[i]); 3060 } 3061 3062 n.line = pos[0]; 3063 n.col = pos[1]; 3064 n.eline = pos[2]; 3065 n.ecol = pos[3]; 3066 3067 return n; 3068 } 3069 }; 3070 3071 var lc = function (lc1) { 3072 return [lc1.first_line, lc1.first_column, lc1.last_line, lc1.last_column]; 3073 }; 3074 3075 /* generated by jison-lex 0.3.4 */ 3076 var lexer = (function(){ 3077 var lexer = ({ 3078 3079 EOF:1, 3080 3081 parseError:function parseError(str, hash) { 3082 if (this.yy.parser) { 3083 this.yy.parser.parseError(str, hash); 3084 } else { 3085 throw new Error(str); 3086 } 3087 }, 3088 3089 // resets the lexer, sets new input 3090 setInput:function (input, yy) { 3091 this.yy = yy || this.yy || {}; 3092 this._input = input; 3093 this._more = this._backtrack = this.done = false; 3094 this.yylineno = this.yyleng = 0; 3095 this.yytext = this.matched = this.match = ''; 3096 this.conditionStack = ['INITIAL']; 3097 this.yylloc = { 3098 first_line: 1, 3099 first_column: 0, 3100 last_line: 1, 3101 last_column: 0 3102 }; 3103 if (this.options.ranges) { 3104 this.yylloc.range = [0,0]; 3105 } 3106 this.offset = 0; 3107 return this; 3108 }, 3109 3110 // consumes and returns one char from the input 3111 input:function () { 3112 var ch = this._input[0]; 3113 this.yytext += ch; 3114 this.yyleng++; 3115 this.offset++; 3116 this.match += ch; 3117 this.matched += ch; 3118 var lines = ch.match(/(?:\r\n?|\n).*/g); 3119 if (lines) { 3120 this.yylineno++; 3121 this.yylloc.last_line++; 3122 } else { 3123 this.yylloc.last_column++; 3124 } 3125 if (this.options.ranges) { 3126 this.yylloc.range[1]++; 3127 } 3128 3129 this._input = this._input.slice(1); 3130 return ch; 3131 }, 3132 3133 // unshifts one char (or a string) into the input 3134 unput:function (ch) { 3135 var len = ch.length; 3136 var lines = ch.split(/(?:\r\n?|\n)/g); 3137 3138 this._input = ch + this._input; 3139 this.yytext = this.yytext.substr(0, this.yytext.length - len); 3140 //this.yyleng -= len; 3141 this.offset -= len; 3142 var oldLines = this.match.split(/(?:\r\n?|\n)/g); 3143 this.match = this.match.substr(0, this.match.length - 1); 3144 this.matched = this.matched.substr(0, this.matched.length - 1); 3145 3146 if (lines.length - 1) { 3147 this.yylineno -= lines.length - 1; 3148 } 3149 var r = this.yylloc.range; 3150 3151 this.yylloc = { 3152 first_line: this.yylloc.first_line, 3153 last_line: this.yylineno + 1, 3154 first_column: this.yylloc.first_column, 3155 last_column: lines ? 3156 (lines.length === oldLines.length ? this.yylloc.first_column : 0) 3157 + oldLines[oldLines.length - lines.length].length - lines[0].length : 3158 this.yylloc.first_column - len 3159 }; 3160 3161 if (this.options.ranges) { 3162 this.yylloc.range = [r[0], r[0] + this.yyleng - len]; 3163 } 3164 this.yyleng = this.yytext.length; 3165 return this; 3166 }, 3167 3168 // When called from action, caches matched text and appends it on next action 3169 more:function () { 3170 this._more = true; 3171 return this; 3172 }, 3173 3174 // 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. 3175 reject:function () { 3176 if (this.options.backtrack_lexer) { 3177 this._backtrack = true; 3178 } else { 3179 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(), { 3180 text: "", 3181 token: null, 3182 line: this.yylineno 3183 }); 3184 3185 } 3186 return this; 3187 }, 3188 3189 // retain first n characters of the match 3190 less:function (n) { 3191 this.unput(this.match.slice(n)); 3192 }, 3193 3194 // displays already matched input, i.e. for error messages 3195 pastInput:function () { 3196 var past = this.matched.substr(0, this.matched.length - this.match.length); 3197 return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); 3198 }, 3199 3200 // displays upcoming input, i.e. for error messages 3201 upcomingInput:function () { 3202 var next = this.match; 3203 if (next.length < 20) { 3204 next += this._input.substr(0, 20-next.length); 3205 } 3206 return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); 3207 }, 3208 3209 // displays the character position where the lexing error occurred, i.e. for error messages 3210 showPosition:function () { 3211 var pre = this.pastInput(); 3212 var c = new Array(pre.length + 1).join("-"); 3213 return pre + this.upcomingInput() + "\n" + c + "^"; 3214 }, 3215 3216 // test the lexed token: return FALSE when not a match, otherwise return token 3217 test_match:function(match, indexed_rule) { 3218 var token, 3219 lines, 3220 backup; 3221 3222 if (this.options.backtrack_lexer) { 3223 // save context 3224 backup = { 3225 yylineno: this.yylineno, 3226 yylloc: { 3227 first_line: this.yylloc.first_line, 3228 last_line: this.last_line, 3229 first_column: this.yylloc.first_column, 3230 last_column: this.yylloc.last_column 3231 }, 3232 yytext: this.yytext, 3233 match: this.match, 3234 matches: this.matches, 3235 matched: this.matched, 3236 yyleng: this.yyleng, 3237 offset: this.offset, 3238 _more: this._more, 3239 _input: this._input, 3240 yy: this.yy, 3241 conditionStack: this.conditionStack.slice(0), 3242 done: this.done 3243 }; 3244 if (this.options.ranges) { 3245 backup.yylloc.range = this.yylloc.range.slice(0); 3246 } 3247 } 3248 3249 lines = match[0].match(/(?:\r\n?|\n).*/g); 3250 if (lines) { 3251 this.yylineno += lines.length; 3252 } 3253 this.yylloc = { 3254 first_line: this.yylloc.last_line, 3255 last_line: this.yylineno + 1, 3256 first_column: this.yylloc.last_column, 3257 last_column: lines ? 3258 lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : 3259 this.yylloc.last_column + match[0].length 3260 }; 3261 this.yytext += match[0]; 3262 this.match += match[0]; 3263 this.matches = match; 3264 this.yyleng = this.yytext.length; 3265 if (this.options.ranges) { 3266 this.yylloc.range = [this.offset, this.offset += this.yyleng]; 3267 } 3268 this._more = false; 3269 this._backtrack = false; 3270 this._input = this._input.slice(match[0].length); 3271 this.matched += match[0]; 3272 token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); 3273 if (this.done && this._input) { 3274 this.done = false; 3275 } 3276 if (token) { 3277 return token; 3278 } else if (this._backtrack) { 3279 // recover context 3280 for (var k in backup) { 3281 this[k] = backup[k]; 3282 } 3283 return false; // rule action called reject() implying the next rule should be tested instead. 3284 } 3285 return false; 3286 }, 3287 3288 // return next match in input 3289 next:function () { 3290 if (this.done) { 3291 return this.EOF; 3292 } 3293 if (!this._input) { 3294 this.done = true; 3295 } 3296 3297 var token, 3298 match, 3299 tempMatch, 3300 index; 3301 if (!this._more) { 3302 this.yytext = ''; 3303 this.match = ''; 3304 } 3305 var rules = this._currentRules(); 3306 for (var i = 0; i < rules.length; i++) { 3307 tempMatch = this._input.match(this.rules[rules[i]]); 3308 if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { 3309 match = tempMatch; 3310 index = i; 3311 if (this.options.backtrack_lexer) { 3312 token = this.test_match(tempMatch, rules[i]); 3313 if (token !== false) { 3314 return token; 3315 } else if (this._backtrack) { 3316 match = false; 3317 continue; // rule action called reject() implying a rule MISmatch. 3318 } else { 3319 // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) 3320 return false; 3321 } 3322 } else if (!this.options.flex) { 3323 break; 3324 } 3325 } 3326 } 3327 if (match) { 3328 token = this.test_match(match, rules[index]); 3329 if (token !== false) { 3330 return token; 3331 } 3332 // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) 3333 return false; 3334 } 3335 if (this._input === "") { 3336 return this.EOF; 3337 } else { 3338 return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { 3339 text: "", 3340 token: null, 3341 line: this.yylineno 3342 }); 3343 } 3344 }, 3345 3346 // return next match that has a token 3347 lex:function lex () { 3348 var r = this.next(); 3349 if (r) { 3350 return r; 3351 } else { 3352 return this.lex(); 3353 } 3354 }, 3355 3356 // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) 3357 begin:function begin (condition) { 3358 this.conditionStack.push(condition); 3359 }, 3360 3361 // pop the previously active lexer condition state off the condition stack 3362 popState:function popState () { 3363 var n = this.conditionStack.length - 1; 3364 if (n > 0) { 3365 return this.conditionStack.pop(); 3366 } else { 3367 return this.conditionStack[0]; 3368 } 3369 }, 3370 3371 // produce the lexer rule set which is active for the currently active lexer condition state 3372 _currentRules:function _currentRules () { 3373 if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { 3374 return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; 3375 } else { 3376 return this.conditions["INITIAL"].rules; 3377 } 3378 }, 3379 3380 // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available 3381 topState:function topState (n) { 3382 n = this.conditionStack.length - 1 - Math.abs(n || 0); 3383 if (n >= 0) { 3384 return this.conditionStack[n]; 3385 } else { 3386 return "INITIAL"; 3387 } 3388 }, 3389 3390 // alias for begin(condition) 3391 pushState:function pushState (condition) { 3392 this.begin(condition); 3393 }, 3394 3395 // return the number of states currently on the stack 3396 stateStackSize:function stateStackSize() { 3397 return this.conditionStack.length; 3398 }, 3399 options: {}, 3400 performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { 3401 var YYSTATE=YY_START; 3402 switch($avoiding_name_collisions) { 3403 case 0:/* ignore */ 3404 break; 3405 case 1:return 78 3406 break; 3407 case 2:return 78 3408 break; 3409 case 3: return 77; 3410 break; 3411 case 4: return 77; 3412 break; 3413 case 5:/* ignore comment */ 3414 break; 3415 case 6:/* ignore multiline comment */ 3416 break; 3417 case 7:return 7 3418 break; 3419 case 8:return 12 3420 break; 3421 case 9:return 14 3422 break; 3423 case 10:return 17 3424 break; 3425 case 11:return 15 3426 break; 3427 case 12:return 91 3428 break; 3429 case 13:return 93 3430 break; 3431 case 14:return 19 3432 break; 3433 case 15:return 23 3434 break; 3435 case 16:return 21 3436 break; 3437 case 17:return 75 3438 break; 3439 case 18:return 76 3440 break; 3441 case 19:return 74 3442 break; 3443 case 20:return 80 3444 break; 3445 case 21:return 94 3446 break; 3447 case 22:return 94 3448 break; 3449 case 23:return 82 3450 break; 3451 case 24:return 83 3452 break; 3453 case 25:return 26 3454 break; 3455 case 26:return 27 3456 break; 3457 case 27:return 16 3458 break; 3459 case 28:return '#' 3460 break; 3461 case 29:return 34 3462 break; 3463 case 30:return 35 3464 break; 3465 case 31:return 79 3466 break; 3467 case 32:return 64 3468 break; 3469 case 33:return 65 3470 break; 3471 case 34:return 66 3472 break; 3473 case 35:return 8 3474 break; 3475 case 36:return 10 3476 break; 3477 case 37:return 58 3478 break; 3479 case 38:return 57 3480 break; 3481 case 39:return 53 3482 break; 3483 case 40:return 54 3484 break; 3485 case 41:return 55 3486 break; 3487 case 42:return 50 3488 break; 3489 case 43:return 51 3490 break; 3491 case 44:return 47 3492 break; 3493 case 45:return 45 3494 break; 3495 case 46:return 48 3496 break; 3497 case 47:return 46 3498 break; 3499 case 48:return 41 3500 break; 3501 case 49:return 43 3502 break; 3503 case 50:return 42 3504 break; 3505 case 51:return 39 3506 break; 3507 case 52:return 37 3508 break; 3509 case 53:return 32 3510 break; 3511 case 54:return 86 3512 break; 3513 case 55:return 5 3514 break; 3515 case 56:return 20 3516 break; 3517 case 57:return 'INVALID' 3518 break; 3519 } 3520 }, 3521 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_]*)/,/^(?:.)/], 3522 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}} 3523 }); 3524 return lexer; 3525 })(); 3526 parser.lexer = lexer; 3527 function Parser () { 3528 this.yy = {}; 3529 } 3530 Parser.prototype = parser;parser.Parser = Parser; 3531 return new Parser; 3532 })(); 3533 3534 3535 if (typeof require !== 'undefined' && typeof exports !== 'undefined') { 3536 exports.parser = parser; 3537 exports.Parser = parser.Parser; 3538 exports.parse = function () { return parser.parse.apply(parser, arguments); }; 3539 exports.main = function commonjsMain (args) { 3540 if (!args[1]) { 3541 console.log('Usage: '+args[0]+' FILE'); 3542 process.exit(1); 3543 } 3544 var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); 3545 return exports.parser.parse(source); 3546 }; 3547 if (typeof module !== 'undefined' && require.main === module) { 3548 exports.main(process.argv.slice(1)); 3549 } 3550 } 3551 // Work around an issue with browsers that don't support Object.getPrototypeOf() 3552 parser.yy.parseError = parser.parseError; 3553 3554 return JXG.JessieCode; 3555 }); 3556