1 /* 2 * Copyright (C) 2012-2013 DFKI GmbH 3 * Deutsches Forschungszentrum fuer Kuenstliche Intelligenz 4 * German Research Center for Artificial Intelligence 5 * http://www.dfki.de 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28 /** 29 * A Utility class for parsing (eHTML) templates.<br> 30 * 31 * @class ParserUtils 32 * 33 * @see mmir.parser.ParserUtils#constructor 34 * 35 * @example mmir.ParserUtils.parse(str, view) 36 */ 37 //mmir.parser.ParserUtils = (function(){}); 38 39 40 //(function ( mmir ) { 41 42 define([ 'parserModule', 'parsingResult', 'templateProcessor' 43 , 'templateLexer', 'ES3Lexer', 'ES3Parser', 'contentLexer', 'contentParser' 44 , 'scriptLexer', 'scriptParser', 'antlr3' 45 ], 46 47 /** 48 * Utility functions for parsing templates (and template elements, e.g. JS-parts of template expressions) 49 * 50 * @class 51 * @name ParserUtils 52 * @memberOf mmir.parser 53 * @static 54 * 55 * @public 56 */ 57 function( parser, ParsingResult, templateProcessor 58 , MmirTemplateLexer, ES3Lexer, ES3Parser, MmirScriptContentLexer, MmirScriptContentParser 59 , MmirScriptLexer, MmirScriptParser, org 60 ){ 61 62 ////////////////////////////////////helper for debugging / printing error details //////////////////////// 63 64 /** 65 * -2: internal debug 66 * -1: interanl info 67 * 0: debug 68 * 1: info 69 * 2: warn 70 * 3: error 71 * TODO make this set-able (export getter/setter? use configurationManager?) 72 * 73 * @private 74 * @memberOf ParserUtils# 75 */ 76 var errorLevel = 2; 77 78 79 /** 80 * HELPER print internal debug messages during parsing (VERY VERBOSE) 81 * 82 * @private 83 * @memberOf ParserUtils# 84 */ 85 function _print(msg){//FIXME 86 if ( errorLevel <= -2 ) console.log(msg); 87 }; 88 parser.print = _print; 89 90 /** 91 * HELPER print internal, informational messages during parsing (VERBOSE) 92 * 93 * @private 94 * @memberOf ParserUtils# 95 */ 96 function _printInfo(prefix, msg){//FIXME 97 if ( errorLevel <= -1 ) console.info(parser.parserCreatePrintMessage(prefix,msg)); 98 }; 99 parser.printInfo = _printInfo; 100 101 /** 102 * HELPER print debug messages during parsing 103 * 104 * @private 105 * @memberOf ParserUtils# 106 */ 107 function _parserPrintDebug(prefix, msg, source){//FIXME 108 if ( errorLevel <= 0 ) console.debug(parser.parserCreatePrintMessage(prefix,msg, source)); 109 }; 110 parser.parserPrintDebug = _parserPrintDebug; 111 112 /** 113 * HELPER print informational messages during parsing 114 * 115 * @private 116 * @memberOf ParserUtils# 117 */ 118 function _parserPrintInfo(prefix, msg, source){//FIXME 119 if ( errorLevel <= 1 ) console.info(parser.parserCreatePrintMessage(prefix,msg, source)); 120 }; 121 parser.parserPrintInfo = _parserPrintInfo; 122 123 /** 124 * HELPER print warnings during parsing 125 * 126 * @private 127 * @memberOf ParserUtils# 128 */ 129 function _parserPrintWarning(prefix, msg, source){//FIXME 130 if ( errorLevel <= 2 ) console.warn(parser.parserCreatePrintMessage(prefix,msg, source)); 131 }; 132 parser.parserPrintWarning = _parserPrintWarning; 133 134 /** 135 * HELPER print errors during parsing 136 * 137 * @private 138 * @memberOf ParserUtils# 139 */ 140 function _parserPrintError(prefix, msg, source){ 141 if ( errorLevel <= 3 ) console.error(parser.parserCreatePrintMessage(prefix,msg, source)); 142 }; 143 parser.parserPrintError = _parserPrintError; 144 145 /** 146 * HELPER: attach internal print-functions to all classes (ie. prototypes) in the list 147 * 148 * @private 149 * @memberOf ParserUtils# 150 */ 151 var _attachInternalPrintFunc = function(list){ 152 var _prototype; 153 for(var i=0, size=list.length; i < size; ++i){ 154 _prototype = list[i].prototype; 155 _prototype.printInfo = parser.printInfo; 156 _prototype.printDebug = parser.print; 157 } 158 }; 159 160 //attach the internal debug/print functions to all lexers/parsers: 161 // (-> see import-list in define() above) 162 _attachInternalPrintFunc([ 163 MmirTemplateLexer, ES3Lexer, ES3Parser, MmirScriptContentLexer, MmirScriptContentParser 164 , MmirScriptLexer, MmirScriptParser 165 ]); 166 167 /** 168 * @type View 169 * @private 170 * @memberOf ParserUtils# 171 */ 172 var _currentParsedView = null;//FIXME make this an argument in the printXXX functions (e.g. the current mechanism will not work, if templates are parsed concurrently/in parallel/using threads) 173 174 /** 175 * Creates a message with parsing-information. 176 * 177 * In case the <code>msg</code> is an error message containing relative/incorrect location information, 178 * an heuristic will be used to fix the location information; in addition the references location 179 * will be extracted from the source-String and a "pointer-String" will be generated, e.g. 180 * <pre> 181 * source: " @{ mmmm.['sd']=wer ;}@" 182 * pointer: " ^" 183 * </pre> 184 * 185 * @function 186 * @param {String} prefix 187 * a prefix for the message 188 * @param {String} msg 189 * the original message (may contain location-information "line <line_i>:<position_j>") 190 * @param {Object} [tokenSource] OPTIONAL 191 * the token-source, from where the error/message was triggered 192 * If the argument has the field <code>tokenSource.offset</code> (Number) 193 * if will be used to correct/fix the location information in the original message. 194 * If the argument has the fields <code>tokenSource.start</code> (Number) and 195 * <code>tokenSource.end</code> (Number), then this will be used to correct/fix 196 * the location information in the original message text. 197 * @param {Object} [viewObj] OPTIONAL 198 * currently not used! 199 * (will replace _currentParsedView in the future!) 200 * 201 * @private 202 * @memberOf ParserUtils# 203 */ 204 var parserCreatePrintMessage = (function(){//return function(prefix, msg, tokenSource, viewObj) 205 206 /** 207 * 208 * Get the index in the String str, where line number lineNo 209 * starts. 210 * 211 * New lines begin after \n, \r\n, or \r. 212 * 213 * If lineNo is <= 1, the function returns always 0. 214 * 215 * If the lineNo is greater than the count of lines in str, the string length itself is returned. 216 * 217 * <p> 218 * NOTE used by {@link #parserCreatePrintMessage} 219 * 220 * @function 221 * @param {String} str the string 222 * @param {Number} lineNo the line number (first line is 1) 223 * 224 * @private 225 * @memberOf ParserUtils.parserCreatePrintMessage 226 */ 227 var getIndexForLine = (function(){ 228 229 var detectLinebreak = /(\r?\n|\r)/igm; 230 231 return function(str, lineNo){ 232 if(lineNo <= 1){ 233 return 0; 234 } 235 var match; 236 var count = 1; 237 while(match = detectLinebreak.exec(str)){ 238 //ASSERT: lineNo >= 2 239 if(++count == lineNo){ 240 break; 241 } 242 } 243 244 //reset regexpr: 245 detectLinebreak.lastIndex = 0; 246 247 if(match){ 248 return match.index + match[1].length; 249 } 250 251 //request line-no. >= 2 AND loop "detect enough" linebreaks => the request line index starts after strings ends => return string's length 252 return str.length; 253 }; 254 })();//END getIndexForLine 255 256 /** 257 * 258 * Get the line in the String str, in which the char at index is included. 259 * 260 * New lines begin after \n, \r\n, or \r, 261 * e.g. for line X: 262 * <pre> 263 * ...\r\n 264 * ^ 265 * </pre> 266 * the line number will be X (i.e. the line-break itself is still included in the current line). 267 * <p> 268 * If index is < 0, the function returns always 1. 269 * <p> 270 * If the index is greater than str.length, -1 is returned. 271 * <p> 272 * NOTE used by {@link #extractErrorPosition} 273 * 274 * @function 275 * @param {String} str the string 276 * @param {Number} index the char index for which to find the line number (first line is 1) 277 * 278 * @private 279 * 280 * @memberOf ParserUtils.parserCreatePrintMessage 281 * 282 */ 283 var getLineForIndex = (function(){ 284 285 var detectLinebreak = /(\r?\n|\r)/ig; 286 287 return function(str, index){ 288 if(index < 0){ 289 return 1; 290 } 291 if(index >= str.length){ 292 return -1; 293 } 294 //ASSERT index is at least within line 1 295 var match; 296 var count = 1; 297 var isNextLineFound = false; 298 var currentPos = -1; 299 var lastPos = 0; 300 while(match = detectLinebreak.exec(str)){ 301 currentPos = match.index + match[1].length; 302 if(currentPos > index){ 303 isNextLineFound = true; 304 break; 305 } 306 lastPos = currentPos; 307 ++count; 308 } 309 310 //reset regexpr: 311 detectLinebreak.lastIndex = 0; 312 313 return { 314 line : count, 315 index: index - lastPos 316 }; 317 }; 318 })();//END getLineForIndex 319 320 /** 321 * 322 * NOTE used by {@link #parserCreatePrintMessage} 323 * 324 * @private 325 * @function 326 * @memberOf ParserUtils.parserCreatePrintMessage 327 */ 328 var extractErrorPosition = (function(){ 329 330 var detectLineNo = /line (\d+):(-?\d+)/i; 331 332 return function extractErrorPositionImpl(msg, offset, originalContent, tokenSource){ 333 // console.log('\nTEST1_extractErrorPositionImpl with arguments '+arguments.length+'\n'); 334 335 var result = detectLineNo.exec(msg); 336 337 //reset regexpr: 338 detectLineNo.lastIndex = 0; 339 340 // console.log('\nTEST2_result for "'+msg+'": '+result+'\n'); 341 var pos = null; 342 if(result){ 343 344 var line = parseInt(result[1],10); 345 var index = parseInt(result[2],10); 346 347 var isCorrected = false; 348 349 if(tokenSource){ 350 351 //if we have "invalid" position-info.: 352 // -> the error probably occured at the very beginning of the parsed expression 353 // -> try to extract position from parent parser/lexer 354 if(line === 0 || index === -1){ 355 line = tokenSource.getLine(); 356 index = tokenSource.getCharPositionInLine(); 357 } 358 359 //if there is an offest supplied by the tokenSource -> use it: 360 if(tokenSource.offset){ 361 362 var iOffset = tokenSource.offset; 363 // if(line === 1){ 364 // // 365 // //this position information is derived from a script-eval (-> ConentElement.ScriptEvalError) 366 // // -> need to increase offset by 1 or 2, since all script-elements have 367 // // an additional, internal offset of 1 or 2 (this is only an heuristical value...) 368 // // e.g. @( ... 369 // // @{ ... 370 // // @for( ... 371 // iOffset += 2; 372 // } 373 374 var contentOffset = getLineForIndex(originalContent, iOffset); 375 376 //if it is "relatively" the first line, we need to adjust to index 377 // (i.e. the position within the line) 378 if(line === 1){ 379 index += contentOffset.index; 380 } 381 382 //adjust the line, i.e. make "relative" -> "absolute" line number 383 line += contentOffset.line - 1; 384 385 isCorrected = true; 386 } 387 388 } 389 390 pos = { 391 line: line, 392 index: index 393 }; 394 // console.log('\nTEST3_pos: '+JSON.stringify(pos)+', offset: '+offset+'\n'); 395 396 if(offset && offset !== 0){ 397 // console.log('\nTEST4_offset: '+offset+'\n'); 398 399 var newLine = line; 400 var newIndex = index; 401 if( ! isCorrected){ 402 var lineOffset = getLineForIndex(originalContent, offset); 403 if(line < 2){ 404 newIndex = lineOffset.index + index; 405 pos.originalIndex = index; 406 pos.index = newIndex; 407 } 408 newLine = lineOffset.line + line - 1; 409 pos.originalLine = line; 410 pos.line = newLine; 411 } 412 413 var fixed = msg.substring(0,result.index + 'line '.length) + newLine + ':' + newIndex + msg.substring(result.index + result[0].length); 414 pos.text = fixed; 415 // pos.originalContent = originalContent; 416 // pos.offset = offset + pos.index; 417 } 418 else { 419 pos.text = msg; 420 } 421 } 422 else if(tokenSource && tokenSource.start && tokenSource.end){ 423 424 pos = getLineForIndex(originalContent, tokenSource.start); 425 pos.text = ' near /'; 426 } 427 428 return pos; 429 }; 430 })();//END extractErrorPosition 431 432 /** 433 * Create a message for parsing-information. 434 * 435 * In case the <code>msg</code> is an error message containing relative/incorrect location information, 436 * an heuristic will be used to fix the location information; in addition the references location 437 * will be extracted from the source-String and a "pointer-String" will be generated, e.g. 438 * <pre> 439 * source: " @{ mmmm.['sd']=wer ;}@" 440 * pointer: " ^" 441 * </pre> 442 * 443 * @private 444 * 445 * @param {String} prefix 446 * a prefix for the message 447 * @param {String} msg 448 * the original message (may contain location-information "line <line_i>:<position_j>") 449 * @param {Object} [tokenSource] OPTIONAL 450 * the token-source, from where the error/message was triggered 451 * If the argument has the field <code>tokenSource.offset</code> (Number) 452 * if will be used to correct/fix the location information in the original message. 453 * If the argument has the fields <code>tokenSource.start</code> (Number) and 454 * <code>tokenSource.end</code> (Number), then this will be used to correct/fix 455 * the location information in the original message text. 456 * @param {Object} [viewObj] OPTIONAL 457 * currently not used! 458 * (will replace _currentParsedView in the future!) 459 */ 460 return function parserCreatePrintMessageImpl(prefix, msg, tokenSource, viewObj){//FIXME 461 var currentView = _currentParsedView; 462 if(currentView != null){ 463 464 var rootView = null; 465 var details = ''; 466 if(currentView.getController){ 467 details += 'CTRL("' + currentView.getController().getName() + '")'; 468 } 469 470 if(currentView.getView){ 471 if(details.length > 0){ 472 details += '->'; 473 } 474 details += 'VIEW("' + currentView.getView().getName() + '")'; 475 rootView = currentView.getView(); 476 } 477 478 if(details.length > 0){ 479 details += '->'; 480 } 481 details += currentView.constructor.name; 482 483 if(currentView.getName){ 484 details += '("' + currentView.getName() + '")'; 485 } 486 487 if(rootView && typeof currentView.getStart !== 'undefined'){ 488 489 var pos = extractErrorPosition(msg, currentView.getOffset(), rootView.getDefinition(), tokenSource); 490 // console.log('\nTEST_A_pos: '+JSON.stringify(pos)+', offset: '+currentView.getStart() +'\n'); 491 if(pos){ 492 493 msg = pos.text; 494 495 //msg += '\n\t at line '+pos.line+', index '+pos.index; 496 var content = rootView.getDefinition(); 497 var line = null; 498 var offset = currentView.getStart(); 499 500 501 if(content){ 502 var start = getIndexForLine(content, pos.line); 503 var end = start; 504 var len = content.length; 505 while(end < len && (content[end] != '\r' && content[end] != '\n')){ 506 ++end; 507 } 508 509 line = content.substring(start,end); 510 } 511 512 if(line){ 513 514 //marker for "pointing" the error 515 var marker = []; 516 for(var i=0; i < pos.index; ++i){ 517 if(line[i] == '\t'){ 518 //need to include tabs themselves, since they 519 // take more than 1 char-positions when displayed: 520 marker.push('\t'); 521 } 522 else { 523 marker.push(' '); 524 } 525 } 526 //add marker symbol, that points to error in the line above: 527 marker.push('^'); 528 529 msg += ' at line '+pos.line+':'; 530 msg += '\n "'+line+'"'; //<- the line with the error 531 msg += '\n '+marker.join(''); //<- the marker line (will only be correctly aligned for fixed-width fonts) 532 } 533 } 534 } 535 536 return prefix + 'in ' + details + ' - ' + msg; 537 } 538 else { 539 return prefix+msg; 540 } 541 };//END parserCreatePrintMessage 542 543 })();//END var parserCreatePrintMessage = ... 544 545 parser.parserCreatePrintMessage = parserCreatePrintMessage; 546 547 //////////////////////////////////// END: helper for debugging, error details etc. //////////////////////// 548 549 /** 550 * Object containing the instance of the class ParserUtils 551 * 552 * @type ParserUtils 553 * @private 554 * 555 * @memberOf ParserUtils# 556 */ 557 var instance = null; 558 559 /** 560 * @private 561 * @memberOf ParserUtils# 562 */ 563 var isDebug = true;//TODO read/set from configuration 564 565 MmirTemplateLexer.prototype.emitErrorMessage = function(msg) { 566 parser.parserPrintError('[ERROR] TemplateLexer: ', msg, this); 567 }; 568 // MmirTemplateParser.prototype.emitErrorMessage = function(msg) { 569 // parser.parserPrintError('[ERROR] TemplateParser: ',msg); 570 // }; 571 572 ES3Lexer.prototype.emitErrorMessage = function(msg) { 573 parser.parserPrintError('[ERROR] JavaScriptLexer_ES3: ', msg, this); 574 }; 575 ES3Parser.prototype.emitErrorMessage = function(msg) { 576 parser.parserPrintError('[ERROR] JavaScriptParser_ES3: ', msg, this.getTokenStream().getTokenSource()); 577 }; 578 579 MmirScriptLexer.prototype.emitErrorMessage = function(msg) { 580 var mode = this.isStatementMode()? 'Statement' : 'Block'; 581 parser.parserPrintError('[ERROR] Script'+mode+'Lexer: ',msg, this); 582 }; 583 MmirScriptParser.prototype.emitErrorMessage = function(msg) { 584 parser.parserPrintError('[ERROR] ScriptParser: ',msg, this.getTokenStream().getTokenSource()); 585 }; 586 587 MmirScriptContentLexer.prototype.emitErrorMessage = function(msg) { 588 parser.parserPrintError('[ERROR] ContentLexer: ',msg, this); 589 }; 590 MmirScriptContentParser.prototype.emitErrorMessage = function(msg) { 591 parser.parserPrintError('[ERROR] ContentParser: ',msg, this.getTokenStream().getTokenSource()); 592 }; 593 594 /** 595 * @private 596 * @memberOf ParserUtils# 597 */ 598 function internalParse(text) { 599 600 var input = new org.antlr.runtime.ANTLRStringStream(text);//FIXME change, how dependency 'antlr3' is exported? 601 var lexer = new MmirTemplateLexer(input); 602 603 lexer.isDebug = isDebug; 604 605 var tokens = new org.antlr.runtime.CommonTokenStream(lexer);//FIXME change, how dependency 'antlr3' is exported? 606 607 var result = {}; 608 result.rawTemplateText = tokens.toString(); 609 result.scripts = lexer.includeScripts; 610 result.styles = lexer.includeStyles; 611 result.localizations = lexer.locales; 612 result.ifs = lexer.ifs; 613 result.fors = lexer.fors; 614 result.yields = lexer.yields; 615 result.contentFors = lexer.yieldContents; 616 result.helpers = lexer.helpers; 617 result.partials = lexer.renderPartials; 618 result.escapes = lexer.escape; 619 result.scriptStatements = lexer.scriptStatements; 620 result.scriptBlocks = lexer.scriptBlocks; 621 result.vars = lexer.vars; 622 result.comments = lexer.comments; 623 //end: parsing results 624 625 626 lexer = null; 627 628 return result; 629 } 630 631 /** 632 * @private 633 * @memberOf ParserUtils# 634 */ 635 function internalParseJS(text, entryRuleName, offset) { 636 637 var input = new org.antlr.runtime.ANTLRStringStream(text); 638 var lexer = new ES3Lexer(input); 639 lexer.isDebug = isDebug; 640 lexer.offset = offset; 641 642 var tokens = new org.antlr.runtime.CommonTokenStream(lexer); 643 var parser = new ES3Parser(tokens); 644 parser.offset = offset; 645 646 if(!entryRuleName){ 647 // var parseResult = 648 parser.program();//<- parse with main rule 'program' in ES3Parser 649 } 650 else { 651 // var parseResult = 652 parser[entryRuleName]();//<- parse with main rule 'program' in ES3Parser 653 } 654 var result = new Object(); 655 result.rawTemplateText = tokens.toString(); 656 657 var varRefs = parser.getVarReferences(); 658 if(varRefs){ 659 result.varReferences = varRefs; 660 } 661 662 //TODO handle potentially global var-declaration (i.e. assignments without preceding var, where the variable is undefined yet) 663 664 //end: parsing results 665 666 lexer = null; 667 parser = null; 668 669 return result; 670 } 671 672 // var getVarReferences = function(parser){ 673 // 674 // var size = parser.ampersatIdentifiers.length; 675 // 676 // if(size === 0){ 677 // return null; 678 // } 679 // 680 // var varRefs = new Array(size); 681 // for(var i=0; i < size; ++i){ 682 // var ref = parser.ampersatIdentifiers[i]; 683 // 684 // var refObj = new mmir.parser.ParsingResult(ref); 685 //// refObj.start = ref.start; 686 // 687 // //correct end-position (token's stop-index is exactly the last char-index, whereas ParsingResult's end-position is token.stopIndex + 1) 688 // refObj.end = refObj.getEnd() + 1; 689 // 690 // refObj.type = mmir.parser.element.VAR_REFERENCE; 691 // 692 // varRefs[i] = refObj; 693 // } 694 // return varRefs; 695 // }; 696 697 /** 698 * Constructor-Method of Singleton mmir.parser.ParserUtils 699 * 700 * @constructs ParserUtils 701 * @memberOf ParserUtils.prototype 702 * @private 703 * @ignore 704 * 705 */ 706 function constructor(){ 707 //private members (currently none) 708 709 /** @lends ParserUtils.prototype */ 710 return { 711 //public members: 712 713 /** 714 * Parse a text as view template (e.g. *.ehtml files). 715 * 716 * @param {String} rawTemplateString the text that should be parsed 717 * @param {Object} [view] (optional) the view to which the <tt>rawTemplateString</tt> belongs (only used for error messages) 718 * @returns {mmir.parser.ParsingResult} the parsing result 719 * 720 * @public 721 * @memberOf mmir.parser.ParserUtils.prototype 722 */ 723 parse: function(rawTemplateString, view){ 724 725 if(view){ 726 _currentParsedView = view; 727 } 728 else { 729 _currentParsedView = null; 730 } 731 732 return internalParse(rawTemplateString); 733 }, 734 735 /** 736 * Parse a text as JavaScript. 737 * 738 * @param {String} rawTemplateString the text that should be parsed 739 * @param {String} [parseEntryRuleName] (optional) specifies the JavaScript element that should be parsed for 740 * @param {Object} [view] (optional) the view to which the <tt>rawTemplateString</tt> belongs (only used for error messages) 741 * @returns {mmir.parser.ParsingResult} the parsing result 742 * 743 * @public 744 */ 745 parseJS: function(rawTemplateString, parseEntryRuleName, view, inViewOffset){ 746 747 //in case only 2 or 3 arguments are present: is 2nd the View object? 748 if(!inViewOffset && typeof parseEntryRuleName !== 'string' && parseEntryRuleName !== null && typeof parseEntryRuleName === 'object'){ 749 750 if(typeof view === 'number'){ 751 inViewOffset = view; 752 } 753 754 view = parseEntryRuleName; 755 parseEntryRuleName = null; 756 757 758 } 759 760 if(view){ 761 _currentParsedView = view; 762 } 763 else { 764 _currentParsedView = null; 765 } 766 767 return internalParseJS(rawTemplateString, parseEntryRuleName, inViewOffset); 768 } 769 };//END: return{} 770 771 }//END: constructor() 772 773 instance = new constructor(); 774 775 /** 776 * @deprecated instead, use ParseUtils object directly (i.e. omit getInstance() call) 777 * 778 * @function 779 * @name getInstance 780 * 781 * @public 782 * @memberOf ParserUtils# 783 */ 784 instance.getInstance = function(){ 785 return this; 786 }; 787 788 //FIXME should the renderer be exported to parser.ParserUtils here? 789 parser.ParserUtils = instance; 790 791 return instance; 792 793 });//END define(..., function(){ 794 795 796