~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/script/api/qscriptcontext.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
4
** All rights reserved.
 
5
** Contact: Nokia Corporation (qt-info@nokia.com)
 
6
**
 
7
** This file is part of the QtScript module of the Qt Toolkit.
 
8
**
 
9
** $QT_BEGIN_LICENSE:LGPL$
 
10
** No Commercial Usage
 
11
** This file contains pre-release code and may not be distributed.
 
12
** You may use this file in accordance with the terms and conditions
 
13
** contained in the Technology Preview License Agreement accompanying
 
14
** this package.
 
15
**
 
16
** GNU Lesser General Public License Usage
 
17
** Alternatively, this file may be used under the terms of the GNU Lesser
 
18
** General Public License version 2.1 as published by the Free Software
 
19
** Foundation and appearing in the file LICENSE.LGPL included in the
 
20
** packaging of this file.  Please review the following information to
 
21
** ensure the GNU Lesser General Public License version 2.1 requirements
 
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
23
**
 
24
** In addition, as a special exception, Nokia gives you certain additional
 
25
** rights.  These rights are described in the Nokia Qt LGPL Exception
 
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
27
**
 
28
** If you have questions regarding the use of this file, please contact
 
29
** Nokia at qt-info@nokia.com.
 
30
**
 
31
**
 
32
**
 
33
**
 
34
**
 
35
**
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "config.h"
 
43
#include "qscriptcontext.h"
 
44
 
 
45
#include "qscriptcontext_p.h"
 
46
#include "qscriptcontextinfo.h"
 
47
#include "qscriptengine.h"
 
48
#include "qscriptengine_p.h"
 
49
#include "../bridge/qscriptactivationobject_p.h"
 
50
 
 
51
#include "Arguments.h"
 
52
#include "CodeBlock.h"
 
53
#include "Error.h"
 
54
#include "JSFunction.h"
 
55
#include "JSObject.h"
 
56
#include "JSGlobalObject.h"
 
57
 
 
58
#include <QtCore/qstringlist.h>
 
59
 
 
60
QT_BEGIN_NAMESPACE
 
61
 
 
62
/*!
 
63
  \since 4.3
 
64
  \class QScriptContext
 
65
 
 
66
  \brief The QScriptContext class represents a Qt Script function invocation.
 
67
 
 
68
  \ingroup script
 
69
  \mainclass
 
70
 
 
71
  A QScriptContext provides access to the `this' object and arguments
 
72
  passed to a script function. You typically want to access this
 
73
  information when you're writing a native (C++) function (see
 
74
  QScriptEngine::newFunction()) that will be called from script
 
75
  code. For example, when the script code
 
76
 
 
77
  \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 0
 
78
 
 
79
  is evaluated, a QScriptContext will be created, and the context will
 
80
  carry the arguments as QScriptValues; in this particular case, the
 
81
  arguments will be one QScriptValue containing the number 20.5, a second
 
82
  QScriptValue containing the string \c{"hello"}, and a third QScriptValue
 
83
  containing a Qt Script object.
 
84
 
 
85
  Use argumentCount() to get the number of arguments passed to the
 
86
  function, and argument() to get an argument at a certain index. The
 
87
  argumentsObject() function returns a Qt Script array object
 
88
  containing all the arguments; you can use the QScriptValueIterator
 
89
  to iterate over its elements, or pass the array on as arguments to
 
90
  another script function using QScriptValue::call().
 
91
 
 
92
  Use thisObject() to get the `this' object associated with the function call,
 
93
  and setThisObject() to set the `this' object. If you are implementing a
 
94
  native "instance method", you typically fetch the thisObject() and access
 
95
  one or more of its properties:
 
96
 
 
97
  \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 1
 
98
 
 
99
  Use isCalledAsConstructor() to determine if the function was called
 
100
  as a constructor (e.g. \c{"new foo()"} (as constructor) or just
 
101
  \c{"foo()"}).  When a function is called as a constructor, the
 
102
  thisObject() contains the newly constructed object that the function
 
103
  is expected to initialize.
 
104
 
 
105
  Use throwValue() or throwError() to throw an exception.
 
106
 
 
107
  Use callee() to obtain the QScriptValue that represents the function being
 
108
  called. This can for example be used to call the function recursively.
 
109
 
 
110
  Use parentContext() to get a pointer to the context that precedes
 
111
  this context in the activation stack. This is mostly useful for
 
112
  debugging purposes (e.g. when constructing some form of backtrace).
 
113
 
 
114
  The activationObject() function returns the object that is used to
 
115
  hold the local variables associated with this function call. You can
 
116
  replace the activation object by calling setActivationObject(). A
 
117
  typical usage of these functions is when you want script code to be
 
118
  evaluated in the context of the parent context, e.g. to implement an
 
119
  include() function:
 
120
 
 
121
  \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 2
 
122
 
 
123
  Use backtrace() to get a human-readable backtrace associated with
 
124
  this context. This can be useful for debugging purposes when
 
125
  implementing native functions. The toString() function provides a
 
126
  string representation of the context. (QScriptContextInfo provides
 
127
  more detailed debugging-related information about the
 
128
  QScriptContext.)
 
129
 
 
130
  Use engine() to obtain a pointer to the QScriptEngine that this context
 
131
  resides in.
 
132
 
 
133
  \sa QScriptContextInfo, QScriptEngine::newFunction(), QScriptable
 
134
*/
 
