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 "ustring.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 const char *s;
00045 int value;
00049 short int attr;
00054 short int params;
00058 const HashEntry *next;
00059 };
00060
00072 struct HashTable {
00076 int type;
00082 int size;
00087 const HashEntry *entries;
00091 int hashSize;
00092 };
00093
00097 class Lookup {
00098 public:
00102 static int find(const struct HashTable *table, const UString &s);
00103 static int find(const struct HashTable *table,
00104 const UChar *c, unsigned int len);
00105
00111 static const HashEntry* findEntry(const struct HashTable *table,
00112 const UString &s);
00113 static const HashEntry* findEntry(const struct HashTable *table,
00114 const UChar *c, unsigned int len);
00115
00119 static unsigned int hash(const UString &key);
00120 static unsigned int hash(const UChar *c, unsigned int len);
00121 static unsigned int hash(const char *s);
00122 };
00123
00124 class ExecState;
00125 class UString;
00130 template <class FuncImp>
00131 inline Value lookupOrCreateFunction(ExecState *exec, const UString &propertyName,
00132 const ObjectImp *thisObj, int token, int params, int attr)
00133 {
00134
00135 ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName);
00136
00137
00138 if (cachedVal)
00139 return Value(cachedVal);
00140
00141 Value val = Value(new FuncImp(exec,token, params));
00142 ObjectImp *thatObj = const_cast<ObjectImp *>(thisObj);
00143 thatObj->ObjectImp::put(exec, propertyName, val, attr);
00144 return val;
00145 }
00146
00167 template <class FuncImp, class ThisImp, class ParentImp>
00168 inline Value lookupGet(ExecState *exec, const UString &propertyName,
00169 const HashTable* table, const ThisImp* thisObj)
00170 {
00171 const HashEntry* entry = Lookup::findEntry(table, propertyName);
00172
00173 if (!entry)
00174 return thisObj->ParentImp::get(exec, propertyName);
00175
00176
00177 if (entry->attr & Function)
00178 return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
00179 return thisObj->getValueProperty(exec, entry->value);
00180 }
00181
00186 template <class FuncImp, class ParentImp>
00187 inline Value lookupGetFunction(ExecState *exec, const UString &propertyName,
00188 const HashTable* table, const ObjectImp* thisObj)
00189 {
00190 const HashEntry* entry = Lookup::findEntry(table, propertyName);
00191
00192 if (!entry)
00193 return static_cast<const ParentImp *>(thisObj)->ParentImp::get(exec, propertyName);
00194
00195 if (entry->attr & Function)
00196 return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
00197
00198 fprintf(stderr, "Function bit not set! Shouldn't happen in lookupGetFunction!\n" );
00199 return Undefined();
00200 }
00201
00206 template <class ThisImp, class ParentImp>
00207 inline Value lookupGetValue(ExecState *exec, const UString &propertyName,
00208 const HashTable* table, const ThisImp* thisObj)
00209 {
00210 const HashEntry* entry = Lookup::findEntry(table, propertyName);
00211
00212 if (!entry)
00213 return thisObj->ParentImp::get(exec, propertyName);
00214
00215 if (entry->attr & Function)
00216 fprintf(stderr, "Function bit set! Shouldn't happen in lookupGetValue! propertyName was %s\n", propertyName.ascii() );
00217 return thisObj->getValueProperty(exec, entry->value);
00218 }
00219
00224 template <class ThisImp, class ParentImp>
00225 inline void lookupPut(ExecState *exec, const UString &propertyName,
00226 const Value& value, int attr,
00227 const HashTable* table, ThisImp* thisObj)
00228 {
00229 const HashEntry* entry = Lookup::findEntry(table, propertyName);
00230
00231 if (!entry)
00232 thisObj->ParentImp::put(exec, propertyName, value, attr);
00233 else if (entry->attr & Function)
00234 thisObj->ObjectImp::put(exec, propertyName, value, attr);
00235 else if (entry->attr & ReadOnly)
00236 #ifdef KJS_VERBOSE
00237 fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
00238 #else
00239 ;
00240 #endif
00241 else
00242 thisObj->putValueProperty(exec, entry->value, value, attr);
00243 }
00244
00245
00253 template <class ClassCtor>
00254 inline KJS::Object cacheGlobalObject(ExecState *exec, const UString &propertyName)
00255 {
00256 ValueImp *obj = static_cast<KJS::ObjectImp*>(exec->interpreter()->globalObject().imp())->getDirect(propertyName);
00257 if (obj)
00258 return KJS::Object::dynamicCast(Value(obj));
00259 else
00260 {
00261 KJS::Object newObject(new ClassCtor(exec));
00262 exec->interpreter()->globalObject().put(exec, propertyName, newObject, Internal);
00263 return newObject;
00264 }
00265 }
00266
00267
00284 #define DEFINE_PROTOTYPE(ClassName,ClassProto) \
00285 namespace KJS { \
00286 class ClassProto : public KJS::ObjectImp { \
00287 friend KJS::Object cacheGlobalObject<ClassProto>(KJS::ExecState *exec, const KJS::UString &propertyName); \
00288 public: \
00289 static KJS::Object self(KJS::ExecState *exec) \
00290 { \
00291 return cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
00292 } \
00293 protected: \
00294 ClassProto( KJS::ExecState *exec ) \
00295 : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \
00296 \
00297 public: \
00298 virtual const KJS::ClassInfo *classInfo() const { return &info; } \
00299 static const KJS::ClassInfo info; \
00300 KJS::Value get(KJS::ExecState *exec, const KJS::UString &propertyName) const; \
00301 bool hasProperty(KJS::ExecState *exec, const KJS::UString &propertyName) const; \
00302 }; \
00303 const KJS::ClassInfo ClassProto::info = { ClassName, 0, &ClassProto##Table, 0 }; \
00304 }
00305
00306 #define IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc) \
00307 KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::UString &propertyName) const \
00308 { \
00309 \
00310 return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00311 } \
00312 bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::UString &propertyName) const \
00313 { \
00314 return KJS::ObjectImp::hasProperty(exec, propertyName); \
00315 }
00316
00317 #define IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto) \
00318 KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::UString &propertyName) const \
00319 { \
00320 \
00321 KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00322 if ( val.type() != UndefinedType ) return val; \
00323 \
00324 return ParentProto::self(exec).get( exec, propertyName ); \
00325 } \
00326 bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::UString &propertyName) const \
00327 { \
00328 if (KJS::ObjectImp::hasProperty(exec, propertyName)) \
00329 return true; \
00330 return ParentProto::self(exec).hasProperty(exec, propertyName); \
00331 }
00332
00333 #define IMPLEMENT_PROTOFUNC(ClassFunc) \
00334 namespace KJS { \
00335 class ClassFunc : public ObjectImp { \
00336 public: \
00337 ClassFunc(KJS::ExecState *exec, int i, int len) \
00338 : ObjectImp( ), id(i) { \
00339 KJS::Value protect(this); \
00340 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); \
00341 } \
00342 virtual bool implementsCall() const { return true; } \
00343 \
00344 virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \
00345 private: \
00346 int id; \
00347 }; \
00348 }
00349
00350
00351 #define KJS_CHECK_THIS( ClassName, theObj ) \
00352 if (theObj.isNull() || !theObj.inherits(&ClassName::info)) { \
00353 KJS::UString errMsg = "Attempt at calling a function that expects a "; \
00354 errMsg += ClassName::info.className; \
00355 errMsg += " on a "; \
00356 errMsg += thisObj.className(); \
00357 KJS::Object err = KJS::Error::create(exec, KJS::TypeError, errMsg.ascii()); \
00358 exec->setException(err); \
00359 return err; \
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 }
00375
00376 #endif