1
0
forked from 0ad/0ad

Employ some variadic macros to make some of the C++ -> JS function calling code nicer.

Template-ize CallFunctionVoid.
Changes CallFunction parameter order to make template parameter
deduction with
variadic parameters work nicely.

Reviewed By: Itms, wraitii, Yves
Differential Revision: https://code.wildfiregames.com/D77
This was SVN commit r19183.
This commit is contained in:
leper 2017-01-28 23:37:15 +00:00
parent fd5bd8e301
commit 6ae2db53db
11 changed files with 158 additions and 258 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -347,7 +347,7 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev)
JSContext* cx = top()->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, top()->GetGlobalObject());
if (top()->GetScriptInterface()->CallFunction(global, "handleInputBeforeGui", *ev, top()->FindObjectUnderMouse(), handled))
if (top()->GetScriptInterface()->CallFunction(global, "handleInputBeforeGui", handled, *ev, top()->FindObjectUnderMouse()))
if (handled)
return IN_HANDLED;
}
@ -366,7 +366,7 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev)
JS::RootedValue global(cx, top()->GetGlobalObject());
PROFILE("handleInputAfterGui");
if (top()->GetScriptInterface()->CallFunction(global, "handleInputAfterGui", *ev, handled))
if (top()->GetScriptInterface()->CallFunction(global, "handleInputAfterGui", handled, *ev))
if (handled)
return IN_HANDLED;
}

View File

@ -30,10 +30,6 @@ template <typename T> struct MaybeRef;
#define NUMBERED_LIST_TAIL_MAYBE_REF(z, i, data) , typename MaybeRef<data##i>::Type
#define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i
#define NUMBERED_LIST_BALANCED_MAYBE_REF(z, i, data) BOOST_PP_COMMA_IF(i) typename MaybeRef<data##i>::Type
// Some other things
#define TYPED_ARGS(z, i, data) , T##i a##i
#define TYPED_ARGS_MAYBE_REF(z, i, data) , typename MaybeRef<T##i>::Type a##i
#define TYPED_ARGS_CONST_REF(z, i, data) , const T##i& a##i
// TODO: We allow optional parameters when the C++ type can be converted from JS::UndefinedValue.
// FromJSVal is expected to either set a##i or return false (otherwise we could get undefined
@ -54,23 +50,17 @@ template <typename T> struct MaybeRef;
// List-generating macros, named roughly after their first list item
#define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T) // "typename T0, typename T1, "
#define TYPENAME_T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, typename T) // ", typename T0, typename T1"
#define T0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, T) // "T0, T1"
#define T0_MAYBE_REF(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED_MAYBE_REF, T) // "const T0&, T1"
#define T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, T) // "T0, T1, "
#define T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, T) // ", T0, T1"
#define T0_TAIL_MAYBE_REF(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL_MAYBE_REF, T) // ", const T0&, T1"
#define T0_A0(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS, ~) // ",T0 a0, T1 a1"
#define T0_A0_MAYBE_REF(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS_MAYBE_REF, ~) // ",const T0& a0, T1 a1"
#define T0_A0_TAIL_CONST_REF(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS_CONST_REF, ~) // ", const T0& a0, const T1& a1"
#define A0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, a) // "a0, a1"
#define A0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, a) // ", a0, a1"
// Define RegisterFunction<TR, T0..., f>
#define OVERLOADS(z, i, data) \
template <typename R, TYPENAME_T0_HEAD(z,i) R (*fptr) ( ScriptInterface::CxPrivate* T0_TAIL_MAYBE_REF(z,i) )> \
void RegisterFunction(const char* name) { \
Register(name, call<R, T0_HEAD(z,i) fptr>, nargs<0 T0_TAIL(z,i)>()); \
Register(name, call<R T0_TAIL(z,i), fptr>, nargs<T0(z,i)>()); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
@ -98,33 +88,24 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
// Argument-number counter
#define OVERLOADS(z, i, data) \
template <int dummy TYPENAME_T0_TAIL(z,i)> /* add a dummy parameter so we still compile with 0 template args */ \
static size_t nargs() { return i; }
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
template<typename... Ts>
static size_t nargs() { return sizeof...(Ts); }
// Call the named property on the given object
#define OVERLOADS(z, i, data) \
template <typename R TYPENAME_T0_TAIL(z, i)> \
bool CallFunction(JS::HandleValue val, const char* name T0_A0_TAIL_CONST_REF(z,i), R& ret) const;
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
template<typename R, typename... Ts>
bool CallFunction(JS::HandleValue val, const char* name, R& ret, const Ts&... params) const;
// Implicit conversion from JS::Rooted<R>* to JS::MutableHandle<R> does not work with template argument deduction
// (only exact type matches allowed). We need this overload to allow passing Rooted<R>* using the & operator
// (as people would expect it to work based on the SpiderMonkey rooting guide).
#define OVERLOADS(z, i, data) \
template <typename R TYPENAME_T0_TAIL(z, i)> \
bool CallFunction(JS::HandleValue val, const char* name T0_A0_TAIL_CONST_REF(z,i), JS::Rooted<R>* ret) const;
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
template<typename R, typename... Ts>
bool CallFunction(JS::HandleValue val, const char* name, JS::Rooted<R>* ret, const Ts&... params) const;
// This overload is for the case when a JS::MutableHandle<R> type gets passed into CallFunction directly and
// without requiring implicit conversion.
#define OVERLOADS(z, i, data) \
template <typename R TYPENAME_T0_TAIL(z, i)> \
bool CallFunction(JS::HandleValue val, const char* name T0_A0_TAIL_CONST_REF(z,i), JS::MutableHandle<R> ret) const;
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
template<typename R, typename... Ts>
bool CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle<R> ret, const Ts&... params) const;
// Call the named property on the given object, with void return type
template<typename... Ts> \
bool CallFunctionVoid(JS::HandleValue val, const char* name, const Ts&... params) const;

