c++qtqt4qtscript

Is there a way to maintain Qt script context environment outside of QScriptEngine#pushContext/popContext?


In Qt 4.8's scripting engine, "local" variables can be set by obtaining a QScriptContext from QScriptEngine::pushContext then setting the properties of its activation object. This can only be done within push/pop calls, since that's the only place a QScriptContext is available and AFAICT there is no equivalent of QScriptEngine#evaluate that takes a QScriptContext to use as the environment:

QScriptEngine engine;
QScriptContext *local;

local = engine.pushContext();
local->activationObject().setProperty("value", 2); // set value=2
qDebug() << engine.evaluate("value").toNumber(); // outputs 2
engine.popContext();

Is there some way to maintain an environment to use with evaluations outside of the push/pop calls? For example, I've tried creating a QScriptValue to use as the activation object and then setting it:

QScriptEngine engine;
QScriptContext *local;

// Use ao as activation object, set variables here, prior to pushContext.
QScriptValue ao;
ao.setProperty("value", 1);

// Test with ao:
local = engine.pushContext();
local->setActivationObject(ao);
qDebug() << engine.evaluate("value").toNumber();
engine.popContext();

But that doesn't work. It outputs nan instead of 1, as value is undefined. For some reason setActivationObject didn't change the value.

My general goal is:

  1. Set up a local environment outside of the evaluation code.
  2. Then use that pre-configured local environment when evaluating scripts between pushContext and popContext calls, without having to re-set all the variables in that environment every time.

So:

How can I set up a local context but basically not have to re-configure it every time I push a context (since it's essentially lost for good every time I pop the context).


Solution

  • You could use global object. It will share property value accross all evaluations:

    #include <QCoreApplication>
    #include <QDebug>
    #include <QtScript/QScriptEngine>
    #include <QtScript/QScriptContext>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        QScriptEngine engine;
    
        engine.globalObject().setProperty("value", 2);
        engine.globalObject().setProperty("value2", 3);
    
        qDebug() << engine.evaluate("value").toNumber(); // outputs 2
        qDebug() << engine.evaluate("value2").toNumber(); // outputs 3
    
    
        return a.exec();
    }
    

    Or if you do not want global scope :

    #include <QCoreApplication>
    #include <QDebug>
    #include <QtScript/QScriptEngine>
    #include <QtScript/QScriptContext>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        QScriptEngine engine;
        QScriptContext *context;
    
        QScriptValue scope = engine.newObject();
        scope.setProperty("value", 1);
        scope.setProperty("value2", 2);
    
        context = engine.pushContext();
    
        context->pushScope(scope);
        qDebug() << engine.evaluate("value").toNumber(); // outputs 1
        qDebug() << engine.evaluate("value2").toNumber(); // outputs 2
    
        engine.popContext();
    
        return a.exec();
    }