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()
(
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
);
}
//----------------------------------------------------------------------------
- const naRef Hash::get_naRef() const
+ naRef Hash::get_naRef() const
{
return _hash;
}
/**
* Get Nasal representation of Hash
*/
- const naRef get_naRef() const;
+ naRef get_naRef() const;
protected:
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) {}
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
//----------------------------------------------------------------------------
.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)
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) );
VERIFY( objects[1] == d2 );
VERIFY( objects[2] == d3 );
- // TODO actually do something with the ghosts...
-
//----------------------------------------------------------------------------
// Test nasal::CallContext
//----------------------------------------------------------------------------
# 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
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[] = {
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
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
;
{
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
#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>
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.
*/
// 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()
}
# 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
*/
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)
{
( 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)
))
);
*/\
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\
(\
{\
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));\
}
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
#undef n
#undef SG_GHOST_TYPEDEF_FUNC_TYPE
+#endif // SG_DONT_DO_ANYTHING