#ifndef _KJSLOOKUP_H_
#define _KJSLOOKUP_H_
#include "interpreter.h"
#include "identifier.h"
#include "object.h"
#include <stdio.h>
namespace KJS {
class FunctionPrototype;
struct HashEntry {
const char* s;
int value;
short int attr;
short int params;
const HashEntry* next;
};
struct HashTable {
int type;
int size;
const HashEntry* entries;
int hashSize;
};
class Lookup {
public:
static int find(const struct HashTable*, const Identifier&);
static int find(const struct HashTable*, const UChar*, unsigned int len);
static const HashEntry* findEntry(const struct HashTable*, const Identifier&);
};
class ExecState;
class UString;
template <class FuncImp>
inline JSValue* staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
{
JSObject* thisObj = slot.slotBase();
JSValue* cachedVal = thisObj->getDirect(propertyName);
if (cachedVal)
return cachedVal;
const HashEntry* entry = slot.staticEntry();
JSValue* val = new FuncImp(exec, entry->value, entry->params, propertyName);
thisObj->putDirect(propertyName, val, entry->attr);
return val;
}
template <class ThisImp>
inline JSValue* staticValueGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
{
ThisImp* thisObj = static_cast<ThisImp*>(slot.slotBase());
const HashEntry* entry = slot.staticEntry();
return thisObj->getValueProperty(exec, entry->value);
}
template <class FuncImp, class ThisImp, class ParentImp>
inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table,
ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry) return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
if (entry->attr & Function)
slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
else
slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
return true;
}
template <class FuncImp, class ParentImp>
inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table,
JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry) return static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
assert(entry->attr & Function);
slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
return true;
}
template <class ThisImp, class ParentImp>
inline bool getStaticValueSlot(ExecState* exec, const HashTable* table,
ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry) return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
assert(!(entry->attr & Function));
slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
return true;
}
template <class ThisImp>
inline bool lookupPut(ExecState* exec, const Identifier& propertyName,
JSValue* value, int attr,
const HashTable* table, ThisImp* thisObj)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry)
return false;
if (entry->attr & Function) thisObj->JSObject::put(exec, propertyName, value, attr);
else if (entry->attr & ReadOnly) #ifdef KJS_VERBOSE
fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
#else
; #endif
else
thisObj->putValueProperty(exec, entry->value, value, attr);
return true;
}
template <class ThisImp, class ParentImp>
inline void lookupPut(ExecState* exec, const Identifier& propertyName,
JSValue* value, int attr,
const HashTable* table, ThisImp* thisObj)
{
if (!lookupPut<ThisImp>(exec, propertyName, value, attr, table, thisObj))
thisObj->ParentImp::put(exec, propertyName, value, attr); }
template <class ClassCtor>
inline JSObject* cacheGlobalObject(ExecState* exec, const Identifier& propertyName)
{
JSObject* globalObject = static_cast<JSObject*>(exec->lexicalInterpreter()->globalObject());
JSValue* obj = globalObject->getDirect(propertyName);
if (obj) {
assert(obj->isObject());
return static_cast<JSObject* >(obj);
}
JSObject* newObject = new ClassCtor(exec);
globalObject->put(exec, propertyName, newObject, Internal | DontEnum);
return newObject;
}
}
#define KJS_DEFINE_PROTOTYPE(ClassPrototype) \
class ClassPrototype : public KJS::JSObject { \
public: \
static KJS::JSObject* self(KJS::ExecState* exec); \
virtual const KJS::ClassInfo* classInfo() const { return &info; } \
static const KJS::ClassInfo info; \
bool getOwnPropertySlot(KJS::ExecState* , const KJS::Identifier&, KJS::PropertySlot&); \
ClassPrototype(KJS::ExecState* exec) \
: KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { } \
\
};
#define KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(ClassPrototype, ClassPrototypePrototype) \
class ClassPrototype : public KJS::JSObject { \
public: \
static KJS::JSObject* self(KJS::ExecState* exec); \
virtual const KJS::ClassInfo* classInfo() const { return &info; } \
static const KJS::ClassInfo info; \
bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&); \
ClassPrototype(KJS::ExecState* exec) \
: KJS::JSObject(ClassPrototypePrototype::self(exec)) { } \
\
};
#define KJS_IMPLEMENT_PROTOTYPE(ClassName, ClassPrototype, ClassFunction) \
const ClassInfo ClassPrototype::info = { ClassName"Prototype", 0, &ClassPrototype##Table, 0 }; \
JSObject* ClassPrototype::self(ExecState* exec) \
{ \
return KJS::cacheGlobalObject<ClassPrototype>(exec, "[[" ClassName ".prototype]]"); \
} \
bool ClassPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) \
{ \
return getStaticFunctionSlot<ClassFunction, JSObject>(exec, &ClassPrototype##Table, this, propertyName, slot); \
}
#define KJS_IMPLEMENT_PROTOTYPE_FUNCTION(ClassFunction) \
class ClassFunction : public InternalFunctionImp { \
public: \
ClassFunction(ExecState* exec, int i, int len, const Identifier& name) \
: InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name) \
, id(i) \
{ \
put(exec, exec->propertyNames().length, jsNumber(len), DontDelete|ReadOnly|DontEnum); \
} \
\
virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List& args); \
private: \
int id; \
};
#endif