2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / NativeObject.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\r
3  * The contents of this file are subject to the Netscape Public\r
4  * License Version 1.1 (the "License"); you may not use this file\r
5  * except in compliance with the License. You may obtain a copy of\r
6  * the License at http://www.mozilla.org/NPL/\r
7  *\r
8  * Software distributed under the License is distributed on an "AS\r
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
10  * implied. See the License for the specific language governing\r
11  * rights and limitations under the License.\r
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\r
16  * The Initial Developer of the Original Code is Netscape\r
17  * Communications Corporation.  Portions created by Netscape are\r
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s):\r
22  * Norris Boyd\r
23  * Mike McCabe\r
24  *\r
25  * Alternatively, the contents of this file may be used under the\r
26  * terms of the GNU Public License (the "GPL"), in which case the\r
27  * provisions of the GPL are applicable instead of those above.\r
28  * If you wish to allow use of your version of this file only\r
29  * under the terms of the GPL and not to allow others to use your\r
30  * version of this file under the NPL, indicate your decision by\r
31  * deleting the provisions above and replace them with the notice\r
32  * and other provisions required by the GPL.  If you do not delete\r
33  * the provisions above, a recipient may use your version of this\r
34  * file under either the NPL or the GPL.\r
35  */\r
36 \r
37 package org.mozilla.javascript;\r
38 \r
39 import java.util.Hashtable;\r
40 \r
41 /**\r
42  * This class implements the Object native object.\r
43  * See ECMA 15.2.\r
44  * @author Norris Boyd\r
45  */\r
46 public class NativeObject extends IdScriptable {\r
47 \r
48     public static void init(Context cx, Scriptable scope, boolean sealed) {\r
49         NativeObject obj = new NativeObject();\r
50         obj.prototypeFlag = true;\r
51         obj.addAsPrototype(MAX_PROTOTYPE_ID, cx, scope, sealed);\r
52     }\r
53 \r
54     public String getClassName() {\r
55         return "Object";\r
56     }\r
57 \r
58     public int methodArity(int methodId) {\r
59         if (prototypeFlag) {\r
60             switch (methodId) {\r
61                 case Id_constructor:           return 1;\r
62                 case Id_toString:              return 0;\r
63                 case Id_toLocaleString:        return 0;\r
64                 case Id_valueOf:               return 0;\r
65                 case Id_hasOwnProperty:        return 1;\r
66                 case Id_propertyIsEnumerable:  return 1;\r
67                 case Id_isPrototypeOf:         return 1;\r
68             }\r
69         }\r
70         return super.methodArity(methodId);\r
71     }\r
72 \r
73     public Object execMethod\r
74         (int methodId, IdFunction f,\r
75          Context cx, Scriptable scope, Scriptable thisObj, Object[] args)\r
76         throws JavaScriptException\r
77     {\r
78         if (prototypeFlag) {\r
79             switch (methodId) {\r
80                 case Id_constructor:\r
81                     return jsConstructor(cx, args, f, thisObj == null);\r
82 \r
83                 case Id_toString:\r
84                     return jsFunction_toString(cx, thisObj);\r
85 \r
86                 case Id_toLocaleString:\r
87                     return jsFunction_toLocaleString(cx, thisObj);\r
88 \r
89                 case Id_valueOf:\r
90                     return jsFunction_valueOf(thisObj);\r
91 \r
92                 case Id_hasOwnProperty:\r
93                     return jsFunction_hasOwnProperty(thisObj, args);\r
94 \r
95                 case Id_propertyIsEnumerable:\r
96                     return jsFunction_propertyIsEnumerable(cx, thisObj, args);\r
97 \r
98                 case Id_isPrototypeOf:\r
99                     return jsFunction_isPrototypeOf(cx, thisObj, args);\r
100             }\r
101         }\r
102         return super.execMethod(methodId, f, cx, scope, thisObj, args);\r
103     }\r
104 \r
105     private static Object jsConstructor(Context cx, Object[] args,\r
106                                         Function ctorObj, boolean inNewExpr)\r
107         throws JavaScriptException\r
108     {\r
109         if (!inNewExpr) {\r
110             // FunctionObject.construct will set up parent, proto\r
111             return ctorObj.construct(cx, ctorObj.getParentScope(), args);\r
112         }\r
113         if (args.length == 0 || args[0] == null ||\r
114             args[0] == Undefined.instance)\r
115         {\r
116             return new NativeObject();\r
117         }\r
118         return ScriptRuntime.toObject(ctorObj.getParentScope(), args[0]);\r
119     }\r
120 \r
121     public String toString() {\r
122         Context cx = Context.getCurrentContext();\r
123         if (cx != null)\r
124             return jsFunction_toString(cx, this);\r
125         else\r
126             return "[object " + getClassName() + "]";\r
127     }\r
128 \r
129     private static String jsFunction_toString(Context cx, Scriptable thisObj)\r
130     {\r
131         if (cx.getLanguageVersion() != cx.VERSION_1_2)\r
132             return "[object " + thisObj.getClassName() + "]";\r
133 \r
134         return toSource(cx, thisObj);\r
135     }\r
136 \r
137     private static String jsFunction_toLocaleString(Context cx,\r
138                                                     Scriptable thisObj)\r
139     {\r
140         return jsFunction_toString(cx, thisObj);\r
141     }\r
142 \r
143     private static String toSource(Context cx, Scriptable thisObj)\r
144     {\r
145         Scriptable m = thisObj;\r
146 \r
147         if (cx.iterating == null)\r
148             cx.iterating = new Hashtable(31);\r
149 \r
150         if (cx.iterating.get(m) == Boolean.TRUE) {\r
151             return "{}";  // stop recursion\r
152         } else {\r
153             StringBuffer result = new StringBuffer("{");\r
154             Object[] ids = m.getIds();\r
155 \r
156             for(int i=0; i < ids.length; i++) {\r
157                 if (i > 0)\r
158                     result.append(", ");\r
159 \r
160                 Object id = ids[i];\r
161                 String idString = ScriptRuntime.toString(id);\r
162                 Object p = (id instanceof String)\r
163                     ? m.get((String) id, m)\r
164                     : m.get(((Number) id).intValue(), m);\r
165                 if (p instanceof String) {\r
166                     result.append(idString + ":\""\r
167                         + ScriptRuntime\r
168                           .escapeString(ScriptRuntime.toString(p))\r
169                         + "\"");\r
170                 } else {\r
171                     /* wrap changes to cx.iterating in a try/finally\r
172                      * so that the reference always gets removed, and\r
173                      * we don't leak memory.  Good place for weak\r
174                      * references, if we had them.\r
175                      */\r
176                     try {\r
177                         cx.iterating.put(m, Boolean.TRUE); // stop recursion.\r
178                         result.append(idString + ":" + ScriptRuntime.toString(p));\r
179                     } finally {\r
180                         cx.iterating.remove(m);\r
181                     }\r
182                 }\r
183             }\r
184             result.append('}');\r
185             return result.toString();\r
186         }\r
187     }\r
188 \r
189     private static Object jsFunction_valueOf(Scriptable thisObj) {\r
190         return thisObj;\r
191     }\r
192 \r
193     private static Object jsFunction_hasOwnProperty(Scriptable thisObj,\r
194                                                     Object[] args)\r
195     {\r
196         if (args.length != 0) {\r
197             if (thisObj.has(ScriptRuntime.toString(args[0]), thisObj))\r
198                 return Boolean.TRUE;\r
199         }\r
200         return Boolean.FALSE;\r
201     }\r
202 \r
203     private static Object jsFunction_propertyIsEnumerable(Context cx,\r
204                                                           Scriptable thisObj,\r
205                                                           Object[] args)\r
206     {\r
207         try {\r
208             if (args.length != 0) {\r
209                 String name = ScriptRuntime.toString(args[0]);\r
210                 if (thisObj.has(name, thisObj)) {\r
211                     int a = ((ScriptableObject)thisObj).getAttributes(name, thisObj);\r
212                     if ((a & ScriptableObject.DONTENUM) == 0)\r
213                         return Boolean.TRUE;\r
214                 }\r
215             }\r
216         }\r
217         catch (PropertyException x) {\r
218         }\r
219         catch (ClassCastException x) {\r
220         }\r
221         return Boolean.FALSE;\r
222     }\r
223 \r
224     private static Object jsFunction_isPrototypeOf(Context cx,\r
225                                                    Scriptable thisObj,\r
226                                                    Object[] args)\r
227     {\r
228         if (args.length != 0 && args[0] instanceof Scriptable) {\r
229             Scriptable v = (Scriptable) args[0];\r
230             do {\r
231                 v = v.getPrototype();\r
232                 if (v == thisObj)\r
233                     return Boolean.TRUE;\r
234             } while (v != null);\r
235         }\r
236         return Boolean.FALSE;\r
237     }\r
238 \r
239     protected String getIdName(int id) {\r
240         if (prototypeFlag) {\r
241             switch (id) {\r
242                 case Id_constructor:          return "constructor";\r
243                 case Id_toString:             return "toString";\r
244                 case Id_toLocaleString:       return "toLocaleString";\r
245                 case Id_valueOf:              return "valueOf";\r
246                 case Id_hasOwnProperty:       return "hasOwnProperty";\r
247                 case Id_propertyIsEnumerable: return "propertyIsEnumerable";\r
248                 case Id_isPrototypeOf:        return "isPrototypeOf";\r
249             }\r
250         }\r
251         return null;\r
252     }\r
253 \r
254 // #string_id_map#\r
255 \r
256     protected int mapNameToId(String s) {\r
257         if (!prototypeFlag) { return 0; }\r
258         int id;\r
259 // #generated# Last update: 2001-04-24 12:37:03 GMT+02:00\r
260         L0: { id = 0; String X = null; int c;\r
261             L: switch (s.length()) {\r
262             case 7: X="valueOf";id=Id_valueOf; break L;\r
263             case 8: X="toString";id=Id_toString; break L;\r
264             case 11: X="constructor";id=Id_constructor; break L;\r
265             case 13: X="isPrototypeOf";id=Id_isPrototypeOf; break L;\r
266             case 14: c=s.charAt(0);\r
267                 if (c=='h') { X="hasOwnProperty";id=Id_hasOwnProperty; }\r
268                 else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }\r
269                 break L;\r
270             case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; break L;\r
271             }\r
272             if (X!=null && X!=s && !X.equals(s)) id = 0;\r
273         }\r
274 // #/generated#\r
275         return id;\r
276     }\r
277 \r
278     private static final int\r
279         Id_constructor           = 1,\r
280         Id_toString              = 2,\r
281         Id_toLocaleString        = 3,\r
282         Id_valueOf               = 4,\r
283         Id_hasOwnProperty        = 5,\r
284         Id_propertyIsEnumerable  = 6,\r
285         Id_isPrototypeOf         = 7,\r
286         MAX_PROTOTYPE_ID         = 7;\r
287 \r
288 // #/string_id_map#\r
289 \r
290     private boolean prototypeFlag;\r
291 }\r