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 KJS_EXPORT 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
00293 #define PUBLIC_DEFINE_PROTOTYPE(ClassName,ClassProto) \
00294 namespace KJS { \
00295 class ClassProto : public KJS::ObjectImp { \
00296 friend KJS::Object cacheGlobalObject<ClassProto>(KJS::ExecState *exec, const KJS::Identifier &propertyName); \
00297 public: \
00298 static KJS::Object self(KJS::ExecState *exec) \
00299 { \
00300 return cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
00301 } \
00302 protected: \
00303 ClassProto( KJS::ExecState *exec ) \
00304 : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \
00305 \
00306 public: \
00307 virtual const KJS::ClassInfo *classInfo() const { return &info; } \
00308 static const KJS::ClassInfo info; \
00309 KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
00310 bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
00311 }; \
00312 }
00313
00314 #define IMPLEMENT_CLASSINFO(ClassName,ClassProto) \
00315 namespace KJS {\
00316 const KJS::ClassInfo ClassProto::info = { ClassName, 0, &ClassProto##Table, 0 }; \
00317 }
00318
00319 #define DEFINE_PROTOTYPE(ClassName,ClassProto) \
00320 PUBLIC_DEFINE_PROTOTYPE(ClassName,ClassProto) \
00321 IMPLEMENT_CLASSINFO(ClassName,ClassProto)
00322
00323 #define IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc) \
00324 KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00325 { \
00326 \
00327 return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00328 } \
00329 bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00330 { \
00331 return KJS::ObjectImp::hasProperty(exec, propertyName); \
00332 }
00333
00334 #define PUBLIC_IMPLEMENT_PROTOTYPE(ClassProto,ClassName,ClassFunc) \
00335 IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc)\
00336 IMPLEMENT_CLASSINFO(ClassName,ClassProto)
00337
00338 #define IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto) \
00339 KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00340 { \
00341 \
00342 KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00343 if ( val.type() != UndefinedType ) return val; \
00344 \
00345 return ParentProto::self(exec).get( exec, propertyName ); \
00346 } \
00347 bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
00348 { \
00349 if (KJS::ObjectImp::hasProperty(exec, propertyName)) \
00350 return true; \
00351 return ParentProto::self(exec).hasProperty(exec, propertyName); \
00352 }
00353
00354 #define PUBLIC_IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassName,ClassFunc,ParentProto) \
00355 IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto) \
00356 IMPLEMENT_CLASSINFO(ClassName,ClassProto)
00357
00358 #define IMPLEMENT_PROTOFUNC(ClassFunc) \
00359 namespace KJS { \
00360 class ClassFunc : public ObjectImp { \
00361 public: \
00362 ClassFunc(KJS::ExecState *exec, int i, int len) \
00363 : ObjectImp( ), id(i) { \
00364 KJS::Value protect(this); \
00365 put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); \
00366 } \
00367 virtual bool implementsCall() const { return true; } \
00368 \
00369 virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \
00370 private: \
00371 int id; \
00372 }; \
00373 }
00374
00375
00376 #define KJS_CHECK_THIS( ClassName, theObj ) \
00377 if (!theObj.isValid() || !theObj.inherits(&ClassName::info)) { \
00378 KJS::UString errMsg = "Attempt at calling a function that expects a "; \
00379 errMsg += ClassName::info.className; \
00380 errMsg += " on a "; \
00381 errMsg += thisObj.className(); \
00382 KJS::Object err = KJS::Error::create(exec, KJS::TypeError, errMsg.ascii()); \
00383 exec->setException(err); \
00384 return err; \
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 }
00400
00401 #endif