KJS

kjsprototype.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 2008 Harri Porten ([email protected])
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21 
22 #include "kjsprototype.h"
23 #include "kjsinterpreter.h"
24 #include "kjsarguments.h"
25 #include "kjsprivate.h"
26 
27 #include "kjs/object.h"
28 #include "kjs/JSVariableObject.h"
29 #include "kjs/context.h"
30 #include "kjs/interpreter.h"
31 
32 #include <QMap>
33 
34 using namespace KJS;
35 
36 class KJSCustomProperty
37 {
38 public:
39  KJSCustomProperty(KJSPrototype::PropertyGetter g,
41  : getter(g), setter(s)
42  {
43  }
44 
45  JSValue *read(ExecState *exec, void *object);
46  void write(ExecState *exec, void *object, JSValue *value);
47 
48 private:
51 };
52 
53 class CustomObjectInfo
54 {
55 public:
56  CustomObjectInfo(void *v): iv(v) {}
57  virtual ~CustomObjectInfo() {}
58  void *internalValue()
59  {
60  return iv;
61  }
62 protected:
63  void *iv;
64 };
65 
66 template<class Base>
67 class CustomObject : public Base, public CustomObjectInfo
68 {
69 public:
70  CustomObject(JSValue *proto, void *v)
71  : Base(proto),
72  CustomObjectInfo(v)
73  {}
74 
75  using Base::put;
76  void put(ExecState *exec, const Identifier &id,
77  JSValue *value, int attr = None);
78 
79  // rtti
80  static const ClassInfo info;
81  const ClassInfo *classInfo() const
82  {
83  return &info;
84  }
85 };
86 
87 template<>
88 const ClassInfo CustomObject<JSObject>::info = { "CustomObject", nullptr, nullptr, nullptr };
89 
90 template<>
91 const ClassInfo CustomObject<JSGlobalObject>::info = { "CustomGlobalObject", nullptr, nullptr, nullptr };
92 
93 class KJSCustomFunction : public JSObject
94 {
95 public:
96  KJSCustomFunction(ExecState *exec, KJSPrototype::FunctionCall f)
97  : callback(f)
98  {
99  setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
100  }
101 
102  JSValue *callAsFunction(ExecState *exec, JSObject *thisObj,
103  const List &args);
104  bool implementsCall() const
105  {
106  return true;
107  }
108 
109 private:
111 };
112 
113 JSValue *KJSCustomFunction::callAsFunction(ExecState *exec, JSObject *thisObj,
114  const List &args)
115 {
116  // FIXME: does not protect against mixing custom objects
117  CustomObjectInfo *inf = dynamic_cast<CustomObjectInfo *>(thisObj);
118 
119  if (!inf) {
120  const char *errMsg = "Attempt at calling a function with an invalid receiver";
121  KJS::JSObject *err = KJS::Error::create(exec, KJS::TypeError, errMsg);
122  exec->setException(err);
123  return err;
124  }
125 
126  void *thisValue = inf->internalValue();
127 
128  KJSContext ctx(EXECSTATE_HANDLE(exec));
129  KJSArguments a(LIST_HANDLE(&args));
130  KJSObject res = (*callback)(&ctx, thisValue, a);
131  return JSVALUE(&res);
132 }
133 
134 JSValue *KJSCustomProperty::read(ExecState *exec, void *object)
135 {
136  assert(getter);
137 
138  KJSContext ctx(EXECSTATE_HANDLE(exec));
139  KJSObject res = (*getter)(&ctx, object);
140  return JSVALUE(&res);
141 }
142 
143 void KJSCustomProperty::write(ExecState *exec, void *object, JSValue *value)
144 {
145  KJSContext ctx(EXECSTATE_HANDLE(exec));
146 
147  if (setter) {
148  KJSObject vo(JSVALUE_HANDLE(value));
149  (*setter)(&ctx, object, vo);
150  } else {
151  JSObject *e = Error::create(exec, GeneralError,
152  "Property is read-only");
153  exec->setException(e);
154  }
155 }
156 
157 static JSValue *getPropertyValue(ExecState *exec, JSObject *originalObject,
158  const Identifier &, const PropertySlot &sl)
159 {
160  CustomObjectInfo *inf = dynamic_cast<CustomObjectInfo *>(originalObject);
161  if (!inf) {
162  return jsUndefined();
163  }
164 
165  KJSCustomProperty *p =
166  reinterpret_cast<KJSCustomProperty *>(sl.customValue());
167 
168  return p->read(exec, inf->internalValue());
169 }
170 
171 // FIXME: or use Identifier?
172 // FIXME: use values
174 
175 class CustomPrototype : public JSObject
176 {
177 public:
178  CustomPrototype()
179  {
180  }
181  ~CustomPrototype()
182  {
183  qDeleteAll(properties);
184  }
185 
186  using KJS::JSObject::getOwnPropertySlot;
187  bool getOwnPropertySlot(ExecState *exec, const Identifier &id,
188  PropertySlot &sl)
189  {
190  CustomPropertyMap::iterator it = properties.find(id.ustring());
191  if (it == properties.end()) {
192  return JSObject::getOwnPropertySlot(exec, id, sl);
193  }
194 
195  sl.setCustomValue(nullptr, *it, getPropertyValue);
196 
197  return true;
198  }
199 
200  void registerProperty(const QString &name,
203  {
204  properties.insert(toUString(name), new KJSCustomProperty(g, s));
205  }
206 
207  void registerFunction(ExecState *exec,
208  const QString &name, KJSPrototype::FunctionCall f)
209  {
210  putDirect(toIdentifier(name), new KJSCustomFunction(exec, f));
211  }
212 
213  template<typename Base>
214  bool setProperty(ExecState *exec, CustomObject<Base> *obj,
215  const Identifier &id, JSValue *value)
216  {
217  CustomPropertyMap::iterator it = properties.find(id.ustring());
218  if (it == properties.end()) {
219  return false;
220  }
221 
222  (*it)->write(exec, obj->internalValue(), value);
223 
224  return true;
225  }
226 
227 private:
228  CustomPropertyMap properties;
229 };
230 
231 template<class Base>
232 void CustomObject<Base>::put(ExecState *exec, const Identifier &id,
233  JSValue *value, int attr)
234 {
235  CustomPrototype *p = static_cast<CustomPrototype *>(this->prototype());
236 
237  if (!p->setProperty(exec, this, id, value)) {
238  Base::put(exec, id, value, attr);
239  }
240 }
241 
243 {
244  CustomPrototype *p = new CustomPrototype;
245  gcProtect(p);
246 
247  hnd = PROTOTYPE_HANDLE(p);
248 }
249 
251 {
252  gcUnprotect(PROTOTYPE(this));
253 }
254 
255 void KJSPrototype::defineConstant(const QString &name, double value)
256 {
257  CustomPrototype *p = PROTOTYPE(this);
258 
259  p->putDirect(toIdentifier(name), jsNumber(value),
260  DontEnum | DontDelete | ReadOnly);
261 }
262 
263 void KJSPrototype::defineConstant(const QString &name, const QString &value)
264 {
265  CustomPrototype *p = PROTOTYPE(this);
266 
267  p->putDirect(toIdentifier(name), jsString(toUString(value)),
268  DontEnum | DontDelete | ReadOnly);
269 }
270 
271 void KJSPrototype::defineConstant(const QString &name, const KJSObject &value)
272 {
273  CustomPrototype *p = PROTOTYPE(this);
274 
275  p->putDirect(toIdentifier(name), JSVALUE(&value),
276  DontEnum | DontDelete | ReadOnly);
277 }
278 
280 {
281  CustomPrototype *p = PROTOTYPE(this);
282 
283  if (ctx && !p->prototype()) {
284  ExecState *exec = EXECSTATE(ctx);
286  JSObject *objectProto = i->builtinObjectPrototype();
287  p->setPrototype(objectProto);
288  }
289 
290  CustomObject<JSObject> *newObj = new CustomObject<JSObject>(p, internalValue);
291  return KJSObject(JSVALUE_HANDLE(newObj));
292 }
293 
295 {
296  CustomPrototype *p = PROTOTYPE(this);
297 
298  CustomObject<JSGlobalObject> *newObj = new CustomObject<JSGlobalObject>(p, internalValue);
299  return KJSGlobalObject(JSVALUE_HANDLE(newObj));
300 }
301 
303  const QString &name,
304  PropertyGetter getter,
305  PropertySetter setter)
306 {
307  Q_UNUSED(ctx);
308  assert(getter);
309 
310  CustomPrototype *p = PROTOTYPE(this);
311 
312  p->registerProperty(name, getter, setter);
313 }
314 
316  const QString &name, FunctionCall callback)
317 {
318  assert(callback);
319 
320  CustomPrototype *p = PROTOTYPE(this);
321  ExecState *exec = EXECSTATE(ctx);
322 
323  p->registerFunction(exec, name, callback);
324 }
325 
~KJSPrototype()
Destructs this prototype object.
KJSGlobalObject constructGlobalObject(void *internalValue=nullptr)
Similar to constructObject() but specialized on the construction of global objects.
void setException(JSValue *e)
Set the exception associated with this execution state, updating the program counter appropriately...
Definition: ExecState.cpp:169
A class representing a global object of an execution environment.
Definition: kjsobject.h:279
Interpreter objects can be used to evaluate ECMAScript code.
Definition: interpreter.h:56
KGuiItem properties()
A class representing a JavaScript execution context.
Definition: kjscontext.h:41
void defineFunction(KJSContext *ctx, const QString &name, FunctionCall callback)
Define a function.
KIOCORE_EXPORT TransferJob * put(const QUrl &url, int permissions, JobFlags flags=DefaultFlags)
void defineProperty(KJSContext *ctx, const QString &name, PropertyGetter getter, PropertySetter setter=nullptr)
Defines a property of this prototype with C++ callback functions for getting and setting the property...
KJSObject(* FunctionCall)(KJSContext *context, void *object, const KJSArguments &arguments)
Signature for function call callback function.
Definition: kjsprototype.h:92
A class representing a list of JavaScript arguments.
Definition: kjsarguments.h:36
void defineConstant(const QString &name, double value)
Add a read-only numerical property to this object.
JSValue is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects in...
Definition: value.h:58
A class representing a JavaScript value.
Definition: kjsobject.h:48
KJSPrototype()
Constructs a prototype object with its own prototype property set to the Object prototype.
void(* PropertySetter)(KJSContext *context, void *object, KJSObject value)
Function signature for a property setter function.
Definition: kjsprototype.h:75
JSObject * builtinObjectPrototype() const
Returns the builtin "Object.prototype" object.
Native list type.
Definition: list.h:52
Class Information.
Definition: object.h:48
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope&#39;s global object.
Definition: ExecState.cpp:35
KJSObject(* PropertyGetter)(KJSContext *context, void *object)
Function signature for a property getter function.
Definition: kjsprototype.h:70
QCA_EXPORT void setProperty(const QString &name, const QVariant &value)
static JSObject * create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL)
Factory method for error objects.
Definition: object.cpp:813
KJSObject constructObject(KJSContext *ctx, void *internalValue=nullptr)
Construct an object with this prototype and the specified internal value.
Represents the current state of script execution.
Definition: ExecState.h:53
Represents an Identifier for a Javascript object.
Definition: identifier.h:36
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Jan 16 2021 23:02:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.