Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Param type fix #23

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions lundi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,60 @@ class function_wrapper {
virtual ~function_wrapper() {};
};

std::string get_type_name(int lua_type_name) {
switch (lua_type_name) {
case LUA_TNUMBER: return "number";
case LUA_TBOOLEAN: return "bool";
case LUA_TSTRING: return "string";
case LUA_TNIL: return "nil";
case LUA_TUSERDATA: return "userdata";
case LUA_TTHREAD: return "thread";
case LUA_TLIGHTUSERDATA: return "lightuserdata";
case LUA_TTABLE: return "table";
case LUA_TFUNCTION: return "function";
default: return "unknown-type";
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it used? I feel like you wanted to do something with it but didn't go through.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was supposed to be used in error reporting. Hm...


struct fetch_parameter {
lua_State *state;
fetch_parameter(lua_State *s) : state(s) {}

// that function is complementary to peek
// the main difference is that it knows what to expect

// the template version is more flexible, but produces no error message
/*template<typename T>
void operator()(T&) const {
static_assert(false, "This type can't be used in function signature.");
}*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, do we keep it or not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I remember having some problems with that one, lemme take a closer look.


// TODO : add error reporting to that
// it has to utilize userdata stored in state somehow

void operator()(std::string& t) const {
t = lua_tostring(state, -1);
lua_pop(state, 1);
}

void operator()(int& t) const {
t = lua_tointeger(state, -1);
lua_pop(state, 1);
}

void operator()(double& t) const {
t = lua_tonumber(state, -1);
lua_pop(state, 1);
}

void operator()(bool& t) const {
t = static_cast<bool>(lua_toboolean(state, -1));
lua_pop(state, 1);
}

void operator()(lua::nil_type&) const {
lua_pop(state, 1);
}
};

template<typename Ret, typename... Args>
Expand Down Expand Up @@ -131,6 +172,10 @@ char const *stream_name(StreamT &stream) {
class state {
lua_State *state_;
std::function<void(std::string const&)> error_func_;
void report_error(std::string const& error_message) {
if (error_func_)
error_func_(error_message);
}

variant peek(int index) {
switch(lua_type(state_, index)) {
Expand Down Expand Up @@ -165,8 +210,7 @@ class state {
error_msg = std::string(lua_tostring(state_, -1));
lua_pop(state_, -1); // remove error message
}
if (error_func_)
error_func_(error_msg);
report_error(error_msg);
}
}

Expand Down
115 changes: 99 additions & 16 deletions test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,116 @@
#include <string>
#include <exception>

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/for_each.hpp>

#include "lundi.hpp"

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

namespace {
namespace c_funs {

// left for historical purposes
int plop_xyz(int x, int y, std::string z) {
std::cout << x << " " << y << " " << z << std::endl;
return 11;
}

// the naming pattern goes:
// {return_type}_{number_of_args}

// basic empty functions
namespace basic {
template<typename A>
void void_unary(A a) { }
template<typename A>
void void_binary_first(A a, int) { }
template<typename B>
void void_binary_second(int, B b) { }

// function without parameters
template<typename Ret>
Ret nonparam() { return Ret{}; }

// functions returning nonparameter
template<typename A>
A same_unary(A a) { return a; }
template<typename A>
A first_binary_first(A a, int) { return a; }
template<typename B>
B second_binary_second(int, B b) { return b; }
}

// functions with aggregates
/*namespace aggregate{
template<class Aggr, typename A>
void void_unary(Aggr<A> a) { }
// TODO add more
}*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until we support tables, this is nothing more than a wish now, so might as well go away. 🆗

}

// equivalent of Boost.Variant operator==
template<typename V, typename T>
inline bool equals(V const& variant, T const& value){
return boost::get<T>(variant) && boost::get<T>(variant) == value;
}

//[](std::string const& s) { std::cerr << "Lua ERROR : " << s << std::endl; }
void defaultErrorReporter(std::string const& s) {
std::cerr << "Lua ERROR : " << s << std::endl;
}

void exceptionErrorReporter(std::string const& s) {
throw lua::exception(s);
}

}

#define BASIC_TYPES (int)(double)(bool)(std::string)(lua::nil_type)

TEST_CASE( "coverage/register_void_return", "Check if basic calls in form of void(T) compile." ) {
lua::state lua (&exceptionErrorReporter);

#define MACRO(r, data, Elem) \
REQUIRE_NOTHROW(lua.register_function("foo", c_funs::basic::void_unary<Elem>)); \
REQUIRE_NOTHROW(lua.register_function("foo", c_funs::basic::void_binary_first<Elem>)); \
REQUIRE_NOTHROW(lua.register_function("foo", c_funs::basic::void_binary_second<Elem>));
BOOST_PP_SEQ_FOR_EACH(MACRO, _, BASIC_TYPES)
#undef MACRO
}

TEST_CASE(" coverage/register_nonvoid_return", "Check if basic calls in form of void(T) compile.") {
lua::state lua(&exceptionErrorReporter);

int plop_xyz(int x, int y, std::string z) {
std::cout << x << " " << y << " " << z << std::endl;
return 11;
#define MACRO(r, data, Elem) \
REQUIRE_NOTHROW(lua.register_function("foo", c_funs::basic::same_unary<Elem>)); \
REQUIRE_NOTHROW(lua.register_function("foo", c_funs::basic::first_binary_first<Elem>)); \
REQUIRE_NOTHROW(lua.register_function("foo", c_funs::basic::second_binary_second<Elem>));

BOOST_PP_SEQ_FOR_EACH(MACRO, _, BASIC_TYPES)
#undef MACRO
}

// equivalent of Boost.Variant operator==
template<typename V, typename T>
inline bool equals(V const& variant, T const& value){
return boost::get<T>(variant) && boost::get<T>(variant) == value;
}
TEST_CASE( "coverage/void_lambda_call", "Check if basic calls in form of void <lambda>(T) compile." ) {
lua::state lua(&exceptionErrorReporter);

//[](std::string const& s) { std::cerr << "Lua ERROR : " << s << std::endl; }
void defaultErrorReporter(std::string const& s) {
std::cerr << "Lua ERROR : " << s << std::endl;
#define MACRO(r, data, Elem) \
REQUIRE_NOTHROW(lua.register_function("foo", [](Elem){})); \
REQUIRE_NOTHROW(lua.register_function("foo", [](Elem, Elem){}));
BOOST_PP_SEQ_FOR_EACH(MACRO, _, BASIC_TYPES)
#undef MACRO
}

void exceptionErrorReporter(std::string const& s) {
throw lua::exception(s);
}
TEST_CASE("coverage/type_lambda_call", "Check if basic calls in form of T <lambda>(T) compile.") {
lua::state lua(&exceptionErrorReporter);

#define MACRO(r, data, Elem) \
REQUIRE_NOTHROW(lua.register_function("foo", [](Elem){ return Elem {}; })); \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context, is {} any different than ()? Just wondering.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more jazz and pop and C++11 and Web 2.0.

IOW, nope.

REQUIRE_NOTHROW(lua.register_function("foo", [](Elem, Elem){ return Elem {}; }));
BOOST_PP_SEQ_FOR_EACH(MACRO, _, BASIC_TYPES)
#undef MACRO
}

TEST_CASE( "simple/set_global", "Check if the set_global works properly." ) {
Expand Down Expand Up @@ -118,7 +201,7 @@ TEST_CASE( "simple/callWithParameters", "Lua function is called with a few param
TEST_CASE( "simple/callCppFunction", "Desc" ) {
lua::state lua(&exceptionErrorReporter);

lua.register_function("plop_xyz", plop_xyz);
lua.register_function("plop_xyz", c_funs::plop_xyz);
lua.eval("x = plop_xyz(2, 6, 'hello')");
std::cout << lua.get_global("x") << std::endl;

Expand Down Expand Up @@ -148,7 +231,7 @@ TEST_CASE( "advanced/callLambdaReturns", "Checks for lambdas returning values")
lua.register_function("f", []{ return true; });
lua.register_function("g", []{ return std::string("str"); });
lua.register_function("h", []{});
lua.register_function("i", []{ return lua::nil(); });
lua.register_function("i", []{ return lua::nil; });
}

TEST_CASE( "advanced/callLambda2", "A C++ lambda is exposed to lua and called") {
Expand Down