Reviewed by Darin.
[WebKit-https.git] / JavaScriptCore / kjs / object_object.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2008 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #include "config.h"
22 #include "object_object.h"
23
24 #include "JSGlobalObject.h"
25 #include "operations.h"
26 #include "function_object.h"
27 #include <stdio.h>
28
29 namespace KJS {
30
31 // ------------------------------ ObjectPrototype --------------------------------
32
33 static JSValue* objectProtoFuncValueOf(ExecState*, JSObject*, const List&);
34 static JSValue* objectProtoFuncHasOwnProperty(ExecState*, JSObject*, const List&);
35 static JSValue* objectProtoFuncIsPrototypeOf(ExecState*, JSObject*, const List&);
36 static JSValue* objectProtoFuncDefineGetter(ExecState*, JSObject*, const List&);
37 static JSValue* objectProtoFuncDefineSetter(ExecState*, JSObject*, const List&);
38 static JSValue* objectProtoFuncLookupGetter(ExecState*, JSObject*, const List&);
39 static JSValue* objectProtoFuncLookupSetter(ExecState*, JSObject*, const List&);
40 static JSValue* objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, const List&);
41 static JSValue* objectProtoFuncToLocaleString(ExecState*, JSObject*, const List&);
42 static JSValue* objectProtoFuncToString(ExecState*, JSObject*, const List&);
43
44 ObjectPrototype::ObjectPrototype(ExecState* exec, FunctionPrototype* functionPrototype)
45     : JSObject() // [[Prototype]] is null
46 {
47     static const Identifier* hasOwnPropertyPropertyName = new Identifier("hasOwnProperty");
48     static const Identifier* propertyIsEnumerablePropertyName = new Identifier("propertyIsEnumerable");
49     static const Identifier* isPrototypeOfPropertyName = new Identifier("isPrototypeOf");
50     static const Identifier* defineGetterPropertyName = new Identifier("__defineGetter__");
51     static const Identifier* defineSetterPropertyName = new Identifier("__defineSetter__");
52     static const Identifier* lookupGetterPropertyName = new Identifier("__lookupGetter__");
53     static const Identifier* lookupSetterPropertyName = new Identifier("__lookupSetter__");
54
55     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum);
56     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum);
57     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum);
58     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *hasOwnPropertyPropertyName, objectProtoFuncHasOwnProperty), DontEnum);
59     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *propertyIsEnumerablePropertyName, objectProtoFuncPropertyIsEnumerable), DontEnum);
60     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *isPrototypeOfPropertyName, objectProtoFuncIsPrototypeOf), DontEnum);
61
62     // Mozilla extensions
63     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 2, *defineGetterPropertyName, objectProtoFuncDefineGetter), DontEnum);
64     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 2, *defineSetterPropertyName, objectProtoFuncDefineSetter), DontEnum);
65     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *lookupGetterPropertyName, objectProtoFuncLookupGetter), DontEnum);
66     putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *lookupSetterPropertyName, objectProtoFuncLookupSetter), DontEnum);
67 }
68
69
70 // ------------------------------ Functions --------------------------------
71
72 // ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7
73
74 JSValue* objectProtoFuncValueOf(ExecState*, JSObject* thisObj, const List&)
75 {
76     return thisObj;
77 }
78
79 JSValue* objectProtoFuncHasOwnProperty(ExecState* exec, JSObject* thisObj, const List& args)
80 {
81     return jsBoolean(thisObj->hasOwnProperty(exec, Identifier(args[0]->toString(exec))));
82 }
83
84 JSValue* objectProtoFuncIsPrototypeOf(ExecState*, JSObject* thisObj, const List& args)
85 {
86     if (!args[0]->isObject())
87         return jsBoolean(false);
88
89     JSValue* v = static_cast<JSObject*>(args[0])->prototype();
90
91     while (true) {
92         if (!v->isObject())
93             return jsBoolean(false);
94         if (thisObj == static_cast<JSObject*>(v))\v
95             return jsBoolean(true);
96         v = static_cast<JSObject*>(v)->prototype();
97     }
98 }
99
100 JSValue* objectProtoFuncDefineGetter(ExecState* exec, JSObject* thisObj, const List& args)
101 {
102     if (!args[1]->isObject() || !static_cast<JSObject*>(args[1])->implementsCall())
103         return throwError(exec, SyntaxError, "invalid getter usage");
104
105     thisObj->defineGetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
106     return jsUndefined();
107 }
108
109 JSValue* objectProtoFuncDefineSetter(ExecState* exec, JSObject* thisObj, const List& args)
110 {
111     if (!args[1]->isObject() || !static_cast<JSObject*>(args[1])->implementsCall())
112         return throwError(exec, SyntaxError, "invalid setter usage");
113
114     thisObj->defineSetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
115     return jsUndefined();
116 }
117
118 JSValue* objectProtoFuncLookupGetter(ExecState* exec, JSObject* thisObj, const List& args)
119 {
120     Identifier propertyName = Identifier(args[0]->toString(exec));
121     JSObject* obj = thisObj;
122     while (true) {
123         JSValue* v = obj->getDirect(propertyName);
124         if (v) {
125             if (v->type() != GetterSetterType)
126                 return jsUndefined();
127             JSObject* funcObj = static_cast<GetterSetterImp*>(v)->getGetter();
128             if (!funcObj)
129                 return jsUndefined();
130             return funcObj;
131         }
132
133         if (!obj->prototype() || !obj->prototype()->isObject())
134             return jsUndefined();
135         obj = static_cast<JSObject*>(obj->prototype());
136     }
137 }
138
139 JSValue* objectProtoFuncLookupSetter(ExecState* exec, JSObject* thisObj, const List& args)
140 {
141     Identifier propertyName = Identifier(args[0]->toString(exec));
142     JSObject* obj = thisObj;
143     while (true) {
144         JSValue* v = obj->getDirect(propertyName);
145         if (v) {
146             if (v->type() != GetterSetterType)
147                 return jsUndefined();
148             JSObject* funcObj = static_cast<GetterSetterImp*>(v)->getSetter();
149             if (!funcObj)
150                 return jsUndefined();
151             return funcObj;
152         }
153
154         if (!obj->prototype() || !obj->prototype()->isObject())
155             return jsUndefined();
156         obj = static_cast<JSObject*>(obj->prototype());
157     }
158 }
159
160 JSValue* objectProtoFuncPropertyIsEnumerable(ExecState* exec, JSObject* thisObj, const List& args)
161 {
162     return jsBoolean(thisObj->propertyIsEnumerable(exec, Identifier(args[0]->toString(exec))));
163 }
164
165 JSValue* objectProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List&)
166 {
167     return jsString(thisObj->toString(exec));
168 }
169
170 JSValue* objectProtoFuncToString(ExecState*, JSObject* thisObj, const List&)
171 {
172     return jsString("[object " + thisObj->className() + "]");
173 }
174
175 // ------------------------------ ObjectObjectImp --------------------------------
176
177 ObjectObjectImp::ObjectObjectImp(ExecState* exec, ObjectPrototype* objProto, FunctionPrototype* funcProto)
178   : InternalFunctionImp(funcProto)
179 {
180   // ECMA 15.2.3.1
181   putDirect(exec->propertyNames().prototype, objProto, DontEnum|DontDelete|ReadOnly);
182
183   // no. of arguments for constructor
184   putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
185 }
186
187
188 bool ObjectObjectImp::implementsConstruct() const
189 {
190   return true;
191 }
192
193 // ECMA 15.2.2
194 JSObject* ObjectObjectImp::construct(ExecState* exec, const List& args)
195 {
196   JSValue* arg = args[0];
197   switch (arg->type()) {
198   case StringType:
199   case BooleanType:
200   case NumberType:
201   case ObjectType:
202       return arg->toObject(exec);
203   case NullType:
204   case UndefinedType:
205       return new JSObject(exec->lexicalGlobalObject()->objectPrototype());
206   default:
207       ASSERT_NOT_REACHED();
208       return 0;
209   }
210 }
211
212 JSValue* ObjectObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List &args)
213 {
214     return construct(exec, args);
215 }
216
217 } // namespace KJS