source: branches/4.5.1/src/script/qscriptcontext.cpp@ 921

Last change on this file since 921 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 16.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtScript module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
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.
22**
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.
27**
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.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptcontext.h"
43
44#ifndef QT_NO_SCRIPT
45
46#include "qscriptcontextinfo.h"
47#include "qscriptengine_p.h"
48#include "qscriptvalueimpl_p.h"
49#include "qscriptcontext_p.h"
50#include "qscriptmember_p.h"
51#include "qscriptobject_p.h"
52
53QT_BEGIN_NAMESPACE
54
55/*!
56 \since 4.3
57 \class QScriptContext
58
59 \brief The QScriptContext class represents a Qt Script function invocation.
60
61 \ingroup script
62 \mainclass
63
64 A QScriptContext provides access to the `this' object and arguments
65 passed to a script function. You typically want to access this
66 information when you're writing a native (C++) function (see
67 QScriptEngine::newFunction()) that will be called from script
68 code. For example, when the script code
69
70 \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 0
71
72 is evaluated, a QScriptContext will be created, and the context will
73 carry the arguments as QScriptValues; in this particular case, the
74 arguments will be one QScriptValue containing the number 20.5, a second
75 QScriptValue containing the string \c{"hello"}, and a third QScriptValue
76 containing a Qt Script object.
77
78 Use argumentCount() to get the number of arguments passed to the
79 function, and argument() to get an argument at a certain index. The
80 argumentsObject() function returns a Qt Script array object
81 containing all the arguments; you can use the QScriptValueIterator
82 to iterate over its elements, or pass the array on as arguments to
83 another script function using QScriptValue::call().
84
85 Use thisObject() to get the `this' object associated with the function call,
86 and setThisObject() to set the `this' object. If you are implementing a
87 native "instance method", you typically fetch the thisObject() and access
88 one or more of its properties:
89
90 \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 1
91
92 Use isCalledAsConstructor() to determine if the function was called
93 as a constructor (e.g. \c{"new foo()"} (as constructor) or just
94 \c{"foo()"}). When a function is called as a constructor, the
95 thisObject() contains the newly constructed object that the function
96 is expected to initialize.
97
98 Use throwValue() or throwError() to throw an exception.
99
100 Use callee() to obtain the QScriptValue that represents the function being
101 called. This can for example be used to call the function recursively.
102
103 Use parentContext() to get a pointer to the context that precedes
104 this context in the activation stack. This is mostly useful for
105 debugging purposes (e.g. when constructing some form of backtrace).
106
107 The activationObject() function returns the object that is used to
108 hold the local variables associated with this function call. You can
109 replace the activation object by calling setActivationObject(). A
110 typical usage of these functions is when you want script code to be
111 evaluated in the context of the parent context, e.g. to implement an
112 include() function:
113
114 \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 2
115
116 Use backtrace() to get a human-readable backtrace associated with
117 this context. This can be useful for debugging purposes when
118 implementing native functions. The toString() function provides a
119 string representation of the context. (QScriptContextInfo provides
120 more detailed debugging-related information about the
121 QScriptContext.)
122
123 Use engine() to obtain a pointer to the QScriptEngine that this context
124 resides in.
125
126 \sa QScriptContextInfo, QScriptEngine::newFunction(), QScriptable
127*/
128
129/*!
130 \enum QScriptContext::ExecutionState
131
132 This enum specifies the execution state of the context.
133
134 \value NormalState The context is in a normal state.
135
136 \value ExceptionState The context is in an exceptional state.
137*/
138
139/*!
140 \enum QScriptContext::Error
141
142 This enum specifies types of error.
143
144 \value ReferenceError A reference error.
145
146 \value SyntaxError A syntax error.
147
148 \value TypeError A type error.
149
150 \value RangeError A range error.
151
152 \value URIError A URI error.
153
154 \value UnknownError An unknown error.
155*/
156
157/*!
158 Throws an exception with the given \a value.
159 Returns the value thrown (the same as the argument).
160
161 \sa throwError(), state()
162*/
163QScriptValue QScriptContext::throwValue(const QScriptValue &value)
164{
165 Q_D(QScriptContext);
166 d->m_result = d->engine()->toImpl(value);
167 d->m_state = QScriptContext::ExceptionState;
168#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
169 d->engine()->notifyException(d);
170#endif
171 return value;
172}
173
174/*!
175 Throws an \a error with the given \a text.
176 Returns the created error object.
177
178 The \a text will be stored in the \c{message} property of the error
179 object.
180
181 The error object will be initialized to contain information about
182 the location where the error occurred; specifically, it will have
183 properties \c{lineNumber}, \c{fileName} and \c{stack}. These
184 properties are described in \l {QtScript Extensions to ECMAScript}.
185
186 \sa throwValue(), state()
187*/
188QScriptValue QScriptContext::throwError(Error error, const QString &text)
189{
190 Q_D(QScriptContext);
191 return d->engine()->toPublic(d->throwError(error, text));
192}
193
194/*!
195 \overload
196
197 Throws an error with the given \a text.
198 Returns the created error object.
199
200 \sa throwValue(), state()
201*/
202QScriptValue QScriptContext::throwError(const QString &text)
203{
204 Q_D(QScriptContext);
205 return d->engine()->toPublic(d->throwError(text));
206}
207
208/*!
209 \internal
210*/
211QScriptContext::QScriptContext():
212 d_ptr(new QScriptContextPrivate())
213{
214 d_ptr->q_ptr = this;
215}
216
217/*!
218 Destroys this QScriptContext.
219*/
220QScriptContext::~QScriptContext()
221{
222 delete d_ptr;
223 d_ptr = 0;
224}
225
226/*!
227 Returns the QScriptEngine that this QScriptContext belongs to.
228*/
229QScriptEngine *QScriptContext::engine() const
230{
231 Q_D(const QScriptContext);
232 return QScriptEnginePrivate::get(d->engine());
233}
234
235/*!
236 Returns the function argument at the given \a index.
237
238 If \a index >= argumentCount(), a QScriptValue of
239 the primitive type Undefined is returned.
240
241 \sa argumentCount()
242*/
243QScriptValue QScriptContext::argument(int index) const
244{
245 Q_D(const QScriptContext);
246 if (index < 0)
247 return QScriptValue();
248 return d->engine()->toPublic(d->argument(index));
249}
250
251/*!
252 Returns the callee. The callee is the function object that this
253 QScriptContext represents an invocation of.
254*/
255QScriptValue QScriptContext::callee() const
256{
257 Q_D(const QScriptContext);
258 return d->engine()->toPublic(d->m_callee);
259}
260
261/*!
262 Returns the arguments object of this QScriptContext.
263
264 The arguments object has properties \c callee (equal to callee())
265 and \c length (equal to argumentCount()), and properties \c 0, \c 1,
266 ..., argumentCount() - 1 that provide access to the argument
267 values. Initially, property \c P (0 <= \c P < argumentCount()) has
268 the same value as argument(\c P). In the case when \c P is less
269 than the number of formal parameters of the function, \c P shares
270 its value with the corresponding property of the activation object
271 (activationObject()). This means that changing this property changes
272 the corresponding property of the activation object and vice versa.
273
274 \sa argument(), activationObject()
275*/
276QScriptValue QScriptContext::argumentsObject() const
277{
278 Q_D(const QScriptContext);
279 return d->engine()->toPublic(d->argumentsObject());
280}
281
282/*!
283 Returns true if the function was called as a constructor
284 (e.g. \c{"new foo()"}); otherwise returns false.
285
286 When a function is called as constructor, the thisObject()
287 contains the newly constructed object to be initialized.
288*/
289bool QScriptContext::isCalledAsConstructor() const
290{
291 Q_D(const QScriptContext);
292 return d->m_calledAsConstructor;
293}
294
295/*!
296 Returns the parent context of this QScriptContext.
297*/
298QScriptContext *QScriptContext::parentContext() const
299{
300 Q_D(const QScriptContext);
301 return QScriptContextPrivate::get(d->previous);
302}
303
304/*!
305 Returns the number of arguments passed to the function
306 in this invocation.
307
308 Note that the argument count can be different from the
309 formal number of arguments (the \c{length} property of
310 callee()).
311
312 \sa argument()
313*/
314int QScriptContext::argumentCount() const
315{
316 Q_D(const QScriptContext);
317 return d->argc;
318}
319
320/*!
321 \internal
322*/
323QScriptValue QScriptContext::returnValue() const
324{
325 Q_D(const QScriptContext);
326 return d->engine()->toPublic(d->m_result);
327}
328
329/*!
330 \internal
331*/
332void QScriptContext::setReturnValue(const QScriptValue &result)
333{
334 Q_D(QScriptContext);
335 d->m_result = d->engine()->toImpl(result);
336}
337
338/*!
339 Returns the activation object of this QScriptContext. The activation
340 object provides access to the local variables associated with this
341 context.
342
343 \sa argument(), argumentsObject()
344*/
345QScriptValue QScriptContext::activationObject() const
346{
347 Q_D(const QScriptContext);
348 return d->engine()->toPublic(d->activationObject());
349}
350
351/*!
352 Sets the activation object of this QScriptContext to be the given \a
353 activation.
354
355 If \a activation is not an object, this function does nothing.
356*/
357void QScriptContext::setActivationObject(const QScriptValue &activation)
358{
359 Q_D(QScriptContext);
360 if (!activation.isObject()) {
361 return;
362 } else if (activation.engine() != engine()) {
363 qWarning("QScriptContext::setActivationObject() failed: "
364 "cannot set an object created in "
365 "a different engine");
366 } else {
367 d->m_activation = d->engine()->toImpl(activation);
368 }
369}
370
371/*!
372 Returns the `this' object associated with this QScriptContext.
373*/
374QScriptValue QScriptContext::thisObject() const
375{
376 Q_D(const QScriptContext);
377 return d->engine()->toPublic(d->m_thisObject);
378}
379
380/*!
381 Sets the `this' object associated with this QScriptContext to be
382 \a thisObject.
383
384 If \a thisObject is not an object, this function does nothing.
385*/
386void QScriptContext::setThisObject(const QScriptValue &thisObject)
387{
388 Q_D(QScriptContext);
389 if (!thisObject.isObject()) {
390 } else if (thisObject.engine() != engine()) {
391 qWarning("QScriptContext::setThisObject() failed: "
392 "cannot set an object created in "
393 "a different engine");
394 } else {
395 d->m_thisObject = d->engine()->toImpl(thisObject);
396 }
397}
398
399/*!
400 Returns the execution state of this QScriptContext.
401*/
402QScriptContext::ExecutionState QScriptContext::state() const
403{
404 Q_D(const QScriptContext);
405 return d->m_state;
406}
407
408/*!
409 Returns a human-readable backtrace of this QScriptContext.
410
411 Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}.
412
413 To access individual pieces of debugging-related information (for
414 example, to construct your own backtrace representation), use
415 QScriptContextInfo.
416
417 \sa QScriptEngine::uncaughtExceptionBacktrace(), QScriptContextInfo, toString()
418*/
419QStringList QScriptContext::backtrace() const
420{
421 Q_D(const QScriptContext);
422 return d->backtrace();
423}
424
425static QString safeValueToString(const QScriptValue &value)
426{
427 if (value.isObject())
428 return QLatin1String("[object Object]");
429 else
430 return value.toString();
431}
432
433/*!
434 \since 4.4
435
436 Returns a string representation of this context.
437 This is useful for debugging.
438
439 \sa backtrace()
440*/
441QString QScriptContext::toString() const
442{
443 QScriptContextInfo info(this);
444 QString result;
445
446 QString functionName = info.functionName();
447 if (functionName.isEmpty()) {
448 if (parentContext()) {
449 if (info.functionType() == QScriptContextInfo::ScriptFunction)
450 result.append(QLatin1String("<anonymous>"));
451 else
452 result.append(QLatin1String("<native>"));
453 } else {
454 result.append(QLatin1String("<global>"));
455 }
456 } else {
457 result.append(functionName);
458 }
459
460 QStringList parameterNames = info.functionParameterNames();
461 result.append(QLatin1String(" ("));
462 for (int i = 0; i < argumentCount(); ++i) {
463 if (i > 0)
464 result.append(QLatin1String(", "));
465 if (i < parameterNames.count()) {
466 result.append(parameterNames.at(i));
467 result.append(QLatin1Char('='));
468 }
469 QScriptValue arg = argument(i);
470 result.append(safeValueToString(arg));
471 }
472 result.append(QLatin1String(")"));
473
474 QString fileName = info.fileName();
475 int lineNumber = info.lineNumber();
476 result.append(QLatin1String(" at "));
477 if (!fileName.isEmpty()) {
478 result.append(fileName);
479 result.append(QLatin1Char(':'));
480 }
481 result.append(QString::number(lineNumber));
482 return result;
483}
484
485/*!
486 \internal
487 \since 4.5
488
489 Returns the scope chain of this QScriptContext.
490*/
491QScriptValueList QScriptContext::scopeChain() const
492{
493 Q_D(const QScriptContext);
494 // make sure arguments properties are initialized
495 const QScriptContextPrivate *ctx = d;
496 while (ctx) {
497 (void)ctx->activationObject();
498 ctx = ctx->previous;
499 }
500 QScriptValueList result;
501 QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine());
502 QScriptValueImpl scope = d->m_scopeChain;
503 while (scope.isObject()) {
504 if (scope.classInfo() == eng_p->m_class_with)
505 result.append(eng_p->toPublic(scope.prototype()));
506 else
507 result.append(eng_p->toPublic(scope));
508 scope = scope.scope();
509 }
510 return result;
511}
512
513/*!
514 \internal
515 \since 4.5
516
517 Adds the given \a object to the front of this context's scope chain.
518
519 If \a object is not an object, this function does nothing.
520*/
521void QScriptContext::pushScope(const QScriptValue &object)
522{
523 Q_D(QScriptContext);
524 if (!object.isObject()) {
525 return;
526 } else if (object.engine() != engine()) {
527 qWarning("QScriptContext::pushScope() failed: "
528 "cannot push an object created in "
529 "a different engine");
530 return;
531 }
532 QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine());
533 if (!d->m_scopeChain.isValid()) {
534 d->m_scopeChain = eng_p->toImpl(object);
535 } else {
536 QScriptValueImpl withObject;
537 eng_p->newObject(&withObject, eng_p->toImpl(object), eng_p->m_class_with);
538 withObject.m_object_value->m_scope = d->m_scopeChain;
539 withObject.setInternalValue(1); // to differentiate from with-statement objects
540 d->m_scopeChain = withObject;
541 }
542}
543
544/*!
545 \internal
546 \since 4.5
547
548 Removes the front object from this context's scope chain, and
549 returns the removed object.
550
551 If the scope chain is already empty, this function returns an
552 invalid QScriptValue.
553*/
554QScriptValue QScriptContext::popScope()
555{
556 Q_D(QScriptContext);
557 if (!d->m_scopeChain.isObject())
558 return QScriptValue();
559 QScriptValueImpl result;
560 QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine());
561 if (d->m_scopeChain.classInfo() != eng_p->m_class_with)
562 result = d->m_scopeChain;
563 else
564 result = d->m_scopeChain.prototype();
565 d->m_scopeChain = d->m_scopeChain.m_object_value->m_scope;
566 return eng_p->toPublic(result);
567}
568
569QT_END_NAMESPACE
570
571#endif // QT_NO_SCRIPT
Note: See TracBrowser for help on using the repository browser.