root/trunk/lua/mixins.d

Revision 324, 12.5 kB (checked in by Trass3r, 3 years ago)

+ D2 compatibility!
+ precompiled lua 5.1.4
+ Exceptions support file and line arguments
* changed file encoding to UTF-8
* several bugfixes

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