cppbind: allow calling methods with 'me' object from C++.
This commit is contained in:
@@ -542,6 +542,11 @@ namespace nasal
|
||||
return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
|
||||
}
|
||||
|
||||
// Build dependency for CMake, gcc, etc.
|
||||
#define SG_DONT_DO_ANYTHING
|
||||
# include <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
||||
#undef SG_DONT_DO_ANYTHING
|
||||
|
||||
#define BOOST_PP_ITERATION_LIMITS (0, 9)
|
||||
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
||||
#include BOOST_PP_ITERATE()
|
||||
@@ -732,7 +737,7 @@ namespace nasal
|
||||
(
|
||||
c,
|
||||
"method called on object of wrong type: is '%s' expected '%s'",
|
||||
ghost_type ? ghost_type->name : "unknown",
|
||||
naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
|
||||
_ghost_type.name
|
||||
);
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace nasal
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const naRef Hash::get_naRef() const
|
||||
naRef Hash::get_naRef() const
|
||||
{
|
||||
return _hash;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace nasal
|
||||
/**
|
||||
* Get Nasal representation of Hash
|
||||
*/
|
||||
const naRef get_naRef() const;
|
||||
naRef get_naRef() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ struct Base
|
||||
std::string var;
|
||||
const std::string& getVar() const { return var; }
|
||||
void setVar(const std::string v) { var = v; }
|
||||
|
||||
unsigned long getThis() const { return (unsigned long)this; }
|
||||
};
|
||||
|
||||
void baseVoidFunc(Base& b) {}
|
||||
@@ -173,6 +175,19 @@ int main(int argc, char* argv[])
|
||||
VERIFY( fma );
|
||||
VERIFY( fma("test", 3, .5) == "test" );
|
||||
|
||||
typedef boost::function<naRef (naRef)> naRefMemFunc;
|
||||
naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
|
||||
VERIFY( fmem );
|
||||
naRef ret = fmem(hash.get_naRef()),
|
||||
hash_ref = hash.get_naRef();
|
||||
VERIFY( memcmp(&ret, &hash_ref, sizeof(naRef)) == 0 );
|
||||
|
||||
// Check if nasal::Me gets passed as self/me and remaining arguments are
|
||||
// passed on to function
|
||||
typedef boost::function<int (Me, int)> MeIntFunc;
|
||||
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
|
||||
VERIFY( fmeint(naNil(), 5) == 5 );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Test exposing classes to Nasal
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -190,7 +205,8 @@ int main(int argc, char* argv[])
|
||||
.method("void_c", &baseConstVoidFunc)
|
||||
.method("int2args", &baseFunc2Args)
|
||||
.method("bool2args", &Base::test2Args)
|
||||
.method("str_ptr", &testPtr);
|
||||
.method("str_ptr", &testPtr)
|
||||
.method("this", &Base::getThis);
|
||||
Ghost<DerivedPtr>::init("DerivedPtr")
|
||||
.bases<BasePtr>()
|
||||
.member("x", &Derived::getX, &Derived::setX)
|
||||
@@ -216,6 +232,17 @@ int main(int argc, char* argv[])
|
||||
VERIFY( naIsGhost(derived) );
|
||||
VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name );
|
||||
|
||||
// Get member function from ghost...
|
||||
naRef thisGetter = naNil();
|
||||
VERIFY( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
|
||||
VERIFY( naIsFunc(thisGetter) );
|
||||
|
||||
// ...and check if it really gets passed the correct instance
|
||||
typedef boost::function<unsigned long (Me)> MemFunc;
|
||||
MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
|
||||
VERIFY( fGetThis );
|
||||
VERIFY( fGetThis(derived) == (unsigned long)d.get() );
|
||||
|
||||
BasePtr d2( new DoubleDerived );
|
||||
derived = to_nasal(c, d2);
|
||||
VERIFY( naIsGhost(derived) );
|
||||
@@ -292,8 +319,6 @@ int main(int argc, char* argv[])
|
||||
VERIFY( objects[1] == d2 );
|
||||
VERIFY( objects[2] == d3 );
|
||||
|
||||
// TODO actually do something with the ghosts...
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Test nasal::CallContext
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# error Nasal cppbind - do not include this file!
|
||||
#endif
|
||||
|
||||
#ifndef SG_DONT_DO_ANYTHING
|
||||
#define n BOOST_PP_ITERATION()
|
||||
|
||||
#ifndef SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||
@@ -12,14 +13,12 @@
|
||||
|
||||
template<
|
||||
class Ret
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
typename boost::disable_if<boost::is_void<Ret>, Ret>::type
|
||||
callNasalFunction( const ObjectHolder<SGReferenced>* holder
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0)
|
||||
)
|
||||
callNasalMethod( const ObjectHolder<SGReferenced>* holder,
|
||||
Me self
|
||||
BOOST_PP_ENUM_TRAILING(n, SG_CALL_TRAITS_PARAM, 0) )
|
||||
{
|
||||
naContext ctx = naNewContext();
|
||||
naRef args[] = {
|
||||
@@ -28,33 +27,43 @@
|
||||
const int num_args = sizeof(args)/sizeof(args[0]);
|
||||
|
||||
naRef result =
|
||||
naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil());
|
||||
naCallMethodCtx(ctx, holder->get_naRef(), self, num_args, args, naNil());
|
||||
|
||||
const char* error = naGetError(ctx);
|
||||
std::string error_str(error ? error : "");
|
||||
|
||||
Ret r = Ret();
|
||||
if( !error )
|
||||
r = from_nasal_helper(ctx, result, static_cast<Ret*>(0));
|
||||
|
||||
Ret r = from_nasal_helper(ctx, result, static_cast<Ret*>(0));
|
||||
naFreeContext(ctx);
|
||||
|
||||
if( error )
|
||||
throw std::runtime_error(error_str);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template<
|
||||
class Ret
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
typename boost::enable_if<boost::is_void<Ret>, Ret>::type
|
||||
callNasalFunction( const ObjectHolder<SGReferenced>* holder
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0)
|
||||
)
|
||||
callNasalMethod( const ObjectHolder<SGReferenced>* holder,
|
||||
Me self
|
||||
BOOST_PP_ENUM_TRAILING(n, SG_CALL_TRAITS_PARAM, 0) )
|
||||
{
|
||||
naContext ctx = naNewContext();
|
||||
naRef args[] = {
|
||||
BOOST_PP_ENUM(n, SG_CALL_ARG, 0)
|
||||
};
|
||||
const int num_args = sizeof(args)/sizeof(args[0]);
|
||||
|
||||
naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil());
|
||||
naFreeContext(ctx);
|
||||
callNasalMethod<
|
||||
naRef // do not do any conversion and just ignore the return value
|
||||
// TODO warn if something different to nil is returned?
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_PARAMS(n, A)
|
||||
>
|
||||
(
|
||||
holder,
|
||||
self
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, a)
|
||||
);
|
||||
}
|
||||
|
||||
# undef SG_CALL_TRAITS_PARAM
|
||||
@@ -63,10 +72,13 @@
|
||||
|
||||
template<
|
||||
class Ret
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
|
||||
typename boost::disable_if<
|
||||
// free function if first argument is not nasal::Me or no argument at all
|
||||
boost::is_same<BOOST_PP_IF(n, A0, void), Me>,
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
|
||||
>::type
|
||||
boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A)))
|
||||
#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||
;
|
||||
@@ -74,12 +86,43 @@
|
||||
{
|
||||
return boost::bind
|
||||
(
|
||||
&callNasalFunction<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, A)>,
|
||||
ObjectHolder<SGReferenced>::makeShared(code)
|
||||
&callNasalMethod<Ret BOOST_PP_ENUM_TRAILING_PARAMS(n, A)>,
|
||||
ObjectHolder<SGReferenced>::makeShared(code),
|
||||
boost::bind(naNil)
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if n > 0
|
||||
template<
|
||||
class Ret
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
typename boost::enable_if<
|
||||
// method if type of first argument is nasal::Me
|
||||
boost::is_same<A0, Me>,
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
|
||||
>::type
|
||||
boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A)))
|
||||
#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||
;
|
||||
#else
|
||||
{
|
||||
return boost::bind
|
||||
(
|
||||
&callNasalMethod<
|
||||
Ret
|
||||
BOOST_PP_COMMA_IF(BOOST_PP_DEC(n))
|
||||
BOOST_PP_ENUM_SHIFTED_PARAMS(n, A)
|
||||
>,
|
||||
ObjectHolder<SGReferenced>::makeShared(code),
|
||||
BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef n
|
||||
#endif // SG_DONT_DO_ANYTHING
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
@@ -71,6 +74,21 @@ namespace nasal
|
||||
std::string _msg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap a naRef to indicate it references the self/me object in Nasal method
|
||||
* calls.
|
||||
*/
|
||||
struct Me
|
||||
{
|
||||
naRef _ref;
|
||||
|
||||
Me(naRef ref):
|
||||
_ref(ref)
|
||||
{}
|
||||
|
||||
operator naRef() { return _ref; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple pass through for unified handling also of naRef.
|
||||
*/
|
||||
@@ -193,7 +211,14 @@ namespace nasal
|
||||
// Helpers for wrapping calls to Nasal functions into boost::function
|
||||
namespace detail
|
||||
{
|
||||
#define BOOST_PP_ITERATION_LIMITS (0, 9)
|
||||
// Dummy include to add a build dependency on this file for gcc/CMake/etc.
|
||||
#define SG_DONT_DO_ANYTHING
|
||||
# include <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||
#undef SG_DONT_DO_ANYTHING
|
||||
|
||||
// Now the actual include (we are limited to 8 arguments (+me) here because
|
||||
// boost::bind has an upper limit of 9)
|
||||
#define BOOST_PP_ITERATION_LIMITS (0, 8)
|
||||
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||
#include BOOST_PP_ITERATE()
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
# error Nasal cppbind - do not include this file!
|
||||
#endif
|
||||
|
||||
#ifndef SG_DONT_DO_ANYTHING
|
||||
#define n BOOST_PP_ITERATION()
|
||||
|
||||
#define SG_GHOST_FUNC_TYPE\
|
||||
boost::function<Ret (raw_type& BOOST_PP_COMMA_IF(n)BOOST_PP_ENUM_PARAMS(n,A))>
|
||||
boost::function<Ret (raw_type& BOOST_PP_ENUM_TRAILING_PARAMS(n,A))>
|
||||
|
||||
/**
|
||||
* Bind any callable entity accepting an instance of raw_type and an arbitrary
|
||||
@@ -13,8 +14,7 @@
|
||||
*/
|
||||
template<
|
||||
class Ret
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
Ghost& method(const std::string& name, const SG_GHOST_FUNC_TYPE& func)
|
||||
{
|
||||
@@ -36,8 +36,7 @@
|
||||
( boost::bind(
|
||||
func,
|
||||
_1
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM(n, SG_GHOST_REQUIRE_ARG, 0)
|
||||
BOOST_PP_ENUM_TRAILING(n, SG_GHOST_REQUIRE_ARG, 0)
|
||||
))
|
||||
);
|
||||
|
||||
@@ -50,8 +49,7 @@
|
||||
*/\
|
||||
template<\
|
||||
class Ret\
|
||||
BOOST_PP_COMMA_IF(n)\
|
||||
BOOST_PP_ENUM_PARAMS(n, class A)\
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)\
|
||||
>\
|
||||
Ghost& method\
|
||||
(\
|
||||
@@ -61,8 +59,7 @@
|
||||
{\
|
||||
return method<\
|
||||
Ret\
|
||||
BOOST_PP_COMMA_IF(n)\
|
||||
BOOST_PP_ENUM_PARAMS(n,A)\
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n,A)\
|
||||
>(name, SG_GHOST_FUNC_TYPE(fn));\
|
||||
}
|
||||
|
||||
@@ -83,13 +80,12 @@
|
||||
template<
|
||||
class Ret,
|
||||
class Type
|
||||
BOOST_PP_COMMA_IF(n)
|
||||
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
Ghost& method
|
||||
(
|
||||
const std::string& name,
|
||||
Ret (*fn)(Type BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,A))
|
||||
Ret (*fn)(Type BOOST_PP_ENUM_TRAILING_PARAMS(n,A))
|
||||
)
|
||||
{
|
||||
BOOST_STATIC_ASSERT
|
||||
@@ -102,3 +98,4 @@
|
||||
|
||||
#undef n
|
||||
#undef SG_GHOST_TYPEDEF_FUNC_TYPE
|
||||
#endif // SG_DONT_DO_ANYTHING
|
||||
|
||||
Reference in New Issue
Block a user