View File

@ -57,10 +57,8 @@ PASS_BY_VALUE_IN_NATIVE_WRAPPER(double)
// remove them from here and check if this causes error C2244 when compiling.
#undef NUMBERED_LIST_TAIL_MAYBE_REF
#undef NUMBERED_LIST_BALANCED_MAYBE_REF
#undef TYPED_ARGS_MAYBE_REF
#define NUMBERED_LIST_TAIL_MAYBE_REF(z, i, data) , typename ScriptInterface::MaybeRef<data##i>::Type
#define NUMBERED_LIST_BALANCED_MAYBE_REF(z, i, data) BOOST_PP_COMMA_IF(i) typename ScriptInterface::MaybeRef<data##i>::Type
#define TYPED_ARGS_MAYBE_REF(z, i, data) , typename ScriptInterface::MaybeRef<T##i>::Type a##i
// (NativeWrapperDecls.h set up a lot of the macros we use here)
@ -69,52 +67,46 @@ PASS_BY_VALUE_IN_NATIVE_WRAPPER(double)
// Templated on the return type so void can be handled separately
template <typename R>
struct ScriptInterface_NativeWrapper {
#define OVERLOADS(z, i, data) \
template<TYPENAME_T0_HEAD(z,i) typename F> \
static void call(JSContext* cx, JS::MutableHandleValue rval, F fptr T0_A0_MAYBE_REF(z,i)) { \
ScriptInterface::AssignOrToJSValUnrooted<R>(cx, rval, fptr(ScriptInterface::GetScriptInterfaceAndCBData(cx) A0_TAIL(z,i))); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
struct ScriptInterface_NativeWrapper
{
template<typename F, typename... Ts>
static void call(JSContext* cx, JS::MutableHandleValue rval, F fptr, Ts... params)
{
ScriptInterface::AssignOrToJSValUnrooted<R>(cx, rval, fptr(ScriptInterface::GetScriptInterfaceAndCBData(cx), params...));
}
};
// Overloaded to ignore the return value from void functions
template <>
struct ScriptInterface_NativeWrapper<void> {
#define OVERLOADS(z, i, data) \
template<TYPENAME_T0_HEAD(z,i) typename F> \
static void call(JSContext* cx, JS::MutableHandleValue /*rval*/, F fptr T0_A0_MAYBE_REF(z,i)) { \
fptr(ScriptInterface::GetScriptInterfaceAndCBData(cx) A0_TAIL(z,i)); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
struct ScriptInterface_NativeWrapper<void>
{
template<typename F, typename... Ts>
static void call(JSContext* cx, JS::MutableHandleValue UNUSED(rval), F fptr, Ts... params)
{
fptr(ScriptInterface::GetScriptInterfaceAndCBData(cx), params...);
}
};
// Same idea but for method calls:
template <typename R, typename TC>
struct ScriptInterface_NativeMethodWrapper {
#define OVERLOADS(z, i, data) \
template<TYPENAME_T0_HEAD(z,i) typename F> \
static void call(JSContext* cx, JS::MutableHandleValue rval, TC* c, F fptr T0_A0_MAYBE_REF(z,i)) { \
ScriptInterface::AssignOrToJSValUnrooted<R>(cx, rval, (c->*fptr)( A0(z,i) )); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
struct ScriptInterface_NativeMethodWrapper
{
template<typename F, typename... Ts>
static void call(JSContext* cx, JS::MutableHandleValue rval, TC* c, F fptr, Ts... params)
{
ScriptInterface::AssignOrToJSValUnrooted<R>(cx, rval, (c->*fptr)(params...));
}
};
template <typename TC>
struct ScriptInterface_NativeMethodWrapper<void, TC> {
#define OVERLOADS(z, i, data) \
template<TYPENAME_T0_HEAD(z,i) typename F> \
static void call(JSContext* /*cx*/, JS::MutableHandleValue /*rval*/, TC* c, F fptr T0_A0_MAYBE_REF(z,i)) { \
(c->*fptr)( A0(z,i) ); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
struct ScriptInterface_NativeMethodWrapper<void, TC>
{
template<typename F, typename... Ts>
static void call(JSContext* UNUSED(cx), JS::MutableHandleValue UNUSED(rval), TC* c, F fptr, Ts... params)
{
(c->*fptr)(params...);
}
};
// JSFastNative-compatible function that wraps the function identified in the template argument list
@ -126,7 +118,7 @@ struct ScriptInterface_NativeMethodWrapper<void, TC> {
JSAutoRequest rq(cx); \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
JS::RootedValue rval(cx); \
ScriptInterface_NativeWrapper<R>::template call<T0_HEAD(z,i) R( ScriptInterface::CxPrivate* T0_TAIL_MAYBE_REF(z,i))>(cx, &rval, fptr A0_TAIL(z,i)); \
ScriptInterface_NativeWrapper<R>::template call<R( ScriptInterface::CxPrivate* T0_TAIL_MAYBE_REF(z,i)) T0_TAIL(z,i)>(cx, &rval, fptr A0_TAIL(z,i)); \
args.rval().set(rval); \
return !ScriptInterface::IsExceptionPending(cx); \
}
@ -146,7 +138,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
if (! c) return false; \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
JS::RootedValue rval(cx); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<T0_HEAD(z,i) R (TC::*)(T0_MAYBE_REF(z,i))>(cx, &rval, c, fptr A0_TAIL(z,i)); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<R (TC::*)(T0_MAYBE_REF(z,i)) T0_TAIL(z,i)>(cx, &rval, c, fptr A0_TAIL(z,i)); \
args.rval().set(rval); \
return !ScriptInterface::IsExceptionPending(cx); \
}
@ -166,65 +158,77 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
if (! c) return false; \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
JS::RootedValue rval(cx); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<T0_HEAD(z,i) R (TC::*)(T0_MAYBE_REF(z,i)) const>(cx, &rval, c, fptr A0_TAIL(z,i)); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<R (TC::*)(T0_MAYBE_REF(z,i)) const T0_TAIL(z,i)>(cx, &rval, c, fptr A0_TAIL(z,i)); \
args.rval().set(rval); \
return !ScriptInterface::IsExceptionPending(cx); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
#define ASSIGN_OR_TO_JS_VAL(z, i, data) AssignOrToJSVal(cx, argv[i], a##i);
#define OVERLOADS(z, i, data) \
template<typename R TYPENAME_T0_TAIL(z, i)> \
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name T0_A0_TAIL_CONST_REF(z,i), R& ret) const \
{ \
JSContext* cx = GetContext(); \
JSAutoRequest rq(cx); \
JS::RootedValue jsRet(cx); \
JS::AutoValueVector argv(cx); \
argv.resize(i); \
BOOST_PP_REPEAT_##z (i, ASSIGN_OR_TO_JS_VAL, ~) \
bool ok = CallFunction_(val, name, argv, &jsRet); \
if (!ok) \
return false; \
return FromJSVal(cx, jsRet, ret); \
template<int i, typename T, typename... Ts>
static void AssignOrToJSValHelper(JSContext* cx, JS::AutoValueVector& argv, const T& a, const Ts&... params)
{
ScriptInterface::AssignOrToJSVal(cx, argv[i], a);
AssignOrToJSValHelper<i+1>(cx, argv, params...);
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
#define OVERLOADS(z, i, data) \
template<typename R TYPENAME_T0_TAIL(z, i)> \
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name T0_A0_TAIL_CONST_REF(z,i), JS::Rooted<R>* ret) const \
{ \
JSContext* cx = GetContext(); \
JSAutoRequest rq(cx); \
JS::MutableHandle<R> jsRet(ret); \
JS::AutoValueVector argv(cx); \
argv.resize(i); \
BOOST_PP_REPEAT_##z (i, ASSIGN_OR_TO_JS_VAL, ~) \
return CallFunction_(val, name, argv, jsRet); \
template<int i, typename... Ts>
static void AssignOrToJSValHelper(JSContext* UNUSED(cx), JS::AutoValueVector& UNUSED(argv))
{
cassert(sizeof...(Ts) == 0);
// Nop, for terminating the template recursion.
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
#define OVERLOADS(z, i, data) \
template<typename R TYPENAME_T0_TAIL(z, i)> \
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name T0_A0_TAIL_CONST_REF(z,i), JS::MutableHandle<R> ret) const \
{ \
JSContext* cx = GetContext(); \
JSAutoRequest rq(cx); \
JS::AutoValueVector argv(cx); \
argv.resize(i); \
BOOST_PP_REPEAT_##z (i, ASSIGN_OR_TO_JS_VAL, ~) \
bool ok = CallFunction_(val, name, argv, ret); \
if (!ok) \
return false; \
return true; \
template<typename R, typename... Ts>
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, R& ret, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
bool ok = CallFunction_(val, name, argv, &jsRet);
if (!ok)
return false;
return FromJSVal(cx, jsRet, ret);
}
template<typename R, typename... Ts>
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Rooted<R>* ret, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::MutableHandle<R> jsRet(ret);
JS::AutoValueVector argv(cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
return CallFunction_(val, name, argv, jsRet);
}
template<typename R, typename... Ts>
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle<R> ret, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::AutoValueVector argv(cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
return CallFunction_(val, name, argv, ret);
}
// Call the named property on the given object, with void return type
template<typename... Ts>
bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
return CallFunction_(val, name, argv, &jsRet);
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
#undef ASSIGN_OR_TO_JS_VAL
// Clean up our mess
#undef NUMBERED_LIST_HEAD
@ -232,19 +236,10 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef NUMBERED_LIST_TAIL_MAYBE_REF
#undef NUMBERED_LIST_BALANCED
#undef NUMBERED_LIST_BALANCED_MAYBE_REF
#undef TYPED_ARGS
#undef TYPED_ARGS_MAYBE_REF
#undef TYPED_ARGS_CONST_REF
#undef CONVERT_ARG
#undef TYPENAME_T0_HEAD
#undef TYPENAME_T0_TAIL
#undef T0
#undef T0_MAYBE_REF
#undef T0_HEAD
#undef T0_TAIL
#undef T0_TAIL_MAYBE_REF
#undef T0_A0
#undef T0_A0_MAYBE_REF
#undef T0_A0_TAIL_CONST_REF
#undef A0
#undef A0_TAIL

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -562,14 +562,6 @@ JSObject* ScriptInterface::CreateCustomObject(const std::string& typeName) const
return JS_NewObjectWithGivenProto(m->m_cx, it->second.m_Class, prototype);
}
bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name)
{
JSAutoRequest rq(m->m_cx);
JS::RootedValue jsRet(m->m_cx);
return CallFunction_(val, name, JS::HandleValueArray::empty(), &jsRet);
}
bool ScriptInterface::CallFunction_(JS::HandleValue val, const char* name, JS::HandleValueArray argv, JS::MutableHandleValue ret) const
{
JSAutoRequest rq(m->m_cx);

View File

@ -131,29 +131,6 @@ public:
*/
void CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out);
/**
* Call the named property on the given object, with void return type and 0 arguments
*/
bool CallFunctionVoid(JS::HandleValue val, const char* name);
/**
* Call the named property on the given object, with void return type and 1 argument
*/
template<typename T0>
bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0);
/**
* Call the named property on the given object, with void return type and 2 arguments
*/
template<typename T0, typename T1>
bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1);
/**
* Call the named property on the given object, with void return type and 3 arguments
*/
template<typename T0, typename T1, typename T2>
bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1, const T2& a2);
JSObject* CreateCustomObject(const std::string & typeName) const;
void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
@ -443,8 +420,20 @@ public:
// template <R, T0..., JSClass*, TC, TR (TC:*fptr) const (T0...)>
// static JSNative callMethodConst;
//
// template <dummy, T0...>
// template <T0...>
// static size_t nargs();
//
// template <R, T0...>
// bool CallFunction(JS::HandleValue val, const char* name, R& ret, const T0&...) const;
//
// template <R, T0...>
// bool CallFunction(JS::HandleValue val, const char* name, JS::Rooted<R>* ret, const T0&...) const;
//
// template <R, T0...>
// bool CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle<R> ret, const T0&...) const;
//
// template <T0...>
// bool CallFunctionVoid(JS::HandleValue val, const char* name, const T0&...) const;
};
// Implement those declared functions
@ -495,45 +484,6 @@ inline JS::HandleValue ScriptInterface::AssignOrFromJSVal<JS::HandleValue>(JSCon
return val;
}
template<typename T0>
bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
argv.resize(1);
AssignOrToJSVal(cx, argv[0], a0);
return CallFunction_(val, name, argv, &jsRet);
}
template<typename T0, typename T1>
bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
argv.resize(2);
AssignOrToJSVal(cx, argv[0], a0);
AssignOrToJSVal(cx, argv[1], a1);
return CallFunction_(val, name, argv, &jsRet);
}
template<typename T0, typename T1, typename T2>
bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const T0& a0, const T1& a1, const T2& a2)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
argv.resize(3);
AssignOrToJSVal(cx, argv[0], a0);
AssignOrToJSVal(cx, argv[1], a1);
AssignOrToJSVal(cx, argv[2], a2);
return CallFunction_(val, name, argv, &jsRet);
}
template<typename T>
bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace)
{

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -45,7 +45,7 @@ class TestScriptConversions : public CxxTest::TestSuite
// since they might not be objects. So just use uneval.
std::string source;
JS::RootedValue global(cx, script.GetGlobalObject());
TS_ASSERT(script.CallFunction(global, "uneval", v1, source));
TS_ASSERT(script.CallFunction(global, "uneval", source, v1));
TS_ASSERT_STR_EQUALS(source, expected);
}
@ -63,7 +63,7 @@ class TestScriptConversions : public CxxTest::TestSuite
std::string source;
JS::RootedValue global(cx, script.GetGlobalObject());
TS_ASSERT(script.CallFunction(global, "uneval", v1, source));
TS_ASSERT(script.CallFunction(global, "uneval", source, v1));
if (expected)
TS_ASSERT_STR_EQUALS(source, expected);
@ -89,12 +89,12 @@ class TestScriptConversions : public CxxTest::TestSuite
T r;
JS::RootedValue r1(cx);
TS_ASSERT(script.CallFunction(u1, func.c_str(), v1, r));
TS_ASSERT(script.CallFunction(u1, func.c_str(), r, v1));
ScriptInterface::ToJSVal(cx, &r1, r);
std::string source;
JS::RootedValue global(cx, script.GetGlobalObject());
TS_ASSERT(script.CallFunction(global, "uneval", r1, source));
TS_ASSERT(script.CallFunction(global, "uneval", source, r1));
TS_ASSERT_STR_EQUALS(source, expected);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -170,7 +170,7 @@ public:
TS_ASSERT_EQUALS(4, nbr);
// CallFunction const JS::RootedValue& parameter overload
script.CallFunction(val, "add", nbrVal, nbr);
script.CallFunction(val, "add", nbr, nbrVal);
TS_ASSERT_EQUALS(7, nbr);
// GetProperty JS::RootedValue* overload
@ -202,7 +202,7 @@ public:
TS_ASSERT_EQUALS(4, nbr);
// CallFunction const JS::HandleValue& parameter overload
script.CallFunction(val, "add", nbrVal, nbr);
script.CallFunction(val, "add", nbr, nbrVal);
TS_ASSERT_EQUALS(7, nbr);
// GetProperty JS::MutableHandleValue overload

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -32,11 +32,11 @@ public:
virtual void GetRepresentation(JS::MutableHandleValue ret)
{
return m_Script.CallRef("GetRepresentation", ret);
m_Script.CallRef("GetRepresentation", ret);
}
virtual void GetFullRepresentation(JS::MutableHandleValue ret, bool flushEvents = false)
{
return m_Script.CallRef("GetFullRepresentation",flushEvents, ret);
m_Script.CallRef("GetFullRepresentation", ret, flushEvents);
}
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2012 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -32,7 +32,7 @@ public:
virtual void GetAllTechs(JS::MutableHandleValue ret)
{
return m_Script.CallRef("GetAllTechs", ret);
m_Script.CallRef("GetAllTechs", ret);
}
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -32,7 +32,7 @@ public:
virtual void ScriptCall(int player, const std::wstring& cmd, JS::HandleValue data, JS::MutableHandleValue ret)
{
m_Script.CallRef("ScriptCall", player, cmd, data, ret);
m_Script.CallRef("ScriptCall", ret, player, cmd, data);
}
};

