You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
7.6KB

  1. #include "ScriptEngine.hpp"
  2. #include <luajit-2.0/lua.hpp>
  3. struct LuaJITEngine : ScriptEngine {
  4. lua_State* L = NULL;
  5. struct SafeArray {
  6. void* p;
  7. size_t len;
  8. };
  9. ~LuaJITEngine() {
  10. if (L)
  11. lua_close(L);
  12. }
  13. std::string getEngineName() override {
  14. return "Lua";
  15. }
  16. int run(const std::string& path, const std::string& script) override {
  17. ProcessBlock* block = getProcessBlock();
  18. L = luaL_newstate();
  19. if (!L) {
  20. display("Could not create LuaJIT context");
  21. return -1;
  22. }
  23. // Import a subset of the standard library
  24. luaopen_base(L);
  25. luaopen_string(L);
  26. luaopen_table(L);
  27. luaopen_math(L);
  28. luaopen_bit(L);
  29. // Set user pointer
  30. lua_pushlightuserdata(L, this);
  31. lua_setglobal(L, "_engine");
  32. // Set global functions
  33. // lua_pushcfunction(L, native_print);
  34. // lua_setglobal(L, "print");
  35. lua_pushcfunction(L, native_display);
  36. lua_setglobal(L, "display");
  37. // Set config
  38. lua_newtable(L);
  39. {
  40. // frameDivider
  41. lua_pushinteger(L, 32);
  42. lua_setfield(L, -2, "frameDivider");
  43. // bufferSize
  44. lua_pushinteger(L, 1);
  45. lua_setfield(L, -2, "bufferSize");
  46. }
  47. lua_setglobal(L, "config");
  48. // Compile script
  49. if (luaL_loadbuffer(L, script.c_str(), script.size(), path.c_str())) {
  50. const char* s = lua_tostring(L, -1);
  51. WARN("LuaJIT: %s", s);
  52. display(s);
  53. lua_pop(L, 1);
  54. return -1;
  55. }
  56. // Run script
  57. if (lua_pcall(L, 0, 0, 0)) {
  58. const char* s = lua_tostring(L, -1);
  59. WARN("LuaJIT: %s", s);
  60. display(s);
  61. lua_pop(L, 1);
  62. return -1;
  63. }
  64. // Get config
  65. lua_getglobal(L, "config");
  66. {
  67. // frameDivider
  68. lua_getfield(L, -1, "frameDivider");
  69. int frameDivider = lua_tointeger(L, -1);
  70. setFrameDivider(frameDivider);
  71. lua_pop(L, 1);
  72. // bufferSize
  73. lua_getfield(L, -1, "bufferSize");
  74. int bufferSize = lua_tointeger(L, -1);
  75. setBufferSize(bufferSize);
  76. lua_pop(L, 1);
  77. }
  78. lua_pop(L, 1);
  79. // Get process function
  80. lua_getglobal(L, "process");
  81. if (!lua_isfunction(L, -1)) {
  82. display("No process() function");
  83. return -1;
  84. }
  85. // FloatArray metatable
  86. lua_newtable(L);
  87. {
  88. // __index
  89. lua_pushcfunction(L, native_FloatArray_index);
  90. lua_setfield(L, -2, "__index");
  91. // __newindex
  92. lua_pushcfunction(L, native_FloatArray_newindex);
  93. lua_setfield(L, -2, "__newindex");
  94. // __len
  95. lua_pushcfunction(L, native_FloatArray_len);
  96. lua_setfield(L, -2, "__len");
  97. }
  98. lua_setglobal(L, "FloatArray");
  99. // BoolArray metatable
  100. lua_newtable(L);
  101. {
  102. // __index
  103. lua_pushcfunction(L, native_BoolArray_index);
  104. lua_setfield(L, -2, "__index");
  105. // __newindex
  106. lua_pushcfunction(L, native_BoolArray_newindex);
  107. lua_setfield(L, -2, "__newindex");
  108. // __len
  109. lua_pushcfunction(L, native_BoolArray_len);
  110. lua_setfield(L, -2, "__len");
  111. }
  112. lua_setglobal(L, "BoolArray");
  113. // Create block object
  114. lua_newtable(L);
  115. {
  116. // inputs
  117. lua_newtable(L);
  118. for (int i = 0; i < NUM_ROWS; i++) {
  119. SafeArray* input = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray));
  120. input->p = &block->inputs[i];
  121. input->len = block->bufferSize;
  122. lua_getglobal(L, "FloatArray");
  123. lua_setmetatable(L, -2);
  124. lua_rawseti(L, -2, i + 1);
  125. }
  126. lua_setfield(L, -2, "inputs");
  127. // outputs
  128. lua_newtable(L);
  129. for (int i = 0; i < NUM_ROWS; i++) {
  130. SafeArray* output = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray));
  131. output->p = &block->outputs[i];
  132. output->len = block->bufferSize;
  133. lua_getglobal(L, "FloatArray");
  134. lua_setmetatable(L, -2);
  135. lua_rawseti(L, -2, i + 1);
  136. }
  137. lua_setfield(L, -2, "outputs");
  138. // knobs
  139. SafeArray* knobs = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray));
  140. knobs->p = &block->knobs;
  141. knobs->len = 6;
  142. lua_getglobal(L, "FloatArray");
  143. lua_setmetatable(L, -2);
  144. lua_setfield(L, -2, "knobs");
  145. // switches
  146. SafeArray* switches = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray));
  147. switches->p = &block->switches;
  148. switches->len = 6;
  149. lua_getglobal(L, "BoolArray");
  150. lua_setmetatable(L, -2);
  151. lua_setfield(L, -2, "switches");
  152. // lights
  153. lua_newtable(L);
  154. for (int i = 0; i < NUM_ROWS; i++) {
  155. SafeArray* light = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray));
  156. light->p = &block->lights[i];
  157. light->len = 3;
  158. lua_getglobal(L, "FloatArray");
  159. lua_setmetatable(L, -2);
  160. lua_rawseti(L, -2, i + 1);
  161. }
  162. lua_setfield(L, -2, "lights");
  163. // switchLights
  164. lua_newtable(L);
  165. for (int i = 0; i < NUM_ROWS; i++) {
  166. SafeArray* switchLight = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray));
  167. switchLight->p = &block->switchLights[i];
  168. switchLight->len = 3;
  169. lua_getglobal(L, "FloatArray");
  170. lua_setmetatable(L, -2);
  171. lua_rawseti(L, -2, i + 1);
  172. }
  173. lua_setfield(L, -2, "switchLights");
  174. }
  175. return 0;
  176. }
  177. int process() override {
  178. ProcessBlock* block = getProcessBlock();
  179. // Set block
  180. {
  181. // sampleRate
  182. lua_pushnumber(L, block->sampleRate);
  183. lua_setfield(L, -2, "sampleRate");
  184. // sampleTime
  185. lua_pushnumber(L, block->sampleTime);
  186. lua_setfield(L, -2, "sampleTime");
  187. // bufferSize
  188. lua_pushinteger(L, block->bufferSize);
  189. lua_setfield(L, -2, "bufferSize");
  190. }
  191. // Duplicate process function
  192. lua_pushvalue(L, -2);
  193. // Duplicate block
  194. lua_pushvalue(L, -2);
  195. // Call process function
  196. if (lua_pcall(L, 1, 0, 0)) {
  197. const char* err = lua_tostring(L, -1);
  198. WARN("LuaJIT: %s", err);
  199. display(err);
  200. return -1;
  201. }
  202. return 0;
  203. }
  204. static LuaJITEngine* getEngine(lua_State* L) {
  205. lua_getglobal(L, "_engine");
  206. LuaJITEngine* engine = (LuaJITEngine*) lua_touserdata(L, -1);
  207. lua_pop(L, 1);
  208. return engine;
  209. }
  210. // static int native_print(lua_State* L) {
  211. // lua_getglobal(L, "tostring");
  212. // lua_pushvalue(L, 1);
  213. // lua_call(L, 1, 1);
  214. // const char* s = lua_tostring(L, 1);
  215. // INFO("LuaJIT: %s", s);
  216. // return 0;
  217. // }
  218. static int native_display(lua_State* L) {
  219. lua_getglobal(L, "tostring");
  220. lua_pushvalue(L, 1);
  221. lua_call(L, 1, 1);
  222. const char* s = lua_tostring(L, -1);
  223. if (!s)
  224. s = "(null)";
  225. getEngine(L)->display(s);
  226. return 0;
  227. }
  228. static int native_FloatArray_index(lua_State* L) {
  229. SafeArray* a = (SafeArray*) lua_touserdata(L, 1);
  230. float* data = (float*) a->p;
  231. size_t index = lua_tointeger(L, 2) - 1;
  232. if (index >= a->len) {
  233. lua_pushstring(L, "Array out of bounds");
  234. lua_error(L);
  235. }
  236. lua_pushnumber(L, data[index]);
  237. return 1;
  238. }
  239. static int native_FloatArray_newindex(lua_State* L) {
  240. SafeArray* a = (SafeArray*) lua_touserdata(L, 1);
  241. float* data = (float*) a->p;
  242. size_t index = lua_tointeger(L, 2) - 1;
  243. if (index >= a->len) {
  244. lua_pushstring(L, "Array out of bounds");
  245. lua_error(L);
  246. }
  247. data[index] = lua_tonumber(L, 3);
  248. return 0;
  249. }
  250. static int native_FloatArray_len(lua_State* L) {
  251. SafeArray* a = (SafeArray*) lua_touserdata(L, 1);
  252. lua_pushinteger(L, a->len);
  253. return 1;
  254. }
  255. static int native_BoolArray_index(lua_State* L) {
  256. SafeArray* a = (SafeArray*) lua_touserdata(L, 1);
  257. bool* data = (bool*) a->p;
  258. size_t index = lua_tointeger(L, 2) - 1;
  259. if (index >= a->len) {
  260. lua_pushstring(L, "Array out of bounds");
  261. lua_error(L);
  262. }
  263. lua_pushboolean(L, data[index]);
  264. return 1;
  265. }
  266. static int native_BoolArray_newindex(lua_State* L) {
  267. SafeArray* a = (SafeArray*) lua_touserdata(L, 1);
  268. bool* data = (bool*) a->p;
  269. size_t index = lua_tointeger(L, 2) - 1;
  270. if (index >= a->len) {
  271. lua_pushstring(L, "Array out of bounds");
  272. lua_error(L);
  273. }
  274. data[index] = lua_toboolean(L, 3);
  275. return 0;
  276. }
  277. static int native_BoolArray_len(lua_State* L) {
  278. SafeArray* a = (SafeArray*) lua_touserdata(L, 1);
  279. lua_pushinteger(L, a->len);
  280. return 1;
  281. }
  282. };
  283. __attribute__((constructor(1000)))
  284. static void constructor() {
  285. addScriptEngine<LuaJITEngine>("lua");
  286. }