1 /*
  2  * 	Copyright (C) 2012-2016 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  * @module workers/jscc-compiler
 29  */
 30 
 31 
 32 importScripts('asyncCompileUtil.js');
 33 
 34 /////////////// stub for define()/require() //////////////////////////////
 35 // NOTE only single-requires are supported here! (i.e. no lists of required modules)
 36 
 37 var _modules = {
 38 	_idgen: 1,
 39 	_customid: '',//<- set custom ID for next loaded module (will be reset after loading)
 40 	_defined: {},
 41 	_get: function(id){
 42 		return this._defined[id];
 43 	}
 44 };
 45 
 46 define = function(moduleCreateFunc){
 47 	var modId;
 48 	if(_modules._customid){
 49 		modId = _modules._customid;
 50 		_modules._customid = '';
 51 	} else {
 52 		modId = moduleCreateFunc.name? moduleCreateFunc.name : 'mod'+(this._idgen++);
 53 	}
 54 	_modules._defined[modId] =  moduleCreateFunc();
 55 };
 56 
 57 require = function(id, cb){
 58 	if(cb){
 59 		return cb(_modules._get(id));
 60 	}
 61 	return _modules._get(id);
 62 };
 63 
 64 
 65 /////////////// JS/CC compiler setup //////////////////////////////
 66 
 67 var jscc;
 68 function _init(url){
 69 	
 70 	var libUrl = getPath(url) + '.js';
 71 	_modules._customid = 'jscc';
 72 	importScripts(libUrl);//'../vendor/libs/jscc-amd.js');
 73 
 74 	//set global var that holds JS/CC:
 75 	jscc = require('jscc');
 76 }
 77 
 78 
 79 var defaultOptions = {
 80 		//current there are no specific options for JS/CC
 81 };
 82 
 83 // setup JSCC compiler:
 84 
 85 //setup logger for compile-messages
 86 /**
 87  * HELPER for creating default logging / error-print functions
 88  * 
 89  * @function
 90  * @private
 91  * @memberOf JsccGenerator#
 92  * 
 93  * @see mmir.Logging
 94  */
 95 function _createCompileLogFunc(log /*Logger*/, level /*String: log-function-name*/, taskId){
 96 	return function(){
 97 		var args = _makeArray(arguments);
 98 		log.postMessage({error: args, level: level, id: taskId});
 99 	};
100 }
101 
102 function _preparePrintImpl(id){
103 	
104 	/**
105 	 * The default logging function for printing compilation errors.
106 	 * @private
107 	 * @name set_printError
108 	 * @function
109 	 * @memberOf JsccGenerator.jscc#
110 	 */
111 	jscc.set_printError(	_createCompileLogFunc(self, 'error', id));
112 
113 	/**
114 	 * The default logging function for printing compilation warnings.
115 	 * @private
116 	 * @name set_printWarning
117 	 * @function
118 	 * @memberOf JsccGenerator.jscc#
119 	 */
120 	jscc.set_printWarning(	_createCompileLogFunc(self, 'warn', id));
121 
122 	/**
123 	 * The default logging function for printing compilation information.
124 	 * @private
125 	 * @name set_printInfo
126 	 * @function
127 	 * @memberOf JsccGenerator.jscc#
128 	 */
129 	jscc.set_printInfo(		_createCompileLogFunc(self, 'info', id));
130 	
131 	return true;
132 }
133 
134 var _getGenerated = function(genMode, dfaTable){
135 	return {
136 		head: jscc.get_code_head(),
137 		tables: jscc.print_parse_tables(genMode),//jscc.MODE_GEN_JS
138 		dfa: jscc.print_dfa_table(dfaTable),//dfa_table
139 		terminals: jscc.print_term_actions(),
140 		labels: jscc.print_symbol_labels(),
141 		actions: jscc.print_actions(),
142 		error: jscc.get_error_symbol_id(),
143 		eof: jscc.get_eof_symbol_id(),
144 		whitespace: jscc.get_whitespace_symbol_id()
145 	};
146 };
147 
148 
149 self.onmessage = function(e){
150 	
151   switch(e.data.cmd){
152     case 'init':
153       init(e.data);
154       break;
155     case 'parse':
156       parse(e.data.text, e.data.config, e.data.id);
157       break;
158   }
159   
160 };
161 
162 
163 function parse(grammarDefinition, config, id){
164 	
165 	if(!verifyInit(jscc, 'jscc', id)){
166 		return;
167 	}
168 	
169 	var options = _getOptions(config);
170 	
171 	var template = config.template;
172 	var inputFieldName = config.inputFieldName;
173     
174 	//setup print-functions (error, warning, info) for this compile-job:
175 	_preparePrintImpl(id);
176     
177 	//set up the JS/CC compiler:
178     var dfa_table = '';
179     jscc.reset_all( jscc.EXEC_WEB );
180     
181     var hasError = false;
182     var grammarParser;
183     try {
184     	jscc.parse_grammar(grammarDefinition);
185     } catch (err){
186     	var msg = 'Error while compiling grammar: ' + (err.stack?err.stack:err);
187     	hasError = msg;
188     	
189     	msg = '[INVALID GRAMMAR] ' + msg;
190     	grammarParser = 'var msg = '+JSON.stringify(msg)+'; console.error(msg); throw msg;';
191     }
192   
193     if (jscc.getErrors() == 0) {
194     	jscc.undef();
195     	jscc.unreachable();
196             
197         if (jscc.getErrors() == 0) {
198         	jscc.first();
199         	jscc.print_symbols();
200         	dfa_table = jscc.create_subset(jscc.get_nfa_states());
201         	dfa_table = jscc.minimize_dfa(dfa_table);
202         	
203         	jscc.set_dfa_table(dfa_table);//FIXME: check, if this is really necessary
204             
205         	jscc.lalr1_parse_table(false);
206         	jscc.resetErrors();
207         }
208     }
209  
210     if (jscc.getErrors() > 0 || jscc.getWarnings() > 0){
211         jscc.get_printError()(//logger.error(
212 //        		'JSCC', 'compile',
213         		'there occured' 
214         		+ (jscc.getWarnings() > 0? jscc.getWarnings() + ' warning(s)' : '')
215         		+ (jscc.getErrors() > 0? jscc.getErrors() + ' error(s)' : '')
216         		+ ' during compilation.'
217         );
218     }
219     jscc.resetErrors();
220     jscc.resetWarnings();
221  
222     if( ! hasError){
223         grammarParser = _getGenerated(options.targetType, dfa_table);
224     }
225 	
226 	self.postMessage({def: grammarParser, isError: hasError, id: id, done: true});
227 }
228 
229