00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
#ifndef _KJSLOOKUP_H_
00024
#define _KJSLOOKUP_H_
00025
00026
#include "identifier.h"
00027
#include "value.h"
00028
#include "object.h"
00029
#include "interpreter.h"
00030
#include <stdio.h>
00031
00032
namespace KJS {
00033
00037 struct HashEntry {
00041 unsigned short soffset;
00045 short int value;
00049 unsigned char attr;
00054 unsigned char params;
00058 short next;
00059 };
00060
00072 struct HashTable {
00076 int type;
00082 int size;
00087 const HashEntry *
const entries;
00091 int hashSize;
00092
00096 const char*
const sbase;
00097 };
00098
00102 class Lookup {
00103
public:
00107
static int find(
const struct HashTable *table,
const Identifier &s);
00108
static int find(
const struct HashTable *table,
00109
const UChar *c,
unsigned int len);
00110
00116
static const HashEntry*
findEntry(
const struct HashTable *table,
00117
const Identifier &s);
00118
static const HashEntry*
findEntry(
const struct HashTable *table,
00119
const UChar *c,
unsigned int len);
00120
00124
static unsigned int hash(
const Identifier &key);
00125
static unsigned int hash(
const UChar *c,
unsigned int len);
00126
static unsigned int hash(
const char *s);
00127 };
00128
00129
class ExecState;
00130
class UString;
00135
template <
class FuncImp>
00136
inline Value lookupOrCreateFunction(
ExecState *exec,
const Identifier &propertyName,
00137
const ObjectImp *thisObj,
int token,
int params,
int attr)
00138 {
00139
00140
ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName);
00141
00142
00143
if (cachedVal)
00144
return Value(cachedVal);
00145
00146 ObjectImp* func =
new FuncImp( exec, token, params );
00147
Value val( func );
00148 func->setFunctionName( propertyName );
00149 ObjectImp *thatObj = const_cast<ObjectImp *>(thisObj);
00150 thatObj->ObjectImp::put(exec, propertyName, val, attr);
00151
return val;
00152 }
00153
00174
template <
class FuncImp,
class ThisImp,
class ParentImp>
00175
inline Value lookupGet(
ExecState *exec,
const Identifier &propertyName,
00176
const HashTable* table,
const ThisImp* thisObj)
00177 {
00178
const HashEntry* entry =
Lookup::findEntry(table, propertyName);
00179
00180
if (!entry)
00181
return thisObj->ParentImp::get(exec, propertyName);
00182
00183
00184
if (entry->
attr & Function)
00185
return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->
value, entry->
params, entry->
attr);
00186
return thisObj->getValueProperty(exec, entry->
value);
00187 }
00188
00193
template <
class FuncImp,
class ParentImp>
00194
inline Value lookupGetFunction(
ExecState *exec,
const Identifier &propertyName,
00195
const HashTable* table,
const ObjectImp* thisObj)
00196 {
00197
const HashEntry* entry =
Lookup::findEntry(table, propertyName);
00198
00199
if (!entry)
00200
return static_cast<const ParentImp *>(thisObj)->ParentImp::get(exec, propertyName);
00201
00202
if (entry->
attr & Function)
00203
return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->
value, entry->
params, entry->
attr);
00204
00205 fprintf(stderr,
"Function bit not set! Shouldn't happen in lookupGetFunction!\n" );
00206
return Undefined();
00207 }
00208
00213
template <
class ThisImp,
class ParentImp>
00214
inline Value lookupGetValue(
ExecState *exec,
const Identifier &propertyName,
00215
const HashTable* table,
const ThisImp* thisObj)
00216 {
00217
const HashEntry* entry =
Lookup::findEntry(table, propertyName);
00218
00219
if (!entry)
00220
return thisObj->ParentImp::get(exec, propertyName);
00221
00222
if (entry->
attr & Function)
00223 fprintf(stderr,
"Function bit set! Shouldn't happen in lookupGetValue! propertyName was %s\n", propertyName.ascii() );
00224
return thisObj->getValueProperty(exec, entry->
value);
00225 }
00226
00231
template <
class ThisImp,
class ParentImp>
00232
inline void lookupPut(
ExecState *exec,
const Identifier &propertyName,
00233
const Value& value,
int attr,
00234
const HashTable* table, ThisImp* thisObj)
00235 {
00236
const HashEntry* entry =
Lookup::findEntry(table, propertyName);
00237
00238
if (!entry)
00239 thisObj->ParentImp::put(exec, propertyName, value, attr);
00240
else if (entry->
attr & Function)
00241 thisObj->ObjectImp::put(exec, propertyName, value, attr);
00242
else if (entry->
attr & ReadOnly)
00243
#ifdef KJS_VERBOSE
00244
fprintf(stderr,
"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
00245
#else
00246
;
00247
#endif
00248
else
00249 thisObj->putValueProperty(exec, entry->
value, value, attr);
00250 }
00251
00252
00260
template <
class ClassCtor>
00261
inline KJS::Object cacheGlobalObject(
ExecState *exec,
const Identifier &propertyName)
00262 {
00263
ValueImp *obj = static_cast<KJS::ObjectImp*>(exec->
interpreter()->
globalObject().
imp())->getDirect(propertyName);
00264
if (obj)
00265
return KJS::Object::dynamicCast(
Value(obj));
00266
else
00267 {
00268
KJS::Object newObject(
new ClassCtor(exec));
00269 exec->
interpreter()->
globalObject().
put(exec, propertyName, newObject, Internal);
00270
return newObject;
00271 }
00272 }
00273
00274
00291
#define DEFINE_PROTOTYPE(ClassName,ClassProto) \
00292
namespace KJS { \
00293
class ClassProto : public KJS::ObjectImp { \
00294
friend KJS::Object cacheGlobalObject<ClassProto>(KJS::ExecState *exec, const KJS::Identifier &propertyName); \
00295
public: \
00296
static KJS::Object self(KJS::ExecState *exec) \
00297
{ \
00298
return cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
00299
} \
00300
protected: \
00301
ClassProto( KJS::ExecState *exec ) \
00302
: KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \
00303
\
00304
public: \
00305
virtual const KJS::ClassInfo *classInfo() const { return &info; } \
00306
static const KJS::ClassInfo info; \
00307
KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
00308
bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
00309
}; \
00310
const KJS::ClassInfo ClassProto::info = { ClassName, 0, &ClassProto##Table, 0 }; \
00311
}
00312
00313
#define IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc) \
00314
KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00315
{ \
00316
\
00317 return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00318 } \
00319 bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00320 { \
00321 return KJS::ObjectImp::hasProperty(exec, propertyName); \
00322 }
00323
00324
#define IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto) \
00325
KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00326
{ \
00327
\
00328 KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00329 if ( val.type() != UndefinedType ) return val; \
00330 \
00331 return ParentProto::self(exec).get( exec, propertyName ); \
00332 } \
00333 bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00334 { \
00335 if (KJS::ObjectImp::hasProperty(exec, propertyName)) \
00336 return true; \
00337 return ParentProto::self(exec).hasProperty(exec, propertyName); \
00338 }
00339
00340
#define IMPLEMENT_PROTOFUNC(ClassFunc) \
00341
namespace KJS { \
00342
class ClassFunc : public ObjectImp { \
00343
public: \
00344
ClassFunc(KJS::ExecState *exec, int i, int len) \
00345
: ObjectImp( ), id(i) { \
00346 KJS::Value protect(this); \
00347 put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); \
00348 } \
00349 virtual bool implementsCall() const { return true; } \
00350 \
00351 virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \
00352 private: \
00353 int id; \
00354 }; \
00355 }
00356
00357
00358
#define KJS_CHECK_THIS( ClassName, theObj ) \
00359
if (!theObj.isValid() || !theObj.inherits(&ClassName::info)) { \
00360
KJS::UString errMsg = "Attempt at calling a function that expects a "; \
00361
errMsg += ClassName::info.className; \
00362
errMsg += " on a "; \
00363
errMsg += thisObj.className(); \
00364
KJS::Object err = KJS::Error::create(exec, KJS::TypeError, errMsg.ascii()); \
00365
exec->setException(err); \
00366
return err; \
00367
}
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 }
00382
00383
#endif