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 org.descripter.js.api.core.CArray;
023 import org.descripter.js.api.core.CObject;
024 
025 /**
026  * <p>An abstract class of {@link Script} {@link Context}s to emulate function declaration in JavaScript.</p>
027  * 
028  * @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>
029  * @since Descripter 1.0
030  */
031 public abstract class Function<W extends Script<?>> extends CObject
032 {
033     /**
034      * <p>The parent {@link Script} {@link Context}.</p>
035      * @since Descripter 1.0
036      */
037     public final W with;
038     /**
039      * <p>The {@link Global} {@link Script} {@link Context}.</p>
040      * @since Descripter 1.0
041      */
042     public final Global<? extends Core> in;
043 
044     /**
045      * <p>Constructs a script context of this type.</p>
046      * @param with The containing script context.
047      * @param in The {@link Global} {@link Script} {@link Context}
048      * @since Descripter 1.0
049      */
050     protected Function(W with, Global<? extends Core> in) {
051         super(in.core()._Function());
052         this.with = with;
053         this.in   = in;
054         put(core()._constructor, constructor);
055         put(core()._prototype, core().object());
056     }
057 
058     /**
059      * <p>Constructs a script context of this type.</p>
060      * @param with The containing script context.
061      * @since Descripter 1.0
062      */
063     protected Function(W with) {
064         this(with, with.function.in);
065         put(core()._apply, new Function<W>(with, in) {
066             @Override
067             public Functor<W> functor() {
068                 return new Functor<W>(this) {
069                     @Override
070                     public Object function() {
071                         CArray arguments = arguments();
072                         return Function.this.call(this, arguments.get(0), (CArray)arguments.get(1));
073                     }
074                 };
075             }
076         });
077         put(core()._call, new Function<W>(with, in) {
078             @Override
079             public Functor<W> functor() {
080                 return new Functor<W>(this) {
081                     @Override
082                     public Object function() {
083                         CArray arguments = arguments();
084                         return Function.this.call(this, arguments.shift(), arguments);
085                     }
086                 };
087             }
088         });
089     }
090 
091     /**
092      * <p>Gets the engine core of this global script context.</p>
093      * @return The engine core of this global script context
094      * @since Descripter 1.0
095      */
096     @Override
097     public final Core core() {
098         return in.core();
099     }
100 
101     /**
102      * <p>Gets the <tt>apply</tt> member of the {@link Function} object.</p>
103      * @return The <tt>apply</tt> member of the {@link Function} object
104      * @since Descripter 1.0
105      */
106     public final Function<?> apply() {
107         return (Function<?>)get(core()._apply);
108     }
109 
110     /**
111      * <p>Gets the <tt>call</tt> member of the {@link Function} object.</p>
112      * @return The <tt>call</tt> member of the {@link Function} object
113      * @since Descripter 1.0
114      */
115     public final Function<?> call() {
116         return (Function<?>)get(core()._call);
117     }
118 
119     /**
120      * <p>Gets the <tt>prototype</tt> member of the {@link Function} object.</p>
121      * @return The <tt>prototype</tt> member of the {@link Function} object
122      * @since Descripter 1.0
123      */
124     public final CObject prototype() {
125         return (CObject)get(core()._prototype);
126     }
127 
128     /**
129      * <p>Gets the {@link Functor} of the {@link Function} object.</p>
130      * <p>Subclasses need to concretely implement this method.</p>
131      * @return The {@link Functor} of the {@link Function} object
132      * @since Descripter 1.0
133      */
134     protected abstract Functor<W> functor();
135 
136     /**
137      * <p>Allocates a new object with this {@link Function}.</p>
138      * @param script The script context that invoked this service
139      * @param args An array of the arguments passed by the invocation
140      * @return The newly allocated object
141      * @since Descripter 1.0
142      */
143     public <S extends Script<?>> CObject alloc(S script, Object ...args) {
144         CObject o = new CObject(this);
145         call(script, o, script.array(args));
146         return o;
147     }
148 
149     /**
150      * <p>Calls this {@link Function}.</p>
151      * @param script The script context that invoked this service
152      * @param base The base object used to invoke this {@link Function}
153      * @param args An array of the arguments passed by the invocation
154      * @return The return result of the invocation
155      * @since Descripter 1.0
156      */
157     public final <S extends Script<?>> Object call(S script, Object base, CArray args) {
158         Functor<?> f = functor();
159         f.put(core()._this, base);
160         f.put(core()._caller, script.function);
161         f.put(core()._arguments, args.set(core()._callee, this));
162         return f.function();
163     }
164 
165     /**
166      * <p>Returns a string representation of the current object.</p>
167      * @return The string representation of the current object
168      * @since Descripter 1.0
169      */
170     @Override
171     public final String toString() {
172         return "[Function object]";
173     }
174 }