135
 
 
136
/*!
 
137
    \enum QScriptContext::ExecutionState
 
138
 
 
139
    This enum specifies the frameution state of the context.
 
140
 
 
141
    \value NormalState The context is in a normal state.
 
142
 
 
143
    \value ExceptionState The context is in an exceptional state.
 
144
*/
 
145
 
 
146
/*!
 
147
    \enum QScriptContext::Error
 
148
 
 
149
    This enum specifies types of error.
 
150
 
 
151
    \value ReferenceError A reference error.
 
152
 
 
153
    \value SyntaxError A syntax error.
 
154
 
 
155
    \value TypeError A type error.
 
156
 
 
157
    \value RangeError A range error.
 
158
 
 
159
    \value URIError A URI error.
 
160
 
 
161
    \value UnknownError An unknown error.
 
162
*/
 
163
 
 
164
/*!
 
165
  \internal
 
166
*/
 
167
QScriptContext::QScriptContext()
 
168
{
 
169
    //QScriptContext doesn't exist,  pointer to QScriptContext are just pointer to  JSC::CallFrame
 
170
    Q_ASSERT(false);
 
171
}
 
172
 
 
173
/*!
 
174
  Throws an exception with the given \a value.
 
175
  Returns the value thrown (the same as the argument).
 
176
 
 
177
  \sa throwError(), state()
 
178
*/
 
179
QScriptValue QScriptContext::throwValue(const QScriptValue &value)
 
180
{
 
181
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
182
    JSC::JSValue jscValue = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(value);
 
183
    frame->setException(jscValue);
 
184
    return value;
 
185
}
 
186
 
 
187
/*!
 
188
  Throws an \a error with the given \a text.
 
189
  Returns the created error object.
 
190
 
 
191
  The \a text will be stored in the \c{message} property of the error
 
192
  object.
 
193
 
 
194
  The error object will be initialized to contain information about
 
195
  the location where the error occurred; specifically, it will have
 
196
  properties \c{lineNumber}, \c{fileName} and \c{stack}. These
 
197
  properties are described in \l {QtScript Extensions to ECMAScript}.
 
198
 
 
199
  \sa throwValue(), state()
 
200
*/
 
201
QScriptValue QScriptContext::throwError(Error error, const QString &text)
 
202
{
 
203
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
204
    JSC::ErrorType jscError = JSC::GeneralError;
 
205
    switch (error) {
 
206
    case UnknownError:
 
207
        break;
 
208
    case ReferenceError:
 
209
        jscError = JSC::ReferenceError;
 
210
        break;
 
211
    case SyntaxError:
 
212
        jscError = JSC::SyntaxError;
 
213
        break;
 
214
    case TypeError:
 
215
        jscError = JSC::TypeError;
 
216
        break;
 
217
    case RangeError:
 
218
        jscError = JSC::RangeError;
 
219
        break;
 
220
    case URIError:
 
221
        jscError = JSC::URIError;
 
222
        break;
 
223
    }
 
224
    JSC::JSObject *result = JSC::throwError(frame, jscError, text);
 
225
    return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
 
226
}
 
