Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

qt

qt4

qtscript

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:

  • Is there a way to do this?
  • Is it possible I'm on the right track but I set up ao improperly? For example, there is an undocumented QScriptEngine#newActivationObject() that yields an "unimplemented" error when used, perhaps this is a hint?

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).

like image 863
Jason C Avatar asked Aug 24 '16 16:08

Jason C


1 Answers

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();
}
like image 173
j2ko Avatar answered Nov 15 '22 12:11

j2ko