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