227
 
 
228
/*!
 
229
  \overload
 
230
 
 
231
  Throws an error with the given \a text.
 
232
  Returns the created error object.
 
233
 
 
234
  \sa throwValue(), state()
 
235
*/
 
236
QScriptValue QScriptContext::throwError(const QString &text)
 
237
{
 
238
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
239
    JSC::JSObject *result = JSC::throwError(frame, JSC::GeneralError, text);
 
240
    return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
 
241
}
 
242
 
 
243
/*!
 
244
  Destroys this QScriptContext.
 
245
*/
 
246
QScriptContext::~QScriptContext()
 
247
{
 
248
    //QScriptContext doesn't exist,  pointer to QScriptContext are just pointer to JSC::CallFrame
 
249
    Q_ASSERT(false);
 
250
}
 
251
 
 
252
/*!
 
253
  Returns the QScriptEngine that this QScriptContext belongs to.
 
254
*/
 
255
QScriptEngine *QScriptContext::engine() const
 
256
{
 
257
    const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
258
    return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame));
 
259
}
 
260
 
 
261
/*!
 
262
  Returns the function argument at the given \a index.
 
263
 
 
264
  If \a index >= argumentCount(), a QScriptValue of
 
265
  the primitive type Undefined is returned.
 
266
 
 
267
  \sa argumentCount()
 
268
*/
 
269
QScriptValue QScriptContext::argument(int index) const
 
270
{
 
271
    if (index < 0)
 
272
        return QScriptValue();
 
273
    if (index >= argumentCount())
 
274
        return QScriptValue(QScriptValue::UndefinedValue);
 
275
    QScriptValue v = argumentsObject().property(index);
 
276
    return v;
 
277
}
 
278
 
 
279
/*!
 
280
  Returns the callee. The callee is the function object that this
 
281
  QScriptContext represents an invocation of.
 
282
*/
 
283
QScriptValue QScriptContext::callee() const
 
284
{
 
285
    const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
286
    return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->callee());
 
287
}
 
288
 
 
289
/*!
 
290
  Returns the arguments object of this QScriptContext.
 
291
 
 
292
  The arguments object has properties \c callee (equal to callee())
 
293
  and \c length (equal to argumentCount()), and properties \c 0, \c 1,
 
294
  ..., argumentCount() - 1 that provide access to the argument
 
295
  values. Initially, property \c P (0 <= \c P < argumentCount()) has
 
296
  the same value as argument(\c P). In the case when \c P is less
 
297
  than the number of formal parameters of the function, \c P shares
 
298
  its value with the corresponding property of the activation object
 
299
  (activationObject()). This means that changing this property changes
 
300
  the corresponding property of the activation object and vice versa.
 
301
 
 
302
  \sa argument(), activationObject()
 
303
*/
 
304
QScriptValue QScriptContext::argumentsObject() const
 
305
{
 
306
    JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
 
307
 
 
308
    if (frame == frame->lexicalGlobalObject()->globalExec()) {
 
309
        // <global> context doesn't have arguments. return an empty object
 
310
        return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
 
311
    }
 
312
 
 
313
    //for a js function
 
314
    if (frame->codeBlock() && frame->callee()) {
 
315
        JSC::JSValue result = frame->interpreter()->retrieveArguments(frame, JSC::asFunction(frame->callee()));
 
316
        return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
 
317
    }
 
318
 
 
319
    if (frame->callerFrame()->hasHostCallFrameFlag()) {
 
320
        // <eval> context doesn't have arguments. return an empty object
 
321
        return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
 
322
    }
 
323
 
 
324
    //for a native function
 
325
    if (!frame->optionalCalleeArguments()) {
 
326
        Q_ASSERT(frame->argumentCount() > 0); //we need at least 'this' otherwise we'll crash later
 
327
        JSC::Arguments* arguments = new (&frame->globalData())JSC::Arguments(frame, JSC::Arguments::NoParameters);
 
328
        frame->setCalleeArguments(arguments);
 
329
    }
 
330
    return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->optionalCalleeArguments());
 
331
}
 
332
 
 
333
/*!
 
334
  Returns true if the function was called as a constructor
 
335
  (e.g. \c{"new foo()"}); otherwise returns false.
 
336
 
 
337
  When a function is called as constructor, the thisObject()
 
338
  contains the newly constructed object to be initialized.
 
339
*/
 
