示例#1
0
void Session::processSignIn(const QString &data) {

    try {
        switch (m_sessionState) {
            case SessionClosed:
                break;

            case SigningIn: {
                QScriptValue processSignIn = m_scriptObject.property("processSignIn");
                QScriptValueList args;
                args.append(data.trimmed());
                processSignIn.call(m_scriptObject, args);
                break;
            }

            case SignedIn: {
                CommandEvent event(m_player, data);
                event.process();
                break;
            }
        }

        ScriptEngine *engine = ScriptEngine::instance();
        if (engine->hasUncaughtException()) {
            LogUtil::logException("Script Exception: %1\n"
                                  "In Session::processSignIn()", engine->uncaughtException());
        }
    } catch (GameException &exception) {
        LogUtil::logError("Exception in Session::processSignIn(): %1", exception.what());
    }
}
void QScriptDebuggerScriptedConsoleCommandJob::start()
{
    Q_D(QScriptDebuggerScriptedConsoleCommandJob);
    QScriptEngine *engine = d->command->globalObject.engine();
    engine->setGlobalObject(d->command->globalObject);
    QScriptValueList args;
    for (int i = 0; i < d->arguments.size(); ++i)
        args.append(QScriptValue(engine, d->arguments.at(i)));
    QScriptDebuggerConsoleGlobalObject *global;
    global = qobject_cast<QScriptDebuggerConsoleGlobalObject*>(engine->globalObject().toQObject());
    Q_ASSERT(global != 0);
    global->setScheduler(this);
    global->setResponseHandler(this);
    global->setMessageHandler(d->messageHandler);
    global->setConsole(d->console);
    d->commandCount = 0;
    QScriptValue ret = d->command->execFunction.call(QScriptValue(), args);
    global->setScheduler(0);
    global->setResponseHandler(0);
    global->setMessageHandler(0);
    global->setConsole(0);
    if (ret.isError()) {
        qWarning("*** internal error: %s", qPrintable(ret.toString()));
    }
    if (d->commandCount == 0)
        finish();
}
void QScriptDebuggerScriptedConsoleCommandJob::handleResponse(
    const QScriptDebuggerResponse &response,
    int commandId)
{
    Q_D(QScriptDebuggerScriptedConsoleCommandJob);
    // ### generalize
    QScriptEngine *engine = d->command->globalObject.engine();
    engine->setGlobalObject(d->command->globalObject);
    QScriptValueList args;
    args.append(engine->toScriptValue(response));
    args.append(QScriptValue(engine, commandId));
    QScriptDebuggerConsoleGlobalObject *global;
    global = qobject_cast<QScriptDebuggerConsoleGlobalObject*>(d->command->globalObject.toQObject());
    Q_ASSERT(global != 0);
    global->setScheduler(this);
    global->setResponseHandler(this);
    global->setMessageHandler(d->messageHandler);
    global->setConsole(d->console);
    d->commandCount = 0;
    QScriptValue ret = d->command->responseFunction.call(QScriptValue(), args);
    global->setScheduler(0);
    global->setResponseHandler(0);
    global->setMessageHandler(0);
    global->setConsole(0);
    if (ret.isError()) {
        qWarning("*** internal error: %s", qPrintable(ret.toString()));
    }
    if (d->commandCount == 0)
        finish();
}
示例#4
0
QStringList STTwitterText::extractMentions(const QString &text){
    QMutexLocker locker(g_processMutex);
    QString inText=removeUni6(text).trimmed().normalized(QString::NormalizationForm_C);
    QScriptValue caller();
    QScriptValueList args;
    args.append(inText);
    QScriptValue result=g_extractMentionsFunction->call(caller, args);
    if(g_engine->hasUncaughtException()){
        int line = g_engine->uncaughtExceptionLineNumber();

        QByteArray str=g_engine->uncaughtException().toString().toUtf8();

        qFatal("Exception while evaluating twttr.txt.extractMentions at line %d: %s", line, str.data());
    }
    if(result.isUndefined()){
        qFatal("Undefined returned by extractMentions");
    }
    if(!result.isArray()){
        qFatal("Non-array object returned by extractMentions");
    }

    int length=result.property("length").toInteger();
    QStringList res;
    for(int i=0;i<length;i++){
        res<<result.property(i).toString();
    }

    return res;
}
示例#5
0
void Session::open() {

    try {
        setSessionState(SigningIn);

        ScriptEngine *engine = ScriptEngine::instance();
        m_scriptObject = engine->evaluate("new SessionHandler()");
        if (engine->hasUncaughtException()) {
            LogUtil::logException("Script Exception: %1\n"
                                  "In Session::open()", engine->uncaughtException());
            return;
        }

        QScriptValue setSession = m_scriptObject.property("setSession");
        QScriptValueList args;
        args.append(engine->toScriptValue(this));
        setSession.call(m_scriptObject, args);

        if (engine->hasUncaughtException()) {
            LogUtil::logException("Script Exception: %1\n"
                                  "In Session::open()", engine->uncaughtException());
        }
    } catch (GameException &exception) {
        LogUtil::logError("Exception in Session::open(): %1", exception.what());
    }
}
示例#6
0
QVariant TestClass::extension(Extension extension,
                              const QVariant &argument)
{
    if (extension == Callable) {
        Q_ASSERT(m_callableMode != NotCallable);
        QScriptContext *ctx = qvariant_cast<QScriptContext*>(argument);
        if (m_callableMode == CallableReturnsSum) {
            qsreal sum = 0;
            for (int i = 0; i < ctx->argumentCount(); ++i)
                sum += ctx->argument(i).toNumber();
            QScriptValueIterator it(ctx->thisObject());
            while (it.hasNext()) {
                it.next();
                sum += it.value().toNumber();
            }
            return sum;
        } else if (m_callableMode == CallableReturnsArgument) {
            return qVariantFromValue(ctx->argument(0));
        } else if (m_callableMode == CallableReturnsInvalidVariant) {
            return QVariant();
        }
    } else if (extension == HasInstance) {
        Q_ASSERT(m_hasInstance);
        QScriptValueList args = qvariant_cast<QScriptValueList>(argument);
        Q_ASSERT(args.size() == 2);
        QScriptValue obj = args.at(0);
        QScriptValue value = args.at(1);
        return value.property("foo").equals(obj.property("foo"));
    }
    return QVariant();
}
示例#7
0
/*!
  Executes the pending evaluate, if any.
*/
void QScriptDebuggerBackend::doPendingEvaluate(bool postEvent)
{
    Q_D(QScriptDebuggerBackend);
    QString program = d->pendingEvaluateProgram;
    if (program.isEmpty())
        return;
    int contextIndex = d->pendingEvaluateContextIndex;
    QScriptContext *ctx = context(contextIndex);
    Q_ASSERT(ctx != 0);
    QString fileName = d->pendingEvaluateFileName;
    int lineNumber = d->pendingEvaluateLineNumber;
    d->pendingEvaluateProgram = QString();
    d->pendingEvaluateFileName = QString();
    d->pendingEvaluateLineNumber = -1;
    d->pendingEvaluateContextIndex = -1;

    // push a new context and initialize its scope chain etc.
    {
        QScriptContext *evalContext = engine()->pushContext();
        QScriptValueList scopeChain = ctx->scopeChain();
        if (scopeChain.isEmpty())
            scopeChain.append(engine()->globalObject());
        while (!scopeChain.isEmpty())
            evalContext->pushScope(scopeChain.takeLast());
        evalContext->setActivationObject(ctx->activationObject());
        evalContext->setThisObject(ctx->thisObject());
    }

    d->agent->enterContinueMode();
    // set a flag so that any exception that happens in
    // the evaluate() is not sent to the debugger
    d->ignoreExceptions = true;
    bool hadException = engine()->hasUncaughtException();
    QScriptValue ret = engine()->evaluate(program, fileName, lineNumber);
    d->ignoreExceptions = false;
    if (!hadException && engine()->hasUncaughtException())
        engine()->clearExceptions();
    engine()->popContext();

    QScriptDebuggerValue retret(ret);
    QScriptDebuggerEvent e(QScriptDebuggerEvent::InlineEvalFinished);
    e.setScriptValue(retret);
    if (!ret.isUndefined())
        e.setMessage(ret.toString()); // for convenience -- we always need it

    e.setNestedEvaluate(engine()->isEvaluating());

    if (postEvent) {
        QScriptDebuggerEventEvent *de = new QScriptDebuggerEventEvent(e);
        d->postEvent(de);
    } else {
        event(e);
    }
}
示例#8
0
void SmsGatewayQuery::process(const QString &number)
{
	auto engine = m_smsScriptsManager->engine();
	auto jsGatewayQueryObject = engine->evaluate("new GatewayQuery()");
	auto jsGetGateway = jsGatewayQueryObject.property("getGateway");

	QScriptValueList arguments;
	arguments.append(number);
	arguments.append(engine->newQObject(this));

	jsGetGateway.call(jsGatewayQueryObject, arguments);
}
示例#9
0
// Check the overhead of the extension "call"
void tst_QScriptClass::call()
{
    QScriptEngine eng;
    ExtensionScriptClass cls(&eng);
    QScriptValue obj = eng.newObject(&cls);
    QScriptValue thisObject;
    QScriptValueList args;
    args.append(123);
    QBENCHMARK {
        for (int i = 0; i < iterationNumber; ++i)
            (void)obj.call(thisObject, args);
    }
}
示例#10
0
QScriptValue& DerivedNetworkValue::getValue() {
    if (!_value.isValid() && _baseValue->isLoaded()) {
        RootNetworkValue* root = static_cast<RootNetworkValue*>(_baseValue.data());
        ScriptCache* cache = root->getProgram()->getCache();
        QScriptValue generator = _baseValue->getValue().property(cache->getGeneratorString());
        if (generator.isFunction()) {
            QScriptValueList arguments;
            foreach (const ParameterInfo& parameter, root->getParameterInfo()) {
                arguments.append(cache->getEngine()->newVariant(_parameters.value(parameter.name)));
            }
            _value = generator.call(QScriptValue(), arguments);
        
        } else {
示例#11
0
// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args
void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) {
    if (!_registeredHandlers.contains(entityID)) {
        return;
    }
    const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID];
    if (!handlersOnEntity.contains(eventName)) {
        return;
    }
    QScriptValueList handlersForEvent = handlersOnEntity[eventName];
    if (!handlersForEvent.isEmpty()) {
        QScriptValueList args = argGenerator();
        for (int i = 0; i < handlersForEvent.count(); ++i) {
            handlersForEvent[i].call(QScriptValue(), args);
        }
    }
}
示例#12
0
/*!
  \internal
  \since 4.5

  Returns the scope chain of this QScriptContext.
*/
QScriptValueList QScriptContext::scopeChain() const
{
    Q_D(const QScriptContext);
    // make sure arguments properties are initialized
    const QScriptContextPrivate *ctx = d;
    while (ctx) {
        (void)ctx->activationObject();
        ctx = ctx->previous;
    }
    QScriptValueList result;
    QScriptEnginePrivate *eng_p = QScriptEnginePrivate::get(engine());
    QScriptValueImpl scope = d->m_scopeChain;
    while (scope.isObject()) {
        if (scope.classInfo() == eng_p->m_class_with)
            result.append(eng_p->toPublic(scope.prototype()));
        else
            result.append(eng_p->toPublic(scope));
        scope = scope.scope();
    }
    return result;
}
示例#13
0
/*!
  \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);
    QScript::APIShim shim(engine);
    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->inherits(&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;
}
示例#14
0
int STTwitterText::lengthOfTweet(const QString &text){
    QMutexLocker locker(g_processMutex);
    //g_engine->globalObject().setProperty("text", );
    QString inText=removeUni6(text).trimmed().normalized(QString::NormalizationForm_C);
    QScriptValue caller();
    QScriptValueList args;
    args.append(inText);
    QScriptValue result=g_tweetLengthFunction->call(caller, args);
    if(g_engine->hasUncaughtException()){
        int line = g_engine->uncaughtExceptionLineNumber();

        QByteArray str=g_engine->uncaughtException().toString().toUtf8();//result.toString().toUtf8();

        qFatal("Exception while evaluating twttr.txt.getTweetLength at line %d: %s", line, str.data());
    }
    if(result.isUndefined()){
        qFatal("Undefined returned by getTweetLength");
    }

    int vl=result.toInteger();
    //qDebug()<<vl;
    return vl;
}
示例#15
0
void ScriptableWorker::run()
{
    if ( hasLogLevel(LogDebug) ) {
        bool isEval = m_args.length() == Arguments::Rest + 2
                && m_args.at(Arguments::Rest) == "eval";

        for (int i = Arguments::Rest + (isEval ? 1 : 0); i < m_args.length(); ++i) {
            QString indent = isEval ? QString("EVAL:")
                                    : (QString::number(i - Arguments::Rest + 1) + " ");
            foreach (const QByteArray &line, m_args.at(i).split('\n')) {
                SCRIPT_LOG( indent + getTextData(line) );
                indent = "  ";
            }
        }
    }

    bool hasData;
    const quintptr id = m_args.at(Arguments::ActionId).toULongLong(&hasData);
    QVariantMap data;
    if (hasData)
        data = Action::data(id);

    const QString currentPath = getTextData(m_args.at(Arguments::CurrentPath));

    QScriptEngine engine;
    ScriptableProxy proxy(m_wnd, data);
    Scriptable scriptable(&proxy);
    scriptable.initEngine(&engine, currentPath, data);

    if (m_socket) {
        QObject::connect( proxy.signaler(), SIGNAL(sendMessage(QByteArray,int)),
                          m_socket, SLOT(sendMessage(QByteArray,int)) );

        QObject::connect( &scriptable, SIGNAL(sendMessage(QByteArray,int)),
                          m_socket, SLOT(sendMessage(QByteArray,int)) );
        QObject::connect( m_socket, SIGNAL(messageReceived(QByteArray,int)),
                          &scriptable, SLOT(setInput(QByteArray)) );

        QObject::connect( m_socket, SIGNAL(disconnected()),
                          &scriptable, SLOT(abort()) );
        QObject::connect( &scriptable, SIGNAL(destroyed()),
                          m_socket, SLOT(deleteAfterDisconnected()) );

        if ( m_socket->isClosed() ) {
            SCRIPT_LOG("TERMINATED");
            return;
        }

        m_socket->start();
    }

    QObject::connect( &scriptable, SIGNAL(requestApplicationQuit()),
                      qApp, SLOT(quit()) );

    QByteArray response;
    int exitCode;

    if ( m_args.length() <= Arguments::Rest ) {
        SCRIPT_LOG("Error: bad command syntax");
        exitCode = CommandBadSyntax;
    } else {
        const QString cmd = getTextData( m_args.at(Arguments::Rest) );

#ifdef HAS_TESTS
        if ( cmd == "flush" && m_args.length() == Arguments::Rest + 2 ) {
            log( "flush ID: " + getTextData(m_args.at(Arguments::Rest + 1)), LogAlways );
            scriptable.sendMessageToClient(QByteArray(), CommandFinished);
            return;
        }
#endif

        QScriptValue fn = engine.globalObject().property(cmd);
        if ( !fn.isFunction() ) {
            SCRIPT_LOG("Error: unknown command");
            const QString msg =
                    Scriptable::tr("Name \"%1\" doesn't refer to a function.").arg(cmd);
            response = createLogMessage(msg, LogError).toUtf8();
            exitCode = CommandError;
        } else {
            /* Special arguments:
             * "-"  read this argument from stdin
             * "--" read all following arguments without control sequences
             */
            QScriptValueList fnArgs;
            bool readRaw = false;
            for ( int i = Arguments::Rest + 1; i < m_args.length(); ++i ) {
                const QByteArray &arg = m_args.at(i);
                if (!readRaw && arg == "--") {
                    readRaw = true;
                } else {
                    const QScriptValue value = readRaw || arg != "-"
                            ? scriptable.newByteArray(arg)
                            : scriptable.input();
                    fnArgs.append(value);
                }
            }

            engine.evaluate(m_pluginScript);
            QScriptValue result = fn.call(QScriptValue(), fnArgs);

            if ( engine.hasUncaughtException() ) {
                const QString exceptionText =
                        QString("%1\n--- backtrace ---\n%2\n--- end backtrace ---")
                        .arg( engine.uncaughtException().toString(),
                              engine.uncaughtExceptionBacktrace().join("\n") );

                SCRIPT_LOG( QString("Error: Exception in command \"%1\": %2")
                             .arg(cmd, exceptionText) );

                response = createLogMessage(exceptionText, LogError).toUtf8();
                exitCode = CommandError;
            } else {
                response = serializeScriptValue(result);
                exitCode = CommandFinished;
            }
        }
    }

    if (exitCode == CommandFinished && hasData)
        Action::setData(id, scriptable.data());

    scriptable.sendMessageToClient(response, exitCode);

    SCRIPT_LOG("DONE");
}
/*!
  Applies the given \a command to the given \a backend.
*/
QScriptDebuggerResponse QScriptDebuggerCommandExecutor::execute(
    QScriptDebuggerBackend *backend,
    const QScriptDebuggerCommand &command)
{
    QScriptDebuggerResponse response;
    switch (command.type()) {
    case QScriptDebuggerCommand::None:
        break;

    case QScriptDebuggerCommand::Interrupt:
        backend->interruptEvaluation();
        break;

    case QScriptDebuggerCommand::Continue:
        if (backend->engine()->isEvaluating()) {
            backend->continueEvalution();
            response.setAsync(true);
        }
        break;

    case QScriptDebuggerCommand::StepInto: {
        QVariant attr = command.attribute(QScriptDebuggerCommand::StepCount);
        int count = attr.isValid() ? attr.toInt() : 1;
        backend->stepInto(count);
        response.setAsync(true);
    }   break;

    case QScriptDebuggerCommand::StepOver: {
        QVariant attr = command.attribute(QScriptDebuggerCommand::StepCount);
        int count = attr.isValid() ? attr.toInt() : 1;
        backend->stepOver(count);
        response.setAsync(true);
    }   break;

    case QScriptDebuggerCommand::StepOut:
        backend->stepOut();
        response.setAsync(true);
        break;

    case QScriptDebuggerCommand::RunToLocation:
        backend->runToLocation(command.fileName(), command.lineNumber());
        response.setAsync(true);
        break;

    case QScriptDebuggerCommand::RunToLocationByID:
        backend->runToLocation(command.scriptId(), command.lineNumber());
        response.setAsync(true);
        break;

    case QScriptDebuggerCommand::ForceReturn: {
        int contextIndex = command.contextIndex();
        QScriptDebuggerValue value = command.scriptValue();
        QScriptEngine *engine = backend->engine();
        QScriptValue realValue = value.toScriptValue(engine);
        backend->returnToCaller(contextIndex, realValue);
        response.setAsync(true);
    }   break;

    case QScriptDebuggerCommand::Resume:
        backend->resume();
        response.setAsync(true);
        break;

    case QScriptDebuggerCommand::SetBreakpoint: {
        QScriptBreakpointData data = command.breakpointData();
        if (!data.isValid())
            data = QScriptBreakpointData(command.fileName(), command.lineNumber());
        int id = backend->setBreakpoint(data);
        response.setResult(id);
    }   break;

    case QScriptDebuggerCommand::DeleteBreakpoint: {
        int id = command.breakpointId();
        if (!backend->deleteBreakpoint(id))
            response.setError(QScriptDebuggerResponse::InvalidBreakpointID);
    }   break;

    case QScriptDebuggerCommand::DeleteAllBreakpoints:
        backend->deleteAllBreakpoints();
        break;

    case QScriptDebuggerCommand::GetBreakpoints: {
        QScriptBreakpointMap bps = backend->breakpoints();
        if (!bps.isEmpty())
            response.setResult(bps);
    }   break;

    case QScriptDebuggerCommand::GetBreakpointData: {
        int id = command.breakpointId();
        QScriptBreakpointData data = backend->breakpointData(id);
        if (data.isValid())
            response.setResult(data);
        else
            response.setError(QScriptDebuggerResponse::InvalidBreakpointID);
    }   break;

    case QScriptDebuggerCommand::SetBreakpointData: {
        int id = command.breakpointId();
        QScriptBreakpointData data = command.breakpointData();
        if (!backend->setBreakpointData(id, data))
            response.setError(QScriptDebuggerResponse::InvalidBreakpointID);
    }   break;

    case QScriptDebuggerCommand::GetScripts: {
        QScriptScriptMap scripts = backend->scripts();
        if (!scripts.isEmpty())
            response.setResult(scripts);
    }   break;

    case QScriptDebuggerCommand::GetScriptData: {
        qint64 id = command.scriptId();
        QScriptScriptData data = backend->scriptData(id);
        if (data.isValid())
            response.setResult(data);
        else
            response.setError(QScriptDebuggerResponse::InvalidScriptID);
    }   break;

    case QScriptDebuggerCommand::ScriptsCheckpoint:
        backend->scriptsCheckpoint();
        response.setResult(QVariant::fromValue(backend->scriptsDelta()));
        break;

    case QScriptDebuggerCommand::GetScriptsDelta:
        response.setResult(QVariant::fromValue(backend->scriptsDelta()));
        break;

    case QScriptDebuggerCommand::ResolveScript:
        response.setResult(backend->resolveScript(command.fileName()));
        break;

    case QScriptDebuggerCommand::GetBacktrace:
        response.setResult(backend->backtrace());
        break;

    case QScriptDebuggerCommand::GetContextCount:
        response.setResult(backend->contextCount());
        break;

    case QScriptDebuggerCommand::GetContextState: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        if (ctx)
            response.setResult(static_cast<int>(ctx->state()));
        else
            response.setError(QScriptDebuggerResponse::InvalidContextIndex);
    }   break;

    case QScriptDebuggerCommand::GetContextID: {
        int idx = command.contextIndex();
        if ((idx >= 0) && (idx < backend->contextCount()))
            response.setResult(backend->contextIds()[idx]);
        else
            response.setError(QScriptDebuggerResponse::InvalidContextIndex);
    }   break;

    case QScriptDebuggerCommand::GetContextInfo: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        if (ctx)
            response.setResult(QScriptContextInfo(ctx));
        else
            response.setError(QScriptDebuggerResponse::InvalidContextIndex);
    }   break;

    case QScriptDebuggerCommand::GetThisObject: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        if (ctx)
            response.setResult(ctx->thisObject());
        else
            response.setError(QScriptDebuggerResponse::InvalidContextIndex);
    }   break;

    case QScriptDebuggerCommand::GetActivationObject: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        if (ctx)
            response.setResult(ctx->activationObject());
        else
            response.setError(QScriptDebuggerResponse::InvalidContextIndex);
    }   break;

    case QScriptDebuggerCommand::GetScopeChain: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        if (ctx) {
            QScriptDebuggerValueList dest;
            QScriptValueList src = ctx->scopeChain();
            for (int i = 0; i < src.size(); ++i)
                dest.append(src.at(i));
            response.setResult(dest);
        } else {
            response.setError(QScriptDebuggerResponse::InvalidContextIndex);
        }
    }   break;

    case QScriptDebuggerCommand::ContextsCheckpoint: {
        response.setResult(QVariant::fromValue(backend->contextsCheckpoint()));
    }   break;

    case QScriptDebuggerCommand::GetPropertyExpressionValue: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        int lineNumber = command.lineNumber();
        QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute);
        QStringList path = attr.toStringList();
        if (!ctx || path.isEmpty())
            break;
        QScriptContextInfo ctxInfo(ctx);
        if (ctx->callee().isValid()
            && ((lineNumber < ctxInfo.functionStartLineNumber())
                || (lineNumber > ctxInfo.functionEndLineNumber()))) {
            break;
        }
        QScriptValueList objects;
        int pathIndex = 0;
        if (path.at(0) == QLatin1String("this")) {
            objects.append(ctx->thisObject());
            ++pathIndex;
        } else {
            objects << ctx->scopeChain();
        }
        for (int i = 0; i < objects.size(); ++i) {
            QScriptValue val = objects.at(i);
            for (int j = pathIndex; val.isValid() && (j < path.size()); ++j) {
                val = val.property(path.at(j));
            }
            if (val.isValid()) {
                bool hadException = (ctx->state() == QScriptContext::ExceptionState);
                QString str = val.toString();
                if (!hadException && backend->engine()->hasUncaughtException())
                    backend->engine()->clearExceptions();
                response.setResult(str);
                break;
            }
        }
    }   break;

    case QScriptDebuggerCommand::GetCompletions: {
        QScriptContext *ctx = backend->context(command.contextIndex());
        QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute);
        QStringList path = attr.toStringList();
        if (!ctx || path.isEmpty())
            break;
        QScriptValueList objects;
        QString prefix = path.last();
        QSet<QString> matches;
        if (path.size() > 1) {
            const QString &topLevelIdent = path.at(0);
            QScriptValue obj;
            if (topLevelIdent == QLatin1String("this")) {
                obj = ctx->thisObject();
            } else {
                QScriptValueList scopeChain;
                scopeChain = ctx->scopeChain();
                for (int i = 0; i < scopeChain.size(); ++i) {
                    QScriptValue oo = scopeChain.at(i).property(topLevelIdent);
                    if (oo.isObject()) {
                        obj = oo;
                        break;
                    }
                }
            }
            for (int i = 1; obj.isObject() && (i < path.size()-1); ++i)
                obj = obj.property(path.at(i));
            if (obj.isValid())
                objects.append(obj);
        } else {
            objects << ctx->scopeChain();
            QStringList keywords;
            keywords.append(QString::fromLatin1("this"));
            keywords.append(QString::fromLatin1("true"));
            keywords.append(QString::fromLatin1("false"));
            keywords.append(QString::fromLatin1("null"));
            for (int i = 0; i < keywords.size(); ++i) {
                const QString &kwd = keywords.at(i);
                if (isPrefixOf(prefix, kwd))
                    matches.insert(kwd);
            }
        }

        for (int i = 0; i < objects.size(); ++i) {
            QScriptValue obj = objects.at(i);
            while (obj.isObject()) {
                QScriptValueIterator it(obj);
                while (it.hasNext()) {
                    it.next();
                    QString propertyName = it.name();
                    if (isPrefixOf(prefix, propertyName))
                        matches.insert(propertyName);
                }
                obj = obj.prototype();
            }
        }
        QStringList matchesList = matches.toList();
        qStableSort(matchesList);
        response.setResult(matchesList);
    }   break;

    case QScriptDebuggerCommand::NewScriptObjectSnapshot: {
        int id = backend->newScriptObjectSnapshot();
        response.setResult(id);
    }   break;

    case QScriptDebuggerCommand::ScriptObjectSnapshotCapture: {
        int id = command.snapshotId();
        QScriptObjectSnapshot *snap = backend->scriptObjectSnapshot(id);
        Q_ASSERT(snap != 0);
        QScriptDebuggerValue object = command.scriptValue();
        Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue);
        QScriptEngine *engine = backend->engine();
        QScriptValue realObject = object.toScriptValue(engine);
        Q_ASSERT(realObject.isObject());
        QScriptObjectSnapshot::Delta delta = snap->capture(realObject);
        QScriptDebuggerObjectSnapshotDelta result;
        result.removedProperties = delta.removedProperties;
        bool didIgnoreExceptions = backend->ignoreExceptions();
        backend->setIgnoreExceptions(true);
        for (int i = 0; i < delta.changedProperties.size(); ++i) {
            const QScriptValueProperty &src = delta.changedProperties.at(i);
            bool hadException = engine->hasUncaughtException();
            QString str = src.value().toString();
            if (!hadException && engine->hasUncaughtException())
                engine->clearExceptions();
            QScriptDebuggerValueProperty dest(src.name(), src.value(), str, src.flags());
            result.changedProperties.append(dest);
        }
        for (int j = 0; j < delta.addedProperties.size(); ++j) {
            const QScriptValueProperty &src = delta.addedProperties.at(j);
            bool hadException = engine->hasUncaughtException();
            QString str = src.value().toString();
            if (!hadException && engine->hasUncaughtException())
                engine->clearExceptions();
            QScriptDebuggerValueProperty dest(src.name(), src.value(), str, src.flags());
            result.addedProperties.append(dest);
        }
        backend->setIgnoreExceptions(didIgnoreExceptions);
        response.setResult(QVariant::fromValue(result));
    }   break;

    case QScriptDebuggerCommand::DeleteScriptObjectSnapshot: {
        int id = command.snapshotId();
        backend->deleteScriptObjectSnapshot(id);
    }   break;

    case QScriptDebuggerCommand::NewScriptValueIterator: {
        QScriptDebuggerValue object = command.scriptValue();
        Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue);
        QScriptEngine *engine = backend->engine();
        QScriptValue realObject = object.toScriptValue(engine);
        Q_ASSERT(realObject.isObject());
        int id = backend->newScriptValueIterator(realObject);
        response.setResult(id);
    }   break;

    case QScriptDebuggerCommand::GetPropertiesByIterator: {
        int id = command.iteratorId();
        int count = 1000;
        QScriptValueIterator *it = backend->scriptValueIterator(id);
        Q_ASSERT(it != 0);
        QScriptDebuggerValuePropertyList props;
        for (int i = 0; (i < count) && it->hasNext(); ++i) {
            it->next();
            QString name = it->name();
            QScriptValue value = it->value();
            QString valueAsString = value.toString();
            QScriptValue::PropertyFlags flags = it->flags();
            QScriptDebuggerValueProperty prp(name, value, valueAsString, flags);
            props.append(prp);
        }
        response.setResult(props);
    }   break;

    case QScriptDebuggerCommand::DeleteScriptValueIterator: {
        int id = command.iteratorId();
        backend->deleteScriptValueIterator(id);
    }   break;

    case QScriptDebuggerCommand::Evaluate: {
        int contextIndex = command.contextIndex();
        QString program = command.program();
        QString fileName = command.fileName();
        int lineNumber = command.lineNumber();
        backend->evaluate(contextIndex, program, fileName, lineNumber);
        response.setAsync(true);
    }   break;

    case QScriptDebuggerCommand::ScriptValueToString: {
        QScriptDebuggerValue value = command.scriptValue();
        QScriptEngine *engine = backend->engine();
        QScriptValue realValue = value.toScriptValue(engine);
        response.setResult(realValue.toString());
    }   break;

    case QScriptDebuggerCommand::SetScriptValueProperty: {
        QScriptDebuggerValue object = command.scriptValue();
        QScriptEngine *engine = backend->engine();
        QScriptValue realObject = object.toScriptValue(engine);
        QScriptDebuggerValue value = command.subordinateScriptValue();
        QScriptValue realValue = value.toScriptValue(engine);
        QString name = command.name();
        realObject.setProperty(name, realValue);
    }   break;

    case QScriptDebuggerCommand::ClearExceptions:
        backend->engine()->clearExceptions();
        break;

    case QScriptDebuggerCommand::UserCommand:
    case QScriptDebuggerCommand::MaxUserCommand:
        break;
    }
    return response;
}
示例#17
0
void ScriptableWorker::run()
{
    MONITOR_LOG("starting");

    QScriptEngine engine;
    ScriptableProxy proxy(m_wnd);
    Scriptable scriptable(&proxy);
    scriptable.initEngine( &engine, QString::fromUtf8(m_args.at(Arguments::CurrentPath)),
                           m_args.at(Arguments::ActionId) );

    if (m_socket) {
        QObject::connect( &scriptable, SIGNAL(sendMessage(QByteArray,int)),
                          m_socket, SLOT(sendMessage(QByteArray,int)) );
        QObject::connect( m_socket, SIGNAL(messageReceived(QByteArray,int)),
                          &scriptable, SLOT(setInput(QByteArray)) );

        QObject::connect( m_socket, SIGNAL(disconnected()),
                          &scriptable, SLOT(abort()) );
        QObject::connect( &scriptable, SIGNAL(destroyed()),
                          m_socket, SLOT(deleteAfterDisconnected()) );

        if ( m_socket->isClosed() ) {
            MONITOR_LOG("terminated");
            return;
        }

        m_socket->start();
    }

    QObject::connect( &scriptable, SIGNAL(requestApplicationQuit()),
                      qApp, SLOT(quit()) );

    QByteArray response;
    int exitCode;

    if ( m_args.length() <= Arguments::Rest ) {
        MONITOR_LOG("Error: bad command syntax");
        exitCode = CommandBadSyntax;
    } else {
        const QString cmd = QString::fromUtf8( m_args.at(Arguments::Rest) );

        if ( hasLogLevel(LogDebug) ) {
            MONITOR_LOG("Client arguments:");
            for (int i = Arguments::Rest; i < m_args.length(); ++i)
                MONITOR_LOG( "    " + QString::fromUtf8(m_args.at(i)) );
        }

#ifdef HAS_TESTS
        if ( cmd == "flush" && m_args.length() == Arguments::Rest + 2 ) {
            MONITOR_LOG( "flush ID: " + QString::fromUtf8(m_args.at(Arguments::Rest + 1)) );
            scriptable.sendMessageToClient(QByteArray(), CommandFinished);
            return;
        }
#endif

        QScriptValue fn = engine.globalObject().property(cmd);
        if ( !fn.isFunction() ) {
            MONITOR_LOG("Error: unknown command");
            response = createLogMessage("CopyQ client",
                                        Scriptable::tr("Name \"%1\" doesn't refer to a function.")
                                        .arg(cmd),
                                        LogError).toUtf8();
            exitCode = CommandError;
        } else {
            QScriptValueList fnArgs;
            for ( int i = Arguments::Rest + 1; i < m_args.length(); ++i )
                fnArgs.append( scriptable.newByteArray(m_args.at(i)) );

            QScriptValue result = fn.call(QScriptValue(), fnArgs);

            if ( engine.hasUncaughtException() ) {
                const QString exceptionText = engine.uncaughtException().toString();
                MONITOR_LOG( QString("Error: exception in command \"%1\": %2")
                             .arg(cmd).arg(exceptionText) );
                response = createLogMessage("CopyQ client", exceptionText, LogError).toUtf8();
                exitCode = CommandError;
            } else {
                response = serializeScriptValue(result);
                exitCode = CommandFinished;
            }
        }
    }

    scriptable.sendMessageToClient(response, exitCode);

    MONITOR_LOG("finished");
}
示例#18
0
bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut,
        bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) {
    
    // get the ids of all the zones (plus the global entity edit filter) that the position
    // lies within
    auto zoneIDs = getZonesByPosition(position);
    for (auto id : zoneIDs) {
        if (!itemID.isInvalidID() && id == itemID) {
            continue;
        }
        
        // get the filter pair, etc...  
        _lock.lockForRead();
        FilterData filterData = _filterDataMap.value(id);
        _lock.unlock();
    
        if (filterData.valid()) {
            if (filterData.rejectAll) {
                return false;
            }

            // check to see if this filter wants to filter this message type
            if ((!filterData.wantsToFilterEdit && filterType == EntityTree::FilterType::Edit) ||
                (!filterData.wantsToFilterPhysics && filterType == EntityTree::FilterType::Physics) ||
                (!filterData.wantsToFilterDelete && filterType == EntityTree::FilterType::Delete) ||
                (!filterData.wantsToFilterAdd && filterType == EntityTree::FilterType::Add)) {

                wasChanged = false;
                return true; // accept the message
            }

            auto oldProperties = propertiesIn.getDesiredProperties();
            auto specifiedProperties = propertiesIn.getChangedProperties();
            propertiesIn.setDesiredProperties(specifiedProperties);
            QScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true);
            propertiesIn.setDesiredProperties(oldProperties);

            auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter.

            QScriptValueList args;
            args << inputValues;
            args << filterType;

            // get the current properties for then entity and include them for the filter call
            if (existingEntity && filterData.wantsOriginalProperties) {
                auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties);
                QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true);
                args << currentValues;
            }


            // get the zone properties
            if (filterData.wantsZoneProperties) {
                auto zoneEntity = _tree->findEntityByEntityItemID(id);
                if (zoneEntity) {
                    auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties);
                    QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true);

                    if (filterData.wantsZoneBoundingBox) {
                        bool success = true;
                        AABox aaBox = zoneEntity->getAABox(success);
                        if (success) {
                            QScriptValue boundingBox = filterData.engine->newObject();
                            QScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner());
                            QScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft());
                            QScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter());
                            QScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions());
                            boundingBox.setProperty("brn", bottomRightNear);
                            boundingBox.setProperty("tfl", topFarLeft);
                            boundingBox.setProperty("center", center);
                            boundingBox.setProperty("dimensions", boundingBoxDimensions);
                            zoneValues.setProperty("boundingBox", boundingBox);
                        }
                    }

                    // If this is an add or delete, or original properties weren't requested
                    // there won't be original properties in the args, but zone properties need
                    // to be the fourth parameter, so we need to pad the args accordingly
                    int EXPECTED_ARGS = 3;
                    if (args.length() < EXPECTED_ARGS) {
                        args << QScriptValue();
                    }
                    assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now!
                    args << zoneValues;
                }
            }

            QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args);

            if (filterData.uncaughtExceptions()) {
                return false;
            }

            if (result.isObject()) {
                // make propertiesIn reflect the changes, for next filter...
                propertiesIn.copyFromScriptValue(result, false);

                // and update propertiesOut too.  TODO: this could be more efficient...
                propertiesOut.copyFromScriptValue(result, false);
                // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON.
                auto out = QJsonValue::fromVariant(result.toVariant());
                wasChanged |= (in != out);
            } else if (result.isBool()) {

                // if the filter returned false, then it's authoritative
                if (!result.toBool()) {
                    return false;
                }

                // otherwise, assume it wants to pass all properties
                propertiesOut = propertiesIn;
                wasChanged = false;
                
            } else {
                return false;
            }
        }
    }
    // if we made it here, 
    return true;
}
void tst_QScriptContext::scopeChain()
{
    QScriptEngine eng;
    {
        QScriptValueList ret = eng.currentContext()->scopeChain();
        QCOMPARE(ret.size(), 1);
        QVERIFY(ret.at(0).strictlyEquals(eng.globalObject()));
    }
    {
        eng.globalObject().setProperty("getScopeChain", eng.newFunction(getScopeChain));
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("getScopeChain()"));
        QCOMPARE(ret.size(), 1);
        QVERIFY(ret.at(0).strictlyEquals(eng.globalObject()));
    }
    {
        eng.evaluate("function foo() { function bar() { return getScopeChain(); } return bar() }");
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("foo()"));
        QEXPECT_FAIL("", "Number of items in returned scope chain is incorrect", Abort);
        QCOMPARE(ret.size(), 3);
        QVERIFY(ret.at(2).strictlyEquals(eng.globalObject()));
        QCOMPARE(ret.at(1).toString(), QString::fromLatin1("activation"));
        QVERIFY(ret.at(1).property("arguments").isObject());
        QCOMPARE(ret.at(0).toString(), QString::fromLatin1("activation"));
        QVERIFY(ret.at(0).property("arguments").isObject());
    }
    {
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(eng.evaluate("o = { x: 123 }; with(o) getScopeChain();"));
        QCOMPARE(ret.size(), 2);
        QVERIFY(ret.at(1).strictlyEquals(eng.globalObject()));
        QVERIFY(ret.at(0).isObject());
        QCOMPARE(ret.at(0).property("x").toInt32(), 123);
    }
    {
        QScriptValueList ret = qscriptvalue_cast<QScriptValueList>(
            eng.evaluate("o1 = { x: 123}; o2 = { y: 456 }; with(o1) { with(o2) { getScopeChain(); } }"));
        QCOMPARE(ret.size(), 3);
        QVERIFY(ret.at(2).strictlyEquals(eng.globalObject()));
        QVERIFY(ret.at(1).isObject());
        QCOMPARE(ret.at(1).property("x").toInt32(), 123);
        QVERIFY(ret.at(0).isObject());
        QCOMPARE(ret.at(0).property("y").toInt32(), 456);
    }
}
示例#20
0
void tst_QScriptClass::extension()
{
    QScriptEngine eng;
    {
        TestClass cls(&eng);
        cls.setCallableMode(TestClass::NotCallable);
        QVERIFY(!cls.supportsExtension(QScriptClass::Callable));
        QVERIFY(!cls.supportsExtension(QScriptClass::HasInstance));
        QScriptValue obj = eng.newObject(&cls);
        QVERIFY(!obj.call().isValid());
        QCOMPARE((int)cls.lastExtensionType(), -1);
        QVERIFY(!obj.instanceOf(obj));
        QCOMPARE((int)cls.lastExtensionType(), -1);
    }
    // Callable
    {
        TestClass cls(&eng);
        cls.setCallableMode(TestClass::CallableReturnsSum);
        QVERIFY(cls.supportsExtension(QScriptClass::Callable));

        QScriptValue obj = eng.newObject(&cls);
        eng.globalObject().setProperty("obj", obj);
        obj.setProperty("one", QScriptValue(&eng, 1));
        obj.setProperty("two", QScriptValue(&eng, 2));
        obj.setProperty("three", QScriptValue(&eng, 3));
        // From C++
        cls.clearReceivedArgs();
        {
            QScriptValueList args;
            args << QScriptValue(&eng, 4) << QScriptValue(&eng, 5);
            QScriptValue ret = obj.call(obj, args);
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isNumber());
            QCOMPARE(ret.toNumber(), qsreal(15));
        }
        // From JS
        cls.clearReceivedArgs();
        {
            QScriptValue ret = eng.evaluate("obj(4, 5)");
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isNumber());
            QCOMPARE(ret.toNumber(), qsreal(15));
        }

        cls.setCallableMode(TestClass::CallableReturnsArgument);
        // From C++
        cls.clearReceivedArgs();
        {
            QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isNumber());
            QCOMPARE(ret.toInt32(), 123);
        }
        cls.clearReceivedArgs();
        {
            QScriptValue ret = obj.call(obj, QScriptValueList() << true);
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isBoolean());
            QCOMPARE(ret.toBoolean(), true);
        }
        {
            QScriptValue ret = obj.call(obj, QScriptValueList() << QString::fromLatin1("ciao"));
            QVERIFY(ret.isString());
            QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
        }
        {
            QScriptValue objobj = eng.newObject();
            QScriptValue ret = obj.call(obj, QScriptValueList() << objobj);
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(objobj));
        }
        {
            QScriptValue ret = obj.call(obj, QScriptValueList() << QScriptValue());
            QVERIFY(ret.isUndefined());
        }
        // From JS
        cls.clearReceivedArgs();
        {
            QScriptValue ret = eng.evaluate("obj(123)");
            QVERIFY(ret.isNumber());
            QCOMPARE(ret.toInt32(), 123);
        }

        cls.setCallableMode(TestClass::CallableReturnsInvalidVariant);
        {
            QScriptValue ret = obj.call(obj);
            QVERIFY(ret.isUndefined());
        }

        cls.setCallableMode(TestClass::CallableReturnsThisObject);
        // From C++
        {
            QScriptValue ret = obj.call(obj);
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(obj));
        }
        // From JS
        {
            QScriptValue ret = eng.evaluate("obj()");
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(eng.globalObject()));
        }

        cls.setCallableMode(TestClass::CallableReturnsCallee);
        // From C++
        {
            QScriptValue ret = obj.call();
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(obj));
        }
        // From JS
        {
            QScriptValue ret = eng.evaluate("obj()");
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(obj));
        }

        cls.setCallableMode(TestClass::CallableReturnsArgumentsObject);
        // From C++
        {
            QScriptValue ret = obj.call(obj, QScriptValueList() << 123);
            QVERIFY(ret.isObject());
            QVERIFY(ret.property("length").isNumber());
            QCOMPARE(ret.property("length").toInt32(), 1);
            QVERIFY(ret.property(0).isNumber());
            QCOMPARE(ret.property(0).toInt32(), 123);
        }
        // From JS
        {
            QScriptValue ret = eng.evaluate("obj(123)");
            QVERIFY(ret.isObject());
            QVERIFY(ret.property("length").isNumber());
            QCOMPARE(ret.property("length").toInt32(), 1);
            QVERIFY(ret.property(0).isNumber());
            QCOMPARE(ret.property(0).toInt32(), 123);
        }

        // construct()
        // From C++
        cls.clearReceivedArgs();
        cls.setCallableMode(TestClass::CallableReturnsGlobalObject);
        {
            QScriptValue ret = obj.construct();
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(eng.globalObject()));
        }
        // From JS
        cls.clearReceivedArgs();
        {
            QScriptValue ret = eng.evaluate("new obj()");
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isObject());
            QVERIFY(ret.strictlyEquals(eng.globalObject()));
        }
        // From C++
        cls.clearReceivedArgs();
        cls.setCallableMode(TestClass::CallableInitializesThisObject);
        {
            QScriptValue ret = obj.construct();
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isQObject());
            QCOMPARE(ret.toQObject(), (QObject*)&eng);
        }
        // From JS
        cls.clearReceivedArgs();
        {
            QScriptValue ret = eng.evaluate("new obj()");
            QCOMPARE(cls.lastExtensionType(), QScriptClass::Callable);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptContext*>());
            QVERIFY(ret.isQObject());
            QCOMPARE(ret.toQObject(), (QObject*)&eng);
        }
    }
    // HasInstance
    {
        TestClass cls(&eng);
        cls.setHasInstance(true);
        QVERIFY(cls.supportsExtension(QScriptClass::HasInstance));

        QScriptValue obj = eng.newObject(&cls);
        obj.setProperty("foo", QScriptValue(&eng, 123));
        QScriptValue plain = eng.newObject();
        QVERIFY(!plain.instanceOf(obj));

        eng.globalObject().setProperty("HasInstanceTester", obj);
        eng.globalObject().setProperty("hasInstanceValue", plain);
        cls.clearReceivedArgs();
        {
            QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
            QCOMPARE(cls.lastExtensionType(), QScriptClass::HasInstance);
            QCOMPARE(cls.lastExtensionArgument().userType(), qMetaTypeId<QScriptValueList>());
            QScriptValueList lst = qvariant_cast<QScriptValueList>(cls.lastExtensionArgument());
            QCOMPARE(lst.size(), 2);
            QVERIFY(lst.at(0).strictlyEquals(obj));
            QVERIFY(lst.at(1).strictlyEquals(plain));
            QVERIFY(ret.isBoolean());
            QVERIFY(!ret.toBoolean());
        }

        plain.setProperty("foo", QScriptValue(&eng, 456));
        QVERIFY(!plain.instanceOf(obj));
        {
            QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
            QVERIFY(ret.isBoolean());
            QVERIFY(!ret.toBoolean());
        }

        plain.setProperty("foo", obj.property("foo"));
        QVERIFY(plain.instanceOf(obj));
        {
            QScriptValue ret = eng.evaluate("hasInstanceValue instanceof HasInstanceTester");
            QVERIFY(ret.isBoolean());
            QVERIFY(ret.toBoolean());
        }
    }
}