blob: 0cbc13d1dd3c76fb4485cb3961326349407e804b [file] [log] [blame]
/*
Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
2004, 2005 Rob Buis <buis@kde.org>
This file is part of the KDE project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#ifndef KDOM_DOMLookup_H
#define KDOM_DOMLookup_H
#ifndef APPLE_CHANGES
#include <ostream>
#endif
#include <kdebug.h>
#include <kjs/value.h>
#include <kjs/object.h>
#include <kjs/lookup.h>
#include <kjs/interpreter.h>
#include <kdom/ecma/ScriptInterpreter.h>
namespace KDOM
{
/**
* Helper method for property lookups.
*
* This method does it all (looking in the hashtable, checking for function
* overrides, creating the function or retrieving from cache, calling
* getValueProperty in case of a non-function property, forwarding to parent[s] if
* unknown property).
*
* Template arguments:
* @param FuncImp the class which implements this object's functions
* @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
* for non-function properties, and the getInParents() method (auto-generated).
*
* Method arguments:
* @param exec execution state, as usual
* @param propertyName the property we're looking for
* @param table the static hashtable for this class
* @param thisObj "this"
*/
template<class FuncImp, class ThisImp>
inline KJS::ValueImp *lookupGet(KJS::ExecState *exec,
const KJS::Identifier &propertyName,
const KJS::HashTable *table,
const ThisImp *thisObj, // the 'impl' object
const KJS::ObjectImp *bridge)
{
#if 0
const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);
if(!entry) // not found, forward to parents
return thisObj->getInParents(exec, propertyName, bridge);
if(entry->attr & KJS::Function)
return KJS::lookupOrCreateFunction<FuncImp>(exec, propertyName,
const_cast<KJS::ObjectImp *>(bridge),
entry->value, entry->params, entry->attr);
return thisObj->getValueProperty(exec, entry->value);
#endif
return KJS::Undefined();
}
/**
* Simplified version of lookupGet in case there are no functions, only "values".
* Using this instead of lookupGet removes the need for a FuncImp class.
*/
template <class ThisImp>
inline KJS::ValueImp *lookupGetValue(KJS::ExecState *exec,
const KJS::Identifier &propertyName,
const KJS::HashTable *table,
const ThisImp *thisObj, // the 'impl' object
const KJS::ObjectImp *bridge)
{
#if 0
const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);
if(!entry) // not found, forward to parents
return thisObj->getInParents(exec, propertyName, bridge);
if(entry->attr & KJS::Function)
kdError(26004) << "Function bit set! Shouldn't happen in lookupGetValue! propertyName was " << propertyName.qstring() << endl;
return thisObj->getValueProperty(exec, entry->value);
#endif
return KJS::Undefined();
}
/**
* This one is for "put".
* Lookup hash entry for property to be set, and set the value.
* The "this" class must implement putValueProperty.
* If it returns false, put() will return false, and KDOMRequest will set a dynamic property in ObjectImp
*/
template <class ThisImp>
inline bool lookupPut(KJS::ExecState *exec,
const KJS::Identifier &propertyName,
KJS::ValueImp *value,
int attr,
const KJS::HashTable *table,
ThisImp *thisObj)
{
const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);
if(!entry) // not found, forward to parents
return thisObj->putInParents(exec, propertyName, value, attr);
else if(entry->attr & KJS::Function) // Function: put as override property
return false;
else if(entry->attr & KJS::ReadOnly && !(attr & KJS::Internal)) // readonly! Can't put!
{
#ifdef KJS_VERBOSE
kdWarning(26004) <<" Attempt to change value of readonly property '" << propertyName.qstring() << "'" << endl;
#endif
return true; // "we did it" -> don't put override property
}
else
{
thisObj->putValueProperty(exec, entry->value, value, attr);
return true;
}
}
}
// These macros are used by the generated files in kdom/bindings/js/*.
// IDLCodeGeneratorJs.pm knows how to use them, read it's source :-)
#define ECMA_IMPLEMENT_CONSTRUCTOR(ClassName, Class) \
KJS::ValueImp *ClassName::get(KJS::ExecState *, const KJS::Identifier &propertyName, const KJS::ObjectImp *) const { \
const KJS::HashEntry *entry = KJS::Lookup::findEntry(&s_hashTable, propertyName); \
if(entry) return KJS::Number(entry->value); \
return KJS::Undefined(); \
} \
bool ClassName::hasProperty(KJS::ExecState *, const KJS::Identifier &propertyName) const { \
return KJS::Lookup::findEntry(&s_hashTable, propertyName); \
} \
KJS::ObjectImp *ClassName::prototype(KJS::ExecState *exec) const { \
return exec->interpreter()->builtinObjectPrototype(); \
} \
const KJS::ClassInfo ClassName::s_classInfo = { Class "Constructor", 0, &s_hashTable, 0 }; \
KJS::ValueImp *get##ClassName(KJS::ExecState *exec) { \
return KJS::cacheGlobalObject<ClassName>(exec, "[[" Class ".constructor]]"); \
}
#define ECMA_DEFINE_CONSTRUCTOR(ClassName) \
class ClassName : public KJS::ObjectImp { \
public: \
ClassName(KJS::ExecState *) : KJS::ObjectImp() { } \
KJS::ValueImp *get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp *obj) const; \
bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
KJS::ObjectImp *prototype(KJS::ExecState *exec) const; \
\
static const KJS::ClassInfo s_classInfo; \
static const struct KJS::HashTable s_hashTable; \
}; \
KJS::ValueImp *get##ClassName(KJS::ExecState *exec);
#define ECMA_DEFINE_PROTOTYPE(ClassProto) \
class ClassProto : public KJS::ObjectImp { \
public: \
static KJS::ObjectImp *self(KJS::ExecState *exec); \
ClassProto(KJS::ExecState *exec) : KJS::ObjectImp(exec->interpreter()->builtinObjectPrototype()) { } \
virtual const KJS::ClassInfo *classInfo() const { return &info; } \
static const KJS::ClassInfo info; \
KJS::ValueImp *get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
static const struct KJS::HashTable s_hashTable; \
};
#define ECMA_IMPLEMENT_PROTOTYPE(ClassName, ClassProto, ClassFunc) \
KJS::ValueImp *ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const { \
return KJS::Undefined(); \
} \
bool ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const { \
return KJS::ObjectImp::hasProperty(exec, propertyName); \
} \
KJS::ObjectImp *ClassProto::self(KJS::ExecState *exec) { \
return KJS::cacheGlobalObject<ClassProto>(exec, "[[" ClassName ".prototype]]"); \
} \
const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 };
#define ECMA_IMPLEMENT_PROTOFUNC(ClassFunc, Class, ClassImpl) \
class ClassFunc : public KJS::ObjectImp { \
public: \
ClassFunc(KJS::ExecState *exec, int i, int len) : KJS::ObjectImp(/* proto? */), id(i) { \
put(exec, "length", KJS::Number(len), KJS::DontDelete | KJS::ReadOnly | KJS::DontEnum); \
} \
/** Used by callAsFunction() to check the type of thisObj. Generated code */ \
ClassImpl *cast(KJS::ExecState *exec, const KJS::ObjectImp *bridge) const; \
\
virtual bool implementsCall() const { return true; } \
virtual KJS::ValueImp *callAsFunction(KJS::ExecState *exec, KJS::ObjectImp *thisObj, const KJS::List &args); \
\
private: \
int id; \
};
// To be used when casting the type of an argument
#define KDOM_CHECK(DOMObjImpl, DOMObjWrapper, theObj) \
DOMObjImpl *obj = cast(exec, static_cast<KJS::ObjectImp *>(theObj)); \
if(!obj) { \
QString errMsg = QString::fromLatin1("Attempt at calling a function that expects a ") + \
QString::fromLatin1(DOMObjWrapper::s_classInfo.className) + \
QString::fromLatin1(" on a ") + \
QString::fromLatin1(theObj->classInfo()->className); \
kdDebug(26004) << k_funcinfo << " " << errMsg << endl; \
KJS::ObjectImp *err = KJS::throwError(exec, KJS::TypeError, errMsg.ascii()); \
return err; \
}
// To be used in all call() implementations!
// Can't use if (!thisObj.inherits(&ClassName::s_classInfo) since
// we don't use the (single-parent) inheritance of ClassInfo...
#define KDOM_CHECK_THIS(DOMObjImpl, DOMObjWrapper) KDOM_CHECK(DOMObjImpl, DOMObjWrapper, thisObj)
// Helpers to hide exception stuff...
// used within get/putValueProprety
#define KDOM_ENTER_SAFE try {
#define KDOM_LEAVE_SAFE_COMMON(Exception) \
catch(Exception##Impl *e) { \
KJS::ObjectImp *err = KJS::throwError(exec, KJS::GeneralError, \
QString::fromLatin1("%1 %2"). \
arg(QString::fromLatin1(Exception##Wrapper::s_classInfo.className)). \
arg(QString::number(e->code())).latin1()); \
err->put(exec, "code", KJS::Number(e->code())); \
}
// The first exceptions uses this macro...
#define KDOM_LEAVE_SAFE(Exception) \
} \
KDOM_LEAVE_SAFE_COMMON(Exception)
// ... and all others this one
#define KDOM_LEAVE_SAFE_NEXT(Exception) \
KDOM_LEAVE_SAFE_COMMON(Exception)
#define KDOM_LEAVE_CALL_SAFE_COMMON(Exception) \
catch(Exception##Impl *e) { \
KJS::ObjectImp *err = KJS::throwError(exec, KJS::GeneralError, \
QString::fromLatin1("%1 %2"). \
arg(QString::fromLatin1(Exception##Wrapper::s_classInfo.className)). \
arg(QString::number(e->code())).latin1()); \
err->put(exec, "code", KJS::Number(e->code())); \
return err; \
}
// The first exceptions uses this macro...
#define KDOM_LEAVE_CALL_SAFE(Exception) \
} \
KDOM_LEAVE_CALL_SAFE_COMMON(Exception)
// ... and all others this one.
#define KDOM_LEAVE_CALL_SAFE_NEXT(Exception) \
KDOM_LEAVE_CALL_SAFE_COMMON(Exception)
#endif
// vim:ts=4:noet