here it is
Just to give some input about how it works:
There a first set of files to provide basic non OOP interface to push/get data from lua stack in a C++ polymorphic way (files luapp11_base.* + included).
There's another file (luapp11_wrappers.hpp defining wrappers and functions to register C/C++ functions/objects to lua.
Finally, there's a few C++ objects to provide a OOP interface to lua stack.
file main.cpp in the unit test directory provides some examples. Here are some basic cases:
Code: Select all
// Start a new MainState and run a script
// It will be closed automatically when L goes out of scope.
main_state L;
L->run("print('A message from lua.')");
// Set/get global variables for pod types
// Note that getter can throw in case of type mismatch
L->set_global("i", 3);
L->set_global("d", .14159);
L->run("pi=i+d print('In lua: pi=',i+d)");
double pi = L->get_global<double>("pi");
L->get_global("pi", pi);
std::cout << "In C++: pi= " << pi << std::endl;
// How to shot yourself in the foot (take care of pointers and references!)
// strings can be set/get as const char* or as std::string
L->set_global<const char*>("a_string", "Everything looks fine!");
auto str1 = L->get_global<std::string>("a_string"); // safe
std::cout << str1 << " And it is fine! @" << (void*)str1.c_str() << std::endl;
auto str2 = L->get_global<const char*>("a_string"); // undefined behavior
std::cout << str2 << " But it's not! @" << (void*)str2 << std::endl;
std::cout << "This last pointer is owned by lua and can be garbaged collected while you're still using it.\n";
std::cout << "Make a string copy or use std::string instead of const char * when retrieving strings from lua.\n";
// Set function and closure
// Basic lua_CFunction (taken from lua API programming guide from lua website)
L->set_global("l_sin", &l_sin); // l_sin is a lua_CFunction to compute sinus. Prototype: static int l_sin (lua_State *L);
L->run("print('l_sin: ', l_sin(3.14159))");
// CClosure ie lua_CFunction with up values
L->set_global("counter", &counter, 0);
L->run("print('counter 1st call: ', counter())"); // print 1
L->run("print(' 2nd call: ', counter())"); // print 2
L->run("print(' 3rd call: ', counter())"); // print 3
// Random functions work too, it builds automatically an implicit wrapper around it.
// We'll see wrappers later on
L->set_global("add", &add);
L->run("print('add(3,.14159)=', add(3,.14159))");
// Finally, lambdas work too, using a special set_global_closure member function
L->set_global_closure("add_lambda", [](double l, double r)->double {return l+r;});
L->run("print('add_lambda(1,.618)=', add_lambda(1,.618))");
// callbacks
// Note that std::tuple is used below to return multiple values.
L->run("function myadd(a, b) return a+b end\n");
L->run("function multiple(s, x) return '2*'..s, 2*x end\n");
callable<float(float, float)> callback1((reference(L, "myadd")));
std::cout << "myadd(3,.14159)=" << callback1.call(3, .14159) << std::endl;
callable<std::tuple<std::string, float>(std::string, float)> callback2((reference(L, "multiple")));
std::cout << "tuple returns: " << callback2.call("PI", 3.14159) << std::endl;
callable<float(float, float)> callback3(L,"function(a, b) return a+b end");
std::cout << "Anonymous function: " << callback3.call(1.61803, 3.14159) << std::endl;
Code: Select all
class A {
std::string value_a;
public:
A(std::string val): value_a(val) {}
~A() {}
std::string getA() {return value_a;}
};
class B {
std::string value_b;
public:
B(std::string val): value_b(val) {}
~B() {}
std::string getB() {return value_b;}
};
class C: public A, public B {
std::string value_c;
public:
C(std::string val_a, std::string val_b, std::string val_c):A(val_a), B(val_b), value_c(val_c) {}
std::string getC() {return value_c;}
};
std::string test_derived(B& b) {
return b.getB();
}
.../...
// Registration and Inheritance with references and pointers
Class<A>("A", Construct<std::string>())
.Def("get_a", &A::getA)
.Register(L);
Class<B>("B", Construct<std::string>())
.Def("get_b", &B::getB)
.Register(L);
Class<C, Bases<A, B>>("C", Construct<std::string, std::string, std::string>())
.Def("get_c", &C::getC)
.Register(L);
L->set_global("test_derived_b", test_derived);
L->run("a=A('A obj')");
L->run("b=B('B obj')");
L->run("c=C('A in a C obj','B in a C obj','C in a C obj')");
L->run("print(a:get_a(), b:get_b())");
L->run("print(c:get_a(), c:get_b(), c:get_c())");
L->run("print(test_derived_b(a))"); // LUA ERROR: <<Type mismatch: expecting a B but got a A instead!>>
L->run("print(test_derived_b(b))"); // B obj
L->run("print(test_derived_b(c))"); // B in a C obj
There's also some support for sandboxing but this might requires some refactoring.
Const support might be messy. There's no const in lua so I've totally ignored it so far...
It's not fully polished (far from it), I might try to finish it once I had time and motivation again :p
Any comment welcome anyway.