root/trunk/lua/mixins.d

Revision 314, 12.4 kB (checked in by xammy, 3 weeks ago)

Bugfixes for LuaLib (package library, thread destruction)

Line 
1 /*******************************************************************************
2
3     copyright:      Copyright (c) 2008 Matthias Walter. All rights reserved
4
5     authors:        Matthias Walter, Andreas Hollandt
6
7 *******************************************************************************/
8
9 module lua.mixins;
10
11 public import lua.error : LuaForwardException;
12 private import lua.utils : rfind, ltrim, removeFirst, join;
13 public import lua.utils : int2string;
14 public import lua.lauxlib : luaL_error;
15 public import lua.lua : lua_State;
16
17 /*******************************************************************************
18
19     Returns the lua-mangled name of a given class.
20
21 *******************************************************************************/
22
23 public static char[] mangleClass (char[] class_name)
24 {
25     char[] result = "d_class_" ~ class_name;
26     foreach (i, c; result)
27     {
28         if (c == '.')
29             result[i] = '_';
30     }
31     return result;
32 }
33
34 /*******************************************************************************
35
36     Returns the lua-mangled name of a given function.
37
38 *******************************************************************************/
39
40 public static char[] mangleFunction (char[] function_name)
41 {
42     char[] result = "d_function_" ~ function_name;
43     foreach (i, c; result)
44     {
45         if (c == '.')
46             result[i] = '_';
47     }
48     return result;
49 }
50
51 /*******************************************************************************
52
53     Internal mixin function for registering a method. Needs a line number to
54     make the resulting wrapper function unique.
55
56     Params:
57     lua_state = Name of a LuaState variable
58     class_name = Name of the class, the methods belongs to
59     method_name = Name of the method
60     lua_name = Method-name in Lua
61     line_number = Line number used in the wrapper function name
62
63 *******************************************************************************/
64
65 public static char[] mixinLuaRegisterMethodAtLine (char[] lua_state, char[] class_name, char[] method_name, char[] lua_name, int line_number)
66 {
67     char[] wrapper = `lua_wrapper_` ~ mangleClass (class_name) ~ "_" ~ method_name ~ "_" ~ int2string (line_number);
68
69     return ``
70         ~ `{`
71         ~ `  extern (C) static int ` ~ wrapper ~ ` (lua_State *L)`
72         ~ `  {`
73         ~ `    auto state = LuaState.states[L];`
74         ~ `    try`
75         ~ `    {`
76         ~ `      void* userdata = luaL_checkudata (L, 1, "` ~ mangleClass (class_name) ~ `");` // Check, whether it's the correct userdata
77         ~ `      luaL_argcheck (L, userdata != null, 1, "class pointer expected");`
78         ~ `      lua_remove (L, 1);` // Remove the userdata
79         ~ `      return (cast (` ~class_name ~ ` *) userdata).` ~ method_name ~ ` (LuaState.states[L]);` // Call the wrapped
80         ~ `    }`
81         ~ `    catch (Exception e)`
82         ~ `    {`
83         ~ `      auto f = new LuaForwardException (state, e, "` ~ class_name ~ `.` ~ method_name ~ `", __FILE__, __LINE__);`
84         ~ `      LuaForwardException.exceptions[cast (void*) f] = f;`
85         ~ `      return luaL_error (L, lua.utils.toStringz ("LFE=" ~ lua.mixins.int2string (cast (ulong) cast(void*)  f) ~ ";"));`
86         ~ `    }`
87         ~ `  }`
88         ~ `  ` ~ lua_state ~ `.loadClassMetatable ("` ~ class_name ~ `");`
89         ~ `  ` ~ lua_state ~ `.registerMethod ("` ~ lua_name ~ `", cast (LuaCFunction) &` ~ wrapper ~ `);`
90         ~ `  ` ~ lua_state ~ `.pop ();`
91         ~ `}`;
92 }
93
94 /*******************************************************************************
95
96     Mixin function for registering a method, like in the following example:
97     ---
98     class MyClass
99     {
100         public int method (LuaState L)
101         {
102             ...
103         }
104     }
105
106     auto L = new LuaState ();
107
108     // Register the class
109     L.registerClass !(MyClass);
110     // Register the method
111     mixin (mixinLuaRegisterMethod ("L", "Module.MyClass.method", "meth"));
112
113     // Wrap a class instance and push it onto the stack
114     L.wrapClass (new MyClass ());
115     // Make it a global variable.
116     L.setGlobal ("instance");
117     // Use it in Lua
118     L.doString ("instance.meth ('abc', 1, 2);");
119     ---
120
121     Params:
122     lua_state = Name of a LuaState variable
123     class_dot_method = Fully qualified name of the class and method divided by a dot
124     lua_name = Method-name in Lua
125
126 *******************************************************************************/
127
128 public static char[] mixinLuaRegisterMethod (char[] lua_state, char[] class_dot_method, char[] lua_name)
129 {
130     int pos = rfind (class_dot_method, '.');
131     char[] class_name = class_dot_method [0 .. pos];
132     char[] method_name = class_dot_method [pos+1 .. $];
133
134     return `mixin (mixinLuaRegisterMethodAtLine ("` ~ lua_state ~ `", "` ~ class_name ~ `", "` ~ method_name ~ `", "` ~ lua_name ~ `", __LINE__));`;
135 }
136
137 /*******************************************************************************
138
139     Internal mixin function for Pushing a global D function. This is a mixin,
140     because it creates a C wrapper routine. It needs a line number to make
141     the resulting wrapper function unique.
142
143     Params:
144     lua_state = Name of a LuaState variable
145     name = Name of the D function
146     line_number = Line number used in the wrapper function name
147
148 *******************************************************************************/
149
150 public static char[] mixinLuaPushFunctionAtLine (char[] lua_state, char[] name, int line_number)
151 {
152     char[] wrapper = "lua_wrapper_" ~ mangleFunction (name) ~ "_" ~ int2string (line_number);
153
154     return ``
155         ~ `{`
156         ~ `  extern (C) static int `  ~ wrapper ~ ` (lua_State *L)`
157         ~ `  {`
158         ~ `    auto state = LuaState.states[L];`
159         ~ `    try`
160         ~ `    {`
161         ~ `      return ` ~ name ~ ` (state);`
162         ~ `    }`
163         ~ `    catch (Exception e)`
164         ~ `    {`
165         ~ `      auto f = new LuaForwardException (state, e, "` ~ name ~ `", __FILE__, __LINE__);`
166         ~ `      LuaForwardException.exceptions[cast (void*) f] = f;`
167         ~ `      return luaL_error (L, lua.utils.toStringz ("LFE=" ~ lua.mixins.int2string (cast (ulong) cast(void*)  f) ~ ";"));`
168         ~ `    }`
169         ~ `  }`
170         ~ `  ` ~ lua_state ~ `.pushCFunction (cast (int function (lua_State *L)) &` ~ wrapper ~ `);`
171         ~ `}`;
172 }
173
174 /*******************************************************************************
175
176     Mixin function for Pushing a global D function. This is a mixin, because
177     it creates a C wrapper routine. Use it like in the following example:
178     ---
179     static int func (LuaState L)
180     {
181         ...
182     }
183
184     auto L = new LuaState ();
185
186     // Push the function
187     mixin (mixinLuaPushFunction ("L", "Module.func"));
188     L.setGlobal ("myfunction");
189
190     // Use it in Lua
191     L.dotring ("myfunction ('abc', 1, 2);");
192     ---
193
194     Params:
195     lua_state = Name of a LuaState variable
196     name = Fully qualified name of the function
197
198 *******************************************************************************/
199
200 public static char[] mixinLuaPushFunction (char[] lua_state, char[] name)
201 {
202     return `mixin (mixinLuaPushFunctionAtLine ("` ~ lua_state ~ `", "` ~ name ~ `", __LINE__));` ;
203 }
204
205 /*******************************************************************************
206
207     Internal mixin function for registering a global D function. This is a
208     mixin, because it creates a C wrapper routine. It needs a line number
209     to make the resulting wrapper function unique.
210
211     Params:
212     lua_state = Name of a LuaState variable
213     name = Name of the D function
214     lua_library_dot_name = Lua module and function name seperated by a dot
215     line_number = Line number used in the wrapper function name
216
217 *******************************************************************************/
218
219 public static char[] mixinLuaRegisterFunctionAtLine (char[] lua_state, char[] name, char[] lua_library_dot_name, int line_number)
220 {
221     int pos = rfind (lua_library_dot_name, '.');
222     char[] lua_library = pos < 0 ? "null" : "\"" ~ lua_library_dot_name[0 .. pos] ~ "\"";
223     char[] lua_function = lua_library_dot_name[pos+1 .. $];
224     char[] wrapper = "lua_wrapper_" ~ mangleFunction (name) ~ "_" ~ int2string (line_number);
225
226     return ``
227         ~ `{`
228         ~ `  extern (C) static int `  ~ wrapper ~ ` (lua_State* L)`
229         ~ `  {`
230         ~ `    auto state = LuaState.states[L];`
231         ~ `    try`
232         ~ `    {`
233         ~ `      return ` ~ name ~ ` (state);`
234         ~ `    }`
235         ~ `    catch (Exception e)`
236         ~ `    {`
237         ~ `      auto f = new LuaForwardException (state, e, "` ~ name ~ `", __FILE__, __LINE__);`
238         ~ `      LuaForwardException.exceptions[cast (void*) f] = f;`
239         ~ `      return luaL_error (L, lua.utils.toStringz ("LFE=" ~ lua.mixins.int2string (cast (ulong) cast(void*)  f) ~ ";"));`
240         ~ `    }`
241         ~ `  }`
242         ~ `  ` ~ lua_state ~ `.registerFunction ("` ~ lua_function ~ `", cast (int function (lua_State* L)) &` ~ wrapper ~ `, ` ~ lua_library ~ `);`
243         ~ `}`;
244 }
245
246 /*******************************************************************************
247
248     Mixin function for registering a global D function. This is a mixin,
249     because it creates a C wrapper routine. Use it like in the following
250     example:
251     ---
252     static int func (LuaState L)
253     {
254         ...
255     }
256
257     auto L = new LuaState ();
258
259     // Push the function
260     mixin (mixinLuaRegisterFunction ("L", "Module.func", "a.b.c.myfunction));
261
262     // Use it in Lua
263     L.dotring ("a.b.c.myfunction ('abc', 1, 2);");
264     ---
265
266     Params:
267     lua_state = Name of a LuaState variable
268     name = Fully qualified name of the function
269     lua_library_dot_name = Lua module and function name seperated by a dot
270
271 *******************************************************************************/
272
273 public static char[] mixinLuaRegisterFunction (char[] lua_state, char[] name, char[] lua_library_dot_name)
274 {
275     return `mixin (mixinLuaRegisterFunctionAtLine ("` ~ lua_state ~ `", "` ~ name ~ `", "` ~ lua_library_dot_name ~ `", __LINE__));` ;
276 }
277
278 /*******************************************************************************
279
280     Internal mixin function for registering a D constructor. This is a mixin,
281     because it creates a C wrapper routine. It needs a line number to make
282     the resulting wrapper function unique.
283
284     Params:
285     lua_state = Name of a LuaState variable
286     class_name = Name of the D class
287     lua_library_dot_name = Lua module and function name seperated by a dot
288     line_number = Line number used in the wrapper function name
289
290 *******************************************************************************/
291
292 public static char[] mixinLuaRegisterConstructorAtLine (char[] lua_state, char[] class_name, char[] lua_library_dot_name, int line_number)
293 {
294     int pos = rfind (lua_library_dot_name, '.');
295     char[] lua_library = pos < 0 ? "" : "\"" ~ lua_library_dot_name[0 .. pos] ~ "\"";
296     char[] lua_function = lua_library_dot_name[pos+1 .. $];
297     char[] wrapper = "lua_wrapper_" ~ mangleClass (class_name) ~ "_ctor_" ~ int2string (line_number);
298
299     return ``
300         ~ `{`
301         ~ `  extern (C) static int ` ~ wrapper ~ ` (lua_State *L)`
302         ~ `  {`
303         ~ `    auto state = LuaState.states[L];`
304         ~ `    try`
305         ~ `    {`
306         ~ `      auto instance = new ` ~ class_name ~ ` (state);`
307         ~ `      state.wrapClass (instance);`
308         ~ `      return 1;`
309         ~ `    }`
310         ~ `    catch (Exception e)`
311         ~ `    {`
312         ~ `      auto f = new LuaForwardException (state, e, "` ~ class_name ~ `.this", __FILE__, __LINE__);`
313         ~ `      LuaForwardException.exceptions[cast (void*) f] = f;`
314         ~ `      return luaL_error (L, lua.utils.toStringz ("LFE=" ~ lua.mixins.int2string (cast (ulong) cast(void*)  f) ~ ";"));`
315         ~ `    }`
316         ~ `  }`
317         ~ `  ` ~ lua_state ~ `.registerFunction ("` ~ lua_function ~ `", cast (int function (lua_State *L)) &` ~ wrapper ~ `, ` ~ lua_library ~ `);`
318         ~ `}`;
319 }
320
321 /*******************************************************************************
322
323     Mixin function for registering a D constructor. This is a mixin,
324     because it creates a C wrapper routine. Use it like in the following
325     example:
326     ---
327     class MyClass
328     {
329         public this (LuaState L)
330         {
331             ...
332         }
333     }
334
335     auto L = new LuaState ();
336
337     // Register the class
338     L.registerClass !(MyClass);
339     // Register the method
340     mixin (mixinLuaRegisterConstructor ("L", "Module.MyClass", "mylib.createmyclass"));
341
342     // Use it in Lua
343     L.doString ("instance = mylib.createmyclass ('abc', 1, 2);");
344     ---
345
346     Params:
347     lua_state = Name of a LuaState variable
348     name = Fully qualified name of the function
349     lua_library_dot_name = Lua module and function name seperated by a dot
350
351 *******************************************************************************/
352
353 public static char[] mixinLuaRegisterConstructor (char[] lua_state, char[] class_name, char[] lua_library_dot_name)
354 {
355     return `mixin (mixinLuaRegisterConstructorAtLine ("` ~ lua_state ~ `", "` ~ class_name ~ `", "` ~ lua_library_dot_name ~ `", __LINE__));` ;
356 }
Note: See TracBrowser for help on using the browser.