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