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 define(['constants', 'grammarConverter', 'logger', 'module' 28 ], 29 /** 30 * @name SemanticInterpreter 31 * @memberOf mmir 32 * @static 33 * @class 34 */ 35 function ( 36 constants, GrammarConverter, Logger, module 37 ){ 38 39 /** 40 * The instance for the singleton SemanticInterpreter 41 * 42 * @type SemanticInterpreter 43 * @private 44 * 45 * @memberOf SemanticInterpreter# 46 */ 47 var instance = null; 48 49 /** 50 * @private 51 * @type Logger 52 * @memberOf SemanticInterpreter# 53 */ 54 var logger = Logger.create(module); 55 56 /** 57 * The version number for the format of generated (JavaScript) grammars. 58 * 59 * This number is "written into" the generated grammars and then 60 * used as argument, when the grammar adds itself via 61 * <code>addGrammar(id, func, versionNumber)</code>. 62 * 63 * See generator function build_grammar() within createAndAddGrammar(). 64 * 65 * NOTE: This version number must be increased, when way changes, how 66 * grammars are generated. 67 * Or more precisely: when previously generated grammars cannot 68 * be used anymore, after the generation mechanism has been changed. 69 * 70 * @constant 71 * @private 72 * 73 * @memberOf SemanticInterpreter# 74 */ 75 var GRAMMAR_FILE_FORMAT_VERSION = 4; 76 77 78 /** 79 * @constructs SemanticInterpreter 80 * @memberOf SemanticInterpreter# 81 * @private 82 * @ignore 83 */ 84 function constructor(){ 85 86 /** 87 * "map" for grammar implementations (e.g. for different languages) 88 * 89 * @private 90 * 91 * @memberOf SemanticInterpreter# 92 */ 93 var grammarImplMap = {}; 94 /** 95 * list of IDs for grammar implementations (e.g. for different languages). 96 * 97 * This list contains the "keys" of all current entries in <tt>grammarImplMap</tt>. 98 * 99 * @private 100 * @type Array<String> 101 * 102 * @memberOf SemanticInterpreter# 103 */ 104 var grammarImplList = []; 105 106 /** 107 * id (i.e. the <em>key</em> for map <tt>grammarImplMap</tt>) for currently used 108 * grammar. 109 * 110 * If for invocations of getASRSemantic(..) etc. function the ID/languageCode 111 * argument is missing/omitted, then this id will be used. 112 * 113 * NOTE: if not <tt>NULL</tt>, the grammar must be available, either 114 * as compiled JS file (which must be already loaded, i.e. already present in <tt>grammarImplMap</tt>), or 115 * as JSON grammar file (which must be available at <tt>/config/languages/[ID]/grammar.json</tt> 116 * 117 * @type String 118 * @private 119 * 120 * @memberOf SemanticInterpreter# 121 */ 122 var currentGrammarId = null; 123 124 /** 125 * @type String 126 * @private 127 * @memberOf SemanticInterpreter# 128 */ 129 var currentGrammarEningeId = null; 130 131 /** 132 * If true, the async versions of the grammar engines are loaded, 133 * i.e. compilation of grammar parsers will be asynchronously done in a WebWorker 134 * 135 * @type Boolean 136 * @private 137 * @default false 138 * @memberOf SemanticInterpreter# 139 */ 140 var _isAsyncCompileMode = false; 141 142 /** 143 * @type String 144 * @constant 145 * @private 146 * @memberOf SemanticInterpreter# 147 */ 148 var DEFAULT_GRAMMAR_ENGINE = 'jscc'; 149 /** 150 * @type String 151 * @constant 152 * @private 153 * @memberOf SemanticInterpreter# 154 */ 155 var GRAMMAR_MODULE_ID_POSTFIX = 'Gen'; 156 /** 157 * @type String 158 * @constant 159 * @private 160 * @memberOf SemanticInterpreter# 161 */ 162 var GRAMMAR_ASYNC_MODULE_MODIFIER = 'Async'; 163 164 /** 165 * @private 166 * @memberOf SemanticInterpreter# 167 */ 168 var doSetGrammarEngine = function(id, asyncCompileMode){ 169 170 currentGrammarEningeId = id; 171 172 if(typeof asyncCompileMode !== 'undefined'){ 173 _isAsyncCompileMode = !!asyncCompileMode; 174 } 175 }; 176 /** 177 * @private 178 * @memberOf SemanticInterpreter# 179 */ 180 var doGetGrammarEngine = function(){ 181 if(currentGrammarEningeId){ 182 return currentGrammarEningeId; 183 } 184 return DEFAULT_GRAMMAR_ENGINE; 185 }; 186 187 /** 188 * Flag for enabling/disabling processing of SemanticInterpreter. 189 * 190 * If disabled, getASRSemantic(), removeStopwords() etc. (+ <tt>_alt</tt> versions) will return <tt>null</tt> values. 191 * 192 * NOTE: if no grammar for any language is available, the SemanticInterpreter should be disabled. 193 * 194 * Setting a language, automatically enables the the SemanticInterpreter. 195 * 196 * @type Boolean 197 * @private 198 * @memberOf SemanticInterpreter# 199 */ 200 var _isEnabled = false; 201 202 203 /** 204 * @private 205 * @memberOf SemanticInterpreter# 206 */ 207 var doSetEnabled = function(isEnabled){ 208 _isEnabled = isEnabled; 209 }; 210 211 /** 212 * @private 213 * @memberOf SemanticInterpreter# 214 */ 215 var doCheckIsEnabled = function(){ 216 return _isEnabled; 217 }; 218 219 /** 220 * 221 * NOTE: if no other grammar is available yet, <tt>currentGrammarId</tt> will be set to <tt>id</tt>. 222 * 223 * NOTE: if currently disabled, calling this function automatically enables ( setEnabled(TRUE) ), 224 * the semantic interpreter. 225 * 226 * @function 227 * @param id {String} ID for the grammar (e.g. an ISO-639 language code) 228 * @param grammarImpl {GrammarConverter|Function} the executable JavaScript grammar implementation 229 * IF {GrammarConverter}: the impl. with valid member {Function} {@link GrammarConverter.executeGrammar()} 230 * IF {Function}: the {Function} {@link GrammarConverter.executeGrammar()} - 231 * In this case, if no GrammarConverter instance fo <tt>id</tt> is present, a new one will be created; 232 * The stopwords must already be set, or must additionally be set for the GrammarConverter instance 233 * (e.g. using {@link mmir.SemanticInterpreter.setStopwords}) 234 * @param {Number|PlainObject} [fileFormatNo] OPTIONAL 235 * If Number and the number given does not match {@link #GRAMMAR_FILE_FORMAT_VERSION} 236 * the file format is assumed to be out-dated and an Error will be thrown. 237 * 238 * If PlainObject, i.e. an options object, the following properties are evaluated 239 * (all properties are opitional): 240 * <code>fileFormat: NUMBER, default: undefined</code> 241 * (desc. see above) 242 * <code>execMode: 'sync' | 'async', default: 'sync'</code> 243 * if 'async' then the grammar is executed asynchronously, i.e. getASRSemantic() 244 * must be invoked with a callback function in order to retrieve the result 245 * 246 * @throws Error if <code>fileFormatNo</code> is given, but does not match GRAMMAR_FILE_FORMAT_VERSION. 247 * 248 * @private 249 * @memberOf SemanticInterpreter# 250 */ 251 var doAddGrammar = function(id, grammarImpl, fileFormatNo){ 252 253 var execMode = 'sync'; 254 if(fileFormatNo && typeof fileFormatNo === 'object'){ 255 256 execMode = fileFormatNo.execMode; 257 258 //lastly: overwrite fileFormatNo with the corresponding property: 259 fileFormatNo = fileFormatNo.fileFormat; 260 } 261 262 //check if the added grammar has correct format 263 if(fileFormatNo && fileFormatNo != GRAMMAR_FILE_FORMAT_VERSION){ 264 265 //grammar has old / out-dated format: 266 throw new Error('Grammar file has wrong format: need grammar file with format version ' 267 +GRAMMAR_FILE_FORMAT_VERSION+', but got: '+fileFormatNo 268 + '. Please update generated grammar (delete ' 269 + constants.getGeneratedGrammarsPath() +' and re-build grammars).' 270 ); 271 } 272 273 //the grammar function must be "wrapped" in a GrammarConverter instance 274 // ... if not, do so now: 275 if( ! (grammarImpl instanceof GrammarConverter)){ 276 var gc = doGetGrammar(id, true); 277 278 //if for this ID (= language code) no grammar-converter 279 // exists yet, create a now one 280 // (otherwise, re-use the existing one) 281 if(!gc){ 282 gc = new GrammarConverter(); 283 } 284 gc.setGrammarFunction(grammarImpl, execMode === 'async'); 285 grammarImpl = gc; 286 } 287 288 var isAlreadyPresent = checkHasGrammar(id); 289 grammarImplMap[id] = grammarImpl; 290 291 if( ! isAlreadyPresent){ 292 293 //DISABLED: this may produce side effects (now: current grammar must be explicitly set using setCurrentGrammar(lang)) 294 // if(grammarImplList.length === 0){ 295 // currentGrammarId = id; 296 // } 297 grammarImplList.push(id); 298 } 299 300 doSetEnabled(true); 301 }; 302 303 /** 304 * @private 305 * @memberOf SemanticInterpreter# 306 */ 307 var doSetStopwords = function(id, stopwordArray){ 308 doGetGrammar(id).setStopWords(stopwordArray); 309 }; 310 /** 311 * HELPER retrieve the executable grammar: 312 * if already loaded, return the grammar instance, otherwise load & compile. 313 * 314 * @param {String} id 315 * the ID (e.g. language code) for the grammar 316 * @param {Boolean} [doNotResolve] OPTIONAL 317 * if <code>false</code> AND the request grammar is not loaded yet, 318 * then the grammar will NOT be loaded (if omitted or <code>true</code> 319 * missing grammars will automatically be loaded and compiled) 320 * @param {Function} [callback] OPTIONAL 321 * if grammar has to be loaded (and compiled), the provided callback 322 * will be called, after completion. 323 * 324 * @return {GrammarExecFunction} 325 * the exectuable grammar (i.e. execution function), if the grammar is 326 * already loaded (if grammar has to loaded and compiled, you need to 327 * wait for the callback-call and then re-invoke doGetGrammar()). 328 * 329 * @private 330 * @memberOf SemanticInterpreter# 331 */ 332 var doGetGrammar = function(id, doNotResolve, callback){//NOTE: this should stay private 333 334 if(!id){ 335 if(!currentGrammarId){ 336 throw 'Could not retrieve grammar: required grammar ID is missing'; 337 } 338 else { 339 id = currentGrammarId; 340 } 341 } 342 343 //shift arguments, if necessary: 344 if(!callback && typeof doNotResolve === 'function'){ 345 callback = doNotResolve; 346 doNotResolve = false; 347 } 348 349 var isDefaultCallback = false; 350 if(!callback && logger.isInfo()){ 351 //create a "debug-info callback" 352 isDefaultCallback = true; 353 callback = function(){ 354 if(logger.isInfo()) logger.info('created executable grammar for "'+id+'" from source '+jsonGrammarUrl); 355 }; 356 } 357 358 if(!doNotResolve && ! checkHasGrammar(id) ){ 359 var jsonGrammarUrl = instance.get_json_grammar_url(id); 360 361 createAndAddGrammar(jsonGrammarUrl, id, callback); 362 } 363 else if(callback && !isDefaultCallback){ 364 callback(); 365 } 366 367 return grammarImplMap[id]; 368 }; 369 /** 370 * @private 371 * @memberOf SemanticInterpreter# 372 */ 373 var checkHasGrammar = function(id){ 374 return typeof grammarImplMap[id] !== 'undefined'; 375 }; 376 /** 377 * @private 378 * @memberOf SemanticInterpreter# 379 */ 380 var doRemoveGrammar = function(id){ 381 382 if( checkHasGrammar(id) ){ 383 384 //remove from impl.-map: 385 delete grammarImplMap[id]; 386 387 //remove from ID-list 388 for(var i=0, size = grammarImplList.length; i < size; ++i){ 389 if(grammarImplList[i]==id){ 390 grammarImplList.splice(i, 1); 391 break; 392 } 393 } 394 } 395 }; 396 397 398 //TODO move create/build into GrammarConverter 399 /** 400 * @param {String|JSONObject} doRecompile 401 * IF {String}: the String's contents will be used as a String-representation of the JSON grammar 402 * IF {Object}: the Object will be used as JSON representation for the grammar 403 * 404 * @param {String} [generatedParserLanguageCode] OPTIONAL 405 * if param doRecompile is used, this String specifies the 406 * language for the generated grammatic-parser. If omitted, the default "de" (German) will be used. 407 * NOTE: this must be a valid ISO language code! 408 * 409 * @param {Function} [callback] OPTIONAL 410 * a callback that is invoked after the grammar was created and added to the SemanticInterpreter. 411 * The callback-function will be invoked without arguments, i.e. <code>callback();</code> 412 * @function 413 * 414 * @private 415 * @memberOf SemanticInterpreter# 416 */ 417 function createAndAddGrammar(doRecompile, generatedParserLanguageCode, callback){ 418 419 var gc = new GrammarConverter(); 420 421 //callback that will be used after the JSON file for the grammar was loaded: 422 function build_grammar(theConverterInstance){//<- argument is the GrammarConverter instance 423 424 var genId = doGetGrammarEngine();//one of ['jscc' | 'pegjs' | 'jison']; 425 var genName = genId + (_isAsyncCompileMode? GRAMMAR_ASYNC_MODULE_MODIFIER : '') + GRAMMAR_MODULE_ID_POSTFIX; 426 427 var onModuleLoaded = function onLoad(gen){ 428 429 //initialize the generator (initialization may be async -> need callback/Promise) 430 // (-> if already initialized, the then-callback will be invoked immediately) 431 gen.init().then(function onInit(){ 432 433 //actually start compilation of the grammar definition: 434 // usually this involves 2 steps: 435 // (1) converting the JSON grammar into a specific ParserParser syntax (e.g. JS/CC syntax) 436 // (2) compiling this syntax using the corresponding Parser-Generator 437 // -> the resulting parser-function will then be registered on the SemanticInterpreter instance 438 // (using its addGrammar() function) along with the stopword definition (using the setStopwords() function) 439 gen.compileGrammar(theConverterInstance, generatedParserLanguageCode, GRAMMAR_FILE_FORMAT_VERSION, function onCompiled(convertedInstance){ 440 441 //add the grammar-parser-text and grammar-definition-text to the newly registered Grammar-instance 442 // (-> registering is done within the compileGrammar() function!) 443 var registeredGrammarInstance = doGetGrammar(generatedParserLanguageCode, true); 444 if(registeredGrammarInstance){ 445 registeredGrammarInstance.setGrammarSource(convertedInstance.getGrammarSource()); 446 registeredGrammarInstance.setGrammarDef(convertedInstance.getGrammarDef()); 447 } 448 else { 449 logger.error('A problem occured during generation of grammar for "'+generatedParserLanguageCode+'"'); 450 } 451 452 //invoke callback if present: 453 if(callback){ 454 callback(registeredGrammarInstance); 455 } 456 }); 457 }); 458 459 };//END: onModuleLoaded([jsccGen]) 460 461 require([genName], onModuleLoaded, function(err){ 462 463 //if async-module could not be loaded, try sync-module 464 if(_isAsyncCompileMode){ 465 466 logger.warn('Cannot use asynchronous compilation for '+genId+ 467 ': no async module available, using sync compilation instead...' 468 ); 469 genName = genId + GRAMMAR_MODULE_ID_POSTFIX; 470 471 require([genName], onModuleLoaded); 472 } 473 }); 474 475 }//END function build_grammar 476 477 if(typeof doRecompile === 'string'){// arg. is URL for JSON grammar definition 478 479 //interpret STRING as URL for the JSON grammar: 480 gc.loadGrammar(build_grammar, function(err){ 481 throw 'Could not find JSON grammar file at "'+doRecompile+'": '+err; 482 }, doRecompile, true 483 ); 484 } else if(typeof doRecompile === 'object'){// arg. is JSONObject (ie. JSON grammar defintion) 485 486 //ASSERT if doRecompile === null => throws error! 487 488 gc.json_grammar_definition = doRecompile; 489 build_grammar(gc); 490 491 } else { 492 logger.error('SemanticInterpreter.__createAndAddGrammar: could not build grammar due to missing argumens'); 493 } 494 } 495 496 /** 497 * @private 498 * @memberOf SemanticInterpreter# 499 */ 500 var process_asr_semantic = function(phrase, stopwordFunc, langCode, callback){ 501 502 if(!doCheckIsEnabled()){ 503 logger.warn('SemanticInterpreter.getASRSemantic: currently disabled!'); 504 return null; 505 } 506 507 if(typeof langCode === 'function'){ 508 callback = langCode; 509 langCode = void(0); 510 } 511 512 var execGrammar = function(grammarConverter, phrase, stopwordFunc, langCode, callback){ 513 514 var strPreparedPhrase = grammarConverter.maskString( phrase.toLowerCase() ); 515 strPreparedPhrase = stopwordFunc(strPreparedPhrase, langCode, grammarConverter); 516 517 if(logger.isDebug()) logger.debug('SemanticInterpreter.process_asr_semantic('+langCode+'): removed stopwords, now parsing phrase "'+strPreparedPhrase+'"');//debug 518 519 if(callback){ 520 521 grammarConverter.executeGrammar( strPreparedPhrase, function(result){ 522 523 //unmask previously mask non-ASCII chars in all Strings of the returned result: 524 result = grammarConverter.unmaskJSON( 525 result 526 ); 527 528 callback(result);//TODO return copy instead of original instance? 529 530 } ); 531 532 533 534 } else { 535 536 var result = grammarConverter.executeGrammar( strPreparedPhrase ); 537 538 //unmask previously mask non-ASCII chars in all Strings of the returned result: 539 result = grammarConverter.unmaskJSON( 540 result 541 ); 542 543 return result;//TODO return copy instead of original instance? 544 } 545 546 }; 547 548 var grammarReadyCallback; 549 if(callback){ 550 551 grammarReadyCallback = function(){ 552 553 var grammarConverter = doGetGrammar(langCode); 554 555 if(grammarConverter.isAsyncExec()){ 556 execGrammar(grammarConverter, phrase, stopwordFunc, langCode, callback); 557 } else { 558 callback(execGrammar(grammarConverter, phrase, stopwordFunc, langCode)); 559 } 560 }; 561 } 562 563 var grammarConverter = doGetGrammar(langCode, grammarReadyCallback); 564 565 if(!grammarConverter && ! grammarReadyCallback){ 566 throw 'NoGrammar_'+langCode; 567 } 568 569 if(!grammarReadyCallback){ 570 return execGrammar(grammarConverter, phrase, stopwordFunc, langCode); 571 } 572 }; 573 574 /** 575 * @private 576 * @memberOf SemanticInterpreter# 577 */ 578 var removeStopwordsFunc = function removeStopwords(thePhrase, lang, gc){ 579 if(!gc){ 580 gc = doGetGrammar(lang); 581 } 582 var stop_words_regexp = gc.getStopWordsRegExpr(); 583 584 var str = thePhrase; 585 var encoded_stop_words_regexp = gc.getStopWordsEncRegExpr(); 586 if(encoded_stop_words_regexp){ 587 str = str.replace(gc.stop_words_regexp_enc, ' ').trim(); 588 } 589 590 return str.replace(stop_words_regexp, '').trim(); 591 }; 592 593 /** 594 * @private 595 * @memberOf SemanticInterpreter# 596 */ 597 var removeStopwordsAltFunc = function removeStopwords_alt(thePhrase, lang, gc){ 598 if(!gc){ 599 gc = doGetGrammar(lang); 600 } 601 var stop_words_regexp = gc.getStopWordsRegExpr_alt(); 602 603 while (thePhrase.match(stop_words_regexp)) { 604 thePhrase = thePhrase.replace(stop_words_regexp, ' '); 605 thePhrase = thePhrase.trim(); 606 } 607 608 return thePhrase; 609 }; 610 /** 611 * @private 612 * @memberOf SemanticInterpreter# 613 */ 614 var doRemoveStopWords = function(thePhrase, lang, func){ 615 if(!doCheckIsEnabled()){ 616 logger.warn('SemanticInterpreter.'+func.name+': currently disabled!'); 617 return null; 618 } 619 620 var grammarConverter = doGetGrammar(lang); 621 622 if(!grammarConverter){ 623 throw 'NoGrammar_'+lang; 624 } 625 626 var str = grammarConverter.maskString( thePhrase ); 627 628 // var str = grammarConverter.encodeUmlauts(thePhrase, true); 629 str = func(str, lang, grammarConverter); 630 return grammarConverter.unmaskString( str );//grammarConverter.decodeUmlauts(str, true); 631 }; 632 633 var _tmpInstance = { // public members 634 635 /** @scope SemanticInterpreter# *///for jsdoc2 636 637 /** 638 * @deprecated use {@link #removeStopwords} instead 639 * @memberOf SemanticInterpreter.prototype 640 * @public 641 */ 642 removeStopwords_alt: function(thePhrase, lang){ 643 return doRemoveStopWords(thePhrase, lang, removeStopwordsAltFunc); 644 }, 645 /** 646 * @param {String} phrase 647 * the phrase that will be parsed 648 * @param {String} langCode 649 * the language code (identifier) for the parser/grammar 650 * @param {Function} [callback] OPTIONAL 651 * a callback function that receives the return value 652 * (instead of receiving the result as return value from 653 * this function directly). 654 * The signature for the callback is: <code>callback(result: Object)</code> 655 * (i.e. the result that would be returned by this function itself is 656 * passed as argument into the callback function; see also documentation 657 * for <em>returns</em>). 658 * NOTE: in case, the grammar for the requested <code>langCode</code> 659 * is not compiled yet (i.e. not present as executable JavaScript), 660 * the corresponding JSON definition of the grammar needs to be 661 * compiled first, before processing the ASR's semantics is possible. 662 * In this case, a <code>callback</code> function <strong>MUST</strong> 663 * be supplied in order to receive a result (since compilation of the 664 * grammar may be <em>asynchronous</em>). 665 * 666 * @returns {Object} 667 * the parsing result (as processed by the parser / grammar; 668 * usually a JSON-like object). 669 * WARNING: if a <code>callback</code> function was provided, then 670 * there is no return object. 671 * 672 * @public 673 */ 674 getASRSemantic: function(phrase, langCode, callback){ 675 676 return process_asr_semantic(phrase, removeStopwordsFunc, langCode, callback); 677 678 }, 679 /** 680 * @public 681 * @deprecated use {@link #getASRSemantic} instead 682 */ 683 getASRSemantic_alt: function(phrase, langCode){ 684 685 return process_asr_semantic(phrase, removeStopwordsAltFunc, langCode); 686 687 }, 688 /** 689 * Removes stopwords using the stopword-list from the parser/grammar 690 * for <code>lang</code>. 691 * 692 * NOTE: <code>{@link #getASRSemantic}</code> automatically applies stopword-removal 693 * (i.e. there is no need to manually remove stopwords using this function 694 * when using <code>{@link #getASRSemantic}</code>). 695 * 696 * @param {String} thePhrase 697 * the Phrase for which stopwords should be removed 698 * @param {String} lang 699 * the language code (identifier) for the parser/grammar 700 * 701 * @public 702 */ 703 removeStopwords: function(thePhrase, lang){ 704 return doRemoveStopWords(thePhrase, lang, removeStopwordsFunc); 705 }, 706 /** NOTE: the grammar must be compiled first, see getNewInstance(true) @public */ 707 getGrammarDefinitionText: function(id){ 708 return doGetGrammar(id).getGrammarDef();//grammarDefinitionText; 709 }, 710 /** NOTE: the grammar must be compiled first, see getNewInstance(true) @public*/ 711 getGrammarParserText: function(id){ 712 return doGetGrammar(id).getGrammarSource();//grammarParser; 713 }, 714 /** 715 * 716 * @public 717 * @param {String} id 718 * @returns {GrammarConverter} 719 */ 720 getGrammarConverter: function(id){ 721 return doGetGrammar(id, true);//<- if no grammar is loaded for this ID, do NOT try to load it! 722 }, 723 /** 724 * 725 * @public 726 * @param {String|JSONObject} rawGrammarSrc 727 * @param {String} id 728 * @param {Function} [callback] 729 * @returns {SemanticInterpreter.prototype} 730 */ 731 createGrammar: function(rawGrammarSrc, id, callback){ 732 733 if(!id){ 734 throw 'missing ID for generated grammar';//TODO 735 } 736 737 createAndAddGrammar(rawGrammarSrc, id, callback); 738 739 return this; 740 }, 741 /** 742 * @public 743 * @function 744 */ 745 addGrammar: doAddGrammar, 746 /** 747 * @public 748 * @function 749 */ 750 setStopwords: doSetStopwords, 751 // getGrammar: doGetGrammar, <- set to private 752 /** 753 * @public 754 * @function 755 */ 756 hasGrammar: checkHasGrammar, 757 /** 758 * @public 759 * @function 760 */ 761 removeGrammar: doRemoveGrammar, 762 763 /** 764 * Sets the current grammar. 765 * 766 * If in invocations of {@link #getASRSemantic} the grammar ID (e.g. language code) is missing, 767 * then this grammar that is set here is used. 768 * 769 * The id must reference either a grammar that was compiled (i.e. generated JavaScript file) 770 * for this id, or there must exists JSON-grammar file for which the language-dir matches the id parameter, 771 * e.g. <code>config/languages/[id]/grammar.json</code>. 772 * 773 * @param {String} id the ID for the grammar, e.g. an ISO language code 774 * 775 * @function 776 * @public 777 */ 778 setCurrentGrammar: function(id){ 779 currentGrammarId = id; 780 781 //set semantic-interpreter to enabled 782 // (this ensures, that JSON-grammars are automatically loaded, 783 // if no corresponding compiled JS-grammar is available yet) 784 doSetEnabled(true); 785 }, 786 /** @public */ 787 getCurrentGrammar: function(){ 788 return currentGrammarId; 789 }, 790 791 /** @public */ 792 setEnabled: function(isEnabled){ 793 doSetEnabled(isEnabled); 794 }, 795 /** @public */ 796 isEnabled: function(){ 797 return doCheckIsEnabled(); 798 }, 799 800 /** 801 * Get the ID of the current grammar engine / compiler. 802 * 803 * @default "jcss" 804 * @returns {String} 805 * the ID of the current grammar engine 806 * @public 807 */ 808 getGrammarEngine: function(){ 809 return doGetGrammarEngine(); 810 }, 811 /** 812 * Set the grammar engine, i.e. the 813 * compiler engine for the JSON grammar 814 * 815 * NOTE: implementations of the grammar engines are located at env/grammar/ 816 * The file-name for an implementation should follow the convention: ID+"Generator.js" 817 * and should be registered with requirejs with the module-ID: ID+"Gen" 818 * 819 * @param {String} egnineId 820 * the ID for the engine. 821 * Possible values: "jscc", "jison", "pegjs" 822 * 823 * @param {Boolean} [asyncCompileMode] OPITIONAL 824 * sets the compile mode (sychronous or asynchronous) when generating new parsers 825 * with the grammar-engine. 826 * DEFAULT: VOID (i.e. leave current set compile-mode setting unchanged) 827 * 828 * @public 829 */ 830 setGrammarEngine: function(engineId, asyncCompileMode){ 831 doSetGrammarEngine(engineId, asyncCompileMode); 832 }, 833 834 /** 835 * Set compile-mode (sychronous or asynchronous) for the grammar engine, i.e. if the 836 * compiler engine for the JSON grammar should run synchronously or asynchronously. 837 * 838 * NOTE: if there is no asynchronous implementation available for the grammar engine, 839 * the sync-impl. is used by default. 840 * 841 * NOTE: asynchronous compile mode requires WebWorkers 842 * 843 * @param {Boolean} asyncCompileMode 844 * sets the compile mode (sychronous or asynchronous) when generating new parsers 845 * with the grammar-engine. 846 * 847 * @public 848 * @default false (i.e. synchronous compile mode) 849 * @require WebWorker (if async mode) 850 */ 851 setEngineCompileMode: function(asyncCompileMode){ 852 _isAsyncCompileMode = !!asyncCompileMode; 853 }, 854 /** 855 * @returns {Number} the current version number that this SemanticInterpreter 856 * instance supports, for the file format of compiled grammars. 857 */ 858 getFileVersion: function(){ 859 return GRAMMAR_FILE_FORMAT_VERSION; 860 }, 861 862 //FIXME rename/move functions 863 get_json_grammar_url: function(id){ 864 var configLangPath = constants.getLanguagePath(); 865 var jsonGrammarFileName = constants.getGrammarFileName(); 866 867 return configLangPath + id + '/' +jsonGrammarFileName; 868 } 869 };//END: var _tmpInstance = {... 870 871 return _tmpInstance; 872 } 873 874 instance = new constructor(); 875 876 /** 877 * @deprecated instead: use <code>mmir.SemanticInterpreter</code> directly 878 * 879 * @function 880 * @name getInstance 881 * @public 882 * @memberOf SemanticInterpreter.prototype 883 */ 884 instance.getInstance = function(){ 885 return instance; 886 }; 887 888 return instance; 889 890 });//END: define(..., function(){ 891