KJS

object_object.cpp
1 // krazy:excludeall=doublequote_chars (UStrings aren't QStrings)
2 /*
3  * This file is part of the KDE libraries
4  * Copyright (C) 1999-2000 Harri Porten ([email protected])
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 "object_object.h"
23 
24 #include "operations.h"
25 #include "function_object.h"
26 #include "propertydescriptor.h"
27 #include <stdio.h>
28 
29 namespace KJS
30 {
31 
38 class ObjectObjectFuncImp : public InternalFunctionImp
39 {
40 public:
41  ObjectObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier &);
42 
43  virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
44 
45  enum { GetOwnPropertyDescriptor, DefineProperty, GetPrototypeOf,
46  GetOwnPropertyNames, Keys, DefineProperties, Create, IsExtensible,
47  PreventExtensible, IsSealed, Seal, IsFrozen, Freeze,
48  //ES6
49  Is
50  };
51 
52 private:
53  int id;
54 };
55 
56 // ------------------------------ ObjectPrototype --------------------------------
57 
58 ObjectPrototype::ObjectPrototype(ExecState *exec, FunctionPrototype *funcProto)
59  : JSObject() // [[Prototype]] is null
60 {
61  static const Identifier *hasOwnPropertyPropertyName = new Identifier("hasOwnProperty");
62  static const Identifier *propertyIsEnumerablePropertyName = new Identifier("propertyIsEnumerable");
63  static const Identifier *isPrototypeOfPropertyName = new Identifier("isPrototypeOf");
64  static const Identifier *defineGetterPropertyName = new Identifier("__defineGetter__");
65  static const Identifier *defineSetterPropertyName = new Identifier("__defineSetter__");
66  static const Identifier *lookupGetterPropertyName = new Identifier("__lookupGetter__");
67  static const Identifier *lookupSetterPropertyName = new Identifier("__lookupSetter__");
68 
69  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum);
70  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ToLocaleString, 0, exec->propertyNames().toLocaleString), DontEnum);
71  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ValueOf, 0, exec->propertyNames().valueOf), DontEnum);
72  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::HasOwnProperty, 1, *hasOwnPropertyPropertyName), DontEnum);
73  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::PropertyIsEnumerable, 1, *propertyIsEnumerablePropertyName), DontEnum);
74  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::IsPrototypeOf, 1, *isPrototypeOfPropertyName), DontEnum);
75 
76  // Mozilla extensions
77  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::DefineGetter, 2, *defineGetterPropertyName), DontEnum);
78  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::DefineSetter, 2, *defineSetterPropertyName), DontEnum);
79  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::LookupGetter, 1, *lookupGetterPropertyName), DontEnum);
80  putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::LookupSetter, 1, *lookupSetterPropertyName), DontEnum);
81 }
82 
83 JSObject *ObjectPrototype::self(ExecState *exec)
84 {
85  return exec->lexicalInterpreter()->builtinObjectPrototype();
86 }
87 
88 // ------------------------------ ObjectProtoFunc --------------------------------
89 
90 ObjectProtoFunc::ObjectProtoFunc(ExecState *exec, FunctionPrototype *funcProto, int i, int len, const Identifier &name)
91  : InternalFunctionImp(funcProto, name)
92  , id(i)
93 {
94  putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum);
95 }
96 
97 // ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7
98 
99 JSValue *ObjectProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
100 {
101  switch (id) {
102  case ValueOf:
103  return thisObj;
104  case HasOwnProperty: {
105  PropertySlot slot;
106  return jsBoolean(thisObj->getOwnPropertySlot(exec, Identifier(args[0]->toString(exec)), slot));
107  }
108  case IsPrototypeOf: {
109  if (!args[0]->isObject()) {
110  return jsBoolean(false);
111  }
112 
113  JSValue *v = static_cast<JSObject *>(args[0])->prototype();
114 
115  while (true) {
116  if (!v->isObject()) {
117  return jsBoolean(false);
118  }
119 
120  if (thisObj == static_cast<JSObject *>(v))
121  return jsBoolean(true);
122 
123  v = static_cast<JSObject *>(v)->prototype();
124  }
125  }
126  case DefineGetter:
127  case DefineSetter: {
128  if (!args[1]->isObject() ||
129  !static_cast<JSObject *>(args[1])->implementsCall()) {
130  if (id == DefineGetter) {
131  return throwError(exec, SyntaxError, "invalid getter usage");
132  } else {
133  return throwError(exec, SyntaxError, "invalid setter usage");
134  }
135  }
136 
137  if (id == DefineGetter) {
138  thisObj->defineGetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
139  } else {
140  thisObj->defineSetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
141  }
142  return jsUndefined();
143  }
144  case LookupGetter:
145  case LookupSetter: {
146  Identifier propertyName = Identifier(args[0]->toString(exec));
147 
148  JSObject *obj = thisObj;
149  while (true) {
150  JSValue *v = obj->getDirect(propertyName);
151 
152  if (v) {
153  if (v->type() != GetterSetterType) {
154  return jsUndefined();
155  }
156 
157  JSObject *funcObj;
158 
159  if (id == LookupGetter) {
160  funcObj = static_cast<GetterSetterImp *>(v)->getGetter();
161  } else {
162  funcObj = static_cast<GetterSetterImp *>(v)->getSetter();
163  }
164 
165  if (!funcObj) {
166  return jsUndefined();
167  } else {
168  return funcObj;
169  }
170  }
171 
172  if (!obj->prototype() || !obj->prototype()->isObject()) {
173  return jsUndefined();
174  }
175 
176  obj = static_cast<JSObject *>(obj->prototype());
177  }
178  }
179  case PropertyIsEnumerable:
180  return jsBoolean(thisObj->propertyIsEnumerable(exec, Identifier(args[0]->toString(exec))));
181  case ToLocaleString:
182  return jsString(thisObj->toString(exec));
183  case ToString:
184  default:
185  return jsString("[object " + thisObj->className() + "]");
186  }
187 }
188 
189 // ------------------------------ ObjectObjectImp --------------------------------
190 
191 ObjectObjectImp::ObjectObjectImp(ExecState *exec, ObjectPrototype *objProto, FunctionPrototype *funcProto)
192  : InternalFunctionImp(funcProto)
193 {
194  static const Identifier *getOwnPropertyDescriptorName = new Identifier("getOwnPropertyDescriptor");
195  static const Identifier *createName = new Identifier("create");
196  static const Identifier *definePropertyName = new Identifier("defineProperty");
197  static const Identifier *definePropertiesName = new Identifier("defineProperties");
198  static const Identifier *getPrototypeOf = new Identifier("getPrototypeOf");
199  static const Identifier *getOwnPropertyNames = new Identifier("getOwnPropertyNames");
200  static const Identifier *sealName = new Identifier("seal");
201  static const Identifier *freezeName = new Identifier("freeze");
202  static const Identifier *preventExtensionsName = new Identifier("preventExtensions");
203  static const Identifier *isSealedName = new Identifier("isSealed");
204  static const Identifier *isFrozenName = new Identifier("isFrozen");
205  static const Identifier *isExtensibleName = new Identifier("isExtensible");
206  static const Identifier *keys = new Identifier("keys");
207  static const Identifier* isName = new Identifier("is");
208 
209  // ECMA 15.2.3.1
210  putDirect(exec->propertyNames().prototype, objProto, DontEnum | DontDelete | ReadOnly);
211 
212  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::GetOwnPropertyDescriptor, 2, *getOwnPropertyDescriptorName), DontEnum);
213  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Create, 2, *createName), DontEnum);
214  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::DefineProperty, 3, *definePropertyName), DontEnum);
215  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::DefineProperties, 2, *definePropertiesName), DontEnum);
216  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::GetPrototypeOf, 1, *getPrototypeOf), DontEnum);
217  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::GetOwnPropertyNames, 1, *getOwnPropertyNames), DontEnum);
218  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Seal, 1, *sealName), DontEnum);
219  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Freeze, 1, *freezeName), DontEnum);
220  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::PreventExtensible, 1, *preventExtensionsName), DontEnum);
221  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::IsSealed, 1, *isSealedName), DontEnum);
222  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::IsFrozen, 1, *isFrozenName), DontEnum);
223  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::IsExtensible, 1, *isExtensibleName), DontEnum);
224  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Keys, 1, *keys), DontEnum);
225  //ES6
226  putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Is, 2, *isName), DontEnum);
227 
228  // no. of arguments for constructor
229  putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
230 }
231 
232 bool ObjectObjectImp::implementsConstruct() const
233 {
234  return true;
235 }
236 
237 // ECMA 15.2.2
238 JSObject *ObjectObjectImp::construct(ExecState *exec, const List &args)
239 {
240  JSValue *arg = args[0];
241  switch (arg->type()) {
242  case StringType:
243  case BooleanType:
244  case NumberType:
245  case ObjectType:
246  return arg->toObject(exec);
247  case NullType:
248  case UndefinedType:
249  return new JSObject(exec->lexicalInterpreter()->builtinObjectPrototype());
250  default:
251  //### ASSERT_NOT_REACHED();
252  return nullptr;
253  }
254 }
255 
256 JSValue *ObjectObjectImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
257 {
258  return construct(exec, args);
259 }
260 
261 // ------------------------------ ObjectObjectFuncImp ----------------------------
262 
263 ObjectObjectFuncImp::ObjectObjectFuncImp(ExecState *exec, FunctionPrototype *funcProto, int i, int len, const Identifier &name)
264  : InternalFunctionImp(funcProto, name), id(i)
265 {
266  putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum);
267 }
268 
269 static JSValue *defineProperties(ExecState *exec, JSObject *object, JSValue *properties)
270 {
271  JSObject *props = properties->toObject(exec);
272  if (exec->hadException()) {
273  return object;
274  }
275  PropertyNameArray names;
276  props->getOwnPropertyNames(exec, names, PropertyMap::ExcludeDontEnumProperties);
277  int size = names.size();
278  Vector<PropertyDescriptor> descriptors;
279  for (int i = 0; i < size; ++i) {
280  PropertyDescriptor desc;
281  if (!desc.setPropertyDescriptorFromObject(exec, props->get(exec, names[i]))) {
282  return jsUndefined();
283  }
284  descriptors.append(desc);
285  }
286  for (int i = 0; i < size; ++i) {
287  object->defineOwnProperty(exec, names[i], descriptors[i], true);
288  if (exec->hadException()) {
289  return jsUndefined();
290  }
291  }
292  return object;
293 }
294 
295 JSValue *ObjectObjectFuncImp::callAsFunction(ExecState *exec, JSObject *, const List &args)
296 {
297  switch (id) {
298  case GetPrototypeOf: { //ECMA Edition 5.1r6 - 15.2.3.2
299  JSObject *jso = args[0]->getObject();
300  if (!jso) {
301  return throwError(exec, TypeError, "Not an Object");
302  }
303  return jso->prototype();
304  }
305  case GetOwnPropertyDescriptor: { //ECMA Edition 5.1r6 - 15.2.3.3
306  JSObject *jso = args[0]->getObject();
307  if (!jso) {
308  return throwError(exec, TypeError, "Not an Object");
309  }
310 
311  UString name = args[1]->toString(exec);
312  PropertyDescriptor desc;
313  if (!jso->getOwnPropertyDescriptor(exec, Identifier(name), desc)) {
314  return jsUndefined();
315  }
316  return desc.fromPropertyDescriptor(exec);
317  }
318  case GetOwnPropertyNames: //ECMA Edition 5.1r6 - 15.2.3.4
319  case Keys: { //ECMA Edition 5.1r6 - 15.2.3.14
320  JSObject *jso = args[0]->getObject();
321  if (!jso) {
322  return throwError(exec, TypeError, "Not an Object");
323  }
324 
325  JSObject *ret = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
326  PropertyNameArray propertyNames;
327 
328  if (id == Keys) {
329  jso->getOwnPropertyNames(exec, propertyNames, PropertyMap::ExcludeDontEnumProperties);
330  } else { // id == GetOwnPropertyNames
331  jso->getOwnPropertyNames(exec, propertyNames, PropertyMap::IncludeDontEnumProperties);
332  }
333  PropertyNameArrayIterator propEnd = propertyNames.end();
334  unsigned int n = 0;
335  for (PropertyNameArrayIterator propIter = propertyNames.begin(); propIter != propEnd; ++propIter) {
336  Identifier name = *propIter;
337  ret->put(exec, n, jsString(name.ustring()), None);
338  ++n;
339  }
340  ret->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
341  return ret;
342  }
343  case Create: { //ECMA Edition 5.1r6 - 15.2.3.5
344  JSObject *proto = args[0]->getObject();
345  if (!proto && !args[0]->isNull()) {
346  return throwError(exec, TypeError, "Not an Object");
347  }
348 
349  JSObject *ret = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty()));
350  if (proto) {
351  ret->setPrototype(proto);
352  } else {
353  ret->setPrototype(jsNull());
354  }
355  if (args.size() >= 2 && !args[1]->isUndefined()) {
356  return defineProperties(exec, ret, args[1]);
357  }
358  return ret;
359  }
360  case DefineProperty: { //ECMA Edition 5.1r6 - 15.2.3.6
361  JSObject *jso = args[0]->getObject();
362  if (!jso) {
363  return throwError(exec, TypeError, "Not an Object");
364  }
365 
366  UString name = args[1]->toString(exec);
367  PropertyDescriptor desc;
368  if (!desc.setPropertyDescriptorFromObject(exec, args[2])) {
369  return jsUndefined();
370  }
371  if (!jso->defineOwnProperty(exec, Identifier(name), desc, true)) {
372  return jsUndefined();
373  }
374  return jso;
375  }
376  case DefineProperties: { //ECMA Edition 5.1r6 - 15.2.3.7
377  if (!args[0]->isObject()) {
378  return throwError(exec, TypeError, "Not an Object");
379  }
380 
381  JSObject *jso = args[0]->getObject();
382  return defineProperties(exec, jso, args[1]);
383  }
384  case Seal: { //ECMA Edition 5.1r6 - 15.2.3.8
385  JSObject *jso = args[0]->getObject();
386  if (!jso) {
387  return throwError(exec, TypeError, "Not an Object");
388  }
389 
390  PropertyNameArray names;
391  jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties);
392  int size = names.size();
393 
394  PropertyDescriptor desc;
395  for (int i = 0; i < size; ++i) {
396  jso->getOwnPropertyDescriptor(exec, names[i], desc);
397  if (desc.configurable()) {
398  desc.setConfigureable(false);
399  if (!jso->defineOwnProperty(exec, names[i], desc, true)) {
400  return jsUndefined();
401  }
402  }
403  }
404  jso->preventExtensions();
405  return jso;
406  }
407  case Freeze: { //ECMA Edition 5.1r6 - 15.2.3.9
408  JSObject *jso = args[0]->getObject();
409  if (!jso) {
410  return throwError(exec, TypeError, "Not an Object");
411  }
412 
413  PropertyNameArray names;
414  jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties);
415  int size = names.size();
416 
417  PropertyDescriptor desc;
418  for (int i = 0; i < size; ++i) {
419  jso->getOwnPropertyDescriptor(exec, names[i], desc);
420  if (desc.isDataDescriptor())
421  if (desc.writable()) {
422  desc.setWritable(false);
423  }
424  if (desc.configurable()) {
425  desc.setConfigureable(false);
426  }
427  if (!jso->defineOwnProperty(exec, names[i], desc, true)) {
428  return jsUndefined();
429  }
430  }
431  jso->preventExtensions();
432  return jso;
433  }
434  case PreventExtensible: { //ECMA Edition 5.1r6 - 15.2.3.10
435  JSObject *jso = args[0]->getObject();
436  if (!jso) {
437  return throwError(exec, TypeError, "Not an Object");
438  }
439  jso->preventExtensions();
440  return jso;
441  }
442  case IsSealed: { //ECMA Edition 5.1r6 - 15.2.3.11
443  JSObject *jso = args[0]->getObject();
444  if (!jso) {
445  return throwError(exec, TypeError, "Not an Object");
446  }
447 
448  PropertyNameArray names;
449  jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties);
450  int size = names.size();
451 
452  PropertyDescriptor desc;
453  for (int i = 0; i < size; ++i) {
454  jso->getOwnPropertyDescriptor(exec, names[i], desc);
455  if (desc.configurable()) {
456  return jsBoolean(false);
457  }
458  }
459  return jsBoolean(!jso->isExtensible());
460  }
461  case IsFrozen: { //ECMA Edition 5.1r6 - 15.2.3.12
462  JSObject *jso = args[0]->getObject();
463  if (!jso) {
464  return throwError(exec, TypeError, "Not an Object");
465  }
466 
467  PropertyNameArray names;
468  jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties);
469  int size = names.size();
470 
471  PropertyDescriptor desc;
472  for (int i = 0; i < size; ++i) {
473  jso->getOwnPropertyDescriptor(exec, names[i], desc);
474  if (desc.isDataDescriptor())
475  if (desc.writable()) {
476  return jsBoolean(false);
477  }
478  if (desc.configurable()) {
479  return jsBoolean(false);
480  }
481  }
482  return jsBoolean(!jso->isExtensible());
483  }
484  case IsExtensible: { //ECMA Edition 5.1r6 - 15.2.3.13
485  JSObject *jso = args[0]->getObject();
486  if (!jso) {
487  return throwError(exec, TypeError, "Not an Object");
488  }
489  return jsBoolean(jso->isExtensible());
490  }
491  case Is: { //ES6 (Draft 08.11.2013) - 19.1.2.10
492  return jsBoolean(sameValue(exec, args[0], args[1]));
493  }
494  default:
495  return jsUndefined();
496  }
497 }
498 
499 } // namespace KJS
char * toString(const T &value)
static const List & empty()
Returns a pointer to a static instance of an empty list.
Definition: list.cpp:311
ObjectType
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Sep 19 2020 22:59:46 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.