lookup.h

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2003 Apple Computer, Inc.
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Lesser General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Lesser General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Lesser General Public
00018  *  License along with this library; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
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       // Look for cached value in dynamic map of properties (in ObjectImp)
00140       ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName);
00141       /*if (cachedVal)
00142         fprintf(stderr, "lookupOrCreateFunction: Function -> looked up in ObjectImp, found type=%d\n", cachedVal->type());*/
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) // not found, forward to parent
00181       return thisObj->ParentImp::get(exec, propertyName);
00182 
00183     //fprintf(stderr, "lookupGet: found value=%d attr=%d\n", entry->value, entry->attr);
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) // not found, forward to parent
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) // not found, forward to parent
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) // not found: forward to parent
00239       thisObj->ParentImp::put(exec, propertyName, value, attr);
00240     else if (entry->attr & Function) // function: put as override property
00241       thisObj->ObjectImp::put(exec, propertyName, value, attr);
00242     else if (entry->attr & ReadOnly) // readonly! Can't put!
00243 #ifdef KJS_VERBOSE
00244       fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
00245 #else
00246       ; // do nothing
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       /*fprintf( stderr, "%sProto::get(%s) [in macro, no parent]\n", info.className, propertyName.ascii());*/ \
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     { /*stupid but we need this to have a common macro for the declaration*/ \
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       /*fprintf( stderr, "%sProto::get(%s) [in macro]\n", info.className, propertyName.ascii());*/ \
00342       KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00343       if ( val.type() != UndefinedType ) return val; \
00344       /* Not found -> forward request to "parent" prototype */ \
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( /*proto? */ ), 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   // To be used in all call() implementations, before casting the type of thisObj
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    * List of things to do when porting an objectimp to the 'static hashtable' mechanism:
00389    * - write the hashtable source, between @begin and @end
00390    * - add a rule to build the .lut.h
00391    * - include the .lut.h
00392    * - mention the table in the classinfo (add a classinfo if necessary)
00393    * - write/update the class enum (for the tokens)
00394    * - turn get() into getValueProperty(), put() into putValueProperty(), using a switch and removing funcs
00395    * - write get() and/or put() using a template method
00396    * - cleanup old stuff (e.g. hasProperty)
00397    * - compile, test, commit ;)
00398    */
00399 } // namespace
00400 
00401 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys