1 // Copyright Daniel Wallin 2008. Use, modification and distribution is
2 // subject to the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #include <luabind/exception_handler.hpp>
8 #include <luabind/make_function.hpp>
10 #include <boost/bind.hpp>
12 namespace luabind
{ namespace detail
{
21 , function_callback
const& call
22 , function_callback
const& score
23 , function_callback
const& signature
28 , m_signature(signature
)
32 int call(lua_State
*) const;
35 function_callback m_call
;
36 function_callback m_score
;
37 function_callback m_signature
;
38 function
const* m_next
;
42 int const max_candidates
= 10;
44 int function::call(lua_State
* L
) const
46 function
const* candidates
[max_candidates
];
47 int candidate_idx
= 0;
49 function
const* best
= 0;
50 int best_score
= std::numeric_limits
<int>::max();
52 int args
= lua_gettop(L
);
54 for (function
const* f
= this; f
!= 0; f
= f
->m_next
)
56 if (args
!= f
->m_arity
)
59 int score
= f
->m_score(L
);
64 if (score
< best_score
)
70 else if (score
== best_score
)
75 assert(candidate_idx
< max_candidates
);
76 candidates
[candidate_idx
++] = f
;
81 if (best_score
!= std::numeric_limits
<int>::max())
84 lua_pushstring(L
, "Ambiguous, candidates:\n");
85 for (int i
= 0; i
< candidate_idx
; ++i
)
88 lua_pushstring(L
, "\n");
89 candidates
[i
]->m_signature(L
);
91 lua_concat(L
, candidate_idx
* 2);
96 lua_pushstring(L
, "No matching overload found, candidates:\n");
98 for (function
const* f
= this; f
!= 0; f
= f
->m_next
)
101 lua_pushstring(L
, "\n");
105 lua_concat(L
, count
* 2);
111 return best
->m_call(L
);
114 int function_dispatcher(lua_State
* L
)
117 (function
const*)lua_touserdata(L
, lua_upvalueindex(1));
121 boost::optional
<int> result
= handle_exceptions
<int>(
122 L
, boost::bind(&function::call
, f
, L
));
134 int function_destroy(lua_State
* L
)
136 function
* fn
= (function
*)lua_touserdata(L
, 1);
141 void push_function_metatable(lua_State
* L
)
143 lua_pushstring(L
, "luabind.function");
144 lua_rawget(L
, LUA_REGISTRYINDEX
);
146 if (lua_istable(L
, -1))
153 lua_pushstring(L
, "__gc");
154 lua_pushcclosure(L
, &function_destroy
, 0);
157 lua_pushstring(L
, "luabind.function");
158 lua_pushvalue(L
, -2);
159 lua_rawset(L
, LUA_REGISTRYINDEX
);
162 } // namespace unnamed
164 LUABIND_API
bool is_luabind_function(lua_State
* L
, int index
)
166 return lua_tocfunction(L
, index
) == &function_dispatcher
;
169 LUABIND_API
void add_overload(
170 object
const& context
, char const* name
, object
const& fn
)
172 if (object overloads
= context
[name
])
174 if (tocfunction(overloads
) == &function_dispatcher
175 && tocfunction(fn
) == &function_dispatcher
)
177 function
* f
= touserdata
<function
>(getupvalue(fn
, 1));
178 f
->m_next
= touserdata
<function
>(getupvalue(overloads
, 1));
179 f
->m_keep_alive
= overloads
;
186 LUABIND_API object
make_function_aux(
187 lua_State
* L
, int arity
188 , function_callback
const& call
189 , function_callback
const& score
190 , function_callback
const& signature
193 void* storage
= lua_newuserdata(L
, sizeof(function
));
194 push_function_metatable(L
);
195 new (storage
) function(arity
, call
, score
, signature
);
196 lua_setmetatable(L
, -2);
198 lua_pushcclosure(L
, &function_dispatcher
, 1);
201 return object(from_stack(L
, -1));
204 }} // namespace luabind::detail