001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package js;
021 
022 import js.core.*;
023 
024 /**
025  * <p>A <b>normal</b> class extended concretely to define a function object, resembling 
026  * function definition in JavaScript.</p>
027  * <p>Note that its enclosed classes and members except for {@link #function(Object, Call)} 
028  * are all <b>opaque</b>. Its subclasses and their members must be <b>normal</b>.</p>
029  *
030  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
031  */
032 
033 public abstract class Function<T> extends Var<JsFunction<T>>
034 {
035     /**
036      * <p>An <b>opaque</b> class used inside function definition resembling JavaScript 
037      * <tt>callee</tt> and <tt>caller</tt>.</p>
038      *
039      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
040      * 
041      * @javascript <b>Opaque</b> types can be resolved but no class objects for them can be 
042      * generated into the target codes. Re-compilers must exit with error on the operations of 
043      * accessing that kind of class objects.
044      */
045     protected static final class Call<T>
046     {
047         private final Function<T> var;
048         /**
049          * <p>The <tt>arguments</tt> field of the current <tt>callee</tt> or 
050          * <tt>caller</tt> instance.</p>
051          * @since 1.0
052          * @javascript Re-compilers must convert the access of this instance field directly 
053          * into a JavaScript expression of the field access to its current instance 
054          * without changing the field name. 
055          */
056         public final Arguments arguments;
057 
058         private Call(Function<T> var, Vars<?> args) {
059             this.var = var;
060             this.arguments = new Arguments(this, args);
061         }
062 
063         /**
064          * <p>Returns the function instance.</p>
065          * @return The function instance.
066          * @since 1.0
067          * @javascript Re-compilers must ignore the instance invocation of this method, that 
068          * is, replacing it with its current function instance.
069          */
070         public final Function<T> var() {
071             return var;
072         }
073 
074         /**
075          * <p>Invokes the current function instance.</p>
076          * @return The return value of the invocation.
077          * @since 1.0
078          * @javascript Re-compilers must convert the instance invocation of this method into 
079          * the JavaScript expression: 
080          * <pre>f()</pre>
081          * where <tt>f</tt> is the current instance of the invocation.
082          */
083         public final T invoke() {
084             return invoke(new Vars<Object>());
085         }
086 
087         /**
088          * <p>Invokes the current function instance, passing the specified argument.</p>
089          * @param arg The argument value.
090          * @return The return value of the invocation.
091          * @since 1.0
092          * @javascript Re-compilers must convert the instance invocation of this method into 
093          * the JavaScript expression: 
094          * <pre>f(arg)</pre>
095          * where <tt>f</tt> is the current instance of the invocation.
096          */
097         public final T invoke(Object arg) {
098             return invoke(new Vars<Object>().add(arg));
099         }
100 
101         /**
102          * <p>Invokes the current function instance, passing the specified arguments.</p>
103          * @param args The list of arguments.
104          * @return The return value of the invocation.
105          * @since 1.0
106          * @javascript Re-compilers must convert the instance invocation of this method into 
107          * the JavaScript expression: 
108          * <pre>f(args)</pre>
109          * where <tt>f</tt> is the current instance of this invocation and <tt>args</tt> 
110          * must be expanded into comma-separated arguments.
111          */
112         public final T invoke(Vars<?> args) {
113             return var.call(Js.core(), args);
114         }
115 
116         /**
117          * <p>Invokes the current function instance as a method of a specified scope object.</p>
118          * @param thisobj The scope object.
119          * @return The return value of the invocation.
120          * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
121          * is invoked with a scope object that is not a function. See {@link Js#err(Object)} 
122          * and {@link js.core.JsTypeError} for JS Simulation.
123          * @since 1.0
124          * @javascript Re-compilers must convert the instance invocation of this method 
125          * directly into a JavaScript invocation on its current instance without changing 
126          * the method name, but expanding variable arguments, if any, into comma-separated values. 
127          */
128         public final T call(Object thisobj) {
129             return call(thisobj, new Vars<Object>());
130         }
131 
132         /**
133          * <p>Invokes the current function instance as a method of a specified scope object, 
134          * passing the specified argument.</p>
135          * @param thisobj The scope object.
136          * @param arg The argument value.
137          * @return The return value of the invocation.
138          * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
139          * is invoked with a scope object that is not a function. See {@link Js#err(Object)} 
140          * and {@link js.core.JsTypeError} for JS Simulation.
141          * @since 1.0
142          * @javascript Re-compilers must convert the instance invocation of this method 
143          * directly into a JavaScript invocation on its current instance without changing 
144          * the method name, but expanding variable arguments, if any, into comma-separated values. 
145          */
146         public final T call(Object thisobj, Object arg) {
147             return call(thisobj, new Vars<Object>().add(arg));
148         }
149 
150         /**
151          * <p>Invokes the current function instance as a method of a specified scope object, 
152          * passing the specified arguments.</p>
153          * @param thisobj The scope object.
154          * @param args The list of arguments.
155          * @return The return value of the invocation.
156          * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
157          * is invoked with a scope object that is not a function. See {@link Js#err(Object)} 
158          * and {@link js.core.JsTypeError} for JS Simulation.
159          * @since 1.0
160          * @javascript Re-compilers must convert the instance invocation of this method 
161          * directly into a JavaScript invocation on its current instance without changing 
162          * the method name, but expanding variable arguments, if any, into comma-separated values. 
163          */
164         public final T call(Object thisobj, Vars<?> args) {
165             return var.call(thisobj, args);
166         }
167 
168         /**
169          * <p>Invokes the current function instance as a method of a specified scope object.</p>
170          * @param thisobj The scope object.
171          * @return The return value of the invocation.
172          * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
173          * is invoked with a scope object that is not a function. See {@link Js#err(Object)} 
174          * and {@link js.core.JsTypeError} for JS Simulation.
175          * @since 1.0
176          * @javascript Re-compilers must convert the instance invocation of this method 
177          * directly into a JavaScript invocation on its current instance without changing 
178          * the method name, but expanding variable arguments, if any, into comma-separated values. 
179          */
180         public final T apply(Object thisobj) {
181             return call(thisobj);
182         }
183 
184         /**
185          * <p>Invokes the current function instance as a method of a specified scope object, 
186          * passing the specified array of arguments.</p>
187          * @param thisobj The scope object.
188          * @param args The array of arguments.
189          * @return The return value of the invocation.
190          * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
191          * is invoked with a scope object that is not a function or if this method is invoked 
192          * with an argument that is not an array or {@link Arguments} object. See 
193          * {@link Js#err(Object)} and {@link js.core.JsTypeError} for JS Simulation.
194          * @since 1.0
195          * @javascript Re-compilers must convert the instance invocation of this method 
196          * directly into a JavaScript invocation on its current instance without changing 
197          * the method name, but expanding variable arguments, if any, into comma-separated values. 
198          */
199         public final T apply(Object thisobj, Object args) {
200             return call(thisobj, Js.s().vars(args));
201         }
202 
203         /**
204          * <p>Returns the string representing the current function instance.</p>
205          * @return A string representing the current function.
206          * @since 1.0
207          * @javascript Re-compilers must convert the instance invocation of this method 
208          * directly into a JavaScript invocation on its current instance without changing 
209          * the method name, but expanding variable arguments, if any, into comma-separated values. 
210          */
211         @Override
212         public final String toString() {
213             return var.toString();
214         }
215     }
216 
217     /**
218      * <p>An <b>opaque</b> class used inside function definition resembling JavaScript 
219      * arguments.</p>
220      *
221      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
222      * 
223      * @javascript <b>Opaque</b> types can be resolved but no class objects for them can be 
224      * generated into the target codes. Re-compilers must exit with error on the operations of 
225      * accessing that kind of class objects.
226      */
227     protected static final class Arguments implements ArrayObject<Object>
228     {
229         /**
230          * <p>A reference to the function that is currently executing.</p>
231          * @since 1.0
232          * @javascript Re-compilers must convert the access of this instance field directly 
233          * into a JavaScript expression of the field access to its current instance 
234          * without changing the field name. 
235          */
236         public final Call<?> callee;
237         private final Vars<?> vars;
238 
239         private Arguments(Call<?> callee, Vars<?> vars) {
240             this.callee = callee;
241             this.vars = vars;
242         }
243 
244         /**
245          * <p>Gets the size of the current arguments instance.</p>
246          * @return size of the arguments
247          * @since 1.0
248          * @javascript Re-compilers must convert the instance invocation of this method into 
249          * the JavaScript expression: 
250          * <pre>a.length</pre>
251          * where <tt>a</tt> is the current instance of the invocation.
252          */
253         public final int length() {
254             return vars.var().length();
255         }
256 
257         /**
258          * <p>Reads an element of the current arguments instance.</p>
259          * @param i Array index of the element
260          * @return value of the element
261          * @since 1.0
262          * @javascript Re-compilers must convert this instance invocation of this method into 
263          * the JavaScript expression: 
264          * <pre>a[i]</pre>
265          * where <tt>a</tt> is the current instance of the invocation.
266          */
267         public final Object get(int i) {
268             return vars.var().get(i);
269         }
270 
271         /**
272          * <p>Internally returns the variable-list version of the current arguments instance.</p>
273          * <p>This method is <b>internal</b> and only called inside of <b>opaque</b> or 
274          * <b>internal</b> classes or class members.</p>
275          * @return The variable argument list.
276          * @since 1.0
277          * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
278          */
279         public final Vars<?> var() {
280             return vars;
281         }
282 
283         /**
284          * <p>Returns the string representing the current arguments instance.</p>
285          * @return A string representing the current arguments.
286          * @since 1.0
287          * @javascript Re-compilers must convert the instance invocation of this method 
288          * directly into a JavaScript invocation on its current instance without changing 
289          * the method name, but expanding variable arguments, if any, into comma-separated values. 
290          */
291         @Override
292         public final String toString() {
293             return var().toString();
294         }
295     }
296 
297     private JsFunction<T> var;
298 
299     /**
300      * <p>Internally constructs a function object on an existed one.</p>
301      * <p>This constructor is <b>internal</b> and only called inside of <b>opaque</b> or 
302      * <b>internal</b> classes or class members.</p>
303      * @param f A function object
304      * @since 1.0
305      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> constructor. 
306      */
307     protected Function(Function<T> f) {
308         var = f == null ? null : f.var();
309     }
310     /**
311      * <p>Internally constructs a function object on an existed function.</p>
312      * <p>This constructor is <b>internal</b> and only called inside of <b>opaque</b> or 
313      * <b>internal</b> classes or class members.</p>
314      * @param var A function
315      * @since 1.0
316      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> constructor. 
317      */
318     protected Function(JsFunction<T> var) {
319         this.var = var;
320     }
321     /**
322      * <p>A default constructor to be extended to define a function object.</p>
323      * @since 1.0
324      */
325     protected Function() {
326     }
327 
328     /**
329      * <p>An abstract method to be concretely overridden to define the body of the function 
330      * of the current function object.</p>
331      * <p>The concrete overridden of this method is used to define the function body of 
332      * the current function object. Re-compilers use the body of the overridden method to 
333      * define the actual function of the current function object.</p>
334      * @param jsthis The scope object.
335      * @param callee The function calling this function.
336      * @return The return value of the function.
337      * @since 1.0
338      */
339     protected abstract T function(final Object jsthis, final Call<T> callee);
340 
341     /**
342      * <p>An <b>opaque</b> method to return the function of the current function object.</p>
343      * @return The function of the current function object.
344      * @see #valueOf()
345      * @since 1.0
346      * @javascript Re-compilers must ignore the instance invocation of this method, that is, 
347      * replacing it with the function of the current function object instance.
348      */
349     @Override
350     public final JsFunction<T> var() {
351         return var != null ? var : (var = Js.s().var(this));
352     }
353 
354     /**
355      * <p>Internally construct an object.</p>
356      * <p>This method is <b>internal</b> and only called inside of <b>opaque</b> or 
357      * <b>internal</b> classes or class members.</p>
358      * @param o The object argument
359      * @return The constructed object
360      * @since 1.0
361      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
362      */
363     protected JsObject construct(Object o) {
364         JsObject ret = JsGlobal.Object.with().create(o);
365         JsObject.constructor.with(ret, var());
366         JsFunction.prototype.with(ret, JsFunction.prototype.with(var()));
367         return ret;
368     }
369 
370     /**
371      * <p>An <b>opaque</b> method to construct an object with the function of the current 
372      * function object.</p>
373      * @return The newly constructed object.
374      * @since 1.0
375      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
376      * <pre>new f()</pre>
377      * where <tt>f</tt> is the function of the current function object instance of the 
378      * invocation.
379      */
380     public JsObject create() {
381         return construct(invoke());
382     }
383 
384     /**
385      * <p>An <b>opaque</b> method to construct an object with the function of the current 
386      * function object, passing the specified argument.</p>
387      * @param arg The argument value.
388      * @return The newly constructed object.
389      * @since 1.0
390      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
391      * <pre>new f(arg)</pre>
392      * where <tt>f</tt> is the function of the current function object instance of the 
393      * invocation.
394      */
395     public JsObject create(Object arg) {
396         return construct(invoke(arg));
397     }
398 
399     /**
400      * <p>An <b>opaque</b> method to construct an object with the function of the current 
401      * function object, passing the specified arguments.</p>
402      * @param args The list of arguments.
403      * @return The newly constructed object.
404      * @since 1.0
405      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
406      * <pre>new f(args)</pre>
407      * where <tt>f</tt> is the function of the current function object instance of the 
408      * invocation and <tt>args</tt> must be expanded into comma-separated arguments.
409      */
410     public JsObject create(Vars<?> args) {
411         return construct(invoke(args));
412     }
413 
414     /**
415      * <p>An <b>opaque</b> method to invoke the function of the current function object.</p>
416      * @return The return value of the invocation.
417      * @since 1.0
418      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
419      * <pre>f()</pre>
420      * where <tt>f</tt> is the function of the current function object instance of the 
421      * invocation.
422      */
423     public final T invoke() {
424         return invoke(new Vars<Object>());
425     }
426 
427     /**
428      * <p>An <b>opaque</b> method to invoke the function of the current function object, 
429      * passing the specified argument.</p>
430      * @param arg The argument value.
431      * @return The return value of the invocation.
432      * @since 1.0
433      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
434      * <pre>f(arg)</pre>
435      * where <tt>f</tt> is the function of the current function object instance of the 
436      * invocation.
437      */
438     public final T invoke(Object arg) {
439         return invoke(new Vars<Object>().add(arg));
440     }
441 
442     /**
443      * <p>An <b>opaque</b> method to invoke the function of the current function object, 
444      * passing the specified arguments.</p>
445      * @param args The list of arguments.
446      * @return The return value of the invocation.
447      * @since 1.0
448      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
449      * <pre>f(args)</pre>
450      * where <tt>f</tt> is the function of the current function object instance of the 
451      * invocation and <tt>args</tt> must be expanded into comma-separated arguments.
452      */
453     public final T invoke(Vars<?> args) {
454         return call(Js.core(), args);
455     }
456 
457     /**
458      * <p>An <b>opaque</b> method to invoke the function of the current function object as 
459      * a method of a specified scope object.</p>
460      * @param thisobj The scope object.
461      * @return The return value of the invocation.
462      * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
463      * is invoked with a scope object that is not a function or if this method is invoked 
464      * with an argument that is not an array or {@link Arguments} object. See 
465      * {@link Js#err(Object)} and {@link js.core.JsTypeError} for JS Simulation.
466      * @since 1.0
467      * @javascript Re-compilers must convert the instance invocation of this method directly 
468      * into a JavaScript invocation on the function of the current function object instance 
469      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
470      */
471     public final T call(Object thisobj) {
472         return call(thisobj, new Vars<Object>());
473     }
474 
475     /**
476      * <p>An <b>opaque</b> method to invoke the function of the current function object as 
477      * a method of a specified scope object, passing the specified argument.</p>
478      * @param thisobj The scope object.
479      * @param arg The argument value.
480      * @return The return value of the invocation.
481      * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
482      * is invoked with a scope object that is not a function or if this method is invoked 
483      * with an argument that is not an array or {@link Arguments} object. See 
484      * {@link Js#err(Object)} and {@link js.core.JsTypeError} for JS Simulation.
485      * @since 1.0
486      * @javascript Re-compilers must convert the instance invocation of this method directly 
487      * into a JavaScript invocation on the function of the current function object instance 
488      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
489      */
490     public final T call(Object thisobj, Object arg) {
491         return call(thisobj, new Vars<Object>().add(arg));
492     }
493 
494     /**
495      * <p>An <b>opaque</b> method to invoke the function of the current function object as 
496      * a method of a specified scope object, passing the specified arguments.</p>
497      * @param thisobj The scope object.
498      * @param args The list of arguments.
499      * @return The return value of the invocation.
500      * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
501      * is invoked with a scope object that is not a function or if this method is invoked 
502      * with an argument that is not an array or {@link Arguments} object. See 
503      * {@link Js#err(Object)} and {@link js.core.JsTypeError} for JS Simulation.
504      * @since 1.0
505      * @javascript Re-compilers must convert the instance invocation of this method directly 
506      * into a JavaScript invocation on the function of the current function object instance 
507      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
508      */
509     public final T call(Object thisobj, Vars<?> args) {
510         Call<T> callee = new Call<T>(this, args);
511         T r = function(thisobj, callee);
512         return r;
513     }
514 
515     /**
516      * <p>An <b>opaque</b> method to invoke the function of the current function object as 
517      * a method of a specified scope object.</p>
518      * @param thisobj The scope object.
519      * @return The return value of the invocation.
520      * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
521      * is invoked with a scope object that is not a function. See {@link Js#err(Object)} 
522      * and {@link js.core.JsTypeError} for JS Simulation.
523      * @since 1.0
524      * @javascript Re-compilers must convert the instance invocation of this method directly 
525      * into a JavaScript invocation on the function of the current function object instance 
526      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
527      */
528     public final T apply(Object thisobj) {
529         return call(thisobj);
530     }
531 
532     /**
533      * <p>An <b>opaque</b> method to invoke the function of the current function object as 
534      * a method of a specified scope object, passing the specified array of arguments.</p>
535      * @param thisobj The scope object.
536      * @param args The array of arguments.
537      * @return The return value of the invocation.
538      * @throws RuntimeException JavaScript throws a <tt>TypeError</tt> if this method 
539      * is invoked with a scope object that is not a function or if this method is invoked 
540      * with an argument that is not an array or {@link Arguments} object. See 
541      * {@link Js#err(Object)} and {@link js.core.JsTypeError} for JS Simulation.
542      * @since 1.0
543      * @javascript Re-compilers must convert the instance invocation of this method directly 
544      * into a JavaScript invocation on the function of the current function object instance 
545      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
546      */
547     public final T apply(Object thisobj, Object args) {
548         return call(thisobj, Js.s().vars(args));
549     }
550 
551     /**
552      * <p>An <b>opaque</b> method to return the string representing the function of the 
553      * current function object.</p>
554      * @return A string representing the function of the current function object.
555      * @since 1.0
556      * @javascript Re-compilers must convert the instance invocation of this method directly 
557      * into a JavaScript invocation on the function of the current function object instance 
558      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
559      */
560     @Override
561     public String toString() {
562         return "function() {\r\n    [native code]\r\n}";
563     }
564 
565     /**
566      * <p>An <b>opaque</b> method to return a string indicating the data-type of the 
567      * function of the current function object.</p>
568      * <p>Simulating the JavaScript <tt>typeof</tt> operator and <tt>typeof()</tt> 
569      * function, this invocation evaluates to "number", "string", or "boolean" if the current 
570      * instance is a number, string, or boolean value. It evaluates to "object" for objects, 
571      * arrays. It evaluates to "function" for function instance and to "undefined" if the 
572      * current instance is undefined.</p>
573      * @return A string indicating the data-type of the function of the current function object.
574      * @see #valueOf()
575      * @see #undefined()
576      * @since 1.0
577      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
578      * <pre>typeof f</pre>
579      * where <tt>f</tt> is the function of the current function object instance of the 
580      * invocation.
581      */
582     @Override
583     public final String typeof() {
584         return "function";
585     }
586 
587     /**
588      * <p>An <b>opaque</b> method to check if the function of the current function object 
589      * is undefined.</p>
590      * @return <tt>true</tt> if the function of the current function object is 
591      * undefined; <tt>false</tt> otherwise.
592      * @see #valueOf()
593      * @see #undefined()
594      * @since 1.0
595      * @javascript Re-compilers must convert this instance invocation into the JavaScript expression: 
596      * <pre>f===undefined</pre>
597      * where <tt>f</tt> is the function of the current function object instance of the 
598      * invocation.
599      */
600     @Override
601     public final boolean undefined() {
602         return false;
603     }
604 
605     /**
606      * <p>An <b>opaque</b> method to return the primitive value associated with the function 
607      * of the current function object, if there is one.</p>
608      * <p>This invocation simply returns the function of the current function object, since 
609      * there is no primitive value for a function.</p>
610      * @return The function of the current function object.
611      * @see #toString()
612      * @since 1.0
613      * @javascript Re-compilers must convert the instance invocation of this method directly 
614      * into a JavaScript invocation on the function of the current function object instance 
615      * without changing the method name, but expanding variable arguments, if any, into comma-separated values. 
616      */
617     @Override
618     public final JsFunction<T> valueOf() {
619         return var();
620     }
621 }