1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | #include "config.h" |
22 | #include "runtime.h" |
23 | |
24 | // LOVE |
25 | #include "Module.h" |
26 | #include "Object.h" |
27 | #include "Reference.h" |
28 | #include "StringMap.h" |
29 | |
30 | // C++ |
31 | #include <algorithm> |
32 | #include <iostream> |
33 | #include <cstdint> |
34 | #include <cstdio> |
35 | #include <cstddef> |
36 | #include <cmath> |
37 | #include <sstream> |
38 | |
39 | // VS2013 doesn't support alignof |
40 | #if defined(_MSC_VER) && _MSC_VER <= 1800 |
41 | #define LOVE_ALIGNOF(x) __alignof(x) |
42 | #else |
43 | #define LOVE_ALIGNOF(x) alignof(x) |
44 | #endif |
45 | |
46 | namespace love |
47 | { |
48 | |
49 | /** |
50 | * Called when an object is collected. The object is released |
51 | * once in this function, possibly deleting it. |
52 | **/ |
53 | static int w__gc(lua_State *L) |
54 | { |
55 | Proxy *p = (Proxy *) lua_touserdata(L, 1); |
56 | if (p->object != nullptr) |
57 | { |
58 | p->object->release(); |
59 | p->object = nullptr; |
60 | } |
61 | return 0; |
62 | } |
63 | |
64 | static int w__tostring(lua_State *L) |
65 | { |
66 | Proxy *p = (Proxy *) lua_touserdata(L, 1); |
67 | const char *typname = lua_tostring(L, lua_upvalueindex(1)); |
68 | lua_pushfstring(L, "%s: %p" , typname, p->object); |
69 | return 1; |
70 | } |
71 | |
72 | static int w__type(lua_State *L) |
73 | { |
74 | lua_pushvalue(L, lua_upvalueindex(1)); |
75 | return 1; |
76 | } |
77 | |
78 | static int w__typeOf(lua_State *L) |
79 | { |
80 | Proxy *p = (Proxy *)lua_touserdata(L, 1); |
81 | Type *t = luax_type(L, 2); |
82 | if (!t) |
83 | luax_pushboolean(L, false); |
84 | else |
85 | luax_pushboolean(L, p->type->isa(*t)); |
86 | return 1; |
87 | } |
88 | |
89 | static int w__eq(lua_State *L) |
90 | { |
91 | Proxy *p1 = (Proxy *)lua_touserdata(L, 1); |
92 | Proxy *p2 = (Proxy *)lua_touserdata(L, 2); |
93 | luax_pushboolean(L, p1->object == p2->object && p1->object != nullptr); |
94 | return 1; |
95 | } |
96 | |
97 | typedef uint64 ObjectKey; |
98 | |
99 | static bool luax_isfulllightuserdatasupported(lua_State *L) |
100 | { |
101 | // LuaJIT prior to commit e9af1abec542e6f9851ff2368e7f196b6382a44c doesn't |
102 | // support lightuserdata > 48 bits. This is not a problem with Android, |
103 | // Windows, macOS, and iOS as they'll use updated LuaJIT or won't use |
104 | // pointers > 48 bits, but this is not the case for Linux. So check for |
105 | // this capability first! |
106 | static bool checked = false; |
107 | static bool supported = false; |
108 | |
109 | if (sizeof(void*) == 4) |
110 | // 32-bit platforms always supports full-lightuserdata. |
111 | return true; |
112 | |
113 | if (!checked) |
114 | { |
115 | lua_pushcclosure(L, [](lua_State *L) -> int |
116 | { |
117 | // Try to push pointer with all bits set. |
118 | lua_pushlightuserdata(L, (void *) (~((size_t) 0))); |
119 | return 1; |
120 | }, 0); |
121 | |
122 | supported = lua_pcall(L, 0, 1, 0) == 0; |
123 | checked = true; |
124 | |
125 | lua_pop(L, 1); |
126 | } |
127 | |
128 | return supported; |
129 | } |
130 | |
131 | // For use with the love object pointer -> Proxy pointer registry. |
132 | // Using the pointer directly via lightuserdata would be ideal, but LuaJIT |
133 | // (before a commit to 2.1 in 2020) cannot use lightuserdata with more than 47 |
134 | // bits whereas some newer arm64 architectures allow pointers which use more |
135 | // than that. |
136 | static ObjectKey luax_computeloveobjectkey(lua_State *L, love::Object *object) |
137 | { |
138 | // love objects should be allocated on the heap, and thus are subject |
139 | // to the alignment rules of operator new / malloc. Lua numbers (doubles) |
140 | // can store all possible integers up to 2^53. We can store pointers that |
141 | // use more than 53 bits if their alignment is guaranteed to be more than 1. |
142 | // For example an alignment requirement of 8 means we can shift the |
143 | // pointer's bits by 3. However, this is not always reliable on 32-bit platforms |
144 | // as can be seen in this bug report: https://github.com/love2d/love/issues/1916. |
145 | // It appears to be ABI violation. However it seems there's no reliable way to |
146 | // get the correct alignment pre-C++17. Consider that 32-bit pointer still fits |
147 | // in 2^53 range, it's perfectly fine to assume alignment of 1 there. |
148 | const size_t minalign = sizeof(void*) == 8 ? LOVE_ALIGNOF(std::max_align_t) : 1; |
149 | uintptr_t key = (uintptr_t) object; |
150 | |
151 | if ((key & (minalign - 1)) != 0) |
152 | { |
153 | luaL_error(L, "Cannot push love object to Lua: unexpected alignment " |
154 | "(pointer is %p but alignment should be %d)" , object, (int) minalign); |
155 | } |
156 | |
157 | static const size_t shift = (size_t) log2(minalign); |
158 | |
159 | key >>= shift; |
160 | |
161 | return (ObjectKey) key; |
162 | } |
163 | |
164 | static void luax_pushloveobjectkey(lua_State *L, ObjectKey key) |
165 | { |
166 | // If full 64-bit lightuserdata is supported, always use that. Otherwise, |
167 | // if the key is smaller than 2^53 (which is integer precision for double |
168 | // datatype), then push number. Otherwise, throw error. |
169 | if (luax_isfulllightuserdatasupported(L)) |
170 | lua_pushlightuserdata(L, (void *) key); |
171 | else if (key > 0x20000000000000ULL) // 2^53 |
172 | luaL_error(L, "Cannot push love object to Lua: pointer value %p is too large" , key); |
173 | else |
174 | lua_pushnumber(L, (lua_Number) key); |
175 | } |
176 | |
177 | static int w__release(lua_State *L) |
178 | { |
179 | Proxy *p = (Proxy *) lua_touserdata(L, 1); |
180 | Object *object = p->object; |
181 | |
182 | if (object != nullptr) |
183 | { |
184 | p->object = nullptr; |
185 | object->release(); |
186 | |
187 | // Fetch the registry table of instantiated objects. |
188 | luax_getregistry(L, REGISTRY_OBJECTS); |
189 | |
190 | if (lua_istable(L, -1)) |
191 | { |
192 | // loveobjects[object] = nil |
193 | ObjectKey objectkey = luax_computeloveobjectkey(L, object); |
194 | luax_pushloveobjectkey(L, objectkey); |
195 | lua_pushnil(L); |
196 | lua_settable(L, -3); |
197 | } |
198 | |
199 | lua_pop(L, 1); |
200 | } |
201 | |
202 | luax_pushboolean(L, object != nullptr); |
203 | return 1; |
204 | } |
205 | |
206 | Reference *luax_refif(lua_State *L, int type) |
207 | { |
208 | Reference *r = nullptr; |
209 | |
210 | // Create a reference only if the test succeeds. |
211 | if (lua_type(L, -1) == type) |
212 | r = new Reference(L); |
213 | else // Pop the value manually if it fails (done by Reference if it succeeds). |
214 | lua_pop(L, 1); |
215 | |
216 | return r; |
217 | } |
218 | |
219 | void luax_printstack(lua_State *L) |
220 | { |
221 | for (int i = 1; i <= lua_gettop(L); i++) |
222 | std::cout << i << " - " << luaL_typename(L, i) << std::endl; |
223 | } |
224 | |
225 | int luax_traceback(lua_State *L) |
226 | { |
227 | if (!lua_isstring(L, 1)) // 'message' not a string? |
228 | return 1; // keep it intact |
229 | |
230 | lua_getglobal(L, "debug" ); |
231 | if (!lua_istable(L, -1)) |
232 | { |
233 | lua_pop(L, 1); |
234 | return 1; |
235 | } |
236 | |
237 | lua_getfield(L, -1, "traceback" ); |
238 | if (!lua_isfunction(L, -1)) |
239 | { |
240 | lua_pop(L, 2); |
241 | return 1; |
242 | } |
243 | |
244 | lua_pushvalue(L, 1); // pass error message |
245 | lua_pushinteger(L, 2); // skip this function and traceback |
246 | lua_call(L, 2, 1); // call debug.traceback |
247 | return 1; |
248 | } |
249 | |
250 | bool luax_isarrayoftables(lua_State *L, int idx) |
251 | { |
252 | if (!lua_istable(L, idx)) |
253 | return false; |
254 | |
255 | lua_rawgeti(L, idx, 1); |
256 | bool tableoftables = lua_istable(L, -1); |
257 | lua_pop(L, 1); |
258 | return tableoftables; |
259 | } |
260 | |
261 | bool luax_toboolean(lua_State *L, int idx) |
262 | { |
263 | return (lua_toboolean(L, idx) != 0); |
264 | } |
265 | |
266 | bool luax_checkboolean(lua_State *L, int idx) |
267 | { |
268 | luaL_checktype(L, idx, LUA_TBOOLEAN); |
269 | return luax_toboolean(L, idx); |
270 | } |
271 | |
272 | void luax_pushboolean(lua_State *L, bool b) |
273 | { |
274 | lua_pushboolean(L, b ? 1 : 0); |
275 | } |
276 | |
277 | bool luax_optboolean(lua_State *L, int idx, bool b) |
278 | { |
279 | if (lua_isboolean(L, idx) == 1) |
280 | return (lua_toboolean(L, idx) == 1 ? true : false); |
281 | return b; |
282 | } |
283 | |
284 | std::string luax_tostring(lua_State *L, int idx) |
285 | { |
286 | size_t len; |
287 | const char *str = lua_tolstring(L, idx, &len); |
288 | return std::string(str, len); |
289 | } |
290 | |
291 | std::string luax_checkstring(lua_State *L, int idx) |
292 | { |
293 | size_t len; |
294 | const char *str = luaL_checklstring(L, idx, &len); |
295 | return std::string(str, len); |
296 | } |
297 | |
298 | void luax_pushstring(lua_State *L, const std::string &str) |
299 | { |
300 | lua_pushlstring(L, str.data(), str.size()); |
301 | } |
302 | |
303 | void luax_pushpointerasstring(lua_State *L, const void *pointer) |
304 | { |
305 | char str[sizeof(void *)]; |
306 | memcpy(str, &pointer, sizeof(void *)); |
307 | lua_pushlstring(L, str, sizeof(void *)); |
308 | } |
309 | |
310 | bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultValue) |
311 | { |
312 | lua_getfield(L, table_index, key); |
313 | |
314 | bool retval; |
315 | if (lua_isnoneornil(L, -1)) |
316 | retval = defaultValue; |
317 | else |
318 | retval = lua_toboolean(L, -1) != 0; |
319 | |
320 | lua_pop(L, 1); |
321 | return retval; |
322 | } |
323 | |
324 | int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue) |
325 | { |
326 | lua_getfield(L, table_index, key); |
327 | |
328 | int retval; |
329 | if (!lua_isnumber(L, -1)) |
330 | retval = defaultValue; |
331 | else |
332 | retval = (int) lua_tointeger(L, -1); |
333 | |
334 | lua_pop(L, 1); |
335 | return retval; |
336 | } |
337 | |
338 | double luax_numberflag(lua_State *L, int table_index, const char *key, double defaultValue) |
339 | { |
340 | lua_getfield(L, table_index, key); |
341 | |
342 | double retval; |
343 | if (!lua_isnumber(L, -1)) |
344 | retval = defaultValue; |
345 | else |
346 | retval = lua_tonumber(L, -1); |
347 | |
348 | lua_pop(L, 1); |
349 | return retval; |
350 | } |
351 | |
352 | int luax_checkintflag(lua_State *L, int table_index, const char *key) |
353 | { |
354 | lua_getfield(L, table_index, key); |
355 | |
356 | int retval; |
357 | if (!lua_isnumber(L, -1)) |
358 | { |
359 | std::string err = "expected integer field " + std::string(key) + " in table" ; |
360 | return luaL_argerror(L, table_index, err.c_str()); |
361 | } |
362 | else |
363 | retval = (int) luaL_checkinteger(L, -1); |
364 | lua_pop(L, 1); |
365 | |
366 | return retval; |
367 | } |
368 | |
369 | int luax_assert_argc(lua_State *L, int min) |
370 | { |
371 | int argc = lua_gettop(L); |
372 | if (argc < min) |
373 | return luaL_error(L, "Incorrect number of arguments. Got [%d], expected at least [%d]" , argc, min); |
374 | return 0; |
375 | } |
376 | |
377 | int luax_assert_argc(lua_State *L, int min, int max) |
378 | { |
379 | int argc = lua_gettop(L); |
380 | if (argc < min || argc > max) |
381 | return luaL_error(L, "Incorrect number of arguments. Got [%d], expected [%d-%d]" , argc, min, max); |
382 | return 0; |
383 | } |
384 | |
385 | int luax_assert_function(lua_State *L, int idx) |
386 | { |
387 | if (!lua_isfunction(L, idx)) |
388 | return luaL_error(L, "Argument must be of type \"function\"." ); |
389 | return 0; |
390 | } |
391 | |
392 | int luax_assert_nilerror(lua_State *L, int idx) |
393 | { |
394 | if (lua_isnoneornil(L, idx)) |
395 | { |
396 | if (lua_isstring(L, idx + 1)) |
397 | return luaL_error(L, lua_tostring(L, idx + 1)); |
398 | else |
399 | return luaL_error(L, "assertion failed!" ); |
400 | } |
401 | return 0; |
402 | } |
403 | |
404 | void luax_setfuncs(lua_State *L, const luaL_Reg *l) |
405 | { |
406 | if (l == nullptr) |
407 | return; |
408 | |
409 | for (; l->name != nullptr; l++) |
410 | { |
411 | lua_pushcfunction(L, l->func); |
412 | lua_setfield(L, -2, l->name); |
413 | } |
414 | } |
415 | |
416 | int luax_require(lua_State *L, const char *name) |
417 | { |
418 | lua_getglobal(L, "require" ); |
419 | lua_pushstring(L, name); |
420 | lua_call(L, 1, 1); |
421 | return 1; |
422 | } |
423 | |
424 | int luax_register_module(lua_State *L, const WrappedModule &m) |
425 | { |
426 | m.type->init(); |
427 | |
428 | // Put a reference to the C++ module in Lua. |
429 | luax_insistregistry(L, REGISTRY_MODULES); |
430 | |
431 | Proxy *p = (Proxy *)lua_newuserdata(L, sizeof(Proxy)); |
432 | p->object = m.module; |
433 | p->type = m.type; |
434 | |
435 | luaL_newmetatable(L, m.module->getName()); |
436 | lua_pushvalue(L, -1); |
437 | lua_setfield(L, -2, "__index" ); |
438 | lua_pushcfunction(L, w__gc); |
439 | lua_setfield(L, -2, "__gc" ); |
440 | |
441 | lua_setmetatable(L, -2); |
442 | lua_setfield(L, -2, m.name); // _modules[name] = proxy |
443 | lua_pop(L, 1); |
444 | |
445 | // Gets the love table. |
446 | luax_insistglobal(L, "love" ); |
447 | |
448 | // Create new table for module. |
449 | lua_newtable(L); |
450 | |
451 | // Register all the functions. |
452 | if (m.functions != nullptr) |
453 | luax_setfuncs(L, m.functions); |
454 | |
455 | // Register types. |
456 | if (m.types != nullptr) |
457 | { |
458 | for (const lua_CFunction *t = m.types; *t != nullptr; t++) |
459 | (*t)(L); |
460 | } |
461 | |
462 | lua_pushvalue(L, -1); |
463 | lua_setfield(L, -3, m.name); // love.graphics = table |
464 | lua_remove(L, -2); // love |
465 | |
466 | // Register module instance |
467 | Module::registerInstance(m.module); |
468 | |
469 | return 1; |
470 | } |
471 | |
472 | int luax_preload(lua_State *L, lua_CFunction f, const char *name) |
473 | { |
474 | lua_getglobal(L, "package" ); |
475 | lua_getfield(L, -1, "preload" ); |
476 | lua_pushcfunction(L, f); |
477 | lua_setfield(L, -2, name); |
478 | lua_pop(L, 2); |
479 | return 0; |
480 | } |
481 | |
482 | int luax_register_type(lua_State *L, love::Type *type, ...) |
483 | { |
484 | type->init(); |
485 | |
486 | // Get the place for storing and re-using instantiated love types. |
487 | luax_getregistry(L, REGISTRY_OBJECTS); |
488 | |
489 | // Create registry._loveobjects if it doesn't exist yet. |
490 | if (!lua_istable(L, -1)) |
491 | { |
492 | lua_newtable(L); |
493 | lua_replace(L, -2); |
494 | |
495 | // Create a metatable. |
496 | lua_newtable(L); |
497 | |
498 | // metatable.__mode = "v". Weak userdata values. |
499 | lua_pushliteral(L, "v" ); |
500 | lua_setfield(L, -2, "__mode" ); |
501 | |
502 | // setmetatable(newtable, metatable) |
503 | lua_setmetatable(L, -2); |
504 | |
505 | // registry._loveobjects = newtable |
506 | lua_setfield(L, LUA_REGISTRYINDEX, "_loveobjects" ); |
507 | } |
508 | else |
509 | lua_pop(L, 1); |
510 | |
511 | luaL_newmetatable(L, type->getName()); |
512 | |
513 | // m.__index = m |
514 | lua_pushvalue(L, -1); |
515 | lua_setfield(L, -2, "__index" ); |
516 | |
517 | // setup gc |
518 | lua_pushcfunction(L, w__gc); |
519 | lua_setfield(L, -2, "__gc" ); |
520 | |
521 | // Add equality |
522 | lua_pushcfunction(L, w__eq); |
523 | lua_setfield(L, -2, "__eq" ); |
524 | |
525 | // Add tostring function. |
526 | lua_pushstring(L, type->getName()); |
527 | lua_pushcclosure(L, w__tostring, 1); |
528 | lua_setfield(L, -2, "__tostring" ); |
529 | |
530 | // Add type |
531 | lua_pushstring(L, type->getName()); |
532 | lua_pushcclosure(L, w__type, 1); |
533 | lua_setfield(L, -2, "type" ); |
534 | |
535 | // Add typeOf |
536 | lua_pushcfunction(L, w__typeOf); |
537 | lua_setfield(L, -2, "typeOf" ); |
538 | |
539 | // Add release |
540 | lua_pushcfunction(L, w__release); |
541 | lua_setfield(L, -2, "release" ); |
542 | |
543 | va_list fs; |
544 | va_start(fs, type); |
545 | for (const luaL_Reg *f = va_arg(fs, const luaL_Reg *); f; f = va_arg(fs, const luaL_Reg *)) |
546 | luax_setfuncs(L, f); |
547 | va_end(fs); |
548 | |
549 | lua_pop(L, 1); // Pops metatable. |
550 | return 0; |
551 | } |
552 | |
553 | void luax_gettypemetatable(lua_State *L, const love::Type &type) |
554 | { |
555 | const char *name = type.getName(); |
556 | lua_getfield(L, LUA_REGISTRYINDEX, name); |
557 | } |
558 | |
559 | int luax_table_insert(lua_State *L, int tindex, int vindex, int pos) |
560 | { |
561 | if (tindex < 0) |
562 | tindex = lua_gettop(L)+1+tindex; |
563 | if (vindex < 0) |
564 | vindex = lua_gettop(L)+1+vindex; |
565 | |
566 | if (pos == -1) |
567 | { |
568 | lua_pushvalue(L, vindex); |
569 | lua_rawseti(L, tindex, (int) luax_objlen(L, tindex)+1); |
570 | return 0; |
571 | } |
572 | else if (pos < 0) |
573 | pos = (int) luax_objlen(L, tindex)+1+pos; |
574 | |
575 | for (int i = (int) luax_objlen(L, tindex)+1; i > pos; i--) |
576 | { |
577 | lua_rawgeti(L, tindex, i-1); |
578 | lua_rawseti(L, tindex, i); |
579 | } |
580 | |
581 | lua_pushvalue(L, vindex); |
582 | lua_rawseti(L, tindex, pos); |
583 | return 0; |
584 | } |
585 | |
586 | int luax_register_searcher(lua_State *L, lua_CFunction f, int pos) |
587 | { |
588 | // Add the package loader to the package.loaders table. |
589 | lua_getglobal(L, "package" ); |
590 | |
591 | if (lua_isnil(L, -1)) |
592 | return luaL_error(L, "Can't register searcher: package table does not exist." ); |
593 | |
594 | lua_getfield(L, -1, "loaders" ); |
595 | |
596 | // Lua 5.2 renamed package.loaders to package.searchers. |
597 | if (lua_isnil(L, -1)) |
598 | { |
599 | lua_pop(L, 1); |
600 | lua_getfield(L, -1, "searchers" ); |
601 | } |
602 | |
603 | if (lua_isnil(L, -1)) |
604 | return luaL_error(L, "Can't register searcher: package.loaders table does not exist." ); |
605 | |
606 | lua_pushcfunction(L, f); |
607 | luax_table_insert(L, -2, -1, pos); |
608 | lua_pop(L, 3); |
609 | return 0; |
610 | } |
611 | |
612 | void luax_rawnewtype(lua_State *L, love::Type &type, love::Object *object) |
613 | { |
614 | Proxy *u = (Proxy *)lua_newuserdata(L, sizeof(Proxy)); |
615 | |
616 | object->retain(); |
617 | |
618 | u->object = object; |
619 | u->type = &type; |
620 | |
621 | const char *name = type.getName(); |
622 | luaL_newmetatable(L, name); |
623 | |
624 | lua_getfield(L, -1, "__gc" ); |
625 | bool has_gc = !lua_isnoneornil(L, -1); |
626 | lua_pop(L, 1); |
627 | |
628 | // Make sure mt.__gc exists, so Lua states which don't have the object's |
629 | // module loaded will still clean the object up when it's collected. |
630 | if (!has_gc) |
631 | { |
632 | lua_pushcfunction(L, w__gc); |
633 | lua_setfield(L, -2, "__gc" ); |
634 | } |
635 | |
636 | lua_setmetatable(L, -2); |
637 | } |
638 | |
639 | void luax_pushtype(lua_State *L, love::Type &type, love::Object *object) |
640 | { |
641 | if (object == nullptr) |
642 | { |
643 | lua_pushnil(L); |
644 | return; |
645 | } |
646 | |
647 | // Fetch the registry table of instantiated objects. |
648 | luax_getregistry(L, REGISTRY_OBJECTS); |
649 | |
650 | // The table might not exist - it should be insisted in luax_register_type. |
651 | if (lua_isnoneornil(L, -1)) |
652 | { |
653 | lua_pop(L, 1); |
654 | return luax_rawnewtype(L, type, object); |
655 | } |
656 | |
657 | ObjectKey objectkey = luax_computeloveobjectkey(L, object); |
658 | |
659 | // Get the value of loveobjects[object] on the stack. |
660 | luax_pushloveobjectkey(L, objectkey); |
661 | lua_gettable(L, -2); |
662 | |
663 | // If the Proxy userdata isn't in the instantiated types table yet, add it. |
664 | if (lua_type(L, -1) != LUA_TUSERDATA) |
665 | { |
666 | lua_pop(L, 1); |
667 | |
668 | luax_rawnewtype(L, type, object); |
669 | |
670 | luax_pushloveobjectkey(L, objectkey); |
671 | lua_pushvalue(L, -2); |
672 | |
673 | // loveobjects[object] = Proxy. |
674 | lua_settable(L, -4); |
675 | } |
676 | |
677 | // Remove the loveobjects table from the stack. |
678 | lua_remove(L, -2); |
679 | |
680 | // Keep the Proxy userdata on the stack. |
681 | } |
682 | |
683 | bool luax_istype(lua_State *L, int idx, love::Type &type) |
684 | { |
685 | if (lua_type(L, idx) != LUA_TUSERDATA) |
686 | return false; |
687 | |
688 | Proxy *p = (Proxy *) lua_touserdata(L, idx); |
689 | |
690 | if (p->type != nullptr) |
691 | return p->type->isa(type); |
692 | else |
693 | return false; |
694 | } |
695 | |
696 | int luax_getfunction(lua_State *L, const char *mod, const char *fn) |
697 | { |
698 | lua_getglobal(L, "love" ); |
699 | if (lua_isnil(L, -1)) return luaL_error(L, "Could not find global love!" ); |
700 | lua_getfield(L, -1, mod); |
701 | if (lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s!" , mod); |
702 | lua_getfield(L, -1, fn); |
703 | if (lua_isnil(L, -1)) return luaL_error(L, "Could not find love.%s.%s!" , mod, fn); |
704 | |
705 | lua_remove(L, -2); // remove mod |
706 | lua_remove(L, -2); // remove fn |
707 | return 0; |
708 | } |
709 | |
710 | int luax_convobj(lua_State *L, int idx, const char *mod, const char *fn) |
711 | { |
712 | // Convert to absolute index if necessary. |
713 | if (idx < 0 && idx > LUA_REGISTRYINDEX) |
714 | idx += lua_gettop(L) + 1; |
715 | |
716 | // Convert string to a file. |
717 | luax_getfunction(L, mod, fn); |
718 | lua_pushvalue(L, idx); // The initial argument. |
719 | lua_call(L, 1, 2); // Call the function, one arg, one return value (plus optional errstring.) |
720 | luax_assert_nilerror(L, -2); // Make sure the function returned something. |
721 | lua_pop(L, 1); // Pop the second return value now that we don't need it. |
722 | lua_replace(L, idx); // Replace the initial argument with the new object. |
723 | return 0; |
724 | } |
725 | |
726 | int luax_convobj(lua_State *L, const int idxs[], int n, const char *mod, const char *fn) |
727 | { |
728 | luax_getfunction(L, mod, fn); |
729 | for (int i = 0; i < n; i++) |
730 | { |
731 | lua_pushvalue(L, idxs[i]); // The arguments. |
732 | } |
733 | lua_call(L, n, 2); // Call the function, n args, one return value (plus optional errstring.) |
734 | luax_assert_nilerror(L, -2); // Make sure the function returned something. |
735 | lua_pop(L, 1); // Pop the second return value now that we don't need it. |
736 | if (n > 0) |
737 | lua_replace(L, idxs[0]); // Replace the initial argument with the new object. |
738 | return 0; |
739 | } |
740 | |
741 | int luax_convobj(lua_State *L, const std::vector<int>& idxs, const char *module, const char *function) |
742 | { |
743 | const int *idxPtr = idxs.size() > 0 ? &idxs[0] : nullptr; |
744 | return luax_convobj(L, idxPtr, (int) idxs.size(), module, function); |
745 | } |
746 | |
747 | int luax_pconvobj(lua_State *L, int idx, const char *mod, const char *fn) |
748 | { |
749 | // Convert string to a file. |
750 | luax_getfunction(L, mod, fn); |
751 | lua_pushvalue(L, idx); // The initial argument. |
752 | int ret = lua_pcall(L, 1, 1, 0); // Call the function, one arg, one return value. |
753 | if (ret == 0) |
754 | lua_replace(L, idx); // Replace the initial argument with the new object. |
755 | return ret; |
756 | } |
757 | |
758 | int luax_pconvobj(lua_State *L, const int idxs[], int n, const char *mod, const char *fn) |
759 | { |
760 | luax_getfunction(L, mod, fn); |
761 | for (int i = 0; i < n; i++) |
762 | { |
763 | lua_pushvalue(L, idxs[i]); // The arguments. |
764 | } |
765 | int ret = lua_pcall(L, n, 1, 0); // Call the function, n args, one return value. |
766 | if (ret == 0) |
767 | lua_replace(L, idxs[0]); // Replace the initial argument with the new object. |
768 | return ret; |
769 | } |
770 | |
771 | int luax_pconvobj(lua_State *L, const std::vector<int>& idxs, const char *module, const char *function) |
772 | { |
773 | const int *idxPtr = idxs.size() > 0 ? &idxs[0] : nullptr; |
774 | return luax_pconvobj(L, idxPtr, (int) idxs.size(), module, function); |
775 | } |
776 | |
777 | int luax_insist(lua_State *L, int idx, const char *k) |
778 | { |
779 | // Convert to absolute index if necessary. |
780 | if (idx < 0 && idx > LUA_REGISTRYINDEX) |
781 | idx += lua_gettop(L) + 1; |
782 | |
783 | lua_getfield(L, idx, k); |
784 | |
785 | // Create if necessary. |
786 | if (!lua_istable(L, -1)) |
787 | { |
788 | lua_pop(L, 1); // Pop the non-table. |
789 | lua_newtable(L); |
790 | lua_pushvalue(L, -1); // Duplicate the table to leave on top. |
791 | lua_setfield(L, idx, k); // lua_stack[idx][k] = lua_stack[-1] (table) |
792 | } |
793 | |
794 | return 1; |
795 | } |
796 | |
797 | int luax_insistglobal(lua_State *L, const char *k) |
798 | { |
799 | lua_getglobal(L, k); |
800 | |
801 | if (!lua_istable(L, -1)) |
802 | { |
803 | lua_pop(L, 1); // Pop the non-table. |
804 | lua_newtable(L); |
805 | lua_pushvalue(L, -1); |
806 | lua_setglobal(L, k); |
807 | } |
808 | |
809 | return 1; |
810 | } |
811 | |
812 | int luax_c_insistglobal(lua_State *L, const char *k) |
813 | { |
814 | return luax_insistglobal(L, k); |
815 | } |
816 | |
817 | int luax_insistlove(lua_State *L, const char *k) |
818 | { |
819 | luax_insistglobal(L, "love" ); |
820 | luax_insist(L, -1, k); |
821 | |
822 | // The love table should be replaced with the top stack |
823 | // item. Only the reqested table should remain on the stack. |
824 | lua_replace(L, -2); |
825 | |
826 | return 1; |
827 | } |
828 | |
829 | int luax_getlove(lua_State *L, const char *k) |
830 | { |
831 | lua_getglobal(L, "love" ); |
832 | |
833 | if (!lua_isnil(L, -1)) |
834 | { |
835 | lua_getfield(L, -1, k); |
836 | lua_replace(L, -2); |
837 | } |
838 | |
839 | return 1; |
840 | } |
841 | |
842 | int luax_insistregistry(lua_State *L, Registry r) |
843 | { |
844 | switch (r) |
845 | { |
846 | case REGISTRY_MODULES: |
847 | return luax_insistlove(L, "_modules" ); |
848 | case REGISTRY_OBJECTS: |
849 | return luax_insist(L, LUA_REGISTRYINDEX, "_loveobjects" ); |
850 | default: |
851 | return luaL_error(L, "Attempted to use invalid registry." ); |
852 | } |
853 | } |
854 | |
855 | int luax_getregistry(lua_State *L, Registry r) |
856 | { |
857 | switch (r) |
858 | { |
859 | case REGISTRY_MODULES: |
860 | return luax_getlove(L, "_modules" ); |
861 | case REGISTRY_OBJECTS: |
862 | lua_getfield(L, LUA_REGISTRYINDEX, "_loveobjects" ); |
863 | return 1; |
864 | default: |
865 | return luaL_error(L, "Attempted to use invalid registry." ); |
866 | } |
867 | } |
868 | |
869 | static const char *MAIN_THREAD_KEY = "_love_mainthread" ; |
870 | |
871 | lua_State *luax_insistpinnedthread(lua_State *L) |
872 | { |
873 | lua_getfield(L, LUA_REGISTRYINDEX, MAIN_THREAD_KEY); |
874 | |
875 | if (lua_isnoneornil(L, -1)) |
876 | { |
877 | lua_pop(L, 1); |
878 | |
879 | // lua_pushthread returns 1 if it's actually the main thread, but we |
880 | // can't actually get the real main thread if lua_pushthread doesn't |
881 | // return it (in Lua 5.1 at least), so we ignore that for now... |
882 | // We do store a strong reference to the current thread/coroutine in |
883 | // the registry, however. |
884 | lua_pushthread(L); |
885 | lua_pushvalue(L, -1); |
886 | lua_setfield(L, LUA_REGISTRYINDEX, MAIN_THREAD_KEY); |
887 | } |
888 | |
889 | lua_State *thread = lua_tothread(L, -1); |
890 | lua_pop(L, 1); |
891 | return thread; |
892 | } |
893 | |
894 | lua_State *luax_getpinnedthread(lua_State *L) |
895 | { |
896 | lua_getfield(L, LUA_REGISTRYINDEX, MAIN_THREAD_KEY); |
897 | lua_State *thread = lua_tothread(L, -1); |
898 | lua_pop(L, 1); |
899 | return thread; |
900 | } |
901 | |
902 | void luax_markdeprecated(lua_State *L, const char *name, APIType api) |
903 | { |
904 | luax_markdeprecated(L, name, api, DEPRECATED_NO_REPLACEMENT, nullptr); |
905 | } |
906 | |
907 | void luax_markdeprecated(lua_State *L, const char *name, APIType api, DeprecationType type, const char *replacement) |
908 | { |
909 | MarkDeprecated deprecated(name, api, type, replacement); |
910 | |
911 | if (deprecated.info != nullptr && deprecated.info->uses == 1) |
912 | { |
913 | luaL_where(L, 1); |
914 | const char *where = lua_tostring(L, -1); |
915 | if (where != nullptr) |
916 | deprecated.info->where = where; |
917 | lua_pop(L, 1); |
918 | } |
919 | } |
920 | |
921 | extern "C" int luax_typerror(lua_State *L, int narg, const char *tname) |
922 | { |
923 | int argtype = lua_type(L, narg); |
924 | const char *argtname = nullptr; |
925 | |
926 | // We want to use the love type name for userdata, if possible. |
927 | if (argtype == LUA_TUSERDATA && luaL_getmetafield(L, narg, "type" ) != 0) |
928 | { |
929 | lua_pushvalue(L, narg); |
930 | if (lua_pcall(L, 1, 1, 0) == 0 && lua_type(L, -1) == LUA_TSTRING) |
931 | { |
932 | argtname = lua_tostring(L, -1); |
933 | |
934 | // Non-love userdata might have a type metamethod which doesn't |
935 | // describe its type properly, so we only use it for love types. |
936 | if (!Type::byName(argtname)) |
937 | argtname = nullptr; |
938 | } |
939 | } |
940 | |
941 | if (argtname == nullptr) |
942 | argtname = lua_typename(L, argtype); |
943 | |
944 | const char *msg = lua_pushfstring(L, "%s expected, got %s" , tname, argtname); |
945 | return luaL_argerror(L, narg, msg); |
946 | } |
947 | |
948 | int luax_enumerror(lua_State *L, const char *enumName, const char *value) |
949 | { |
950 | return luaL_error(L, "Invalid %s: %s" , enumName, value); |
951 | } |
952 | |
953 | int luax_enumerror(lua_State *L, const char *enumName, const std::vector<std::string> &values, const char *value) |
954 | { |
955 | std::stringstream valueStream; |
956 | bool first = true; |
957 | for (auto value : values) |
958 | { |
959 | valueStream << (first ? "'" : ", '" ) << value << "'" ; |
960 | first = false; |
961 | } |
962 | |
963 | std::string valueString = valueStream.str(); |
964 | return luaL_error(L, "Invalid %s '%s', expected one of: %s" , enumName, value, valueString.c_str()); |
965 | } |
966 | |
967 | size_t luax_objlen(lua_State *L, int ndx) |
968 | { |
969 | #if LUA_VERSION_NUM == 501 |
970 | return lua_objlen(L, ndx); |
971 | #else |
972 | return lua_rawlen(L, ndx); |
973 | #endif |
974 | } |
975 | |
976 | void luax_register(lua_State *L, const char *name, const luaL_Reg *l) |
977 | { |
978 | if (name) |
979 | lua_newtable(L); |
980 | |
981 | luax_setfuncs(L, l); |
982 | if (name) |
983 | { |
984 | lua_pushvalue(L, -1); |
985 | lua_setglobal(L, name); |
986 | } |
987 | } |
988 | |
989 | void luax_runwrapper(lua_State *L, const char *filedata, size_t datalen, const char *filename, const love::Type &type, void *ffifuncs) |
990 | { |
991 | luax_gettypemetatable(L, type); |
992 | |
993 | // Load and execute the given Lua file, sending the metatable and the ffi |
994 | // functions struct pointer as arguments. |
995 | if (lua_istable(L, -1)) |
996 | { |
997 | std::string chunkname = std::string("=[love \"" ) + std::string(filename) + std::string("\"]" ); |
998 | |
999 | luaL_loadbuffer(L, filedata, datalen, chunkname.c_str()); |
1000 | lua_pushvalue(L, -2); |
1001 | if (ffifuncs != nullptr) |
1002 | luax_pushpointerasstring(L, ffifuncs); |
1003 | else |
1004 | lua_pushnil(L); |
1005 | lua_call(L, 2, 0); |
1006 | } |
1007 | |
1008 | // Pop the metatable. |
1009 | lua_pop(L, 1); |
1010 | } |
1011 | |
1012 | Type *luax_type(lua_State *L, int idx) |
1013 | { |
1014 | return Type::byName(luaL_checkstring(L, idx)); |
1015 | } |
1016 | |
1017 | int luax_resume(lua_State *L, int nargs, int* nres) |
1018 | { |
1019 | #if LUA_VERSION_NUM >= 504 |
1020 | return lua_resume(L, nullptr, nargs, nres); |
1021 | #elif LUA_VERSION_NUM >= 502 |
1022 | LOVE_UNUSED(nres); |
1023 | return lua_resume(L, nullptr, nargs); |
1024 | #else |
1025 | LOVE_UNUSED(nres); |
1026 | return lua_resume(L, nargs); |
1027 | #endif |
1028 | } |
1029 | |
1030 | } // love |
1031 | |