std::Vector<Int> const int copy constructor


#1

I’m trying to use a std::vector passed from C++ to Chaiscript and set a member of the vector to a var (GLOBAL) in the Chaiscript. But I keep coming across this error “Missing clone or copy constructor for right hand side of equation” With parameters: (const int) during evaluation at (2, 8)"

Dunno why it doesn’t know how to copy a const int? I tried iv.at(0); too with the same issue.

The code for the vector type is

std::vector<std::string> SaveStrs;
std::vector<int>         SaveInts;
engine->add(chaiscript::bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
engine->add(chaiscript::bootstrap::standard_library::vector_type<std::vector<std::string> >("StringVector"));

Basically, this is a save/load system for the scripts since I don’t think you can save Chaiscripts state…

MSVC 14.0


#2

I’m going to need a complete standalone example to be able to debug this. I cannot think of any reason why a vector of int would not work.

-Jason


#3

I actually accidently fixed this issue by redesigning parts of the reloading system. I went ahead and made a stripped down version of my engine anyways.

I included a define (BREAK_CHAISCRIPT) which allows you to switch between a patched and error prone version.

Basically, I wanted to reset the Chaiscript state, but I saw no real built in way to do it. So I tried to reset the Chaiscript state to a new state via “engine->set_state(chaiscript::ChaiScript::State());”. Now this worked except when reloading the file/script in bool reinit_engine(ScriptEngine & sEngine).

Not sure if that’s a bug or just an improper way of clearing the script. What I ended up doing is making the chaiscript var a pointer, new-ing it, then deleting and renewing it to reload it.

I think a reset state feature would be nice to have though. There are certian situations where the script data should be dumped and reloaded (aka in networked turn-based games where the clients desync, and so does the script)

#include <string>
#include <iostream>
#include <vector>
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>

class ScriptEngine
{
public:
    std::string path;
    chaiscript::ChaiScript * engine;

    std::vector<std::string> SaveStrs;
    std::vector<int>         SaveInts;

    // Functions
    std::function<void()> main;
    std::function<void(std::vector<std::string>&, std::vector<int>&)> reinit;
    std::function<void(std::vector<std::string>&, std::vector<int>&)> deinit;
};

#define ENGINE_ADD_VECTOR_STL(type, name) sEngine.engine->add(chaiscript::bootstrap::standard_library::vector_type<type>(name));
void dump_script_data(ScriptEngine & sEngine);
bool reinit_engine(ScriptEngine & sEngine);
void init_call_back_functions(class ScriptEngine & sEngine);
bool add_script(const std::string & scriptPath);

const std::string scrSource = "global i = 0; def reinit(StringVector sv, IntVector iv) { i = iv[0]; } def deinit(StringVector sv, IntVector iv)  { iv.push_back(i); } def main() { i = i + 1; }";

ScriptEngine test;

#define BREAK_CHAISCRIPT 1

int main() 
{

    // Empty because that part of the engine was stripped out.
    add_script("");

    for (int i = 0; i < 20; i++) 
    {
        test.main();
    }

    // Dump Data
    dump_script_data(test);

    std::cout << "global i was " << test.SaveInts[0] << '\n';

    // Reload engine and load in i back into global.
    reinit_engine(test);

    for (int i = 0; i < 20; i++)
    {
        test.main();
    }

    // Dump Data 2
    dump_script_data(test);

    std::cout << "global i was " << test.SaveInts[0] << '\n';

    return 0;
}

void init_engine(class ScriptEngine & sEngine)
{
    // C++
    ENGINE_ADD_VECTOR_STL(std::vector<int>, "IntVector");
    ENGINE_ADD_VECTOR_STL(std::vector<std::string>, "StringVector");
}

bool add_script(const std::string & scriptPath)
{
   // Debug->log("Loading script %s....\n", scriptPath.c_str());
    //if (btl_fileExists(scriptPath))
    {
        //scripts.resize(scripts.size() + 1);
        class ScriptEngine & newEngine = test;//scripts[scripts.size() - 1];
        newEngine.path = scriptPath;
        newEngine.engine = new chaiscript::ChaiScript(chaiscript::Std_Lib::library());
        init_engine(newEngine);

        try
        {
            //newEngine.engine->eval_file(scriptPath);
            newEngine.engine->eval(scrSource);

            // Get function data
            init_call_back_functions(newEngine);

            return true; // Success!
        }
        catch (const chaiscript::exception::eval_error &ee)
        {
            std::cout << ee.what();
            if (ee.call_stack.size() > 0)
            {
                std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
            }
        }
    }
    return false; // Fail!
}

void dump_script_data(ScriptEngine & sEngine)
{
    sEngine.SaveStrs.clear();
    sEngine.SaveInts.clear();

    if (sEngine.deinit)
    {
        try
        {
            sEngine.deinit(sEngine.SaveStrs, sEngine.SaveInts);
        }
        catch (const chaiscript::exception::eval_error &ee)
        {
            sEngine.SaveStrs.clear();
            sEngine.SaveInts.clear();

            std::cout << ee.what();
            if (ee.call_stack.size() > 0)
            {
                std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
            }
        }
    }
}

bool reinit_engine(ScriptEngine & sEngine)
{
    //if (btl_fileExists(sEngine.path))
    {
#if !BREAK_CHAISCRIPT
        // If there is no engine (from cold reload), create new one.
        if (sEngine.engine) delete sEngine.engine;

        // Init Engine
        sEngine.engine = new chaiscript::ChaiScript(chaiscript::Std_Lib::library());
#else
        // Reset state, causes error.
        sEngine.engine->set_state(chaiscript::ChaiScript::State());
#endif

        // Init Core
        init_engine(sEngine);

        try
        {
            //sEngine.engine->eval_file(sEngine.path);
            sEngine.engine->eval(scrSource);

            // Get function data
            init_call_back_functions(sEngine);

            // Call Init function
            sEngine.reinit(sEngine.SaveStrs, sEngine.SaveInts);

            // Clear saved data
            sEngine.SaveStrs.clear();
            sEngine.SaveInts.clear();
            return true;
        }
        catch (const chaiscript::exception::eval_error &ee)
        {
            if (ee.call_stack.size() > 0)
            {
                std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
            }
        }
    }

    return false;
}

void init_call_back_functions(class ScriptEngine & sEngine)
{
    auto funcs = sEngine.engine->get_state().engine_state.m_functions;

    for (const auto & func : funcs)
    {
        if (func.first == "main")
        {
            sEngine.main = sEngine.engine->eval<std::function<void()>>("main");
        }
        else if (func.first == "reinit")
        {
            sEngine.reinit = sEngine.engine->eval<std::function<void(std::vector<std::string>&, std::vector<int>&)>>("reinit");
        }
        else if (func.first == "deinit")
        {
            sEngine.deinit = sEngine.engine->eval<std::function<void(std::vector<std::string>&, std::vector<int>&)>>("deinit");
        }
    }
}

#4

What you probably want to do is:

auto state = chai.get_state();

// do a bunch of stuff

chai.set_state(state);

Setting a blank state, like you were, would be interesting since it would erase all of the standard library and built in functions also.

-Jason