1 /*!
  2  * 
  3  * JavaLikeScript
  4  * 
  5  */
  6 /**
  7  * jls Base framework.
  8  * All the framework objects are created under the jls namespace.
  9  * The default objects are extended using prototype like behaviors.
 10  * 
 11  * @namespace
 12  * @see jls.lang
 13  */
 14 var jls = {};
 15 
 16 /**
 17  * @namespace Provides base classes for the jls language.
 18  * @see jls.lang.Exception
 19  * @see jls.lang.Logger
 20  * @see jls.lang.ClassLoader
 21  */
 22 jls.lang = {};
 23 
 24 /*
 25  * Begin prototype.js
 26  */
 27 Array.prototype.clone = function() {
 28   return [].concat(this);
 29 };
 30 Array.prototype.toArray = Array.prototype.clone;
 31 // The primary use of Array.from() is to obtain an actual Array object based on anything that could pass as an array.
 32 // the predefined arguments reference within your functions
 33 Array.from = function(iterable) {
 34   if (!iterable) return [];
 35   if (iterable.toArray) return iterable.toArray();
 36   var length = iterable.length || 0, results = new Array(length);
 37   while (length--) results[length] = iterable[length];
 38   return results;
 39 }
 40 // extend Object
 41 Object.extend = function(destination, source) {
 42   for (var property in source)
 43     destination[property] = source[property];
 44   return destination;
 45 };
 46 Object.extend(Object, {
 47   toJSON: function(object) {
 48     var type = typeof object;
 49     switch (type) {
 50       case 'undefined':
 51       case 'function':
 52       case 'unknown': return;
 53       case 'boolean': return object.toString();
 54     }
 55     if (object === null) return 'null';
 56     if (object.toJSON) return object.toJSON();
 57     var results = [];
 58     for (var property in object) {
 59       var value = Object.toJSON(object[property]);
 60       if (!Object.isUndefined(value))
 61         results.push(property.toJSON() + ': ' + value);
 62     }
 63     return '{' + results.join(', ') + '}';
 64   },
 65   keys: function(object) {
 66     var keys = [];
 67     for (var property in object)
 68       keys.push(property);
 69     return keys;
 70   },
 71   values: function(object) {
 72     var values = [];
 73     for (var property in object)
 74       values.push(object[property]);
 75     return values;
 76   },
 77   isArray: function(object) {
 78     return object != null && typeof object == "object" &&
 79       'splice' in object && 'join' in object;
 80   },
 81   isHash: function(object) {
 82     return object instanceof Hash;
 83   },
 84   isFunction: function(object) {
 85     return typeof object == "function";
 86   },
 87   isString: function(object) {
 88     return typeof object == "string";
 89   },
 90   isNumber: function(object) {
 91     return typeof object == "number";
 92   },
 93   isUndefined: function(object) {
 94     return typeof object == "undefined";
 95   },
 96   inheritConstants: function(destination, source) {
 97     for (var property in source) {
 98       if ((typeof source[property] == "string") || (typeof source[property] == "number")) {
 99           destination[property] = source[property];
100       }
101     }
102     return destination;
103   }
104 });
105 // extend Function
106 Object.extend(Function.prototype, {
107   argumentNames: function() {
108     var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
109       .replace(/\s+/g, '').split(',');
110     return names.length == 1 && !names[0] ? [] : names;
111   },
112   bind: function() {
113     if (arguments.length < 2 && (typeof arguments[0] == "undefined")) return this;
114     var __method = this, args = Array.from(arguments), object = args.shift();
115     return function() {
116       return __method.apply(object, args.concat(Array.from(arguments)));
117     }
118   },
119   curry: function() {
120     if (!arguments.length) return this;
121     var __method = this, args = Array.from(arguments);
122     return function() {
123       return __method.apply(this, args.concat(Array.from(arguments)));
124     }
125   },
126   wrap: function(wrapper) {
127     var __method = this;
128     return function() {
129       return wrapper.apply(this, [__method.bind(this)].concat(Array.from(arguments)));
130     }
131   },
132   methodize: function() {
133     if (this._methodized) return this._methodized;
134     var __method = this;
135     return this._methodized = function() {
136       return __method.apply(null, [this].concat(Array.from(arguments)));
137     };
138   }
139 });
140 Object.extend(String.prototype, {
141   camelize: function(prefix, suffix) {
142     var parts = this.split('-');
143     if (prefix) parts.unshift(prefix);
144     if (suffix) parts.push(suffix);
145     var len = parts.length;
146     if (len == 1) return parts[0];
147 
148     var camelized = this.charAt(0) == '-'
149       ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
150       : parts[0];
151 
152     for (var i = 1; i < len; i++)
153       camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
154 
155     return camelized;
156   },
157   capitalize: function() {
158     return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
159   },
160   startsWith: function(pattern) {
161     return this.indexOf(pattern) === 0;
162   },
163   endsWith: function(pattern) {
164     var d = this.length - pattern.length;
165     return d >= 0 && this.lastIndexOf(pattern) === d;
166   },
167   empty: function() {
168     return this == '';
169   },
170   // TODO Remove this
171   times: function(count) {
172     return count < 1 ? '' : new Array(count + 1).join(this);
173   },
174   toJSON: function() {
175     // TODO Fix quotes...
176     return '\'' + this.toString().replace(/([\\'])/g, '\\$1') + '\'';
177   }
178 });
179 Object.extend(Number.prototype, {
180   toPaddedString: function(length, radix) {
181     var string = this.toString(radix || 10);
182     return '0'.times(length - string.length) + string;
183   },
184   toJSON: function() {
185     return isFinite(this) ? this.toString() : 'null';
186   }
187 });
188 Object.extend(Array.prototype, {
189   indexOf: function(object, from) {
190     var len = this.length;
191     from = from || 0;
192     for (var i = from; i < len; i++) {
193       if (this[i] === object) {
194         return i;
195       }
196     }
197     return -1;
198   },
199   remove: function(object) {
200     var index = 0;
201     if (typeof object == 'number') {
202       index = object;
203     } else {
204       index = this.indexOf(object);
205       if (index < 0) {
206         return null;
207       }
208     }
209     return this.splice(index, 1)[0];
210   },
211   toJSON: function() {
212     var results = [];
213     this.each(function(object) {
214       var value = Object.toJSON(object);
215       if (!Object.isUndefined(value)) results.push(value);
216     });
217     return '[' + results.join(', ') + ']';
218   }
219 });
220 Object.extend(Date.prototype, {
221   // TODO Fix UTC
222   toJSON: function() {
223     return '"' + this.getUTCFullYear() + '-' +
224       (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
225       this.getUTCDate().toPaddedString(2) + 'T' +
226       this.getUTCHours().toPaddedString(2) + ':' +
227       this.getUTCMinutes().toPaddedString(2) + ':' +
228       this.getUTCSeconds().toPaddedString(2) + 'Z"';
229   }
230 });
231 /**
232  * @class Class like creation with inheritance. Based on Alex Arnell's inheritance implementation.
233  */
234 jls.lang.Class = {/** @lends jls.lang.Class */
235     /**
236      * Creates a new class.
237      * 
238      * @param {Object} declaration An object containing the class declaration.
239      * @returns {Object} The new class.
240      */
241   create: function() {
242     var parent = null, properties = Array.from(arguments);
243     if (typeof properties[0] == "function")
244       parent = properties.shift();
245 
246     function klass() {
247       this.initialize.apply(this, arguments);
248     }
249 
250     Object.extend(klass, jls.lang.Class.Methods);
251     klass.superclass = parent;
252     klass.subclasses = [];
253 
254     if (parent) {
255       var subclass = function() { };
256       subclass.prototype = parent.prototype;
257       klass.prototype = new subclass;
258       parent.subclasses.push(klass);
259     }
260 
261     for (var i = 0; i < properties.length; i++)
262       klass.addMethods(properties[i]);
263 
264     if (!klass.prototype.initialize)
265       klass.prototype.initialize = jls.lang.Class.emptyFunction;
266 
267     klass.prototype.constructor = klass;
268 
269     return klass;
270   },
271   emptyFunction: function() { },
272   notAvailableFunction: function() {
273       throw new jls.lang.Exception('Function not available');
274   },
275   abstractMethod: function() {
276       throw new jls.lang.Exception('Abstract method');
277   },
278   // instantiate
279   newInstance: function(object) {
280     if (!(object && object.classname)) {
281       throw new jls.lang.Exception('Invalid object, the classname property is required');
282     }
283     var classname = object.classname;
284     jls.loader.require(classname);
285     /*var properties = Array.from(arguments);
286     var args = '';
287     for (var i = 0; i < properties.length; i++) {
288       if (i > 0) args += ', ';
289       args += 'properties[' + i + ']';
290     }*/
291     var args = 'object';
292     for (var i = 1; i < arguments.length; i++) {
293       args += ', arguments[' + i + ']';
294     }
295     //jls.logger.info('newInstance() : eval(\'new ' + classname + '(' + args + ')\')');
296     return eval('new ' + classname + '(' + args + ')');
297   }
298 };
299 /**
300  * @class Class helper.
301  */
302 jls.lang.Class.Methods = /** @lends jls.lang.Class.Methods */
303 {
304   addMethods: function(source) {
305     var ancestor   = this.superclass && this.superclass.prototype;
306     var properties = Object.keys(source);
307 
308     if (!Object.keys({ toString: true }).length)
309       properties.push("toString", "valueOf");
310 
311     for (var i = 0, length = properties.length; i < length; i++) {
312       var property = properties[i], value = source[property];
313       if (ancestor && (typeof value == 'function') &&
314           value.argumentNames()[0] == "$super") {
315         var method = value;
316         value = (function(m) {
317           return function() { return ancestor[m].apply(this, arguments) };
318         })(property).wrap(method);
319 
320         value.valueOf = method.valueOf.bind(method);
321         value.toString = method.toString.bind(method);
322       }
323       this.prototype[property] = value;
324     }
325 
326     return this;
327   }
328 };
329 /**
330  * @class Class bean helper.
331  */
332 jls.lang.Class.Bean = /** @lends jls.lang.Class.Bean */
333 {
334   set : function(key, value) {
335     var setter = key.camelize('set');
336     if (Object.isFunction(this[setter])) {
337       this[setter](value);
338     }
339     return this;
340   },
341   get : function(key) {
342     var getter = key.camelize('get');
343     if (Object.isFunction(this[getter])) {
344       return this[getter]();
345     }
346     return null;
347   },
348   setAll : function(values) {
349     for (var key in values) {
350       this.set(key, values[key]);
351     }
352     return this;
353   }
354 };
355 /* End prototype.js */
356 
357 // Load base classes
358 _native.core.evalScript('jls/lang/Exception.js');
359 _native.core.evalScript('jls/lang/Logger.js');
360 
361 /**
362  * Logger.
363  * 
364  * @type jls.lang.Logger
365  * @memberOf jls
366  */
367 jls.logger = new jls.lang.Logger(jls.lang.Logger.INFO);
368 
369 if ('jls.logger.logLevel' in _native.core.properties) {
370     jls.logger.setLogLevel(_native.core.properties['jls.logger.logLevel']);
371 }
372 
373 _native.core.evalScript('jls/lang/ClassLoader.js');
374 
375 /**
376  * ClassLoader.
377  * 
378  * @type jls.lang.ClassLoader
379  * @memberOf jls
380  */
381 jls.loader = new jls.lang.ClassLoader();
382 
383 // Register base classes
384 jls.loader.provide('jls.lang.Exception', true);
385 jls.loader.provide('jls.lang.Logger', true);
386 jls.loader.provide('jls.lang.ClassLoader', true);
387 
388 /*
389  * Add default namespaces
390  */
391 /**
392  * @namespace Provides graphical user interface.
393  * @see jls.gui.Element
394  */
395 jls.gui = {};
396 /**
397  * @namespace Provides for system input and output through data streams, serialization and the file system.
398  * @see jls.io.File
399  */
400 jls.io = {};
401 /**
402  * @namespace Provides character sets.
403  * @see jls.io.cs.Charset
404  */
405 jls.io.cs = {};
406 /**
407  * @namespace Provides JSUnit core classes.
408  * @see jls.jsunit.TestCase
409  */
410 jls.jsunit = {};
411 /**
412  * @namespace Provides the classes for implementing networking applications.
413  * @see jls.net.Socket
414  */
415 jls.net = {};
416 /**
417  * @namespace Provides HTTP classes.
418  * @see jls.net.http.ServerMgr
419  */
420 jls.net.http = {};
421 /**
422  * @namespace Provides utility classes for the jls language.
423  */
424 jls.util = {};
425 
426 /*
427  * Provide all lang classes
428  */
429 jls.loader.require('jls.lang.Buffer');
430 jls.loader.require('jls.lang.Process');
431 jls.loader.require('jls.lang.Runtime');
432 jls.loader.require('jls.lang.System');
433 
434 jls.lang.System._initialize();
435 
436 jls.loader.require('jls.lang.Thread');
437 jls.loader.require('jls.lang.Signal');
438 jls.loader.require('jls.lang.Lock');
439 jls.loader.require('jls.lang.Monitor');
440 //jls.loader.require('jls.lang.ProcessBuilder');
441 jls.loader.require('jls.lang.Struct');
442 //jls.loader.require('jls.lang.AssertionError');
443 
444 if ('jls.disableDefaultExceptionHandler' in _native.core.properties) {
445     jls.logger.info('Default exception handler disabled');
446 } else {
447     /*
448      * Override exception handler
449      */
450     _native.core.exceptionHandler = function(e) {
451         jls.lang.Exception.wrap(e).printStackTrace(jls.lang.System.err);
452     }
453 }
454 
455 if ('jls.disableDefaultSignalHandler' in _native.core.properties) {
456     jls.logger.info('Default signal handlers disabled');
457 } else {
458     /*
459      * Register default signal handlers.
460      */
461     jls.lang.Signal.handle(jls.lang.Signal.SIGINT, function() {
462         jls.lang.Runtime.exit(0);
463     });
464     /*
465      * Don't know how to dump javascript thread stacktraces
466      */
467     /*jls.lang.Signal.handle(jls.lang.Signal.SIGBREAK, function() {
468         //jls.lang.System.out.println('... Dump stack trace ...');
469         //new jls.lang.Exception().printStackTrace(jls.lang.System.out);
470         var name = 'jlsdump.' + new Date().getTime() + '.log';
471         jls.lang.System.out.println('... Dump head to ' + name + '...');
472         _native.core.dumpHead(name);
473     });*/
474 }
475 
476 if (_native.core.arguments.length > 0) {
477     var args = Array.from(_native.core.arguments);
478     var arg = args.shift();
479     
480     if ((arg == null) || (arg == '-help')) {
481         _native.core.boot = function() {
482             var lines = [
483                 'Usage: jls [options] classname [args...]',
484                 'where options include:',
485                 '\t-bs <bootstrap script file name>',
486                 '\t\tThe file name of the script to use for bootstrap.',
487                 '\t-ep <extension path>',
488                 '\t\tA directory to search for native library files,',
489                 '\t\tscript ZIP files and directories.',
490                 '\t-lp <library search path of directories>',
491                 '\t\tA ; separated list of directories to search for native library files.',
492                 '\t-sp <script search path of directories and ZIP files>',
493                 '\t\tA ; separated list of directories and ZIP archives',
494                 '\t\tto search for script files.',
495                 '\t-D<name>=<value>',
496                 '\t\tSet a system property.',
497                 '\t-logLevel <level>',
498                 '\t\tSet the native log level.',
499                 '\t--',
500                 '\t\tStop the jls options parsing.',
501                 'where system properties include:',
502                 '\t-Djls.logger.logLevel=<level>',
503                 '\t\tSet the log level.',
504                 '\t-Djls.disableDefaultExceptionHandler',
505                 '\t\tDisable uncaught exception default handler.',
506                 '\t-Djls.disableDefaultSignalHandler',
507                 '\t\tDisable default signal handlers.',
508                 '\t-Djls.keep',
509                 '\t\tWaits Ctrl-C if an exception occurs at boot phase.',
510                 '\t-Djls.interactive',
511                 '\t\tEnables interactive boot mode.',
512                 'See http://javalikescript.free.fr/ for more details.'
513             ];
514             for (var i = 0; i < lines.length; i++) {
515                 jls.lang.System.out.println(lines[i]);
516             }
517         }
518     } else if (! arg.endsWith('.js')) {
519         /*
520          * Override boot function
521          */
522         _native.core.boot = function() {
523             jls.loader.require(arg);
524             var mainclass = eval(arg);
525             if (! ('main' in mainclass)) {
526                 throw new jls.lang.Exception('The class ' + arg + ' does not have a main method.');
527             }
528             mainclass['main'](args);
529         };
530     }
531 } else {
532     if ('jls.interactive' in _native.core.properties) {
533         // TODO
534     }
535 }
536 
537 if ('jls.keep' in _native.core.properties) {
538     var previousBoot = _native.core.boot;
539     _native.core.boot = function() {
540         try {
541             previousBoot.apply(this, arguments);
542         } catch (e) {
543             jls.lang.System.err.println('Error during boot, hit ctrl-c to end.');
544             jls.lang.Exception.wrap(e).printStackTrace(jls.lang.System.err);
545             // Start an infinite non daemon thread
546             var thread = new jls.lang.Thread();
547             thread.run = function() {
548                 while (true) {
549                     jls.lang.Thread.sleep(500);
550                 }
551             };
552             thread.start();
553         }
554     };
555 }
556