Removed worthless gettable/settable metamethods.
[luabind.git] / src / function.cpp
blob99636a4abe41ed1b1f5dda0f48e0a123f1ce6be5
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)
5 #define LUABIND_SOURCE
7 #include <luabind/exception_handler.hpp>
8 #include <luabind/make_function.hpp>
10 #include <boost/bind.hpp>
12 namespace luabind { namespace detail {
14 namespace
17 struct function
19 function(
20 int arity
21 , function_callback const& call
22 , function_callback const& score
23 , function_callback const& signature
25 : m_arity(arity)
26 , m_call(call)
27 , m_score(score)
28 , m_signature(signature)
29 , m_next(0)
32 int call(lua_State*) const;
34 int m_arity;
35 function_callback m_call;
36 function_callback m_score;
37 function_callback m_signature;
38 function const* m_next;
39 object m_keep_alive;
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)
57 continue;
59 int score = f->m_score(L);
61 if (score < 0)
62 continue;
64 if (score < best_score)
66 best = f;
67 best_score = score;
68 candidate_idx = 0;
70 else if (score == best_score)
72 best = 0;
75 assert(candidate_idx < max_candidates);
76 candidates[candidate_idx++] = f;
79 if (!best)
81 if (best_score != std::numeric_limits<int>::max())
83 // Ambiguous
84 lua_pushstring(L, "Ambiguous, candidates:\n");
85 for (int i = 0; i < candidate_idx; ++i)
87 if (i != 0)
88 lua_pushstring(L, "\n");
89 candidates[i]->m_signature(L);
91 lua_concat(L, candidate_idx * 2);
93 else
95 // No overload
96 lua_pushstring(L, "No matching overload found, candidates:\n");
97 int count = 0;
98 for (function const* f = this; f != 0; f = f->m_next)
100 if (count != 0)
101 lua_pushstring(L, "\n");
102 f->m_signature(L);
103 ++count;
105 lua_concat(L, count * 2);
108 return -2;
111 return best->m_call(L);
114 int function_dispatcher(lua_State* L)
116 function const* f =
117 (function const*)lua_touserdata(L, lua_upvalueindex(1));
119 int results = -2;
121 boost::optional<int> result = handle_exceptions<int>(
122 L, boost::bind(&function::call, f, L));
124 if (result)
125 results = *result;
128 if (results == -2)
129 lua_error(L);
131 return results;
134 int function_destroy(lua_State* L)
136 function* fn = (function*)lua_touserdata(L, 1);
137 fn->~function();
138 return 0;
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))
147 return;
149 lua_pop(L, 1);
151 lua_newtable(L);
153 lua_pushstring(L, "__gc");
154 lua_pushcclosure(L, &function_destroy, 0);
155 lua_rawset(L, -3);
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;
183 context[name] = fn;
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);
199 stack_pop pop(L, 1);
201 return object(from_stack(L, -1));
204 }} // namespace luabind::detail