KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > es > NativeFunction


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.es;
30
31 import com.caucho.es.parser.Parser;
32 import com.caucho.vfs.ReadStream;
33 import com.caucho.vfs.Vfs;
34
35 import java.io.IOException JavaDoc;
36 import java.util.ArrayList JavaDoc;
37
38 /**
39  * JavaScript object
40  */

41 class NativeFunction extends Native {
42   static final int NEW = 1;
43   static final int TO_STRING = NEW + 1;
44   static final int CALL = TO_STRING + 1;
45   static final int APPLY = CALL + 1;
46
47   static ESId LENGTH = ESId.intern("length");
48
49   /**
50    * Create a new object based on a prototype
51    */

52   private NativeFunction(String JavaDoc name, int n, int len)
53   {
54     super(name, len);
55
56     this.n = n;
57   }
58
59   /**
60    * Creates the native Function object
61    *
62    * XXX: incomplete
63    */

64   static NativeWrapper create(Global resin)
65   {
66     ESBase []scope = new ESBase[] { resin.getGlobalProto() };
67     ESClosure funProto = new ESClosure(scope, 1);
68     funProto.name = ESId.intern("Function");
69
70     Native natFunction = new NativeFunction("Function", NEW, 1);
71     NativeWrapper function = new NativeWrapper(resin, natFunction,
72                            funProto, ESThunk.FUN_THUNK);
73     resin.funProto = funProto;
74     
75     put(funProto, "toString", TO_STRING, 0);
76     put(funProto, "call", CALL, 1);
77     put(funProto, "apply", APPLY, 2);
78     funProto.prototype = resin.objProto;
79
80     funProto.setClean();
81     function.setClean();
82
83     return function;
84   }
85
86   private static void put(ESObject proto, String JavaDoc name, int n, int len)
87   {
88     ESId id = ESId.intern(name);
89
90     proto.put(id, new NativeFunction(name, n, len), DONT_ENUM);
91   }
92
93   public ESBase call(Call eval, int length) throws Throwable JavaDoc
94   {
95     switch (n) {
96     case NEW:
97       return createAnonymous(eval, length);
98
99       // Object prototype stuff
100
case TO_STRING:
101       // XXX: Is this correct? Test.
102
if (eval.getThis() instanceof ESClosure) {
103     ESClosure closure = (ESClosure) eval.getThis();
104
105     return ESString.create(closure.decompile());
106       } else if (eval.getThis() instanceof NativeWrapper) {
107     NativeWrapper wrapper = (NativeWrapper) eval.getThis();
108
109     return wrapper.fun.toStr();
110       } else
111       throw new ESException("to string bound to function: " +
112               eval.getThis().getClass());
113
114     case CALL:
115       int oldTop = eval.top;
116       ESBase fun = eval.getArg(-1);
117       ESBase callThis = null;
118
119       try {
120     if (length > 0) {
121       callThis = eval.getArg(0);
122     } else
123       callThis = esNull;
124
125     if (callThis == esNull || callThis == esUndefined ||
126         callThis == esEmpty)
127       eval.setArg(0, eval.getGlobal());
128     else
129       eval.setArg(0, callThis.toObject());
130     eval.top++;
131
132     return fun.call(eval, length > 0 ? length - 1 : 0);
133       } finally {
134     eval.top = oldTop;
135       }
136
137     case APPLY:
138       return apply(eval, length);
139
140     default:
141       throw new ESException("Unknown object function");
142     }
143   }
144
145   /**
146    * Create a new parser instance.
147    */

148   private ESClosure parseFunction(Call eval, int length) throws Throwable JavaDoc
149   {
150     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
151
152     sbuf.append("function anonymous(");
153     ArrayList JavaDoc argList = new ArrayList JavaDoc();
154     for (int i = 0; i < length - 1; i++) {
155       if (i != 0)
156     sbuf.append(",");
157       String JavaDoc str = eval.getArg(i).toString();
158       int j = 0;
159       int p = 0;
160       
161       while ((p = str.indexOf(',', j)) >= 0 ||
162              (p = str.indexOf(' ', j)) >= 0) {
163         if (j < p)
164           argList.add(ESId.intern(str.substring(j, p)));
165         j = p + 1;
166       }
167       if (j < str.length())
168         argList.add(ESId.intern(str.substring(j)));
169       
170       sbuf.append(str);
171     }
172     ESId []args = new ESId[argList.size()];
173     argList.toArray(args);
174     sbuf.append("){");
175     if (length > 0)
176       sbuf.append(eval.getArg(length - 1).toString());
177     sbuf.append("}\n");
178     sbuf.append("return anonymous();");
179
180     Global resin = Global.getGlobalProto();
181     Script script = null;
182     try {
183       Parser parser = new Parser();
184       ReadStream is = Vfs.openString(sbuf.toString());
185       script = parser.parse(is, "anonymous", 1);
186       is.close();
187     } catch (IOException JavaDoc e) {
188       e.printStackTrace();
189     }
190
191     ESCallable jsClass = script.initClass(resin, eval.getGlobal());
192
193     // It's known that the function will be #2.
194
ESClosure fun = new ESClosure(ESId.intern("anonymous"), jsClass,
195                                   null, 2, args, eval.getGlobal());
196     
197     return fun;
198   }
199
200   private ESBase createAnonymous(Call eval, int length) throws Throwable JavaDoc
201   {
202     return parseFunction(eval, length);
203   }
204
205   private ESBase apply(Call eval, int length) throws Throwable JavaDoc
206   {
207     Global resin = Global.getGlobalProto();
208     Call call = eval.getCall();
209
210     call.top = 1;
211     call.global = eval.global;
212     call.caller = eval;
213
214     ESBase fun = eval.getArg(-1);
215     ESBase callThis = null;
216
217     if (length > 0) {
218       callThis = eval.getArg(0);
219     } else
220       callThis = esNull;
221
222     if (callThis == esNull || callThis == esUndefined ||
223     callThis == esEmpty)
224       call.setArg(-1, eval.getGlobal());
225     else
226       call.setArg(-1, callThis.toObject());
227
228     int j = 0;
229     for (int i = 1; i < length; i++) {
230       ESBase arg = eval.getArg(i);
231
232       if (arg == esNull || arg == esUndefined || arg == esEmpty)
233     continue;
234
235       ESBase arglen = arg.hasProperty(LENGTH);
236
237       if (arglen == null)
238     call.setArg(j++, arg);
239       else {
240     int len = arglen.toInt32();
241
242     if (j + len > call.stack.length - 2)
243       throw new ESException("stack overflow");
244
245     for (int k = 0; k < len; k++)
246       call.setArg(j++, arg.getProperty(ESString.create(k)));
247
248     if (len < 0)
249       call.setArg(j++, arg);
250       }
251     }
252
253     ESBase value = fun.call(call, j);
254
255     resin.freeCall(call);
256
257     return value;
258   }
259 }
260
Popular Tags