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

source code of qtscript/src/script/api/qscriptcontext.cpp