1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
|
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2001 Harri Porten ([email protected])
* Copyright (C) 2001 Peter Kelly ([email protected])
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef _KJS_OBJECT_H_
#define _KJS_OBJECT_H_
// Objects
#include "value.h"
#include "types.h"
#include "reference_list.h"
#include "identifier.h"
#include "property_map.h"
#include "scope_chain.h"
namespace KJS {
class ObjectImpPrivate;
class PropertyMap;
class HashTable;
struct HashEntry;
class ListImp;
/** Attributes (only applicable to the Object type).
* See ECMA 262-3 8.6.1
*/
enum Attribute { None = 0,
ReadOnly = 1 << 1, ///< property can be only read, not written
DontEnum = 1 << 2, ///< property doesn't appear in (for .. in ..)
DontDelete = 1 << 3, ///< property can't be deleted
Internal = 1 << 4, ///< an internal property, set to by pass checks
Function = 1 << 5 }; ///< property is a function - only used by static hashtables
/**
* Class Information
*/
struct ClassInfo {
/**
* A string denoting the class name. Example: "Window".
*/
const char* className;
/**
* Pointer to the class information of the base class.
* 0L if there is none.
*/
const ClassInfo *parentClass;
/**
* Static hash-table of properties.
*/
const HashTable *propHashTable;
/**
* Reserved for future extension.
*/
void *dummy;
};
/**
* Represents an Object. This is a wrapper for ObjectImp
*/
class KJS_EXPORT Object : public Value {
public:
Object() { }
explicit Object(ObjectImp *v);
ObjectImp *imp() const;
const ClassInfo *classInfo() const;
bool inherits(const ClassInfo *cinfo) const;
/**
* Converts a Value into an Object. If the value's type is not ObjectType,
* a null object will be returned (i.e. one with it's internal pointer set
* to 0). If you do not know for sure whether the value is of type
* ObjectType, you should check the isValid() methods afterwards before
* calling any methods on the Object.
*
* @return The value converted to an object
*/
static Object dynamicCast(const Value &v);
/**
* Returns the prototype of this object. Note that this is not the same as
* the "prototype" property.
*
* See ECMA 8.6.2
*
* @return The object's prototype
*/
Value prototype() const;
/**
* Returns the class name of the object
*
* See ECMA 8.6.2
*
* @return The object's class name
*/
UString className() const;
/**
* Retrieves the specified property from the object. If neither the object
* or any other object in it's prototype chain have the property, this
* function will return Undefined.
*
* See ECMA 8.6.2.1
*
* @param exec The current execution state
* @param propertyName The name of the property to retrieve
*
* @return The specified property, or Undefined
*/
Value get(ExecState *exec, const Identifier &propertyName) const;
Value get(ExecState *exec, unsigned propertyName) const;
/**
* Sets the specified property.
*
* See ECMA 8.6.2.2
*
* @param exec The current execution state
* @param propertyName The name of the property to set
* @param value The value to set
* @param attr The Attribute value for the property
*/
void put(ExecState *exec, const Identifier &propertyName,
const Value &value, int attr = None);
void put(ExecState *exec, unsigned propertyName,
const Value &value, int attr = None);
/**
* Used to check whether or not a particular property is allowed to be set
* on an object
*
* See ECMA 8.6.2.3
*
* @param exec The current execution state
* @param propertyName The name of the property
* @return true if the property can be set, otherwise false
*/
bool canPut(ExecState *exec, const Identifier &propertyName) const;
/**
* Checks to see whether the object (or any object in it's prototype chain)
* has a property with the specified name.
*
* See ECMA 8.6.2.4
*
* @param exec The current execution state
* @param propertyName The name of the property to check for
* @return true if the object has the property, otherwise false
*/
bool hasProperty(ExecState *exec, const Identifier &propertyName) const;
bool hasProperty(ExecState *exec, unsigned propertyName) const;
/**
* Removes the specified property from the object.
*
* See ECMA 8.6.2.5
*
* @param exec The current execution state
* @param propertyName The name of the property to delete
* @return true if the property was successfully deleted or did not
* exist on the object. false if deleting the specified property is not
* allowed.
*/
bool deleteProperty(ExecState *exec, const Identifier &propertyName);
bool deleteProperty(ExecState *exec, unsigned propertyName);
/**
* Converts the object into a primitive value. The value return may differ
* depending on the supplied hint
*
* See ECMA 8.6.2.6
*
* @param exec The current execution state
* @param hint The desired primitive type to convert to
* @return A primitive value converted from the objetc. Note that the
* type of primitive value returned may not be the same as the requested
* hint.
*/
Value defaultValue(ExecState *exec, Type hint) const;
/**
* Whether or not the object implements the construct() method. If this
* returns false you should not call the construct() method on this
* object (typically, an assertion will fail to indicate this).
*
* @return true if this object implements the construct() method, otherwise
* false
*/
bool implementsConstruct() const;
/**
* Creates a new object based on this object. Typically this means the
* following:
* 1. A new object is created
* 2. The prototype of the new object is set to the value of this object's
* "prototype" property
* 3. The call() method of this object is called, with the new object
* passed as the this value
* 4. The new object is returned
*
* In some cases, Host objects may differ from these semantics, although
* this is discouraged.
*
* If an error occurs during construction, the execution state's exception
* will be set. This can be tested for with ExecState::hadException().
* Under some circumstances, the exception object may also be returned.
*
* Note: This function should not be called if implementsConstruct() returns
* false, in which case it will result in an assertion failure.
*
* @param exec The current execution state
* @param args The arguments to be passed to call() once the new object has
* been created
* @return The newly created & initialized object
*/
Object construct(ExecState *exec, const List &args);
/**
* Whether or not the object implements the call() method. If this returns
* false you should not call the call() method on this object (typically,
* an assertion will fail to indicate this).
*
* @return true if this object implements the call() method, otherwise
* false
*/
bool implementsCall() const;
/**
* Calls this object as if it is a function.
*
* Note: This function should not be called if implementsCall() returns
* false, in which case it will result in an assertion failure.
*
* See ECMA 8.6.2.3
*
* @param exec The current execution state
* @param thisObj The obj to be used as "this" within function execution.
* Note that in most cases this will be different from the C++ "this"
* object. For example, if the ECMAScript code "window.location.toString()"
* is executed, call() will be invoked on the C++ object which implements
* the toString method, with the thisObj being window.location
* @param args List of arguments to be passed to the function
* @return The return value from the function
*/
Value call(ExecState *exec, Object &thisObj, const List &args);
/**
* Whether or not the object implements the hasInstance() method. If this
* returns false you should not call the hasInstance() method on this
* object (typically, an assertion will fail to indicate this).
*
* @return true if this object implements the hasInstance() method,
* otherwise false
*/
bool implementsHasInstance() const;
/**
* Checks whether value delegates behavior to this object. Used by the
* instanceof operator.
*
* @param exec The current execution state
* @param value The value to check
* @return true if value delegates behavior to this object, otherwise
* false
*/
Boolean hasInstance(ExecState *exec, const Value &value);
/**
* Returns the scope of this object. This is used when execution declared
* functions - the execution context for the function is initialized with
* extra object in it's scope. An example of this is functions declared
* inside other functions:
*
* \code
* function f() {
*
* function b() {
* return prototype;
* }
*
* var x = 4;
* // do some stuff
* }
* f.prototype = new String();
* \endcode
*
* When the function f.b is executed, its scope will include properties of
* f. So in the example above the return value of f.b() would be the new
* String object that was assigned to f.prototype.
*
* @return The function's scope
*/
const ScopeChain &scope() const;
void setScope(const ScopeChain &s);
/**
* Returns a List of References to all the properties of the object. Used
* in "for x in y" statements. The list is created new, so it can be freely
* modified without affecting the object's properties. It should be deleted
* by the caller.
*
* Subclasses can override this method in ObjectImpl to provide the
* appearance of
* having extra properties other than those set specifically with put().
*
* @param exec The current execution state
* @param recursive Whether or not properties in the object's prototype
* chain should be
* included in the list.
* @return A List of References to properties of the object.
**/
ReferenceList propList(ExecState *exec, bool recursive = true);
/**
* Returns the internal value of the object. This is used for objects such
* as String and Boolean which are wrappers for native types. The interal
* value is the actual value represented by the wrapper objects.
*
* @see ECMA 8.6.2
* @return The internal value of the object
*/
Value internalValue() const;
/**
* Sets the internal value of the object
*
* @see internalValue()
*
* @param v The new internal value
*/
void setInternalValue(const Value &v);
};
inline Object Value::toObject(ExecState *exec) const { return rep->dispatchToObject(exec); }
class KJS_EXPORT ObjectImp : public ValueImp {
friend class ObjectProtoFuncImp;
public:
/**
* Creates a new ObjectImp with the specified prototype
*
* @param proto The prototype
*/
ObjectImp(const Object &proto);
ObjectImp(ObjectImp *proto);
/**
* Creates a new ObjectImp with a prototype of Null()
* (that is, the ECMAScript "null" value, not a null Object).
*
*/
ObjectImp();
virtual ~ObjectImp();
virtual void mark();
Type type() const;
/**
* A pointer to a ClassInfo struct for this class. This provides a basic
* facility for run-time type information, and can be used to check an
* object's class an inheritance (see inherits()). This should
* always return a statically declared pointer, or 0 to indicate that
* there is no class information.
*
* This is primarily useful if you have application-defined classes that you
* wish to check against for casting purposes.
*
* For example, to specify the class info for classes FooImp and BarImp,
* where FooImp inherits from BarImp, you would add the following in your
* class declarations:
*
* \code
* class BarImp : public ObjectImp {
* virtual const ClassInfo *classInfo() const { return &info; }
* static const ClassInfo info;
* // ...
* };
*
* class FooImp : public ObjectImp {
* virtual const ClassInfo *classInfo() const { return &info; }
* static const ClassInfo info;
* // ...
* };
* \endcode
*
* And in your source file:
*
* \code
* const ClassInfo BarImp::info = {0, 0, 0}; // no parent class
* const ClassInfo FooImp::info = {&BarImp::info, 0, 0};
* \endcode
*
* @see inherits()
*/
virtual const ClassInfo *classInfo() const;
/**
* Checks whether this object inherits from the class with the specified
* classInfo() pointer. This requires that both this class and the other
* class return a non-NULL pointer for their classInfo() methods (otherwise
* it will return false).
*
* For example, for two ObjectImp pointers obj1 and obj2, you can check
* if obj1's class inherits from obj2's class using the following:
*
* if (obj1->inherits(obj2->classInfo())) {
* // ...
* }
*
* If you have a handle to a statically declared ClassInfo, such as in the
* classInfo() example, you can check for inheritance without needing
* an instance of the other class:
*
* if (obj1->inherits(FooImp::info)) {
* // ...
* }
*
* @param cinfo The ClassInfo pointer for the class you want to check
* inheritance against.
* @return true if this object's class inherits from class with the
* ClassInfo pointer specified in cinfo
*/
bool inherits(const ClassInfo *cinfo) const;
// internal properties (ECMA 262-3 8.6.2)
/**
* Implementation of the [[Prototype]] internal property (implemented by
* all Objects)
*
* @see Object::prototype()
*/
Value prototype() const;
void setPrototype(const Value &proto);
/**
* Implementation of the [[Class]] internal property (implemented by all
* Objects)
*
* The default implementation uses classInfo().
* You should either implement classInfo(), or
* if you simply need a classname, you can reimplement className()
* instead.
*
* @see Object::className()
*/
virtual UString className() const;
/**
* Implementation of the [[Get]] internal property (implemented by all
* Objects)
*
* @see Object::get()
*/
// [[Get]] - must be implemented by all Objects
virtual Value get(ExecState *exec, const Identifier &propertyName) const;
virtual Value getPropertyByIndex(ExecState *exec,
unsigned propertyName) const;
/**
* Implementation of the [[Put]] internal property (implemented by all
* Objects)
*
* @see Object::put()
*/
virtual void put(ExecState *exec, const Identifier &propertyName,
const Value &value, int attr = None);
virtual void putPropertyByIndex(ExecState *exec, unsigned propertyName,
const Value &value, int attr = None);
/**
* Implementation of the [[CanPut]] internal property (implemented by all
* Objects)
*
* @see Object::canPut()
*/
virtual bool canPut(ExecState *exec, const Identifier &propertyName) const;
/**
* Implementation of the [[HasProperty]] internal property (implemented by
* all Objects)
*
* @see Object::hasProperty()
*/
virtual bool hasProperty(ExecState *exec,
const Identifier &propertyName) const;
virtual bool hasPropertyByIndex(ExecState *exec, unsigned propertyName) const;
/**
* Implementation of the [[Delete]] internal property (implemented by all
* Objects)
*
* @see Object::deleteProperty()
*/
virtual bool deleteProperty(ExecState *exec,
const Identifier &propertyName);
virtual bool deletePropertyByIndex(ExecState *exec, unsigned propertyName);
/**
* Remove all properties from this object.
* This doesn't take DontDelete into account, and isn't in the ECMA spec.
* It's simply a quick way to remove everything before destroying.
*/
void deleteAllProperties(ExecState *);
/**
* Implementation of the [[DefaultValue]] internal property (implemented by
* all Objects)
*
* @see Object::defaultValue()
*/
virtual Value defaultValue(ExecState *exec, Type hint) const;
virtual bool implementsConstruct() const;
/**
* Implementation of the [[Construct]] internal property
*
* @see Object::construct()
*/
virtual Object construct(ExecState *exec, const List &args);
virtual bool implementsCall() const;
/**
* Implementation of the [[Call]] internal property
*
* @see Object::call()
*/
virtual Value call(ExecState *exec, Object &thisObj,
const List &args);
virtual bool implementsHasInstance() const;
/**
* Implementation of the [[HasInstance]] internal property
*
* @see Object::hasInstance()
*/
virtual Boolean hasInstance(ExecState *exec, const Value &value);
/**
* Implementation of the [[Scope]] internal property
*
* @see Object::scope()
*/
const ScopeChain &scope() const { return _scope; }
void setScope(const ScopeChain &s) { _scope = s; }
virtual ReferenceList propList(ExecState *exec, bool recursive = true);
Value internalValue() const;
void setInternalValue(const Value &v);
void setInternalValue(ValueImp *v);
Value toPrimitive(ExecState *exec,
Type preferredType = UnspecifiedType) const;
bool toBoolean(ExecState *exec) const;
double toNumber(ExecState *exec) const;
UString toString(ExecState *exec) const;
Object toObject(ExecState *exec) const;
// This get method only looks at the property map.
// A bit like hasProperty(recursive=false), this doesn't go to the prototype.
// This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
// to look up in the prototype, it might already exist there)
ValueImp *getDirect(const Identifier& propertyName) const
{ return _prop.get(propertyName); }
void putDirect(const Identifier &propertyName, ValueImp *value, int attr = 0);
void putDirect(const Identifier &propertyName, int value, int attr = 0);
/**
* Sets the name of the function, if this is an InternalFunctionImp object.
* (calling InternalFunctionImp::setName)
*/
void setFunctionName(const Identifier &propertyName);
protected:
PropertyMap _prop;
private:
const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
ObjectImpPrivate *_od;
ValueImp *_proto;
ValueImp *_internalValue;
ScopeChain _scope;
};
/**
* Types of Native Errors available. For custom errors, GeneralError
* should be used.
*/
enum ErrorType { GeneralError = 0,
EvalError = 1,
RangeError = 2,
ReferenceError = 3,
SyntaxError = 4,
TypeError = 5,
URIError = 6};
/**
* @short Factory methods for error objects.
*/
class KJS_EXPORT Error {
public:
/**
* Factory method for error objects.
*
* @param exec The current execution state
* @param errtype Type of error.
* @param message Optional error message.
* @param lineno Optional line number.
* @param sourceId Optional source id.
*/
static Object create(ExecState *exec, ErrorType errtype = GeneralError,
const char *message = 0, int lineno = -1,
int sourceId = -1);
/**
* Array of error names corresponding to ErrorType
*/
static const char * const * const errorNames;
};
inline Object::Object(ObjectImp *v) : Value(v) { }
inline ObjectImp *Object::imp() const { return static_cast<ObjectImp*>(rep); }
inline const ClassInfo *Object::classInfo() const
{ return imp()->classInfo(); }
inline bool Object::inherits(const ClassInfo *cinfo) const
{ return imp()->inherits(cinfo); }
inline Value Object::prototype() const
{ return Value(imp()->prototype()); }
inline UString Object::className() const
{ return imp()->className(); }
inline Value Object::get(ExecState *exec, const Identifier &propertyName) const
{ return imp()->get(exec,propertyName); }
inline Value Object::get(ExecState *exec, unsigned propertyName) const
{ return imp()->getPropertyByIndex(exec, propertyName); }
inline void Object::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
{ imp()->put(exec,propertyName,value,attr); }
inline void Object::put(ExecState *exec, unsigned propertyName, const Value &value, int attr)
{ imp()->putPropertyByIndex(exec, propertyName, value, attr); }
inline bool Object::canPut(ExecState *exec, const Identifier &propertyName) const
{ return imp()->canPut(exec,propertyName); }
inline bool Object::hasProperty(ExecState *exec, const Identifier &propertyName) const
{ return imp()->hasProperty(exec, propertyName); }
inline bool Object::hasProperty(ExecState *exec, unsigned propertyName) const
{ return imp()->hasPropertyByIndex(exec, propertyName); }
inline bool Object::deleteProperty(ExecState *exec, const Identifier &propertyName)
{ return imp()->deleteProperty(exec,propertyName); }
inline bool Object::deleteProperty(ExecState *exec, unsigned propertyName)
{ return imp()->deletePropertyByIndex(exec, propertyName); }
inline Value Object::defaultValue(ExecState *exec, Type hint) const
{ return imp()->defaultValue(exec,hint); }
inline bool Object::implementsConstruct() const
{ return imp()->implementsConstruct(); }
inline Object Object::construct(ExecState *exec, const List &args)
{ return imp()->construct(exec,args); }
inline bool Object::implementsCall() const
{ return imp()->implementsCall(); }
inline bool Object::implementsHasInstance() const
{ return imp()->implementsHasInstance(); }
inline Boolean Object::hasInstance(ExecState *exec, const Value &value)
{ return imp()->hasInstance(exec,value); }
inline const ScopeChain &Object::scope() const
{ return imp()->scope(); }
inline void Object::setScope(const ScopeChain &s)
{ imp()->setScope(s); }
inline ReferenceList Object::propList(ExecState *exec, bool recursive)
{ return imp()->propList(exec,recursive); }
inline Value Object::internalValue() const
{ return imp()->internalValue(); }
inline void Object::setInternalValue(const Value &v)
{ imp()->setInternalValue(v); }
} // namespace
#endif // _KJS_OBJECT_H_
|