kjs Library API Documentation

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 
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       /*fprintf( stderr, "%sProto::get(%s) [in macro, no parent]\n", info.className, propertyName.ascii());*/ \
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     { /*stupid but we need this to have a common macro for the declaration*/ \
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       /*fprintf( stderr, "%sProto::get(%s) [in macro]\n", info.className, propertyName.ascii());*/ \
00328       KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
00329       if ( val.type() != UndefinedType ) return val; \
00330       /* Not found -> forward request to "parent" prototype */ \
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( /*proto? */ ), 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   // To be used in all call() implementations, before casting the type of thisObj
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    * List of things to do when porting an objectimp to the 'static hashtable' mechanism:
00371    * - write the hashtable source, between @begin and @end
00372    * - add a rule to build the .lut.h
00373    * - include the .lut.h
00374    * - mention the table in the classinfo (add a classinfo if necessary)
00375    * - write/update the class enum (for the tokens)
00376    * - turn get() into getValueProperty(), put() into putValueProperty(), using a switch and removing funcs
00377    * - write get() and/or put() using a template method
00378    * - cleanup old stuff (e.g. hasProperty)
00379    * - compile, test, commit ;)
00380    */
00381 } // namespace
00382 
00383 #endif
KDE Logo
This file is part of the documentation for kjs Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Nov 1 10:32:46 2005 by doxygen 1.4.3 written by Dimitri van Heesch, © 1997-2003