View File

@ -22,10 +22,6 @@
#include "ps/CLogger.h"
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
class CSimContext;
class CParamNode;
class ISerializer;
@ -33,6 +29,7 @@ class IDeserializer;
class CComponentTypeScript
{
NONCOPYABLE(CComponentTypeScript);
public:
CComponentTypeScript(ScriptInterface& scriptInterface, JS::HandleValue instance);
@ -45,43 +42,30 @@ public:
void Serialize(ISerializer& serialize);
void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize, entity_id_t ent);
// Use Boost.PP to define:
// template<typename R> R Call(const char* funcname) const;
// template<typename R, typename T0> R Call(const char* funcname, const T0& a0) const;
// ...
// template<typename R> void CallRef(const char* funcname, R ret) const;
// template<typename R, typename T0> void CallRef(const char* funcname, const T0& a0, R ret) const;
// ...
// void CallVoid(const char* funcname) const;
// template<typename T0> void CallVoid(const char* funcname, const T0& a0) const;
// ...
// CallRef is mainly used for returning script values with correct stack rooting.
#define OVERLOADS(z, i, data) \
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(i, typename T)> \
R Call(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) const \
{ \
R ret; \
if (m_ScriptInterface.CallFunction(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
return ret; \
LOGERROR("Error calling component script function %s", funcname); \
return R(); \
} \
template<typename R BOOST_PP_ENUM_TRAILING_PARAMS(i, typename T)> \
void CallRef(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a), R ret) const \
{ \
if (!m_ScriptInterface.CallFunction(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
LOGERROR("Error calling component script function %s", funcname); \
} \
BOOST_PP_IF(i, template<, ) BOOST_PP_ENUM_PARAMS(i, typename T) BOOST_PP_IF(i, >, ) \
void CallVoid(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) const \
{ \
if (m_ScriptInterface.CallFunctionVoid(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \
return; \
LOGERROR("Error calling component script function %s", funcname); \
template<typename R, typename... Ts>
R Call(const char* funcname, const Ts&... params) const
{
R ret;
if (m_ScriptInterface.CallFunction(m_Instance, funcname, ret, params...))
return ret;
LOGERROR("Error calling component script function %s", funcname);
return R();
}
// CallRef is mainly used for returning script values with correct stack rooting.
template<typename R, typename... Ts>
void CallRef(const char* funcname, R ret, const Ts&... params) const
{
if (!m_ScriptInterface.CallFunction(m_Instance, funcname, ret, params...))
LOGERROR("Error calling component script function %s", funcname);
}
template<typename... Ts>
void CallVoid(const char* funcname, const Ts&... params) const
{
if (!m_ScriptInterface.CallFunctionVoid(m_Instance, funcname, params...))
LOGERROR("Error calling component script function %s", funcname);
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
private:
ScriptInterface& m_ScriptInterface;
@ -89,8 +73,6 @@ private:
bool m_HasCustomSerialize;
bool m_HasCustomDeserialize;
bool m_HasNullSerialize;
NONCOPYABLE(CComponentTypeScript);
};
#endif // INCLUDED_SCRIPTCOMPONENT