340
bool QScriptContext::isCalledAsConstructor() const
 
341
{
 
342
    JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
 
343
 
 
344
    //For native functions, look up flags.
 
345
    uint flags = QScriptEnginePrivate::contextFlags(frame);
 
346
    if (flags & QScriptEnginePrivate::NativeContext)
 
347
        return flags & QScriptEnginePrivate::CalledAsConstructorContext;
 
348
 
 
349
    //Not a native function, try to look up in the bytecode if we where called from op_construct
 
350
    JSC::Instruction* returnPC = frame->returnPC();
 
351
 
 
352
    if (!returnPC)
 
353
        return false;
 
354
 
 
355
    JSC::CallFrame *callerFrame = QScriptEnginePrivate::frameForContext(parentContext());
 
356
    if (!callerFrame)
 
357
        return false;
 
358
 
 
359
    if (returnPC[-JSC::op_construct_length].u.opcode == frame->interpreter()->getOpcode(JSC::op_construct)) {
 
360
        //We are maybe called from the op_construct opcode which has 6 opperands.
 
361
        //But we need to check we are not called from op_call with 4 opperands
 
362
 
 
363
        //we make sure that the returnPC[-1] (thisRegister) is smaller than the returnPC[-3] (registerOffset)
 
364
        //as if it was an op_call, the returnPC[-1] would be the registerOffset, bigger than returnPC[-3] (funcRegister)
 
365
        return returnPC[-1].u.operand < returnPC[-3].u.operand;
 
366
    }
 
367
    return false;
 
368
}
 
369
 
 
370
/*!
 
371
  Returns the parent context of this QScriptContext.
 
372
*/
 
373
QScriptContext *QScriptContext::parentContext() const
 
374
{
 
375
    const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
376
    JSC::CallFrame *callerFrame = frame->callerFrame()->removeHostCallFrameFlag();
 
377
    return QScriptEnginePrivate::contextForFrame(callerFrame);
 
378
}
 
379
 
 
380
/*!
 
381
  Returns the number of arguments passed to the function
 
382
  in this invocation.
 
383
 
 
384
  Note that the argument count can be different from the
 
385
  formal number of arguments (the \c{length} property of
 
386
  callee()).
 
387
 
 
388
  \sa argument()
 
389
*/
 
390
int QScriptContext::argumentCount() const
 
391
{
 
392
    const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
393
    int argc = frame->argumentCount();
 
394
    if (argc != 0)
 
395
        --argc; // -1 due to "this"
 
396
    return argc;
 
397
}
 
398
 
 
399
/*!
 
400
  \internal
 
401
*/
 
402
QScriptValue QScriptContext::returnValue() const
 
403
{
 
404
    qWarning("QScriptContext::returnValue() not implemented");
 
405
    return QScriptValue();
 
406
}
 
407
 
 
408
/*!
 
409
  \internal
 
410
*/
 
411
void QScriptContext::setReturnValue(const QScriptValue &result)
 
412
{
 
413
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
414
    JSC::CallFrame *callerFrame = frame->callerFrame();
 
415
    if (!callerFrame->codeBlock())
 
416
        return;
 
417
    Q_ASSERT_X(false, Q_FUNC_INFO, "check me");
 
418
    int dst = frame->registers()[JSC::RegisterFile::ReturnValueRegister].i(); // returnValueRegister() is private
 
419
    callerFrame[dst] = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(result);
 
420
}
 
421
 
 
422
/*!
 
423
  Returns the activation object of this QScriptContext. The activation
 
424
  object provides access to the local variables associated with this
 
425
  context.
 
426
 
 
427
  \sa argument(), argumentsObject()
 
428
*/
 
429
 
 
430
QScriptValue QScriptContext::activationObject() const
 
