KickJava   Java API By Example, From Geeks To Geeks.

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


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 /**
32  * Implementation class representing a JavaScript function.
33  */

34 public class ESClosure extends ESObject {
35   static ESString LENGTH = ESId.intern("length");
36   static ESString CALLEE = ESId.intern("callee");
37   static ESString ARGUMENTS = ESId.intern("arguments");
38   static ESString OBJECT = ESId.intern("Object");
39   static ESString PROTOTYPE = ESId.intern("prototype");
40   static ESString CONSTRUCTOR = ESId.intern("constructor");
41
42   public ESString name;
43   private ESCallable esClass;
44   public int n;
45
46   ESId []formals;
47   int nFormals;
48
49   ESBase proto;
50
51   ESGlobal global;
52   int stackRequired; // how much argument stack space this function requires
53
int scopeRequired; // how much scope space
54
ESBase []scope;
55   int scopeLength;
56
57   boolean hasFields;
58
59   public ESClosure(ESString name, ESCallable esClass, ESObject proto,
60                    int n, ESId []formals, ESObject global)
61   {
62     this.className = "Function";
63     this.prototype = Global.getGlobalProto().funProto;
64     this.name = name;
65     this.esClass = esClass;
66     this.proto = proto;
67     this.n = n;
68     this.formals = formals;
69     this.nFormals = formals.length;
70
71     if (global instanceof ESGlobal)
72       this.global = (ESGlobal) global;
73
74     if (global != null) {
75       this.scopeLength = 1;
76       this.scope = new ESBase[1];
77       this.scope[0] = global;
78     }
79   }
80
81   protected ESClosure(ESBase []scope, int scopeLength)
82   {
83     super("Function", null);
84
85     hasFields = true;
86     this.scope = scope;
87     this.scopeLength = scopeLength;
88   }
89   /**
90    * Create a new object based on a prototype
91    */

92   protected ESClosure() {}
93
94   public void closure(Call env)
95   {
96     if (scope == null) {
97       scope = new ESBase[16];
98     }
99
100     for (; scopeLength < env.scopeLength; scopeLength++)
101       scope[scopeLength] = env.scope[scopeLength];
102
103     if (scopeLength == 0)
104       scope[scopeLength++] = env.global;
105
106     global = (ESGlobal) scope[0];
107   }
108
109   /**
110    * Create a new object based on a prototype
111    */

112   void setScope(ESBase []scope, int scopeLength)
113   {
114     this.scope = scope;
115     this.scopeLength = scopeLength;
116   }
117
118   public ESBase hasProperty(ESString id)
119     throws Throwable JavaDoc
120   {
121     if (id.equals(PROTOTYPE)) {
122       if (proto == null) {
123         ESObject obj = Global.getGlobalProto().createObject();
124         proto = obj;
125         obj.put(CONSTRUCTOR, this, DONT_ENUM);
126       }
127
128       return proto;
129     } else if (id.equals(LENGTH)) {
130       return ESNumber.create(nFormals);
131     } else if (hasFields) {
132       return super.hasProperty(id);
133     } else if (prototype != null)
134       return prototype.hasProperty(id);
135     else
136       return ESBase.esEmpty;
137   }
138
139   public ESBase getProperty(ESString id)
140     throws Throwable JavaDoc
141   {
142     if (id.equals(PROTOTYPE)) {
143       if (proto == null) {
144         ESObject obj = Global.getGlobalProto().createObject();
145         proto = obj;
146         obj.put(CONSTRUCTOR, this, DONT_ENUM);
147       }
148
149       return proto;
150     } else if (id.equals(LENGTH)) {
151       return ESNumber.create(nFormals);
152     } else if (hasFields) {
153       return super.getProperty(id);
154     } else
155       return prototype.getProperty(id);
156   }
157
158   public boolean canPut(ESString id)
159   {
160     if (id.equals(PROTOTYPE)) {
161       return true;
162     } else if (id.equals(LENGTH)) {
163       return false;
164     } else if (hasFields) {
165       return super.canPut(id);
166     } else {
167       return true;
168     }
169   }
170
171   public void setProperty(ESString id, ESBase value)
172     throws Throwable JavaDoc
173   {
174     if (id.equals(PROTOTYPE)) {
175       proto = value;
176     } else if (id.equals(LENGTH)) {
177     } else if (hasFields) {
178       super.setProperty(id, value);
179     } else {
180       init(className, prototype);
181       hasFields = true;
182       super.setProperty(id, value);
183     }
184   }
185
186   public void put(ESString id, ESBase value, int flags)
187   {
188     if (id.equals(PROTOTYPE)) {
189       proto = value;
190     } else if (id.equals(LENGTH)) {
191     } else if (hasFields) {
192       super.put(id, value, flags);
193     } else {
194       init(className, prototype);
195       hasFields = true;
196       super.put(id, value, flags);
197     }
198   }
199
200   public ESBase delete(ESString id)
201     throws Throwable JavaDoc
202   {
203     if (id.equals(PROTOTYPE)) {
204       proto = ESBase.esEmpty;
205       return ESBoolean.TRUE;
206     } else if (id.equals(LENGTH)) {
207       return ESBoolean.FALSE;
208     } else if (hasFields) {
209       return super.delete(id);
210     } else
211       return ESBoolean.TRUE;
212   }
213
214   public ESString toStr()
215   {
216     return ESString.create(decompile());
217   }
218
219   String JavaDoc decompile()
220   {
221     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
222
223     sbuf.append("function ");
224     if (name != null && ! name.toString().startsWith("$lambda"))
225         sbuf.append(name);
226     sbuf.append("(");
227     for (int i = 0; formals != null && i < nFormals; i++) {
228       if (i != 0)
229         sbuf.append(", ");
230       sbuf.append(formals[i]);
231     }
232
233     sbuf.append(") ");
234
235     sbuf.append("{ ");
236     sbuf.append("[compiled code]");
237     sbuf.append(" }");
238
239     return sbuf.toString();
240   }
241
242   protected ESBase dispatch() throws ESException
243   {
244     throw new ESException("dispatch not specialized");
245   }
246
247   public ESBase call(Call call, int length) throws Throwable JavaDoc
248   {
249     if (global != null)
250       call.global = global;
251
252     if (esClass != null)
253       return esClass.call(n, call, length);
254     else
255       return ESBase.esUndefined;
256   }
257
258   public ESBase construct(Call eval, int length) throws Throwable JavaDoc
259   {
260     Global resin = Global.getGlobalProto();
261     ESObject obj = Global.getGlobalProto().createObject();
262     ESBase proto = this.proto;
263
264     if (! (proto instanceof ESObject))
265       proto = resin.object.getProperty(PROTOTYPE);
266
267     if (proto instanceof ESObject)
268       obj.prototype = proto;
269
270     eval.setThis(obj);
271
272     ESBase value = call(eval, length);
273
274     return value instanceof ESObject ? (ESObject) value : obj;
275   }
276
277   public ESBase typeof() throws ESException
278   {
279     return ESString.create("function");
280   }
281
282   protected void copy(Object JavaDoc newObj)
283   {
284     ESClosure closure = (ESClosure) newObj;
285
286     super.copy(newObj);
287
288     closure.name = name;
289     closure.esClass = esClass;
290     closure.n = n;
291     closure.formals = formals;
292     closure.nFormals = nFormals;
293
294     closure.stackRequired = stackRequired;
295     closure.scopeRequired = scopeRequired;
296     closure.scopeLength = scopeLength;
297     closure.scope = new ESBase[scopeLength];
298     closure.hasFields = hasFields;
299
300     for (int i = 0; i < scopeLength; i++) {
301       if (scope[i] != null) {
302         closure.scope[i] = (ESBase) scope[i];
303       }
304     }
305
306     closure.proto = proto; // XXX: should be copied?
307
}
308
309   public ESObject dup() { return new ESClosure(); }
310
311   ESObject resinCopy()
312   {
313     ESObject obj = dup();
314
315     copy(obj);
316
317     return obj;
318   }
319
320   ESObject getClassPrototype()
321     throws Throwable JavaDoc
322   {
323     ESBase proto = hasProperty(PROTOTYPE);
324
325     return (ESObject) proto;
326   }
327
328   void setClassPrototype(ESObject proto)
329     throws ESException
330   {
331     this.proto = proto;
332     proto.put(CONSTRUCTOR, this, DONT_ENUM);
333   }
334 }
335
Popular Tags