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)
4 
5 #define LUABIND_BUILDING
6 
7 #include <luabind/make_function.hpp>
8 
9 namespace luabind { namespace detail {
10 
11 namespace
12 {
13 
function_destroy(lua_State * L)14   int function_destroy(lua_State* L)
15   {
16       function_object* fn = *(function_object**)lua_touserdata(L, 1);
17       delete fn;
18       return 0;
19   }
20 
push_function_metatable(lua_State * L)21   void push_function_metatable(lua_State* L)
22   {
23       lua_pushstring(L, "luabind.function");
24       lua_rawget(L, LUA_REGISTRYINDEX);
25 
26       if (lua_istable(L, -1))
27           return;
28 
29       lua_pop(L, 1);
30 
31       lua_newtable(L);
32 
33       lua_pushstring(L, "__gc");
34       lua_pushcclosure(L, &function_destroy, 0);
35       lua_rawset(L, -3);
36 
37       lua_pushstring(L, "luabind.function");
38       lua_pushvalue(L, -2);
39       lua_rawset(L, LUA_REGISTRYINDEX);
40   }
41 
42   // A pointer to this is used as a tag value to identify functions exported
43   // by luabind.
44   int function_tag = 0;
45 
46 } // namespace unnamed
47 
is_luabind_function(lua_State * L,int index)48 LUABIND_API bool is_luabind_function(lua_State* L, int index)
49 {
50     if (!lua_getupvalue(L, index, 2))
51         return false;
52     bool result = lua_touserdata(L, -1) == &function_tag;
53     lua_pop(L, 1);
54     return result;
55 }
56 
57 namespace
58 {
59 
is_luabind_function(object const & obj)60   inline bool is_luabind_function(object const& obj)
61   {
62       obj.push(obj.interpreter());
63       bool result = detail::is_luabind_function(obj.interpreter(), -1);
64       lua_pop(obj.interpreter(), 1);
65       return result;
66   }
67 
68 } // namespace unnamed
69 
add_overload(object const & context,char const * name,object const & fn)70 LUABIND_API void add_overload(
71     object const& context, char const* name, object const& fn)
72 {
73     function_object* f = *touserdata<function_object*>(getupvalue(fn, 1));
74     f->name = name;
75 
76     if (object overloads = context[name])
77     {
78         if (is_luabind_function(overloads) && is_luabind_function(fn))
79         {
80             f->next = *touserdata<function_object*>(getupvalue(overloads, 1));
81             f->keepalive = overloads;
82         }
83     }
84 
85     context[name] = fn;
86 }
87 
make_function_aux(lua_State * L,function_object * impl)88 LUABIND_API object make_function_aux(lua_State* L, function_object* impl)
89 {
90     void* storage = lua_newuserdata(L, sizeof(function_object*));
91     push_function_metatable(L);
92     *(function_object**)storage = impl;
93     lua_setmetatable(L, -2);
94 
95     lua_pushlightuserdata(L, &function_tag);
96     lua_pushcclosure(L, impl->entry, 2);
97     stack_pop pop(L, 1);
98 
99     return object(from_stack(L, -1));
100 }
101 
format_error(lua_State * L,function_object const * overloads) const102 void invoke_context::format_error(
103     lua_State* L, function_object const* overloads) const
104 {
105     char const* function_name =
106         overloads->name.empty() ? "<unknown>" : overloads->name.c_str();
107 
108     if (candidate_index == 0)
109     {
110         lua_pushstring(L, "No matching overload found, candidates:\n");
111         int count = 0;
112         for (function_object const* f = overloads; f != 0; f = f->next)
113         {
114             if (count != 0)
115                 lua_pushstring(L, "\n");
116             f->format_signature(L, function_name);
117             ++count;
118         }
119         lua_concat(L, count * 2);
120     }
121     else
122     {
123         // Ambiguous
124         lua_pushstring(L, "Ambiguous, candidates:\n");
125         for (int i = 0; i < candidate_index; ++i)
126         {
127             if (i != 0)
128                 lua_pushstring(L, "\n");
129             candidates[i]->format_signature(L, function_name);
130         }
131         lua_concat(L, candidate_index * 2);
132     }
133 }
134 
135 }} // namespace luabind::detail
136 
137