431
{
 
432
    JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
 
433
    JSC::JSObject *result = 0;
 
434
 
 
435
    uint flags = QScriptEnginePrivate::contextFlags(frame);
 
436
    if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) {
 
437
        //For native functions, lazily create it if needed
 
438
        QScript::QScriptActivationObject *scope = new (frame) QScript::QScriptActivationObject(frame);
 
439
        frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
 
440
        result = scope;
 
441
        QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
 
442
    } else {
 
443
        // look in scope chain
 
444
        JSC::ScopeChainNode *node = frame->scopeChain();
 
445
        JSC::ScopeChainIterator it(node);
 
446
        for (it = node->begin(); it != node->end(); ++it) {
 
447
            if ((*it) && (*it)->isVariableObject()) {
 
448
                result = *it;
 
449
                break;
 
450
            }
 
451
        }
 
452
    }
 
453
    if (!result) {
 
454
        if (!parentContext())
 
455
            return engine()->globalObject();
 
456
 
 
457
        qWarning("QScriptContext::activationObject:  could not get activation object for frame");
 
458
        return QScriptValue();
 
459
        /*JSC::CodeBlock *codeBlock = frame->codeBlock();
 
460
        if (!codeBlock) {
 
461
            // non-Qt native function 
 
462
            Q_ASSERT(true); //### this should in theorry not happen
 
463
            result = new (frame)QScript::QScriptActivationObject(frame);
 
464
        } else {
 
465
            // ### this is wrong
 
466
            JSC::FunctionBodyNode *body = static_cast<JSC::FunctionBodyNode*>(codeBlock->ownerNode());
 
467
            result = new (frame)JSC::JSActivation(frame, body);
 
468
        }*/
 
469
    }
 
470
 
 
471
    if (result && result->inherits(&QScript::QScriptActivationObject::info)
 
472
        && (static_cast<QScript::QScriptActivationObject*>(result)->delegate() != 0)) {
 
473
        // Return the object that property access is being delegated to
 
474
        result = static_cast<QScript::QScriptActivationObject*>(result)->delegate();
 
475
    }
 
476
 
 
477
    return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
 
478
}
 
479
 
 
480
/*!
 
481
  Sets the activation object of this QScriptContext to be the given \a
 
482
  activation.
 
483
 
 
484
  If \a activation is not an object, this function does nothing.
 
485
*/
 
486
void QScriptContext::setActivationObject(const QScriptValue &activation)
 
487
{
 
488
    if (!activation.isObject())
 
489
        return;
 
490
    else if (activation.engine() != engine()) {
 
491
        qWarning("QScriptContext::setActivationObject() failed: "
 
492
                 "cannot set an object created in "
 
493
                 "a different engine");
 
494
        return;
 
495
    }
 
496
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
497
    QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
 
498
    JSC::JSObject *object = JSC::asObject(engine->scriptValueToJSCValue(activation));
 
499
    if (object == engine->originalGlobalObjectProxy)
 
500
        object = engine->originalGlobalObject();
 
501
 
 
502
    uint flags = QScriptEnginePrivate::contextFlags(frame);
 
503
    if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) {
 
504
        //For native functions, we create a scope node
 
505
        JSC::JSObject *scope = object;
 
506
        if (!scope->isVariableObject()) {
 
507
            // Create a QScriptActivationObject that acts as a proxy
 
508
            scope = new (frame) QScript::QScriptActivationObject(frame, scope);
 
509
        }
 
510
        frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
 
511
        QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
 
512
        return;
 
513
    }
 
514
 
 
515
    // else replace the first activation object in the scope chain
 
516
    JSC::ScopeChainNode *node = frame->scopeChain();
 
517
    while (node != 0) {
 
518
        if (node->object && node->object->isVariableObject()) {
 
519
            if (!object->isVariableObject()) {
 
520
                if (node->object->inherits(&QScript::QScriptActivationObject::info)) {
 
521
                    static_cast<QScript::QScriptActivationObject*>(node->object)->setDelegate(object);
 
522
                } else {
 
523
                    // Create a QScriptActivationObject that acts as a proxy
 
524
                    node->object = new (frame) QScript::QScriptActivationObject(frame, object);
 
525
                }
 
526
            } else {
 
527
                node->object = object;
 
528
            }
 
529
            break;
 
530
        }
 
531
        node = node->next;
 
532
    }
 
533
}
 
534
 
 
535
/*!
 
536
  Returns the `this' object associated with this QScriptContext.
 
537
*/
 
538
QScriptValue QScriptContext::thisObject() const
 
