From 812b87d38ab53a7539103891bba9cac4399941c9 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Tue, 21 Jan 2014 15:55:29 -0800 Subject: [PATCH] Add a few class tests and update README. --- README.md | 118 ++++++++++++++++++++++++++++++------------- test/Test.cpp | 4 +- test/class_tests.h | 18 +++++-- test/interop_tests.h | 23 ++++++--- test/test.lua | 5 ++ 5 files changed, 122 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index f399a49..7f862fa 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ ____/ \___| _| \___| _| _| \___| ``` -# Selene - Simple C++11 friendly bindings to Lua. ## Building @@ -26,67 +24,119 @@ addition, this will build all tests in the `test` directory. ## Usage -Currently, these bindings support calling lua function from C++ and vice versa. +### Establishing Lua Context + +```c++ +using namespace sel; +State state; // creates a Lua context +State state{true]; // creates a Lua context and loads standard Lua libraries +``` + +When a `sel::State` object goes out of scope, the Lua context is +automatically destroyed in addition to all objects associated with it +(including C++ objects). + +### Calling Lua functions from C++ ```lua +// test.lua + function foo() end function add(a, b) - return a + b + return a + b end function sum_and_difference(a, b) - return (a+b), (a-b); + return (a+b), (a-b); end function bar() - return 4, true, "hi" + return 4, true, "hi" +end + +mytable = {} +function mytable.foo() + return 4 end ``` ```c++ -#include -#include +sel::State state; +state.Load("/path/to/test.lua"); + +// Call function with no arguments or returns +state.Call("foo"); + +// Call function with two arguments that returns an int +int result = state.Call("add", 5, 2); +assert(result == 7); + + +// Call function that returns multiple values +int sum, difference; +std::tie(sum, difference) = state.Call("sum_and_difference", 3, 1); +assert(sum == 4 && difference == 2); + +// Call function in table +result = state.CallField("mytable", "foo"); +assert(result == 4); +``` + +### Calling Free-standing C++ functions from Lua +```c++ int my_multiply(int a, int b) { return (a*b); } -int main() { - sel::State state; - state.Load("../test/test.lua"); +sel::State state; - // Call function with no arguments or returns - state.Call("foo"); +// Register the function to the Lua global "c_multiply" +state.Register("c_multiply", &my_multiply); - // Call function with two arguments that returns an int - int result = state.Call("add", 5, 2); - assert(result == 7); +// Now we can call it (we can also call it from within lua) +result = state.Call("my_multiply", 5, 2); +assert(result == 10); +``` - // Multiple return types - int sum, difference; - std::tie(sum, difference) = state.Call("sum_and_difference", 3, 1); - assert(sum == 4 && difference == 2); +You can also register functor objects, lambdas, and any fully +qualified `std::function`. See `test/interop_tests.h` for details. + +### Registering Object Instances - // Heterogeneous return types +```c++ +struct Foo { int x; - bool y; - std::string z; - std::tie(x, y, z) = state.Call("bar"); - assert(x == 4 && y == true && z == "hi"); + Foo(int x_) : x(x_) {} - // Call C function from Lua - state.Register("c_multiply", &my_multiply); - result = state.Call("my_multiply", 5, 2); - assert(result == 10); + int DoubleAdd(int y) { return 2 * (x + y); } + void SetX(int x_) { x = x_; } +}; - std::cout << "Call tests finished successfully." << std::endl; -} +sel::State state; + +// Instantiate a foo object with x initially set to 2 +Foo foo(2); + +// Binds the C++ instance foo to a table also called foo in Lua along +// with two methods bound to fields of that table +state.Register("foo", foo, + std::make_pair("double_add", &Foo::DoubleAdd), + std::make_pair("set_x", &Foo::SetX)); + +state.CallField("foo", "set_x", 4); +assert(foo.x == 4); + +int result = state.CallField("foo", "double_add", 3); +assert(result == 14); ``` -You can also register functor objects, lambdas, and any fully -qualified `std::function`. See `test/tests.h` for details. +In the above example, the functions `foo.double_add` and `foo.set_x` +will also be accessible from within Lua after registration occurs. + +## Writeup You can read more about this project in the blogpost that describes it [here](http://www.jeremyong.com/blog/2014/01/10/interfacing-lua-with-templates-in-c-plus-plus-11/). @@ -97,6 +147,6 @@ and in the second part The following features are planned, although nothing is guaranteed: -- Object oriented type aware table interface with Lua +- Object lifetime handling - Smarter Lua module loading - Hooks for module reloading diff --git a/test/Test.cpp b/test/Test.cpp index 5750eae..1f30849 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -9,6 +9,7 @@ static std::vector tests = { test_add, test_multi_return, test_heterogeneous_return, + test_call_field, test_call_c_function, test_call_c_fun_from_lua, test_no_return, @@ -20,7 +21,8 @@ static std::vector tests = { test_multivalue_c_fun_from_lua, test_c_fun_destructor, test_register_class, - test_mutate_instance + test_mutate_instance, + test_multiple_methods }; diff --git a/test/class_tests.h b/test/class_tests.h index 7d0268c..71c5de2 100644 --- a/test/class_tests.h +++ b/test/class_tests.h @@ -8,8 +8,8 @@ struct Foo { int DoubleAdd(int y) { return 2 * (x + y); } - void SetX(int x2) { - x = x2; + void SetX(int x_) { + x = x_; } }; @@ -19,7 +19,7 @@ bool test_register_class() { state.Register("foo_instance", foo_instance, std::make_pair("double_add", &Foo::DoubleAdd)); - int answer = state.CallField("foo_instance", "double_add", 3); + const int answer = state.CallField("foo_instance", "double_add", 3); return (answer == 8); } @@ -32,3 +32,15 @@ bool test_mutate_instance() { state.CallField("foo_instance", "set_x", 4); return (foo_instance.x == 4); } + +bool test_multiple_methods() { + Foo foo_instance(1); + sel::State state; + state.Register("foo_instance", + foo_instance, + std::make_pair("double_add", &Foo::DoubleAdd), + std::make_pair("set_x", &Foo::SetX)); + state.CallField("foo_instance", "set_x", 4); + const int answer = state.CallField("foo_instance", "double_add", 3); + return (answer == 14); +} diff --git a/test/interop_tests.h b/test/interop_tests.h index 678f33a..3e1216c 100644 --- a/test/interop_tests.h +++ b/test/interop_tests.h @@ -38,7 +38,14 @@ bool test_heterogeneous_return() { bool y; std::string z; std::tie(x, y, z) = state.Call("bar"); - return (x == 4 && y == true && z == "hi"); + return x == 4 && y == true && z == "hi"; +} + +bool test_call_field() { + sel::State state; + state.Load("../test/test.lua"); + int answer = state.CallField("mytable", "foo"); + return answer == 4; } bool test_call_c_function() { @@ -46,7 +53,7 @@ bool test_call_c_function() { state.Load("../test/test.lua"); state.Register("cadd", std::function(my_add)); int answer = state.Call("cadd", 3, 6); - return (answer == 9); + return answer == 9; } bool test_call_c_fun_from_lua() { @@ -54,7 +61,7 @@ bool test_call_c_fun_from_lua() { state.Load("../test/test.lua"); state.Register("cadd", std::function(my_add)); int answer = state.Call("execute"); - return (answer == 11); + return answer == 11; } bool test_no_return() { @@ -70,7 +77,7 @@ bool test_call_lambda() { std::function mult = [](int x, int y){ return x * y; }; state.Register("cmultiply", mult); int answer = state.Call("cmultiply", 5, 6); - return (answer == 30); + return answer == 30; } bool test_call_normal_c_fun() { @@ -78,7 +85,7 @@ bool test_call_normal_c_fun() { state.Load("../test/test.lua"); state.Register("cadd", &my_add); const int answer = state.Call("cadd", 4, 20); - return (answer == 24); + return answer == 24; } bool test_call_normal_c_fun_many_times() { @@ -107,7 +114,7 @@ bool test_call_functor() { state.Load("../test/test.lua"); state.Register("c_the_answer", std::function(functor)); int answer = state.Call("c_the_answer"); - return (answer == 42); + return answer == 42; } @@ -121,7 +128,7 @@ bool test_multivalue_c_fun_return() { state.Register("test_fun", &my_sum_and_difference); int sum, difference; std::tie(sum, difference) = state.Call("test_fun", -2, 2); - return (sum == 0 && difference == -4); + return sum == 0 && difference == -4; } bool test_multivalue_c_fun_from_lua() { @@ -129,7 +136,7 @@ bool test_multivalue_c_fun_from_lua() { state.Load("../test/test.lua"); state.Register("doozy_c", &my_sum_and_difference); int answer = state.Call("doozy", 5); - return (answer == -75); + return answer == -75; } bool test_c_fun_destructor() { diff --git a/test/test.lua b/test/test.lua index 4780b6f..9163d6c 100644 --- a/test/test.lua +++ b/test/test.lua @@ -21,3 +21,8 @@ function doozy(a) x, y = doozy_c(a, 2 * a) return x * y end + +mytable = {} +function mytable.foo() + return 4 +end