src/script/api/qscriptcontext.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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