539
{
 
540
    JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
 
541
    QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
 
542
    JSC::JSValue result = engine->thisForContext(frame);
 
543
    if (!result || result.isNull())
 
544
        result = frame->globalThisValue();
 
545
    return engine->scriptValueFromJSCValue(result);
 
546
}
 
547
 
 
548
/*!
 
549
  Sets the `this' object associated with this QScriptContext to be
 
550
  \a thisObject.
 
551
 
 
552
  If \a thisObject is not an object, this function does nothing.
 
553
*/
 
554
void QScriptContext::setThisObject(const QScriptValue &thisObject)
 
555
{
 
556
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
557
    if (!thisObject.isObject())
 
558
        return;
 
559
    if (thisObject.engine() != engine()) {
 
560
        qWarning("QScriptContext::setThisObject() failed: "
 
561
                 "cannot set an object created in "
 
562
                 "a different engine");
 
563
        return;
 
564
    }
 
565
    if (frame == frame->lexicalGlobalObject()->globalExec()) {
 
566
        engine()->setGlobalObject(thisObject);
 
567
        return;
 
568
    }
 
569
    JSC::JSValue jscThisObject = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(thisObject);
 
570
    JSC::CodeBlock *cb = frame->codeBlock();
 
571
    if (cb != 0) {
 
572
        frame[cb->thisRegister()] = jscThisObject;
 
573
    } else {
 
574
        JSC::Register* thisRegister = QScriptEnginePrivate::thisRegisterForFrame(frame);
 
575
        thisRegister[0] = jscThisObject;
 
576
    }
 
577
}
 
578
 
 
579
/*!
 
580
  Returns the frameution state of this QScriptContext.
 
581
*/
 
582
QScriptContext::ExecutionState QScriptContext::state() const
 
583
{
 
584
    const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
585
    if (frame->hadException())
 
586
        return QScriptContext::ExceptionState;
 
587
    return QScriptContext::NormalState;
 
588
}
 
589
 
 
590
/*!
 
591
  Returns a human-readable backtrace of this QScriptContext.
 
592
 
 
593
  Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}.
 
594
 
 
595
  To access individual pieces of debugging-related information (for
 
596
  example, to construct your own backtrace representation), use
 
597
  QScriptContextInfo.
 
598
 
 
599
  \sa QScriptEngine::uncaughtExceptionBacktrace(), QScriptContextInfo, toString()
 
600
*/
 
601
QStringList QScriptContext::backtrace() const
 
602
{
 
603
    QStringList result;
 
604
    const QScriptContext *ctx = this;
 
605
    while (ctx) {
 
606
        result.append(ctx->toString());
 
607
        ctx = ctx->parentContext();
 
608
    }
 
609
    return result;
 
610
}
 
611
 
 
612
/*!
 
613
  \since 4.4
 
614
 
 
615
  Returns a string representation of this context.
 
616
  This is useful for debugging.
 
617
 
 
618
  \sa backtrace()
 
619
*/
 
620
QString QScriptContext::toString() const
 
621
{
 
622
    QScriptContextInfo info(this);
 
623
    QString result;
 
624
 
 
625
    QString functionName = info.functionName();
 
626
    if (functionName.isEmpty()) {
 
627
        if (parentContext()) {
 
628
            const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
629
            if (info.functionType() == QScriptContextInfo::ScriptFunction)
 
630
                result.append(QLatin1String("<anonymous>"));
 
631
            else if(frame->callerFrame()->hasHostCallFrameFlag())
 
632
                result.append(QLatin1String("<eval>"));
 
633
            else
 
634
                result.append(QLatin1String("<native>"));
 
635
        } else {
 
636
            result.append(QLatin1String("<global>"));
 
637
        }
 
638
    } else {
 
639
        result.append(functionName);
 
640
    }
 
641
 
 
642
    QStringList parameterNames = info.functionParameterNames();
 
643
    result.append(QLatin1Char('('));
 
644
    for (int i = 0; i < argumentCount(); ++i) {
 
645
        if (i > 0)
 
646
            result.append(QLatin1String(", "));
 
647
        if (i < parameterNames.count()) {
 
648
            result.append(parameterNames.at(i));
 
649
            result.append(QLatin1String(" = "));
 
650
        }
 
651
        QScriptValue arg = argument(i);
 
652
        if (arg.isString())
 
653
            result.append(QLatin1Char('\''));
 
654
        result.append(arg.toString());
 
655
        if (arg.isString())
 
656
            result.append(QLatin1Char('\''));
 
657
 
 
658
    }
 
659
    result.append(QLatin1Char(')'));
 
660
 
 
661
    QString fileName = info.fileName();
 
662
    int lineNumber = info.lineNumber();
 
663
    result.append(QLatin1String(" at "));
 
664
    if (!fileName.isEmpty()) {
 
665
        result.append(fileName);
 
666
        result.append(QLatin1Char(':'));
 
667
    }
 
668
    result.append(QString::number(lineNumber));
 
669
    return result;
 
670
}
 
