Don't hide errors in QDirIterator
[qt-netbsd.git] / src / script / qscriptecmafunction.cpp
blob0bb5f12fa0564fec5a963949fe225298769c46a2
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
5 **
6 ** This file is part of the QtScript module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26 ** package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qscriptecmafunction_p.h"
44 #ifndef QT_NO_SCRIPT
46 #include "qscriptengine_p.h"
47 #include "qscriptvalueimpl_p.h"
48 #include "qscriptcontext_p.h"
49 #include "qscriptmember_p.h"
50 #include "qscriptobject_p.h"
52 #include <QtCore/QtDebug>
54 #ifndef QT_NO_QOBJECT
55 # include "qscriptextqobject_p.h"
56 # include <QtCore/QMetaMethod>
57 #endif
59 QT_BEGIN_NAMESPACE
61 namespace QScript { namespace Ecma {
63 class FunctionClassData: public QScriptClassData
65 QScriptClassInfo *m_classInfo;
67 public:
68 FunctionClassData(QScriptClassInfo *classInfo);
69 virtual ~FunctionClassData();
71 inline QScriptClassInfo *classInfo() const
72 { return m_classInfo; }
74 virtual bool resolve(const QScriptValueImpl &object,
75 QScriptNameIdImpl *nameId,
76 QScript::Member *member, QScriptValueImpl *base,
77 QScript::AccessMode access);
78 virtual bool get(const QScriptValueImpl &obj, const Member &m,
79 QScriptValueImpl *out_value);
80 virtual bool put(QScriptValueImpl *object, const QScript::Member &member,
81 const QScriptValueImpl &value);
82 virtual void mark(const QScriptValueImpl &object, int generation);
85 FunctionClassData::FunctionClassData(QScriptClassInfo *classInfo)
86 : m_classInfo(classInfo)
90 FunctionClassData::~FunctionClassData()
94 bool FunctionClassData::resolve(const QScriptValueImpl &object,
95 QScriptNameIdImpl *nameId,
96 QScript::Member *member, QScriptValueImpl *base,
97 QScript::AccessMode /*access*/)
99 if (object.classInfo() != classInfo())
100 return false;
102 QScriptEnginePrivate *eng = object.engine();
104 if ((nameId == eng->idTable()->id_length)
105 || (nameId == eng->idTable()->id_arguments)) {
106 member->native(nameId, /*id=*/ 0,
107 QScriptValue::Undeletable
108 | QScriptValue::ReadOnly
109 | QScriptValue::SkipInEnumeration);
110 *base = object;
111 return true;
114 return false;
117 bool FunctionClassData::get(const QScriptValueImpl &object, const Member &member,
118 QScriptValueImpl *result)
120 if (object.classInfo() != classInfo())
121 return false;
123 QScriptEnginePrivate *eng = object.engine();
124 if (! member.isNativeProperty())
125 return false;
127 if (member.nameId() == eng->idTable()->id_length) {
128 *result = QScriptValueImpl(object.toFunction()->length);
129 return true;
130 } else if (member.nameId() == eng->idTable()->id_arguments) {
131 *result = eng->nullValue();
132 return true;
135 return false;
138 bool FunctionClassData::put(QScriptValueImpl *, const QScript::Member &,
139 const QScriptValueImpl &)
141 return false;
144 void FunctionClassData::mark(const QScriptValueImpl &object, int generation)
146 if (object.classInfo() != classInfo())
147 return;
148 QScriptFunction *fun = object.toFunction();
149 QScriptEnginePrivate *eng = object.engine();
150 fun->mark(eng, generation);
153 Function::Function(QScriptEnginePrivate *eng, QScriptClassInfo *classInfo):
154 Core(eng, classInfo)
156 publicPrototype = eng->createFunction(method_void, 0, classInfo); // public prototype
159 Function::~Function()
163 void Function::initialize()
165 QScriptEnginePrivate *eng = engine();
166 eng->newConstructor(&ctor, this, publicPrototype);
168 addPrototypeFunction(QLatin1String("toString"), method_toString, 1);
169 addPrototypeFunction(QLatin1String("apply"), method_apply, 2);
170 addPrototypeFunction(QLatin1String("call"), method_call, 1);
171 addPrototypeFunction(QLatin1String("connect"), method_connect, 1);
172 addPrototypeFunction(QLatin1String("disconnect"), method_disconnect, 1);
174 classInfo()->setData(new FunctionClassData(classInfo()));
177 void Function::execute(QScriptContextPrivate *context)
179 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
180 engine()->notifyFunctionEntry(context);
181 #endif
182 int lineNumber = context->currentLine;
183 QString contents = buildFunction(context);
184 engine()->evaluate(context, contents, lineNumber);
185 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
186 engine()->notifyFunctionExit(context);
187 #endif
190 QString Function::buildFunction(QScriptContextPrivate *context)
192 int argc = context->argumentCount();
194 QString code;
195 code += QLatin1String("function(");
197 // the formals
198 for (int i = 0; i < argc - 1; ++i) {
199 if (i != 0)
200 code += QLatin1Char(',');
202 code += context->argument(i).toString();
205 code += QLatin1String("){");
207 // the function body
208 if (argc != 0)
209 code += context->argument(argc - 1).toString();
211 code += QLatin1String("\n}");
213 return code;
216 void Function::newFunction(QScriptValueImpl *result, QScriptFunction *foo)
218 engine()->newFunction(result, foo);
221 QScriptValueImpl Function::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *)
223 QScriptValueImpl self = context->thisObject();
224 if (QScriptFunction *foo = self.toFunction()) {
225 QString code = foo->toString(context);
226 return QScriptValueImpl(eng, code);
229 return throwThisObjectTypeError(
230 context, QLatin1String("Function.prototype.toString"));
233 QScriptValueImpl Function::method_call(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *)
235 if (! context->thisObject().isFunction()) {
236 return throwThisObjectTypeError(
237 context, QLatin1String("Function.prototype.call"));
240 QScriptValueImpl thisObject = eng->toObject(context->argument(0));
241 if (! (thisObject.isValid () && thisObject.isObject()))
242 thisObject = eng->globalObject();
244 QScriptValueImplList args;
245 for (int i = 1; i < context->argumentCount(); ++i)
246 args << context->argument(i);
248 return context->thisObject().call(thisObject, args);
251 QScriptValueImpl Function::method_apply(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *)
253 if (! context->thisObject().isFunction()) {
254 return throwThisObjectTypeError(
255 context, QLatin1String("Function.prototype.apply"));
258 QScriptValueImpl thisObject = eng->toObject(context->argument(0));
259 if (! (thisObject.isValid () && thisObject.isObject()))
260 thisObject = eng->globalObject();
262 QScriptValueImplList args;
263 QScriptValueImpl undefined = eng->undefinedValue();
265 QScriptValueImpl arg = context->argument(1);
267 if (Ecma::Array::Instance *arr = eng->arrayConstructor->get(arg)) {
268 QScript::Array actuals = arr->value;
270 for (quint32 i = 0; i < actuals.count(); ++i) {
271 QScriptValueImpl a = actuals.at(i);
272 if (! a.isValid())
273 args << undefined;
274 else
275 args << a;
277 } else if (arg.classInfo() == eng->m_class_arguments) {
278 QScript::ArgumentsObjectData *arguments;
279 arguments = static_cast<QScript::ArgumentsObjectData*> (arg.objectData());
280 QScriptObject *activation = arguments->activation.objectValue();
281 for (uint i = 0; i < arguments->length; ++i)
282 args << activation->m_values[i];
283 } else if (!(arg.isUndefined() || arg.isNull())) {
284 return context->throwError(QScriptContext::TypeError,
285 QLatin1String("Function.prototype.apply: second argument is not an array"));
288 return context->thisObject().call(thisObject, args);
291 QScriptValueImpl Function::method_void(QScriptContextPrivate *, QScriptEnginePrivate *eng, QScriptClassInfo *)
293 return eng->undefinedValue();
296 QScriptValueImpl Function::method_disconnect(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *)
298 #ifndef QT_NO_QOBJECT
299 if (context->argumentCount() == 0) {
300 return context->throwError(
301 QLatin1String("Function.prototype.disconnect: no arguments given"));
304 QScriptValueImpl self = context->thisObject();
305 QScriptFunction *fun = self.toFunction();
306 if ((fun == 0) || (fun->type() != QScriptFunction::Qt)) {
307 return context->throwError(
308 QScriptContext::TypeError,
309 QLatin1String("Function.prototype.disconnect: this object is not a signal"));
312 QtFunction *qtSignal = static_cast<QtFunction*>(fun);
314 const QMetaObject *meta = qtSignal->metaObject();
315 if (!meta) {
316 return context->throwError(
317 QScriptContext::TypeError,
318 QString::fromLatin1("Function.prototype.disconnect: cannot disconnect from deleted QObject"));
321 QMetaMethod sig = meta->method(qtSignal->initialIndex());
322 if (sig.methodType() != QMetaMethod::Signal) {
323 return context->throwError(QScriptContext::TypeError,
324 QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal")
325 .arg(QLatin1String(qtSignal->metaObject()->className()))
326 .arg(QLatin1String(sig.signature())));
329 QScriptValueImpl receiver;
330 QScriptValueImpl slot;
331 QScriptValueImpl arg0 = context->argument(0);
332 if (context->argumentCount() < 2) {
333 receiver = QScriptValueImpl();
334 slot = arg0;
335 } else {
336 receiver = arg0;
337 QScriptValueImpl arg1 = context->argument(1);
338 if (arg1.isFunction())
339 slot = arg1;
340 else
341 slot = receiver.property(arg1.toString(), QScriptValue::ResolvePrototype);
344 if (!slot.isFunction()) {
345 return context->throwError(
346 QScriptContext::TypeError,
347 QLatin1String("Function.prototype.disconnect: target is not a function"));
350 bool ok = eng->scriptDisconnect(self, receiver, slot);
351 if (!ok) {
352 return context->throwError(
353 QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1")
354 .arg(QLatin1String(qtSignal->metaObject()->className()))
355 .arg(QLatin1String(sig.signature())));
357 return eng->undefinedValue();
358 #else
359 Q_UNUSED(eng);
360 return context->throwError(QScriptContext::TypeError,
361 QLatin1String("Function.prototype.disconnect"));
362 #endif // QT_NO_QOBJECT
365 QScriptValueImpl Function::method_connect(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
367 Q_UNUSED(classInfo);
369 #ifndef QT_NO_QOBJECT
370 if (context->argumentCount() == 0) {
371 return context->throwError(
372 QLatin1String("Function.prototype.connect: no arguments given"));
375 QScriptValueImpl self = context->thisObject();
376 QScriptFunction *fun = self.toFunction();
377 if ((fun == 0) || (fun->type() != QScriptFunction::Qt)) {
378 return context->throwError(
379 QScriptContext::TypeError,
380 QLatin1String("Function.prototype.connect: this object is not a signal"));
383 QtFunction *qtSignal = static_cast<QtFunction*>(fun);
385 const QMetaObject *meta = qtSignal->metaObject();
386 if (!meta) {
387 return context->throwError(
388 QScriptContext::TypeError,
389 QString::fromLatin1("Function.prototype.connect: cannot connect to deleted QObject"));
392 QMetaMethod sig = meta->method(qtSignal->initialIndex());
393 if (sig.methodType() != QMetaMethod::Signal) {
394 return context->throwError(QScriptContext::TypeError,
395 QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal")
396 .arg(QLatin1String(qtSignal->metaObject()->className()))
397 .arg(QLatin1String(sig.signature())));
401 QList<int> overloads = qtSignal->overloadedIndexes();
402 if (!overloads.isEmpty()) {
403 overloads.append(qtSignal->initialIndex());
404 QByteArray signature = sig.signature();
405 QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n")
406 .arg(QLatin1String(qtSignal->metaObject()->className()))
407 .arg(QLatin1String(signature.left(signature.indexOf('('))));
408 for (int i = 0; i < overloads.size(); ++i) {
409 QMetaMethod mtd = meta->method(overloads.at(i));
410 message.append(QString::fromLatin1(" %0\n").arg(QString::fromLatin1(mtd.signature())));
412 message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload")
413 .arg(QLatin1String(signature)));
414 return context->throwError(message);
418 QScriptValueImpl receiver;
419 QScriptValueImpl slot;
420 QScriptValueImpl arg0 = context->argument(0);
421 if (context->argumentCount() < 2) {
422 receiver = QScriptValueImpl();
423 slot = arg0;
424 } else {
425 receiver = arg0;
426 QScriptValueImpl arg1 = context->argument(1);
427 if (arg1.isFunction())
428 slot = arg1;
429 else
430 slot = receiver.property(arg1.toString(), QScriptValue::ResolvePrototype);
433 if (!slot.isFunction()) {
434 return context->throwError(
435 QScriptContext::TypeError,
436 QLatin1String("Function.prototype.connect: target is not a function"));
439 bool ok = eng->scriptConnect(self, receiver, slot, Qt::AutoConnection);
440 if (!ok) {
441 return context->throwError(
442 QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1")
443 .arg(QLatin1String(qtSignal->metaObject()->className()))
444 .arg(QLatin1String(sig.signature())));
446 return eng->undefinedValue();
447 #else
448 Q_UNUSED(eng);
449 Q_UNUSED(classInfo);
450 return context->throwError(QScriptContext::TypeError,
451 QLatin1String("Function.prototype.connect"));
452 #endif // QT_NO_QOBJECT
455 } } // namespace QScript::Ecma
457 QT_END_NAMESPACE
459 #endif // QT_NO_SCRIPT