lua_environment.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright (c) 2012-2018 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "config.h"
  6. #include "core/error/error.h"
  7. #include "core/memory/temp_allocator.h"
  8. #include "core/strings/string_stream.h"
  9. #include "device/device.h"
  10. #include "device/log.h"
  11. #include "lua/lua_environment.h"
  12. #include "lua/lua_stack.h"
  13. #include "resource/lua_resource.h"
  14. #include "resource/resource_manager.h"
  15. #include <stdarg.h>
  16. LOG_SYSTEM(LUA, "lua")
  17. namespace crown
  18. {
  19. extern void load_api(LuaEnvironment& env);
  20. static int luaB_print(lua_State* L)
  21. {
  22. TempAllocator2048 ta;
  23. StringStream ss(ta);
  24. int n = lua_gettop(L); /* number of arguments */
  25. lua_getglobal(L, "tostring");
  26. for (int i = 1; i <= n; ++i)
  27. {
  28. const char *s;
  29. lua_pushvalue(L, -1); /* function to be called */
  30. lua_pushvalue(L, i); /* value to print */
  31. lua_call(L, 1, 1);
  32. s = lua_tostring(L, -1); /* get result */
  33. if (s == NULL)
  34. return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print"));
  35. if (i > 1)
  36. ss << "\t";
  37. ss << s;
  38. lua_pop(L, 1); /* pop result */
  39. }
  40. logi(LUA, string_stream::c_str(ss));
  41. return 0;
  42. }
  43. LuaEnvironment::LuaEnvironment()
  44. : L(NULL)
  45. , _num_vec3(0)
  46. , _num_quat(0)
  47. , _num_mat4(0)
  48. {
  49. L = luaL_newstate();
  50. CE_ASSERT(L, "Unable to create lua state");
  51. }
  52. LuaEnvironment::~LuaEnvironment()
  53. {
  54. lua_close(L);
  55. }
  56. void LuaEnvironment::load_libs()
  57. {
  58. lua_gc(L, LUA_GCSTOP, 0);
  59. // Open default libraries
  60. luaL_openlibs(L);
  61. // Register crown libraries
  62. load_api(*this);
  63. // Override print to redirect output to logging system
  64. add_module_function("_G", "print", luaB_print);
  65. // Register custom loader
  66. lua_getfield(L, LUA_GLOBALSINDEX, "package");
  67. lua_getfield(L, -1, "loaders");
  68. lua_remove(L, -2);
  69. int num_loaders = 0;
  70. lua_pushnil(L);
  71. while (lua_next(L, -2) != 0)
  72. {
  73. lua_pop(L, 1);
  74. num_loaders++;
  75. }
  76. lua_pushinteger(L, num_loaders + 1);
  77. lua_pushcfunction(L, require);
  78. lua_rawset(L, -3);
  79. lua_pop(L, 1);
  80. // Create metatable for lightuserdata
  81. lua_pushlightuserdata(L, 0);
  82. lua_getfield(L, LUA_REGISTRYINDEX, "Lightuserdata_mt");
  83. lua_setmetatable(L, -2);
  84. lua_pop(L, 1);
  85. // Ensure stack is clean
  86. CE_ASSERT(lua_gettop(L) == 0, "Stack not clean");
  87. lua_gc(L, LUA_GCRESTART, 0);
  88. }
  89. LuaStack LuaEnvironment::execute(const LuaResource* lr)
  90. {
  91. LuaStack stack(L);
  92. lua_pushcfunction(L, LuaEnvironment::error);
  93. luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "<unknown>");
  94. lua_pcall(L, 0, 1, -2);
  95. lua_pop(L, 1);
  96. return stack;
  97. }
  98. LuaStack LuaEnvironment::execute_string(const char* s)
  99. {
  100. LuaStack stack(L);
  101. lua_pushcfunction(L, LuaEnvironment::error);
  102. luaL_loadstring(L, s);
  103. lua_pcall(L, 0, 0, -2);
  104. lua_pop(L, 1);
  105. return stack;
  106. }
  107. void LuaEnvironment::add_module_function(const char* module, const char* name, const lua_CFunction func)
  108. {
  109. luaL_Reg entry[2];
  110. entry[0].name = name;
  111. entry[0].func = func;
  112. entry[1].name = NULL;
  113. entry[1].func = NULL;
  114. luaL_register(L, module, entry);
  115. lua_pop(L, 1);
  116. }
  117. void LuaEnvironment::add_module_function(const char* module, const char* name, const char* func)
  118. {
  119. // Create module if it does not exist
  120. luaL_Reg entry;
  121. entry.name = NULL;
  122. entry.func = NULL;
  123. luaL_register(L, module, &entry);
  124. lua_pop(L, 1);
  125. lua_getglobal(L, module);
  126. lua_getglobal(L, func);
  127. lua_setfield(L, -2, name);
  128. lua_setglobal(L, module);
  129. }
  130. void LuaEnvironment::add_module_metafunction(const char* module, const char* name, const lua_CFunction func)
  131. {
  132. // Create module if it does not exist
  133. luaL_Reg entry[2];
  134. entry[0].name = NULL;
  135. entry[0].func = NULL;
  136. luaL_register(L, module, entry);
  137. lua_pop(L, 1);
  138. luaL_newmetatable(L, module);
  139. if (func)
  140. {
  141. entry[0].name = name;
  142. entry[0].func = func;
  143. entry[1].name = NULL;
  144. entry[1].func = NULL;
  145. luaL_register(L, NULL, entry);
  146. }
  147. else
  148. {
  149. lua_pushstring(L, name);
  150. lua_pushvalue(L, -2);
  151. lua_settable(L, -3);
  152. }
  153. lua_getglobal(L, module);
  154. lua_pushvalue(L, -2);
  155. lua_setmetatable(L, -2);
  156. lua_pop(L, -1);
  157. }
  158. void LuaEnvironment::call_global(const char* func, u8 argc, ...)
  159. {
  160. CE_ENSURE(NULL != func);
  161. LuaStack stack(L);
  162. va_list vl;
  163. va_start(vl, argc);
  164. lua_pushcfunction(L, LuaEnvironment::error);
  165. lua_getglobal(L, func);
  166. for (u8 i = 0; i < argc; i++)
  167. {
  168. const int type = va_arg(vl, int);
  169. switch (type)
  170. {
  171. case ARGUMENT_FLOAT:
  172. stack.push_float(f32(va_arg(vl, f64)));
  173. break;
  174. default:
  175. CE_FATAL("Unknown argument type");
  176. break;
  177. }
  178. }
  179. va_end(vl);
  180. lua_pcall(L, argc, 0, -argc - 2);
  181. lua_pop(L, -1);
  182. CE_ASSERT(lua_gettop(L) == 0, "Stack not clean");
  183. }
  184. LuaStack LuaEnvironment::get_global(const char* global)
  185. {
  186. LuaStack stack(L);
  187. lua_getglobal(L, global);
  188. return stack;
  189. }
  190. Vector3* LuaEnvironment::next_vector3(const Vector3& v)
  191. {
  192. CE_ASSERT(_num_vec3 < LUA_MAX_VECTOR3, "Maximum number of Vector3 reached");
  193. return &(_vec3[_num_vec3++] = v);
  194. }
  195. Quaternion* LuaEnvironment::next_quaternion(const Quaternion& q)
  196. {
  197. CE_ASSERT(_num_quat < LUA_MAX_QUATERNION, "Maximum number of Quaternion reached");
  198. return &(_quat[_num_quat++] = q);
  199. }
  200. Matrix4x4* LuaEnvironment::next_matrix4x4(const Matrix4x4& m)
  201. {
  202. CE_ASSERT(_num_mat4 < LUA_MAX_MATRIX4X4, "Maximum number of Matrix4x4 reached");
  203. return &(_mat4[_num_mat4++] = m);
  204. }
  205. bool LuaEnvironment::is_vector3(const Vector3* p) const
  206. {
  207. return p >= &_vec3[0]
  208. && p <= &_vec3[LUA_MAX_VECTOR3 - 1];
  209. }
  210. bool LuaEnvironment::is_quaternion(const Quaternion* p) const
  211. {
  212. return p >= &_quat[0]
  213. && p <= &_quat[LUA_MAX_QUATERNION - 1];
  214. }
  215. bool LuaEnvironment::is_matrix4x4(const Matrix4x4* p) const
  216. {
  217. return p >= &_mat4[0]
  218. && p <= &_mat4[LUA_MAX_MATRIX4X4 - 1];
  219. }
  220. void LuaEnvironment::temp_count(u32& num_vec3, u32& num_quat, u32& num_mat4)
  221. {
  222. num_vec3 = _num_vec3;
  223. num_quat = _num_quat;
  224. num_mat4 = _num_mat4;
  225. }
  226. void LuaEnvironment::set_temp_count(u32 num_vec3, u32 num_quat, u32 num_mat4)
  227. {
  228. _num_vec3 = num_vec3;
  229. _num_quat = num_quat;
  230. _num_mat4 = num_mat4;
  231. }
  232. void LuaEnvironment::reset_temporaries()
  233. {
  234. _num_vec3 = 0;
  235. _num_quat = 0;
  236. _num_mat4 = 0;
  237. }
  238. int LuaEnvironment::error(lua_State* L)
  239. {
  240. lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  241. if (!lua_istable(L, -1))
  242. {
  243. lua_pop(L, 1);
  244. return 0;
  245. }
  246. lua_getfield(L, -1, "traceback");
  247. if (!lua_isfunction(L, -1))
  248. {
  249. lua_pop(L, 2);
  250. return 0;
  251. }
  252. lua_pushvalue(L, 1); // Pass error message
  253. lua_pushinteger(L, 2);
  254. lua_call(L, 2, 1); // Call debug.traceback
  255. loge(LUA, lua_tostring(L, -1)); // Print error message
  256. lua_pop(L, 1); // Remove error message from stack
  257. lua_pop(L, 1); // Remove debug.traceback from stack
  258. device()->pause();
  259. return 0;
  260. }
  261. int LuaEnvironment::require(lua_State* L)
  262. {
  263. LuaStack stack(L);
  264. const LuaResource* lr = (LuaResource*)device()->_resource_manager->get(RESOURCE_TYPE_SCRIPT, stack.get_resource_id(1));
  265. luaL_loadbuffer(L, lua_resource::program(lr), lr->size, "");
  266. return 1;
  267. }
  268. } // namespace crown