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