summaryrefslogtreecommitdiffstats
path: root/src/script/api/qscriptcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/api/qscriptcontext.cpp')
-rw-r--r--src/script/api/qscriptcontext.cpp764
1 files changed, 764 insertions, 0 deletions
diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp
new file mode 100644
index 0000000..0b1ca33
--- /dev/null
+++ b/src/script/api/qscriptcontext.cpp
@@ -0,0 +1,764 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtScript module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "config.h"
+#include "qscriptcontext.h"
+
+#include "qscriptcontext_p.h"
+#include "qscriptcontextinfo.h"
+#include "qscriptengine.h"
+#include "qscriptengine_p.h"
+#include "../bridge/qscriptactivationobject_p.h"
+
+#include "Arguments.h"
+#include "CodeBlock.h"
+#include "Error.h"
+#include "JSFunction.h"
+#include "JSObject.h"
+#include "JSGlobalObject.h"
+
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 4.3
+ \class QScriptContext
+
+ \brief The QScriptContext class represents a Qt Script function invocation.
+
+ \ingroup script
+ \mainclass
+
+ A QScriptContext provides access to the `this' object and arguments
+ passed to a script function. You typically want to access this
+ information when you're writing a native (C++) function (see
+ QScriptEngine::newFunction()) that will be called from script
+ code. For example, when the script code
+
+ \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 0
+
+ is evaluated, a QScriptContext will be created, and the context will
+ carry the arguments as QScriptValues; in this particular case, the
+ arguments will be one QScriptValue containing the number 20.5, a second
+ QScriptValue containing the string \c{"hello"}, and a third QScriptValue
+ containing a Qt Script object.
+
+ Use argumentCount() to get the number of arguments passed to the
+ function, and argument() to get an argument at a certain index. The
+ argumentsObject() function returns a Qt Script array object
+ containing all the arguments; you can use the QScriptValueIterator
+ to iterate over its elements, or pass the array on as arguments to
+ another script function using QScriptValue::call().
+
+ Use thisObject() to get the `this' object associated with the function call,
+ and setThisObject() to set the `this' object. If you are implementing a
+ native "instance method", you typically fetch the thisObject() and access
+ one or more of its properties:
+
+ \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 1
+
+ Use isCalledAsConstructor() to determine if the function was called
+ as a constructor (e.g. \c{"new foo()"} (as constructor) or just
+ \c{"foo()"}). When a function is called as a constructor, the
+ thisObject() contains the newly constructed object that the function
+ is expected to initialize.
+
+ Use throwValue() or throwError() to throw an exception.
+
+ Use callee() to obtain the QScriptValue that represents the function being
+ called. This can for example be used to call the function recursively.
+
+ Use parentContext() to get a pointer to the context that precedes
+ this context in the activation stack. This is mostly useful for
+ debugging purposes (e.g. when constructing some form of backtrace).
+
+ The activationObject() function returns the object that is used to
+ hold the local variables associated with this function call. You can
+ replace the activation object by calling setActivationObject(). A
+ typical usage of these functions is when you want script code to be
+ evaluated in the context of the parent context, e.g. to implement an
+ include() function:
+
+ \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 2
+
+ Use backtrace() to get a human-readable backtrace associated with
+ this context. This can be useful for debugging purposes when
+ implementing native functions. The toString() function provides a
+ string representation of the context. (QScriptContextInfo provides
+ more detailed debugging-related information about the
+ QScriptContext.)
+
+ Use engine() to obtain a pointer to the QScriptEngine that this context
+ resides in.
+
+ \sa QScriptContextInfo, QScriptEngine::newFunction(), QScriptable
+*/
+
+/*!
+ \enum QScriptContext::ExecutionState
+
+ This enum specifies the frameution state of the context.
+
+ \value NormalState The context is in a normal state.
+
+ \value ExceptionState The context is in an exceptional state.
+*/
+
+/*!
+ \enum QScriptContext::Error
+
+ This enum specifies types of error.
+
+ \value ReferenceError A reference error.
+
+ \value SyntaxError A syntax error.
+
+ \value TypeError A type error.
+
+ \value RangeError A range error.
+
+ \value URIError A URI error.
+
+ \value UnknownError An unknown error.
+*/
+
+/*!
+ \internal
+*/
+QScriptContext::QScriptContext()
+{
+ //QScriptContext doesn't exist, pointer to QScriptContext are just pointer to JSC::CallFrame
+ Q_ASSERT(false);
+}
+
+/*!
+ Throws an exception with the given \a value.
+ Returns the value thrown (the same as the argument).
+
+ \sa throwError(), state()
+*/
+QScriptValue QScriptContext::throwValue(const QScriptValue &value)
+{
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ JSC::JSValue jscValue = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(value);
+ frame->setException(jscValue);
+ return value;
+}
+
+/*!
+ Throws an \a error with the given \a text.
+ Returns the created error object.
+
+ The \a text will be stored in the \c{message} property of the error
+ object.
+
+ The error object will be initialized to contain information about
+ the location where the error occurred; specifically, it will have
+ properties \c{lineNumber}, \c{fileName} and \c{stack}. These
+ properties are described in \l {QtScript Extensions to ECMAScript}.
+
+ \sa throwValue(), state()
+*/
+QScriptValue QScriptContext::throwError(Error error, const QString &text)
+{
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ JSC::ErrorType jscError = JSC::GeneralError;
+ switch (error) {
+ case UnknownError:
+ break;
+ case ReferenceError:
+ jscError = JSC::ReferenceError;
+ break;
+ case SyntaxError:
+ jscError = JSC::SyntaxError;
+ break;
+ case TypeError:
+ jscError = JSC::TypeError;
+ break;
+ case RangeError:
+ jscError = JSC::RangeError;
+ break;
+ case URIError:
+ jscError = JSC::URIError;
+ break;
+ }
+ JSC::JSObject *result = JSC::throwError(frame, jscError, text);
+ return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
+}
+
+/*!
+ \overload
+
+ Throws an error with the given \a text.
+ Returns the created error object.
+
+ \sa throwValue(), state()
+*/
+QScriptValue QScriptContext::throwError(const QString &text)
+{
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ JSC::JSObject *result = JSC::throwError(frame, JSC::GeneralError, text);
+ return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
+}
+
+/*!
+ Destroys this QScriptContext.
+*/
+QScriptContext::~QScriptContext()
+{
+ //QScriptContext doesn't exist, pointer to QScriptContext are just pointer to JSC::CallFrame
+ Q_ASSERT(false);
+}
+
+/*!
+ Returns the QScriptEngine that this QScriptContext belongs to.
+*/
+QScriptEngine *QScriptContext::engine() const
+{
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame));
+}
+
+/*!
+ Returns the function argument at the given \a index.
+
+ If \a index >= argumentCount(), a QScriptValue of
+ the primitive type Undefined is returned.
+
+ \sa argumentCount()
+*/
+QScriptValue QScriptContext::argument(int index) const
+{
+ if (index < 0)
+ return QScriptValue();
+ if (index >= argumentCount())
+ return QScriptValue(QScriptValue::UndefinedValue);
+ QScriptValue v = argumentsObject().property(index);
+ return v;
+}
+
+/*!
+ Returns the callee. The callee is the function object that this
+ QScriptContext represents an invocation of.
+*/
+QScriptValue QScriptContext::callee() const
+{
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->callee());
+}
+
+/*!
+ Returns the arguments object of this QScriptContext.
+
+ The arguments object has properties \c callee (equal to callee())
+ and \c length (equal to argumentCount()), and properties \c 0, \c 1,
+ ..., argumentCount() - 1 that provide access to the argument
+ values. Initially, property \c P (0 <= \c P < argumentCount()) has
+ the same value as argument(\c P). In the case when \c P is less
+ than the number of formal parameters of the function, \c P shares
+ its value with the corresponding property of the activation object
+ (activationObject()). This means that changing this property changes
+ the corresponding property of the activation object and vice versa.
+
+ \sa argument(), activationObject()
+*/
+QScriptValue QScriptContext::argumentsObject() const
+{
+ JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
+
+ if (frame == frame->lexicalGlobalObject()->globalExec() || frame->callerFrame()->hasHostCallFrameFlag()) {
+ // <global> or <eval> context doesn't have arguments. return an empty object
+ return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
+ }
+
+ //for a js function
+ if (frame->codeBlock() && frame->callee()) {
+ JSC::JSValue result = frame->interpreter()->retrieveArguments(frame, JSC::asFunction(frame->callee()));
+ return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
+ }
+
+ //for a native function
+ if (!frame->optionalCalleeArguments()) {
+ Q_ASSERT(frame->argumentCount() > 0); //we need at least 'this' otherwise we'll crash later
+ JSC::Arguments* arguments = new (&frame->globalData())JSC::Arguments(frame, JSC::Arguments::NoParameters);
+ frame->setCalleeArguments(arguments);
+ }
+ return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->optionalCalleeArguments());
+}
+
+/*!
+ Returns true if the function was called as a constructor
+ (e.g. \c{"new foo()"}); otherwise returns false.
+
+ When a function is called as constructor, the thisObject()
+ contains the newly constructed object to be initialized.
+*/
+bool QScriptContext::isCalledAsConstructor() const
+{
+ JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
+
+ //For native functions, look up flags.
+ uint flags = QScriptEnginePrivate::contextFlags(frame);
+ if (flags & QScriptEnginePrivate::NativeContext)
+ return flags & QScriptEnginePrivate::CalledAsConstructorContext;
+
+ //Not a native function, try to look up in the bytecode if we where called from op_construct
+ JSC::Instruction* returnPC = frame->returnPC();
+
+ if (!returnPC)
+ return false;
+
+ JSC::CallFrame *callerFrame = QScriptEnginePrivate::frameForContext(parentContext());
+ if (!callerFrame)
+ return false;
+
+ if (returnPC[-JSC::op_construct_length].u.opcode == frame->interpreter()->getOpcode(JSC::op_construct)) {
+ //We are maybe called from the op_construct opcode which has 6 opperands.
+ //But we need to check we are not called from op_call with 4 opperands
+
+ //we make sure that the returnPC[-1] (thisRegister) is smaller than the returnPC[-3] (registerOffset)
+ //as if it was an op_call, the returnPC[-1] would be the registerOffset, bigger than returnPC[-3] (funcRegister)
+ return returnPC[-1].u.operand < returnPC[-3].u.operand;
+ }
+ return false;
+}
+
+/*!
+ Returns the parent context of this QScriptContext.
+*/
+QScriptContext *QScriptContext::parentContext() const
+{
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ JSC::CallFrame *callerFrame = frame->callerFrame()->removeHostCallFrameFlag();
+ if (callerFrame && callerFrame->callerFrame()->hasHostCallFrameFlag()
+ && callerFrame->callerFrame()->removeHostCallFrameFlag() == QScript::scriptEngineFromExec(frame)->globalExec()) {
+ //skip the "fake" context created in Interpreter::execute.
+ callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag();
+ }
+ return reinterpret_cast<QScriptContext *>(callerFrame);
+}
+
+/*!
+ Returns the number of arguments passed to the function
+ in this invocation.
+
+ Note that the argument count can be different from the
+ formal number of arguments (the \c{length} property of
+ callee()).
+
+ \sa argument()
+*/
+int QScriptContext::argumentCount() const
+{
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ int argc = frame->argumentCount();
+ if (argc != 0)
+ --argc; // -1 due to "this"
+ return argc;
+}
+
+/*!
+ \internal
+*/
+QScriptValue QScriptContext::returnValue() const
+{
+ qWarning("QScriptContext::returnValue() not implemented");
+ return QScriptValue();
+}
+
+/*!
+ \internal
+*/
+void QScriptContext::setReturnValue(const QScriptValue &result)
+{
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ JSC::CallFrame *callerFrame = frame->callerFrame();
+ if (!callerFrame->codeBlock())
+ return;
+ Q_ASSERT_X(false, Q_FUNC_INFO, "check me");
+ int dst = frame->registers()[JSC::RegisterFile::ReturnValueRegister].i(); // returnValueRegister() is private
+ callerFrame[dst] = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(result);
+}
+
+/*!
+ Returns the activation object of this QScriptContext. The activation
+ object provides access to the local variables associated with this
+ context.
+
+ \sa argument(), argumentsObject()
+*/
+
+QScriptValue QScriptContext::activationObject() const
+{
+ JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
+ JSC::JSObject *result = 0;
+
+ uint flags = QScriptEnginePrivate::contextFlags(frame);
+ if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) {
+ //For native functions, lazily create it if needed
+ QScript::QScriptActivationObject *scope = new (frame) QScript::QScriptActivationObject(frame);
+ frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
+ result = scope;
+ QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
+ } else {
+ // look in scope chain
+ JSC::ScopeChainNode *node = frame->scopeChain();
+ JSC::ScopeChainIterator it(node);
+ for (it = node->begin(); it != node->end(); ++it) {
+ if ((*it) && (*it)->isVariableObject()) {
+ result = *it;
+ break;
+ }
+ }
+ }
+ if (!result) {
+ if (!parentContext())
+ return engine()->globalObject();
+
+ qWarning("QScriptContext::activationObject: could not get activation object for frame");
+ return QScriptValue();
+ /*JSC::CodeBlock *codeBlock = frame->codeBlock();
+ if (!codeBlock) {
+ // non-Qt native function
+ Q_ASSERT(true); //### this should in theorry not happen
+ result = new (frame)QScript::QScriptActivationObject(frame);
+ } else {
+ // ### this is wrong
+ JSC::FunctionBodyNode *body = static_cast<JSC::FunctionBodyNode*>(codeBlock->ownerNode());
+ result = new (frame)JSC::JSActivation(frame, body);
+ }*/
+ }
+
+ if (result && result->isObject(&QScript::QScriptActivationObject::info)
+ && (static_cast<QScript::QScriptActivationObject*>(result)->delegate() != 0)) {
+ // Return the object that property access is being delegated to
+ result = static_cast<QScript::QScriptActivationObject*>(result)->delegate();
+ }
+
+ return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
+}
+
+/*!
+ Sets the activation object of this QScriptContext to be the given \a
+ activation.
+
+ If \a activation is not an object, this function does nothing.
+*/
+void QScriptContext::setActivationObject(const QScriptValue &activation)
+{
+ if (!activation.isObject())
+ return;
+ else if (activation.engine() != engine()) {
+ qWarning("QScriptContext::setActivationObject() failed: "
+ "cannot set an object created in "
+ "a different engine");
+ return;
+ }
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
+ JSC::JSObject *object = JSC::asObject(engine->scriptValueToJSCValue(activation));
+ if (object == engine->originalGlobalObjectProxy)
+ object = engine->originalGlobalObject();
+
+ uint flags = QScriptEnginePrivate::contextFlags(frame);
+ if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) {
+ //For native functions, we create a scope node
+ JSC::JSObject *scope = object;
+ if (!scope->isVariableObject()) {
+ // Create a QScriptActivationObject that acts as a proxy
+ scope = new (frame) QScript::QScriptActivationObject(frame, scope);
+ }
+ frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
+ QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
+ return;
+ }
+
+ // else replace the first activation object in the scope chain
+ JSC::ScopeChainNode *node = frame->scopeChain();
+ while (node != 0) {
+ if (node->object && node->object->isVariableObject()) {
+ if (!object->isVariableObject()) {
+ if (node->object->isObject(&QScript::QScriptActivationObject::info)) {
+ static_cast<QScript::QScriptActivationObject*>(node->object)->setDelegate(object);
+ } else {
+ // Create a QScriptActivationObject that acts as a proxy
+ node->object = new (frame) QScript::QScriptActivationObject(frame, object);
+ }
+ } else {
+ node->object = object;
+ }
+ break;
+ }
+ node = node->next;
+ }
+}
+
+/*!
+ Returns the `this' object associated with this QScriptContext.
+*/
+QScriptValue QScriptContext::thisObject() const
+{
+ JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
+ QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
+ JSC::JSValue result = engine->thisForContext(frame);
+ if (!result || result.isNull())
+ result = frame->globalThisValue();
+ return engine->scriptValueFromJSCValue(result);
+}
+
+/*!
+ Sets the `this' object associated with this QScriptContext to be
+ \a thisObject.
+
+ If \a thisObject is not an object, this function does nothing.
+*/
+void QScriptContext::setThisObject(const QScriptValue &thisObject)
+{
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ if (!thisObject.isObject())
+ return;
+ if (thisObject.engine() != engine()) {
+ qWarning("QScriptContext::setThisObject() failed: "
+ "cannot set an object created in "
+ "a different engine");
+ return;
+ }
+ if (frame == frame->lexicalGlobalObject()->globalExec()) {
+ engine()->setGlobalObject(thisObject);
+ return;
+ }
+ JSC::JSValue jscThisObject = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(thisObject);
+ JSC::CodeBlock *cb = frame->codeBlock();
+ if (cb != 0) {
+ frame[cb->thisRegister()] = jscThisObject;
+ } else {
+ JSC::Register* thisRegister = frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
+ thisRegister[0] = jscThisObject;
+ }
+}
+
+/*!
+ Returns the frameution state of this QScriptContext.
+*/
+QScriptContext::ExecutionState QScriptContext::state() const
+{
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ if (frame->hadException())
+ return QScriptContext::ExceptionState;
+ return QScriptContext::NormalState;
+}
+
+/*!
+ Returns a human-readable backtrace of this QScriptContext.
+
+ Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}.
+
+ To access individual pieces of debugging-related information (for
+ example, to construct your own backtrace representation), use
+ QScriptContextInfo.
+
+ \sa QScriptEngine::uncaughtExceptionBacktrace(), QScriptContextInfo, toString()
+*/
+QStringList QScriptContext::backtrace() const
+{
+ QStringList result;
+ const QScriptContext *ctx = this;
+ while (ctx) {
+ result.append(ctx->toString());
+ ctx = ctx->parentContext();
+ }
+ return result;
+}
+
+/*!
+ \since 4.4
+
+ Returns a string representation of this context.
+ This is useful for debugging.
+
+ \sa backtrace()
+*/
+QString QScriptContext::toString() const
+{
+ QScriptContextInfo info(this);
+ QString result;
+
+ QString functionName = info.functionName();
+ if (functionName.isEmpty()) {
+ if (parentContext()) {
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ if (info.functionType() == QScriptContextInfo::ScriptFunction)
+ result.append(QLatin1String("<anonymous>"));
+ else if(frame->callerFrame()->hasHostCallFrameFlag())
+ result.append(QLatin1String("<eval>"));
+ else
+ result.append(QLatin1String("<native>"));
+ } else {
+ result.append(QLatin1String("<global>"));
+ }
+ } else {
+ result.append(functionName);
+ }
+
+ QStringList parameterNames = info.functionParameterNames();
+ result.append(QLatin1Char('('));
+ for (int i = 0; i < argumentCount(); ++i) {
+ if (i > 0)
+ result.append(QLatin1String(", "));
+ if (i < parameterNames.count()) {
+ result.append(parameterNames.at(i));
+ result.append(QLatin1String(" = "));
+ }
+ QScriptValue arg = argument(i);
+ if (arg.isString())
+ result.append(QLatin1Char('\''));
+ result.append(arg.toString());
+ if (arg.isString())
+ result.append(QLatin1Char('\''));
+
+ }
+ result.append(QLatin1Char(')'));
+
+ QString fileName = info.fileName();
+ int lineNumber = info.lineNumber();
+ result.append(QLatin1String(" at "));
+ if (!fileName.isEmpty()) {
+ result.append(fileName);
+ result.append(QLatin1Char(':'));
+ }
+ result.append(QString::number(lineNumber));
+ return result;
+}
+
+/*!
+ \internal
+ \since 4.5
+
+ Returns the scope chain of this QScriptContext.
+*/
+QScriptValueList QScriptContext::scopeChain() const
+{
+ activationObject(); //ensure the creation of the normal scope for native context
+ const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
+ QScriptValueList result;
+ JSC::ScopeChainNode *node = frame->scopeChain();
+ JSC::ScopeChainIterator it(node);
+ for (it = node->begin(); it != node->end(); ++it) {
+ JSC::JSObject *object = *it;
+ if (!object)
+ continue;
+ if (object->isObject(&QScript::QScriptActivationObject::info)
+ && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) {
+ // Return the object that property access is being delegated to
+ object = static_cast<QScript::QScriptActivationObject*>(object)->delegate();
+ }
+ result.append(engine->scriptValueFromJSCValue(object));
+ }
+ return result;
+}
+
+/*!
+ \internal
+ \since 4.5
+
+ Adds the given \a object to the front of this context's scope chain.
+
+ If \a object is not an object, this function does nothing.
+*/
+void QScriptContext::pushScope(const QScriptValue &object)
+{
+ activationObject(); //ensure the creation of the normal scope for native context
+ if (!object.isObject())
+ return;
+ else if (object.engine() != engine()) {
+ qWarning("QScriptContext::pushScope() failed: "
+ "cannot push an object created in "
+ "a different engine");
+ return;
+ }
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
+ JSC::JSObject *jscObject = JSC::asObject(engine->scriptValueToJSCValue(object));
+ if (jscObject == engine->originalGlobalObjectProxy)
+ jscObject = engine->originalGlobalObject();
+ JSC::ScopeChainNode *scope = frame->scopeChain();
+ Q_ASSERT(scope != 0);
+ if (!scope->object) {
+ // pushing to an "empty" chain
+ if (!jscObject->isGlobalObject()) {
+ qWarning("QScriptContext::pushScope() failed: initial object in scope chain has to be the Global Object");
+ return;
+ }
+ scope->object = jscObject;
+ }
+ else
+ frame->setScopeChain(scope->push(jscObject));
+}
+
+/*!
+ \internal
+ \since 4.5
+
+ Removes the front object from this context's scope chain, and
+ returns the removed object.
+
+ If the scope chain is already empty, this function returns an
+ invalid QScriptValue.
+*/
+QScriptValue QScriptContext::popScope()
+{
+ JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
+ JSC::ScopeChainNode *scope = frame->scopeChain();
+ Q_ASSERT(scope != 0);
+ QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
+ QScriptValue result = engine->scriptValueFromJSCValue(scope->object);
+ if (!scope->next) {
+ // We cannot have a null scope chain, so just zap the object pointer.
+ scope->object = 0;
+ } else {
+ frame->setScopeChain(scope->pop());
+ }
+ return result;
+}
+
+QT_END_NAMESPACE