How to create a QJSValue object of type Error



  • Hi!,

    Does anyone know how to create a QJSValue of type Error?

    Context: I use QJSEngine::evaluate() to execute JavaScript code, that JavaScript code calls a C++ function. The QJSEngine::evaluate() throws a script exception (QJSValue of type Error) only if there is an error in the JavaScript code. Therefore, if there is an error in the C++ function I want to return a QJSValue of type error. I am following that path becasue QJSEngine::evaluate does not catch C++ exceptions.

    Thank you so much.



  • I add additional info:

    Here it is a code snippet of the intended functionality:

    void CMainWindow::slot_ExecuteJVScript()
    {
       myCppClass myObject(parameters); //It has a foo() method.
       QJSEngine myEngine;
       myEngine.globalObject().setProperty("myObj", myEngine.newQObject(&myObject)); //Now we can access the C++ object from JavaScript code.
       QString myScriptJS = "var X = myObj.foo()";  //Calling a C++ function from JavaScript
       QJSValue myValue = myEngine.evaluate(myScriptJS);
       if(myValue.isError())
       {
          //If there is an error in the JavaScript code we enter here
          //But I also wanto to enter here if there is an error in my foo() C++ function. 
       }
       else
       {
          //Do things with myValue
       }
    }
    

    Mini-Example of myCppClass::foo()

    QJSValue myCppClass::foo()
    {       
       if(something)
       {
           //Create a QJSValue myValue with some data
           return myValue;
       }
       else
       {   //ERROR
           //Create a QJSValue of type Error
           return myValueOfTypeError;
       }
    }
    

  • Moderators

    @pablo_worker It seems that ErrorObject is under private headers so I doubt it could be used somehow.
    A dirty workaround would be to force an error from that function :)
    For eg. inside your else part.

    else
       {  
           QJSEngine engine;
           QJSValue val = engine.evaluate("f();"); //undefined function
           val.isError(); // this prints true
       }
    


  • @p3c0 Thank you.
    However, the problem I see is now is that I can't return QJSValue. Because if it has been created inside a function it is deleted when the function ends.

    QJSValue myFunction() {
       QJSEngine engine;
       QJSValue val = engine.evaluate("asdf;"); //rubbish
       val.isError(); //this prints true
       return val;
    }
    
    QJSValue foo = myFunction();
    foo.isError(); //this prints false
    

    In addition, if it has been created with a QJSEngine, it loses its properties after the engine is deleted. Example:

    else
    {
         QJSValue val;
         {
            QJSEngine engine;
            val = engine.evaluate("f()");
            qDebug() << "val.isError:" << val.isError(); //this prints true
         }
         qDebug() << "val.isError:" << val.isError(); //this prints false
    }
    

    I could pass the QJSEngine instance to the function, but still, I don't know how to hard-copy the QJSValue.


  • Moderators

    @pablo_worker You can pass reference of the same QJSEngine.

    QJSValue myFunction(QJSEngine &engine) {
       QJSValue val = engine.evaluate("asdf;"); //rubbish
       val.isError(); //this prints true
       return val;
    }
    
    QJSEngine myEngine;
    myFunction(myEngine).isError();
    


  • @p3c0 Yes, but the QJSValue is deleted after the "return" hence:

    myFunction(myEngine).isError();  //this returns false
    

  • Moderators

    @pablo_worker Nope. They are copied.



  • @p3c0
    I thought so, but there is something strange.
    In this case it is true:
    main.cpp

    #include <QCoreApplication>
    #include <QDebug>
    #include <QJSEngine>
    #include <QJSValue>
    
    QJSValue myFunction(QJSEngine &engine);
    
    int main(int argc, char *argv[])
    {
       QCoreApplication a(argc, argv);
       QJSEngine myEngine;
       QJSValue theVal = myFunction(myEngine);
       qDebug() << "theVal.isError():" << theVal.isError(); //this prints true
       return a.exec();
    }
    
    QJSValue myFunction(QJSEngine &engine)
    {
       QJSValue val = engine.evaluate("asf");
       qDebug() << "val.isError():" << val.isError(); //this prints true
       return val;
    }
    

    However, in this case it is not true

    Calling the cpp function from JavaScript.
    The debug output of this code is:

    In myFunction(), myVal.isError(): true
    Outside, theVal.isError(): false

    CMainWindow.h

    #include <QMainWindow>
    #include <QtWidgets>
    #include "myCppClass.h"
    
    class CMainWindow : public QMainWindow
    {
       Q_OBJECT
    public:
       CMainWindow(QWidget *parent = 0)
       {
          setCentralWidget(new QWidget(this));
    
          QJSEngine myEngine;
          myCppClass myObject(this, &myEngine); //this object has a myFunction() method.
          myEngine.globalObject().setProperty("myObj" ,myEngine.newQObject(&myObject));
          QJSValue theVal = myEngine.evaluate("var X = myObj.myFunction();"); //calling the function from Javascript
          qDebug() << "Outside, theVal.isError():" << theVal.isError(); //this prints false
       }
    };
    

    myCppClass.h

    #include <QObject>
    #include <QJSEngine>
    #include <QJSValue>
    #include <QDebug>
    
    class myCppClass : public QObject
    {
       Q_OBJECT
    public:
       explicit myCppClass(QObject *parent = 0, QJSEngine *theEngine = nullptr)
          : QObject(parent), m_myEng(theEngine){}
    public slots:
       QJSValue myFunction(){      
          QJSValue myVal = m_myEng->evaluate("asdf"); //myVal will be a error.
          qDebug() << "In myFunction(), myVal.isError():" << myVal.isError(); //this prints true;
          return myVal;
       }
    private:
       QJSEngine *m_myEng;
    };
    

    main.cpp

    #include "CMainWindow.h"
    #include <QApplication>
    int main(int argc, char *argv[])
    {
       QApplication a(argc, argv);
       CMainWindow w;
       w.show();
       return a.exec();
    }
    


  • I have also noted something more, if I call the C++ function (that returns a QJSValue of type error) from JavaScript like this:

    QJSValue theVal = myEngine.evaluate("var X = myObj.myFunction();"); //calling the c++ function from Javascript
    

    I don't get the error in the variable "theVal" [theVal.isError() will say "false"]

    However, if I call the function like this:

    QJSValue theVal = myEngine.evaluate("var X = myObj.myFunction(); X "); // note the X
    

    In this case the variable theVal does take the value X. And if I do theVal.isError() in this case it will show true.

    Why is this?


  • Moderators

    @pablo_worker So AFAICS something from JS should be returned so that evaluate reports proper output.



  • @p3c0 Thank you for your help.
    The problem is that what I really want in the end is a way to catch errors thrown by C++ functions transparently to the user that writes JavaScript. So, the user can just write a script like:

    var X = myCppFunction(foo);
    var Y = myOtherCppFunction(bar);
    etc.
    

    And when it is executed (myEngine.evaluate) the errors are catched by the C++ code of my application. Something like:

    try
    {
        QJSValue theVal = myEngine.evaluate(the JavaScript script);
        if(theVal.isError) {//if there are errors in the JS code enter here}
    }
    catch( )
    {
        // If there is an error in the Cpp functions called by the JS code enter here
    }
    

    I have seen in this post that this is not currently possible with QJSEngine. In addition, I have seen that a ticket is already open. Therefore, I will have to think something to get around and wait untill the functionality is implemented.

    Thank you for your help.


Log in to reply