// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include #include #include #include #include void log(const std::string &msg) { std::cout << "[" << time(nullptr) << "] " << msg << '\n'; } void log(const std::string &module, const std::string &msg) { std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n'; } void bound_log(const std::string &msg) { log(msg); } void hello_world(const chaiscript::Boxed_Value & /*o*/) { std::cout << "Hello World\n"; } void hello_constructor(const chaiscript::Boxed_Value & /*o*/) { std::cout << "Hello Constructor\n"; } struct System { std::map > m_callbacks; void add_callback(const std::string &t_name, const std::function &t_func) { m_callbacks[t_name] = t_func; } void do_callbacks(const std::string &inp) { log("Running Callbacks: " + inp); for (std::map >::iterator itr = m_callbacks.begin(); itr != m_callbacks.end(); ++itr) { log("Callback: " + itr->first, itr->second(inp)); } } }; void take_shared_ptr(const std::shared_ptr &p) { std::cout << *p << '\n'; } int main(int /*argc*/, char * /*argv*/[]) { using namespace chaiscript; ChaiScript chai; //Create a new system object and share it with the chaiscript engine System system; chai.add_global(var(&system), "system"); //Add a bound callback method chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound"); //Register the two methods of the System structure. chai.add(fun(&System::add_callback), "add_callback"); chai.add(fun(&System::do_callbacks), "do_callbacks"); chai.add(fun(&take_shared_ptr), "take_shared_ptr"); // Let's use chaiscript to add a new lambda callback to our system. // The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application // in the "add_callback" function of struct System the chaiscript function is converted into a // std::function, so it can be handled and called easily and type-safely chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });"); // Because we are sharing the "system" object with the chaiscript engine we have equal // access to it both from within chaiscript and from C++ code system.do_callbacks("TestString"); chai.eval("system.do_callbacks(\"TestString\");"); // The log function is overloaded, therefore we have to give the C++ compiler a hint as to which // version we want to register. One way to do this is to create a typedef of the function pointer // then cast your function to that typedef. typedef void (*PlainLog)(const std::string &); typedef void (*ModuleLog)(const std::string &, const std::string &); chai.add(fun(PlainLog(&log)), "log"); chai.add(fun(ModuleLog(&log)), "log"); chai.eval("log(\"Test Message\")"); // A shortcut to using eval is just to use the chai operator() chai("log(\"Test Module\", \"Test Message\");"); //Finally, it is possible to register a lambda as a system function, in this //way, we can, for instance add a bound member function to the system chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks"); //Call bound version of do_callbacks chai("do_callbacks()"); std::function caller = chai.eval >("fun() { system.do_callbacks(\"From Functor\"); }"); caller(); //If we would like a type-safe return value from all call, we can use //the templated version of eval: int i = chai.eval("5+5"); std::cout << "5+5: " << i << '\n'; //Add a new variable chai("var scripti = 15"); //We can even get a handle to the variables in the system int &scripti = chai.eval("scripti"); std::cout << "scripti: " << scripti << '\n'; scripti *= 2; std::cout << "scripti (updated): " << scripti << '\n'; chai("print(\"Scripti from chai: \" + to_string(scripti))"); //To do: Add examples of handling Boxed_Values directly when needed //Creating a functor on the stack and using it immediately int x = chai.eval >("fun (x, y) { return x + y; }")(5, 6); std::stringstream ss; ss << x; log("Functor test output", ss.str()); chai.add(var(std::shared_ptr()), "nullvar"); chai("print(\"This should be true.\"); print(nullvar.is_var_null())"); // test the global const action chai.add_global_const(const_var(1), "constvar"); chai("def getvar() { return constvar; }"); chai("print( getvar() )"); //Ability to create our own container types when needed. std::vector and std::map are //mostly supported currently chai.add(bootstrap::standard_library::vector_type >("IntVector")); // Test ability to register a function that excepts a shared_ptr version of a type chai("take_shared_ptr(\"Hello World as a shared_ptr\");"); chai.add(fun(&bound_log, std::string("Msg")), "BoundFun"); //Dynamic objects test chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world"); chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType"); // chai.add(fun(std::function(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr"); chai.eval("var x = TestType()"); // chai.eval("x.attr = \"hi\""); // chai.eval("print(x.attr)"); chai.eval("x.hello_world()"); }