001 
002 /*
003  *  Descripter 1.0 - Java Script Engines
004  *  Copyright (C) 2010-2015  Jianjun Liu (J.J.Liu)
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 org.descripter.js.api;
021 
022 import java.lang.reflect.InvocationTargetException;
023 import java.lang.reflect.Method;
024 
025 import org.descripter.js.api.core.CArray;
026 import org.descripter.js.api.core.CObject;
027 import org.descripter.js.api.core.CRegExp;
028 
029 /**
030  * <p>Emulates script contexts of JavaScript codes.</p>
031  * 
032  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
033  * @since Descripter 1.0
034  */
035 public abstract class Script<W extends Script<?>> extends Objective<W> implements Runnable
036 {
037     /**
038      * <p>The containing function context.</p>
039      * @since Descripter 1.0
040      */
041     public final Function<?> function;
042 
043     /**
044      * <p>Constructs a script context of this type.</p>
045      * @param with The containing script context.
046      * @since Descripter 1.0
047      */
048     protected Script(W with) {
049         super(with);
050         this.function = with != null ? with.function : new Function<Core>((Core)this, (Global<?>)this) {
051             @Override
052             protected Functor<Core> functor() {
053                 return null;
054             }
055         };
056     }
057 
058     /**
059      * <p>Constructs a script context of this type.</p>
060      * @param function The containing function context.
061      * @since Descripter 1.0
062      */
063     protected Script(Function<W> function) {
064         super(function.with);
065         this.function = function;
066     }
067 
068     /**
069      * <p>Returns a string representation of the current object.</p>
070      * @return The string representation of the current object
071      * @since Descripter 1.0
072      */
073     @Override
074     public String toString() {
075         return "[Script object]";
076     }
077 
078     /**
079      * <p>Gets the engine {@link Core} of this {@link Script} context.</p>
080      * @return The engine {@link Core} of this {@link Script} context
081      * @since Descripter 1.0
082      */
083     public Core core() {
084         return function.core();
085     }
086 
087     /**
088      * <p>Allocates an object with the specified function object and arguments.</p>
089      * @param o A function object
090      * @param args An array of arguments
091      * @return The newly allocated object
092      * @since Descripter 1.0
093      */
094     public final CObject alloc(Object o, Object ...args) {
095         o = evaluate(o);
096         if (o instanceof Function<?>) {
097             return ((Function<?>)o).alloc(this, args);
098         }
099         throw new UnsupportedOperationException();
100     }
101 
102     /**
103      * <p>Calls the given function object with the specified arguments.</p>
104      * @param o A function object
105      * @param args An array of arguments
106      * @return The return result of the invocation
107      * @since Descripter 1.0
108      */
109     public final Object call(Object o, Object ...args) {
110         if (o instanceof Var) {
111             return ((Var)o).call(this, args);
112         }
113         o = evaluate(o);
114         if (o instanceof Function<?>) {
115             return ((Function<?>)o).call(this, function.in, array(args));
116         } else if (o instanceof Method &&
117                 Core.class.isAssignableFrom(((Method)o).getDeclaringClass())) {
118             try {
119                 return ((Method)o).invoke(core(), new Object[]{this, args});
120             } catch (IllegalArgumentException e) {
121                 throw new RuntimeException(e);
122             } catch (IllegalAccessException e) {
123                 throw new RuntimeException(e);
124             } catch (InvocationTargetException e) {
125                 throw new RuntimeException(e);
126             }
127         } else if (bnot(o)) {
128             return null;
129         }
130         throw new UnsupportedOperationException();
131     }
132 
133     /**
134      * <p>Checks if an object is instance of a function object.</p>
135      * @param o An object
136      * @param c A function object
137      * @return <tt>true</tt> if the object is instance of the function object; <tt>false</tt>, otherwise.
138      * @since Descripter 1.0
139      */
140     public final boolean instanceOf(Object o, Object c) {
141         o = evaluate(o);
142         if (o instanceof CObject) {
143             c = evaluate(c);
144             if (c instanceof Function<?>) {
145                 return ((CObject)o).with(((Function<?>)c).prototype());
146             }
147         }
148         return false;
149     }
150 
151     /**
152      * <p>Initializes and returns a {@link Var} specified by the given {@link Key}.</p>
153      * @param k The {@link Key} of the {@link Var} to initialize and get
154      * @return The {@link Var} specified by the {@link Key}
155      * @since Descripter 1.0
156      */
157     public final Var my(Key k) {
158         put(k, null);
159         return var(k);
160     }
161 
162     /**
163      * <p>Initializes and returns a {@link Var} specified by the given string key.</p>
164      * @param k The string key of the {@link Var} to initialize and get
165      * @return The {@link Var} specified by the string key
166      * @since Descripter 1.0
167      */
168     public final Var my(String k) {
169         return my(key(k));
170     }
171 
172     /**
173      * <p>Returns a {@link Var} specified by the given string key.</p>
174      * @param k The key of the {@link Var} to get
175      * @return The {@link Var} specified by the key
176      * @since Descripter 1.0
177      */
178     public final Var var(String k) {
179         return var(key(k));
180     }
181 
182     /**
183      * <p>Returns a {@link Var} specified by the given key.</p>
184      * @param o The key of the {@link Var} to get
185      * @return The {@link Var} specified by the key
186      * @since Descripter 1.0
187      */
188     public final Var var(Object o) {
189         if (o instanceof Key) {
190             return var((Key)o);
191         }
192         o = valueOf(o);
193         return o instanceof Key ? var((Key)o) :
194                o instanceof Integer ? var((Integer)o) : var(toString(o));
195     }
196 
197     /**
198      * <p>Returns a {@link Var} specified by the given key and based on an object.</p>
199      * @param o The base object of the {@link Var} to get
200      * @param k The key of the {@link Var} to get
201      * @return The {@link Var} specified by the key and based on the object
202      * @since Descripter 1.0
203      */
204     public final Var var(Object o, Key k) {
205         return object(o).var(k);
206     }
207 
208     /**
209      * <p>Returns a {@link Var} specified by the given string key and based on an object.</p>
210      * @param o The base object of the {@link Var} to get
211      * @param k The string key of the {@link Var} to get
212      * @return The {@link Var} specified by the string key and based on the object
213      * @since Descripter 1.0
214      */
215     public final Var var(Object o, String k) {
216         return object(o).var(key(k));
217     }
218 
219     /**
220      * <p>Returns a {@link Var} specified by the given key and based on an object.</p>
221      * @param o The base object of the {@link Var} to get
222      * @param p The key of the {@link Var} to get
223      * @return The {@link Var} specified by the key and based on the object
224      * @since Descripter 1.0
225      */
226     public final Var var(Object o, Object p) {
227         if (p instanceof Key) {
228             return var(o, (Key)p);
229         }
230         p = valueOf(p);
231         return p instanceof Key ? var(o, (Key)p) :
232                p instanceof Integer ? var(o, (Integer)p) : var(o, toString(p));
233     }
234 
235     /**
236      * <p>Sets the value associated with the specified key and returns the current 
237      * {@link Script} context.</p>
238      * @param k A {@link Key} to set the value
239      * @param o The value to set
240      * @return The current {@link Script} context
241      * @throws RuntimeException if the current context is read-only.
242      * @since Descripter 1.0
243      */
244     @Override
245     public final Script<W> set(Key k, Object o) {
246         in(k).put(k, o);
247         return this;
248     }
249 
250     /**
251      * <p>Sets the value associated with an {@link Objective} context and specified by a {@link Key}.</p>
252      * @param o An {@link Objective} context
253      * @param k A {@link Key} to set the value
254      * @param v The value to set
255      * @return The {@link Objective} context
256      * @throws RuntimeException if the {@link Objective} context is read-only.
257      * @since Descripter 1.0
258      */
259     public final Objective<?> set(Object o, Key k, Object v) {
260         return object(o).set(k, v);
261     }
262 
263     /**
264      * <p>Sets the value associated with an {@link Objective} context and specified by a string key.</p>
265      * @param o An {@link Objective} context
266      * @param k A string key to set the value
267      * @param v The value to set
268      * @return The {@link Objective} context
269      * @throws RuntimeException if the {@link Objective} context is read-only.
270      * @since Descripter 1.0
271      */
272     public final Objective<?> set(Object o, String k, Object v) {
273         return object(o).set(key(k), v);
274     }
275 
276     /**
277      * <p>Sets the value associated with an {@link Objective} context and specified by a key.</p>
278      * @param o An {@link Objective} context
279      * @param p A key to set the value
280      * @param v The value to set
281      * @return The {@link Objective} context
282      * @throws RuntimeException if the {@link Objective} context is read-only.
283      * @since Descripter 1.0
284      */
285     public final Objective<?> set(Object o, Object p, Object v) {
286         if (p instanceof Key) {
287             return set(o, (Key)p, v);
288         }
289         p = valueOf(p);
290         return p instanceof Key ? set(o, (Key)p, v) :
291                p instanceof Integer ? set(o, (Integer)p, v) : set(o, toString(p), v);
292     }
293 
294     /**
295      * <p>Returns a new array.</p>
296      * @return The newly created {@link CArray}
297      * @since Descripter 1.0
298      */
299     public final CArray array() {
300         return new CArray(core()._Array());
301     }
302 
303     /**
304      * <p>Returns a new array from a Java array.</p>
305      * @param array A Java array
306      * @return The newly created {@link CArray}
307      * @since Descripter 1.0
308      */
309     public final CArray array(Object[] array) {
310         return new CArray(core()._Array(), array);
311     }
312 
313     /**
314      * <p>Returns a new object.</p>
315      * @return The newly created {@link CObject}
316      * @since Descripter 1.0
317      */
318     public final CObject object() {
319         return new CObject(core()._Object());
320     }
321 
322     /**
323      * <p>Returns a new object from a specified object.</p>
324      * @param o An existing object
325      * @return The existing or newly created {@link Objective}
326      * @since Descripter 1.0
327      */
328     public final Objective<?> object(Object o) {
329         o = evaluate(o);
330         return o instanceof Objective<?> ? (Objective<?>)o : alloc(core()._Object(), o);
331     }
332 
333     /**
334      * <p>Creates a {@link CRegExp} object.</p>
335      * @param re A regular expression string
336      * @return The newly created {@link CRegExp} object
337      * @since Descripter 1.0
338      */
339     public final CRegExp re(String re) {
340         return new CRegExp(core()._RegExp(), re);
341     }
342 
343     /**
344      * <p>Creates a {@link CRegExp} object with flags.</p>
345      * @param regexp A regular expression string
346      * @param flags A string of flags for regular expression
347      * @return The newly created {@link CRegExp} object
348      * @since Descripter 1.0
349      */
350     public final CRegExp re(String regexp, String flags) {
351         return new CRegExp(core()._RegExp(), regexp, flags);
352     }
353 
354     /**
355      * <p>Locally evaluates a string as JavaScript code.</p>
356      * @param s A string of JavaScript code
357      * @return A result returned from evaluation of the piece of the code or <tt>null</tt> for none
358      * @since Descripter 1.0
359      */
360     public Object eval(String s) {
361         return call(get(core()._eval), s);
362     }
363 
364     /**
365      * <p>Locally evaluates the string value from a variable with the specified {@link Key} as JavaScript code.</p>
366      * @param k A {@link Key} of a variable specifying a string of JavaScript code
367      * @return A result returned from evaluation of the piece of the code or <tt>null</tt> for none
368      * @since Descripter 1.0
369      */
370     public final Object eval(Key k) {
371         return call(get(core()._eval), get(k));
372     }
373 
374     /**
375      * <p>Locally evaluates the string value from an object as JavaScript code.</p>
376      * @param o An object specifying a string of JavaScript code
377      * @return A result returned from evaluation of the piece of the code or <tt>null</tt> for none
378      * @since Descripter 1.0
379      */
380     public final Object eval(Object o) {
381         return call(get(core()._eval), evaluate(o));
382     }
383 
384     /**
385      * <p>Prints the arguments.</p>
386      * <p>This method prints the elements of <tt>args</tt> in lines.</p>
387      * @param args The arguments to print
388      * @return A result returned from calling the corresponding global service
389      * @since Descripter 1.0
390      */
391     public final Object print(Object ... args) {
392         return call(get(core()._print), args);
393     }
394 
395     /**
396      * <p>Locally compiles arguments with calling the corresponding native global service.</p>
397      * @param args The arguments to compile
398      * @return A result returned from calling the corresponding global service
399      * @since Descripter 1.0
400      */
401     public final Object compile(Object ... args) {
402         return call(get(core()._compile), args);
403     }
404 
405     /**
406      * <p>Locally descripts arguments with calling the corresponding native global service.</p>
407      * @param args The arguments to descript
408      * @return A result returned from calling the corresponding global service
409      * @since Descripter 1.0
410      */
411     public final Object descript(Object ... args) {
412         return call(get(core()._descript), args);
413     }
414 
415     /**
416      * <p>Locally executes arguments with calling the corresponding native global service.</p>
417      * @param args The arguments to execute
418      * @return A result returned from calling the corresponding global service
419      * @since Descripter 1.0
420      */
421     public final Object execute(Object ... args) {
422         return call(get(core()._execute), args);
423     }
424 
425     /**
426      * <p>An abstract base class for {@link Script} contexts without generic types.</p>
427      * 
428      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
429      * @since Descripter 1.0
430      */
431     public static abstract class MyScript extends Script<Script<?>>
432     {
433         /**
434          * <p>Constructs a script context of this type.</p>
435          * @param with The containing script context.
436          * @since Descripter 1.0
437          */
438         protected MyScript(Script<?> with) {
439             super(with);
440         }
441     }
442 
443     /**
444      * <p>An abstract base class of {@link Functor} without generic types.</p>
445      * 
446      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
447      * @since Descripter 1.0
448      */
449     public static abstract class MyFunctor extends Functor<Script<?>>
450     {
451         /**
452          * <p>Constructs a script context of this type.</p>
453          * @param with The containing script context.
454          * @since Descripter 1.0
455          */
456         protected MyFunctor(MyFunction with) {
457             super(with);
458         }
459     }
460 
461     /**
462      * <p>An abstract base class of {@link Function} without generic types.</p>
463      * 
464      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
465      * @since Descripter 1.0
466      */
467     public static abstract class MyFunction extends Function<Script<?>>
468     {
469         /**
470          * <p>Constructs a script context of this type.</p>
471          * @param with The containing script context.
472          * @since Descripter 1.0
473          */
474         protected MyFunction(Script<?> with) {
475             super(with);
476         }
477 
478         /**
479          * <p>Gets the {@link MyFunctor} of the {@link MyFunction} object.</p>
480          * <p>Subclasses need to concretely implement this method.</p>
481          * @return The {@link MyFunctor} of the {@link MyFunction} object
482          * @since Descripter 1.0
483          */
484         @Override
485         public abstract MyFunctor functor();
486     }
487 
488     /**
489      * <p>An abstract base class of {@link For} without generic types.</p>
490      * 
491      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
492      * @since Descripter 1.0
493      */
494     public static abstract class MyFor extends For<Script<?>>
495     {
496         /**
497          * <p>Constructs a script context of this type.</p>
498          * @param with The containing script context.
499          * @param base The base object to loop in
500          * @param key The {@link Key} of the looping variable
501          * @since Descripter 1.0
502          */
503         protected MyFor(Script<?> with, Object base, Key key) {
504             super(with, base, key);
505         }
506 
507         /**
508          * <p>Constructs a script context of this type.</p>
509          * @param with The containing script context.
510          * @param base The base object to loop in
511          * @param var A new looping {@link Var}
512          * @since Descripter 1.0
513          */
514         protected MyFor(Script<?> with, Object base, Var var) {
515             super(with, base, var);
516         }
517     }
518 }