source: trunk/src/script/api/qscriptcontext.cpp@ 769

Last change on this file since 769 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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