671
 
 
672
/*!
 
673
  \internal
 
674
  \since 4.5
 
675
 
 
676
  Returns the scope chain of this QScriptContext.
 
677
*/
 
678
QScriptValueList QScriptContext::scopeChain() const
 
679
{
 
680
    activationObject(); //ensure the creation of the normal scope for native context
 
681
    const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
682
    QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
 
683
    QScriptValueList result;
 
684
    JSC::ScopeChainNode *node = frame->scopeChain();
 
685
    JSC::ScopeChainIterator it(node);
 
686
    for (it = node->begin(); it != node->end(); ++it) {
 
687
        JSC::JSObject *object = *it;
 
688
        if (!object)
 
689
            continue;
 
690
        if (object->inherits(&QScript::QScriptActivationObject::info)
 
691
            && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) {
 
692
            // Return the object that property access is being delegated to
 
693
            object = static_cast<QScript::QScriptActivationObject*>(object)->delegate();
 
694
        }
 
695
        result.append(engine->scriptValueFromJSCValue(object));
 
696
    }
 
697
    return result;
 
698
}
 
699
 
 
700
/*!
 
701
  \internal
 
702
  \since 4.5
 
703
 
 
704
  Adds the given \a object to the front of this context's scope chain.
 
705
 
 
706
  If \a object is not an object, this function does nothing.
 
707
*/
 
708
void QScriptContext::pushScope(const QScriptValue &object)
 
709
{
 
710
    activationObject(); //ensure the creation of the normal scope for native context
 
711
    if (!object.isObject())
 
712
        return;
 
713
    else if (object.engine() != engine()) {
 
714
        qWarning("QScriptContext::pushScope() failed: "
 
715
                 "cannot push an object created in "
 
716
                 "a different engine");
 
717
        return;
 
718
    }
 
719
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
720
    QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
 
721
    JSC::JSObject *jscObject = JSC::asObject(engine->scriptValueToJSCValue(object));
 
722
    if (jscObject == engine->originalGlobalObjectProxy)
 
723
        jscObject = engine->originalGlobalObject();
 
724
    JSC::ScopeChainNode *scope = frame->scopeChain();
 
725
    Q_ASSERT(scope != 0);
 
726
    if (!scope->object) {
 
727
        // pushing to an "empty" chain
 
728
        if (!jscObject->isGlobalObject()) {
 
729
            qWarning("QScriptContext::pushScope() failed: initial object in scope chain has to be the Global Object");
 
730
            return;
 
731
        }
 
732
        scope->object = jscObject;
 
733
    }
 
734
    else
 
735
        frame->setScopeChain(scope->push(jscObject));
 
736
}
 
737
 
 
738
/*!
 
739
  \internal
 
740
  \since 4.5
 
741
 
 
742
  Removes the front object from this context's scope chain, and
 
743
  returns the removed object.
 
744
 
 
745
  If the scope chain is already empty, this function returns an
 
746
  invalid QScriptValue.
 
747
*/
 
748
QScriptValue QScriptContext::popScope()
 
749
{
 
750
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
 
751
    JSC::ScopeChainNode *scope = frame->scopeChain();
 
752
    Q_ASSERT(scope != 0);
 
753
    QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
 
754
    QScriptValue result = engine->scriptValueFromJSCValue(scope->object);
 
755
    if (!scope->next) {
 
756
        // We cannot have a null scope chain, so just zap the object pointer.
 
757
        scope->object = 0;
 
758
    } else {
 
759
        frame->setScopeChain(scope->pop());
 
760
    }
 
761
    return result;
 
762
}
 
763
 
 
764
QT_END_NAMESPACE