679425fae516435e1f64d601b2bd9a627a327274
[project/luci.git] / contrib / package / ucode-mod-lua / src / lua.c
1 /*
2 * Copyright (C) 2022 Jo-Philipp Wich <jo@mein.io>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <lua.h>
18 #include <lauxlib.h>
19 #include <lualib.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <math.h>
23 #include <dlfcn.h>
24
25 #include "ucode/module.h"
26
27 static uc_resource_type_t *vm_type, *lv_type;
28
29
30 typedef struct {
31 uc_vm_t *vm;
32 uc_value_t *uv;
33 } ucv_userdata_t;
34
35 typedef struct {
36 uc_value_t *uvL;
37 int ref;
38 } lua_resource_t;
39
40 static int
41 lua_uv_gc(lua_State *L)
42 {
43 ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value");
44
45 ucv_put(ud->uv);
46 ud->uv = NULL;
47
48 return 0;
49 }
50
51 static lua_Integer
52 lua_table_is_arraylike(lua_State *L, int index)
53 {
54 lua_Integer max = 0, count = 0;
55 lua_Number k;
56
57 lua_pushnil(L);
58
59 /* check for non-integer keys */
60 while (lua_next(L, index)) {
61 if (lua_type(L, -2) == LUA_TNUMBER && (k = lua_tonumber(L, -2)) >= 1) {
62 if (floor(k) == k) {
63 if (k > max)
64 max = k;
65
66 count++;
67
68 lua_pop(L, 1);
69
70 continue;
71 }
72 }
73
74 lua_pop(L, 2);
75
76 return -1;
77 }
78
79 if (max > count * 2)
80 return -1;
81
82 return max;
83 }
84
85 static bool
86 lua_table_new_or_ref(lua_State *L, struct lh_table *visited, uc_value_t *uv)
87 {
88 struct lh_entry *entry;
89 unsigned long hash;
90
91 hash = lh_get_hash(visited, uv);
92 entry = lh_table_lookup_entry_w_hash(visited, uv, hash);
93
94 if (!entry) {
95 lua_newtable(L);
96 lua_pushvalue(L, -1);
97 lh_table_insert_w_hash(visited, uv,
98 (void *)(intptr_t)luaL_ref(L, LUA_REGISTRYINDEX), hash, 0);
99
100 return true;
101 }
102
103 lua_rawgeti(L, LUA_REGISTRYINDEX, (int)(intptr_t)entry->v);
104
105 return false;
106 }
107
108 static void
109 ucv_to_lua(uc_vm_t *vm, uc_value_t *uv, lua_State *L, struct lh_table *visited);
110
111 static void
112 ucv_to_lua(uc_vm_t *vm, uc_value_t *uv, lua_State *L, struct lh_table *visited)
113 {
114 struct lh_entry *entry;
115 bool freetbl = false;
116 lua_resource_t **lv;
117 ucv_userdata_t *ud;
118 lua_State **lvL;
119 uc_value_t *e;
120 size_t i;
121 char *s;
122
123 switch (ucv_type(uv)) {
124 case UC_BOOLEAN:
125 lua_pushboolean(L, ucv_boolean_get(uv));
126 break;
127
128 case UC_STRING:
129 lua_pushlstring(L, ucv_string_get(uv), ucv_string_length(uv));
130 break;
131
132 case UC_DOUBLE:
133 lua_pushnumber(L, (lua_Number)ucv_double_get(uv));
134 break;
135
136 case UC_INTEGER:
137 #ifdef LUA_TINT
138 lua_pushinteger(L, (lua_Integer)ucv_int64_get(uv));
139 #else
140 lua_pushnumber(L, (lua_Number)ucv_int64_get(uv));
141 #endif
142 break;
143
144 case UC_REGEXP:
145 s = ucv_to_string(vm, uv);
146
147 if (s)
148 lua_pushstring(L, s);
149 else
150 lua_pushnil(L);
151
152 free(s);
153
154 break;
155
156 case UC_ARRAY:
157 case UC_OBJECT:
158 if (!visited) {
159 freetbl = true;
160 visited = lh_kptr_table_new(16, NULL);
161 }
162
163 if (visited) {
164 if (lua_table_new_or_ref(L, visited, uv)) {
165 if (ucv_type(uv) == UC_ARRAY) {
166 for (i = 0; i < ucv_array_length(uv); i++) {
167 e = ucv_array_get(uv, i);
168 ucv_to_lua(vm, e, L, visited);
169 lua_rawseti(L, -2, (int)i + 1);
170 }
171 }
172 else {
173 ucv_object_foreach(uv, key, val) {
174 ucv_to_lua(vm, val, L, visited);
175 lua_setfield(L, -2, key);
176 }
177 }
178 }
179 }
180 else {
181 lua_pushnil(L);
182 }
183
184 break;
185
186 case UC_CFUNCTION:
187 case UC_CLOSURE:
188 ud = lua_newuserdata(L, sizeof(*ud));
189
190 if (ud) {
191 ud->vm = vm;
192 ud->uv = ucv_get(uv);
193
194 luaL_getmetatable(L, "ucode.value");
195 lua_setmetatable(L, -2);
196 }
197 else {
198 lua_pushnil(L);
199 }
200
201 break;
202
203 case UC_RESOURCE:
204 lv = (lua_resource_t **)ucv_resource_dataptr(uv, "lua.value");
205 lvL = (lv && *lv) ? (lua_State **)ucv_resource_dataptr((*lv)->uvL, "lua.vm") : NULL;
206
207 if (lvL && *lvL == L)
208 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
209 else
210 lua_pushnil(L);
211
212 break;
213
214 default:
215 lua_pushnil(L);
216 break;
217 }
218
219 if (freetbl) {
220 lh_foreach(visited, entry)
221 luaL_unref(L, LUA_REGISTRYINDEX, (int)(intptr_t)entry->v);
222
223 lh_table_free(visited);
224 }
225 }
226
227 static uc_value_t *
228 ucv_table_new_or_ref(lua_State *L, int index, uc_vm_t *vm, struct lh_table *visited, lua_Integer *nkeys)
229 {
230 struct lh_entry *entry;
231 unsigned long hash;
232 const void *tptr;
233 uc_value_t *uv;
234
235 tptr = lua_topointer(L, index);
236 hash = lh_get_hash(visited, tptr);
237 entry = lh_table_lookup_entry_w_hash(visited, tptr, hash);
238
239 if (!entry) {
240 *nkeys = lua_table_is_arraylike(L, index);
241 uv = (*nkeys > 0) ? ucv_array_new(vm) : ucv_object_new(vm);
242 lh_table_insert_w_hash(visited, tptr, uv, hash, 0);
243
244 return uv;
245 }
246
247 *nkeys = -2;
248 uv = (uc_value_t *)entry->v;
249
250 return ucv_get(uv);
251 }
252
253 static uc_value_t *
254 ucv_this_to_uvL(uc_vm_t *vm)
255 {
256 uc_value_t *ctx = uc_vector_last(&vm->callframes)->ctx;
257 void *p;
258
259 p = ucv_resource_dataptr(ctx, "lua.vm");
260
261 if (p)
262 return ucv_get(ctx);
263
264 p = ucv_resource_dataptr(ctx, "lua.value");
265
266 if (p)
267 return ucv_get((*(lua_resource_t **)p)->uvL);
268
269 return NULL;
270 }
271
272 static uc_value_t *
273 lua_to_ucv(lua_State *L, int index, uc_vm_t *vm, struct lh_table *visited);
274
275 static uc_value_t *
276 lua_to_ucv(lua_State *L, int index, uc_vm_t *vm, struct lh_table *visited)
277 {
278 bool freetbl = false;
279 lua_Integer nkeys, i;
280 lua_resource_t *lv;
281 ucv_userdata_t *ud;
282 const char *key;
283 uc_value_t *rv;
284 size_t len;
285
286 switch (lua_type(L, index)) {
287 case LUA_TNIL:
288 rv = NULL;
289 break;
290
291 case LUA_TTABLE:
292 if (!visited) {
293 freetbl = true;
294 visited = lh_kptr_table_new(16, NULL);
295 }
296
297 rv = ucv_table_new_or_ref(L, index, vm, visited, &nkeys);
298
299 if (nkeys > 0) {
300 for (i = 1; i <= nkeys; i++) {
301 lua_rawgeti(L, index, i);
302 ucv_array_push(rv, lua_to_ucv(L, lua_gettop(L), vm, visited));
303 lua_pop(L, 1);
304 }
305 }
306 else if (nkeys == -1) {
307 lua_pushnil(L);
308
309 while (lua_next(L, index)) {
310 lua_pushvalue(L, -2);
311 key = lua_tostring(L, -1);
312
313 if (key)
314 ucv_object_add(rv, key, lua_to_ucv(L, lua_gettop(L) - 1, vm, visited));
315
316 lua_pop(L, 2);
317 }
318 }
319
320 if (freetbl)
321 lh_table_free(visited);
322
323 break;
324
325 case LUA_TBOOLEAN:
326 rv = ucv_boolean_new(lua_toboolean(L, index));
327 break;
328
329 case LUA_TNUMBER:
330 #ifdef LUA_TINT
331 if (lua_isinteger(L, index))
332 rv = ucv_int64_new(lua_tointeger(L, index));
333 else
334 rv = ucv_double_new(lua_tonumber(L, index));
335 #else
336 lua_Number n = lua_tonumber(L, index);
337 i = lua_tointeger(L, index);
338
339 if ((lua_Number)i == n)
340 rv = ucv_int64_new(i);
341 else
342 rv = ucv_double_new(n);
343 #endif
344
345 break;
346
347 case LUA_TSTRING:
348 key = lua_tolstring(L, index, &len);
349 rv = ucv_string_new_length(key, len);
350 break;
351
352 case LUA_TUSERDATA:
353 rv = NULL;
354
355 if (lua_getmetatable(L, index)) {
356 luaL_getmetatable(L, "ucode.value");
357
358 if (lua_rawequal(L, -1, -2)) {
359 ud = lua_touserdata(L, index);
360 rv = (ud->vm == vm) ? ucv_get(ud->uv) : NULL;
361 }
362
363 lua_pop(L, 2);
364 }
365
366 if (rv)
367 break;
368
369 /* fall through */
370
371 default:
372 lua_pushvalue(L, index);
373
374 lv = xalloc(sizeof(*lv));
375 lv->ref = luaL_ref(L, LUA_REGISTRYINDEX);
376 lv->uvL = ucv_this_to_uvL(vm);
377
378 rv = uc_resource_new(lv_type, lv);
379 break;
380 }
381
382 return rv;
383 }
384
385 static const char *
386 uc_exception_type_name(uc_exception_type_t type)
387 {
388 switch (type) {
389 case EXCEPTION_SYNTAX: return "Syntax error";
390 case EXCEPTION_RUNTIME: return "Runtime error";
391 case EXCEPTION_TYPE: return "Type error";
392 case EXCEPTION_REFERENCE: return "Reference error";
393 case EXCEPTION_EXIT: return "Exit";
394 default: return "Exception";
395 }
396 }
397
398 static int
399 lua_uv_call(lua_State *L)
400 {
401 ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value");
402 int nargs = lua_gettop(L), i;
403 uc_value_t *rv;
404
405 if (!ucv_is_callable(ud->uv))
406 return luaL_error(L, "%s: Invoked value is not a function",
407 uc_exception_type_name(EXCEPTION_TYPE));
408
409 uc_vm_stack_push(ud->vm, ucv_get(ud->uv));
410
411 for (i = 2; i <= nargs; i++)
412 uc_vm_stack_push(ud->vm, lua_to_ucv(L, i, ud->vm, NULL));
413
414 if (uc_vm_call(ud->vm, false, nargs - 1)) {
415 rv = ucv_object_get(ucv_array_get(ud->vm->exception.stacktrace, 0), "context", NULL);
416
417 return luaL_error(L, "%s: %s%s%s",
418 uc_exception_type_name(ud->vm->exception.type),
419 ud->vm->exception.message,
420 rv ? "\n" : "", rv ? ucv_string_get(rv) : "");
421 }
422
423 rv = uc_vm_stack_pop(ud->vm);
424
425 ucv_to_lua(ud->vm, rv, L, NULL);
426 ucv_put(rv);
427
428 return 1;
429 }
430
431 static int
432 lua_uv_tostring(lua_State *L)
433 {
434 ucv_userdata_t *ud = luaL_checkudata(L, 1, "ucode.value");
435 char *s = ucv_to_string(ud->vm, ud->uv);
436
437 lua_pushstring(L, s);
438 free(s);
439
440 return 1;
441 }
442
443 static const luaL_reg ucode_ud_methods[] = {
444 { "__gc", lua_uv_gc },
445 { "__call", lua_uv_call },
446 { "__tostring", lua_uv_tostring },
447
448 { }
449 };
450
451 static uc_value_t *
452 uc_lua_vm_claim_result(uc_vm_t *vm, lua_State *L, int oldtop)
453 {
454 int nargs = lua_gettop(L) - oldtop, i;
455 uc_value_t *uv;
456
457 if (nargs > 1) {
458 uv = ucv_array_new_length(vm, nargs);
459
460 for (i = 1; i <= nargs; i++)
461 ucv_array_push(uv, lua_to_ucv(L, oldtop + i, vm, NULL));
462 }
463 else if (nargs == 1) {
464 uv = lua_to_ucv(L, oldtop + 1, vm, NULL);
465 }
466 else {
467 uv = NULL;
468 }
469
470 return uv;
471 }
472
473 static uc_value_t *
474 uc_lua_vm_pcall(uc_vm_t *vm, lua_State *L, int oldtop)
475 {
476 uc_value_t *uv;
477
478 switch (lua_pcall(L, lua_gettop(L) - oldtop - 1, LUA_MULTRET, 0)) {
479 case LUA_ERRRUN:
480 case LUA_ERRMEM:
481 case LUA_ERRERR:
482 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
483 "Lua raised runtime exception: %s",
484 lua_tostring(L, -1));
485
486 uv = NULL;
487 break;
488
489 default:
490 uv = uc_lua_vm_claim_result(vm, L, oldtop);
491 break;
492 }
493
494 return uv;
495 }
496
497 static uc_value_t *
498 uc_lua_vm_invoke(uc_vm_t *vm, size_t nargs)
499 {
500 lua_State **L = uc_fn_this("lua.vm");
501 uc_value_t *name = uc_fn_arg(0);
502 uc_value_t *uv;
503 size_t i;
504 int top;
505
506 if (!L || !*L || ucv_type(name) != UC_STRING)
507 return NULL;
508
509 top = lua_gettop(*L);
510
511 lua_getglobal(*L, ucv_string_get(name));
512
513 for (i = 1; i < nargs; i++) {
514 uv = uc_fn_arg(i);
515 ucv_to_lua(vm, uv, *L, NULL);
516 }
517
518 uv = uc_lua_vm_pcall(vm, *L, top);
519
520 lua_settop(*L, top);
521
522 return uv;
523 }
524
525 static uc_value_t *
526 uc_lua_vm_eval(uc_vm_t *vm, size_t nargs)
527 {
528 lua_State **L = uc_fn_this("lua.vm");
529 uc_value_t *source = uc_fn_arg(0);
530 uc_value_t *uv = NULL;
531 int top;
532
533 if (!L || !*L || ucv_type(source) != UC_STRING)
534 return NULL;
535
536 top = lua_gettop(*L);
537
538 switch (luaL_loadstring(*L, ucv_string_get(source))) {
539 case LUA_ERRSYNTAX:
540 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
541 "Syntax error while compiling Lua code: %s",
542 lua_tostring(*L, -1));
543
544 break;
545
546 case LUA_ERRMEM:
547 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
548 "Out of memory while compiling Lua code: %s",
549 lua_tostring(*L, -1));
550
551 break;
552
553 default:
554 uv = uc_lua_vm_pcall(vm, *L, top);
555 break;
556 }
557
558 lua_settop(*L, top);
559
560 return uv;
561 }
562
563 static uc_value_t *
564 uc_lua_vm_include(uc_vm_t *vm, size_t nargs)
565 {
566 lua_State **L = uc_fn_this("lua.vm");
567 uc_value_t *path = uc_fn_arg(0);
568 uc_value_t *uv = NULL;
569 int top;
570
571 if (!L || !*L || ucv_type(path) != UC_STRING)
572 return NULL;
573
574 top = lua_gettop(*L);
575
576 switch (luaL_loadfile(*L, ucv_string_get(path))) {
577 case LUA_ERRSYNTAX:
578 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
579 "Syntax error while compiling Lua file: %s",
580 lua_tostring(*L, -1));
581
582 break;
583
584 case LUA_ERRFILE:
585 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
586 "IO error while compiling Lua file: %s",
587 lua_tostring(*L, -1));
588
589 break;
590
591 case LUA_ERRMEM:
592 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
593 "Out of memory while compiling Lua file: %s",
594 lua_tostring(*L, -1));
595
596 break;
597
598 default:
599 uv = uc_lua_vm_pcall(vm, *L, top);
600 break;
601 }
602
603 lua_settop(*L, top);
604
605 return uv;
606 }
607
608 static uc_value_t *
609 uc_lua_vm_set(uc_vm_t *vm, size_t nargs)
610 {
611 lua_State **L = uc_fn_this("lua.vm");
612 uc_value_t *key = uc_fn_arg(0);
613 uc_value_t *val = uc_fn_arg(1);
614
615 if (!L || !*L)
616 return NULL;
617
618 if (ucv_type(key) == UC_OBJECT && !val) {
619 ucv_object_foreach(key, k, v) {
620 ucv_to_lua(vm, v, *L, NULL);
621 lua_setglobal(*L, k);
622 }
623 }
624 else if (ucv_type(key) == UC_STRING) {
625 ucv_to_lua(vm, val, *L, NULL);
626 lua_setglobal(*L, ucv_string_get(key));
627 }
628 else {
629 return NULL;
630 }
631
632 return ucv_boolean_new(true);
633 }
634
635 static uc_value_t *
636 uc_lua_vm_get(uc_vm_t *vm, size_t nargs)
637 {
638 lua_State **L = uc_fn_this("lua.vm");
639 uc_value_t *key = uc_fn_arg(0);
640 lua_resource_t *lv;
641 size_t i;
642
643 if (!L || !*L || ucv_type(key) != UC_STRING)
644 return NULL;
645
646 lua_getglobal(*L, ucv_string_get(key));
647
648 for (i = 1; i < nargs; i++) {
649 ucv_to_lua(vm, uc_fn_arg(i), *L, NULL);
650 lua_gettable(*L, -2);
651 }
652
653 lv = xalloc(sizeof(*lv));
654 lv->ref = luaL_ref(*L, LUA_REGISTRYINDEX);
655 lv->uvL = ucv_this_to_uvL(vm);
656
657 if (nargs > 1)
658 lua_pop(*L, nargs - 1);
659
660 return uc_resource_new(lv_type, lv);
661 }
662
663
664 static lua_State *
665 uc_lua_lv_to_L(lua_resource_t **lv)
666 {
667 lua_State **L;
668
669 if (!lv || !*lv)
670 return NULL;
671
672 L = (lua_State **)ucv_resource_dataptr((*lv)->uvL, "lua.vm");
673
674 if (!L)
675 return NULL;
676
677 return *L;
678 }
679
680 static uc_value_t *
681 uc_lua_lv_call(uc_vm_t *vm, size_t nargs)
682 {
683 lua_resource_t **lv = uc_fn_this("lua.value");
684 lua_State *L = uc_lua_lv_to_L(lv);
685 uc_value_t *rv;
686 int oldtop;
687 size_t i;
688
689 if (!L)
690 return NULL;
691
692 oldtop = lua_gettop(L);
693
694 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
695
696 for (i = 0; i < nargs; i++)
697 ucv_to_lua(vm, uc_fn_arg(i), L, NULL);
698
699 rv = uc_lua_vm_pcall(vm, L, oldtop);
700
701 lua_settop(L, oldtop);
702
703 return rv;
704 }
705
706 static uc_value_t *
707 uc_lua_lv_invoke(uc_vm_t *vm, size_t nargs)
708 {
709 lua_resource_t **lv = uc_fn_this("lua.value");
710 lua_State *L = uc_lua_lv_to_L(lv);
711 uc_value_t *method = uc_fn_arg(0);
712 uc_value_t *rv;
713 int oldtop;
714 size_t i;
715
716 if (!L)
717 return NULL;
718
719 oldtop = lua_gettop(L);
720
721 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
722 ucv_to_lua(vm, method, L, NULL);
723 lua_gettable(L, -2);
724 lua_pushvalue(L, -2);
725
726 for (i = 1; i < nargs; i++)
727 ucv_to_lua(vm, uc_fn_arg(i), L, NULL);
728
729 rv = uc_lua_vm_pcall(vm, L, oldtop + 1);
730
731 lua_settop(L, oldtop);
732
733 return rv;
734 }
735
736 static uc_value_t *
737 uc_lua_lv_get_common(uc_vm_t *vm, size_t nargs, bool raw)
738 {
739 lua_resource_t **lv = uc_fn_this("lua.value"), *ref;
740 lua_State *L = uc_lua_lv_to_L(lv);
741 uc_value_t *key;
742 size_t i;
743
744 if (!L)
745 return NULL;
746
747 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
748
749 for (i = 0; i < nargs; i++) {
750 key = uc_fn_arg(i);
751
752 if (raw) {
753 if (ucv_type(key) == UC_INTEGER) {
754 lua_rawgeti(L, -1, (int)ucv_int64_get(key));
755 }
756 else {
757 ucv_to_lua(vm, key, L, NULL);
758 lua_rawget(L, -2);
759 }
760 }
761 else {
762 ucv_to_lua(vm, key, L, NULL);
763 lua_gettable(L, -2);
764 }
765 }
766
767 ref = xalloc(sizeof(*ref));
768 ref->ref = luaL_ref(L, LUA_REGISTRYINDEX);
769 ref->uvL = ucv_this_to_uvL(vm);
770
771 lua_pop(L, nargs);
772
773 return uc_resource_new(lv_type, ref);
774 }
775
776 static uc_value_t *
777 uc_lua_lv_get(uc_vm_t *vm, size_t nargs)
778 {
779 return uc_lua_lv_get_common(vm, nargs, false);
780 }
781
782 static uc_value_t *
783 uc_lua_lv_getraw(uc_vm_t *vm, size_t nargs)
784 {
785 return uc_lua_lv_get_common(vm, nargs, true);
786 }
787
788 static uc_value_t *
789 uc_lua_lv_getmt(uc_vm_t *vm, size_t nargs)
790 {
791 lua_resource_t **lv = uc_fn_this("lua.value"), *ref;
792 uc_value_t *key = uc_fn_arg(0), *uv = NULL;
793 lua_State *L = uc_lua_lv_to_L(lv);
794 int oldtop;
795
796 if (!L || (key && ucv_type(key) != UC_STRING))
797 return NULL;
798
799 oldtop = lua_gettop(L);
800
801 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
802
803 if (lua_getmetatable(L, -1)) {
804 if (key)
805 lua_getfield(L, -1, ucv_string_get(key));
806
807 if (!lua_isnil(L, -1)) {
808 ref = xalloc(sizeof(*ref));
809 ref->ref = luaL_ref(L, LUA_REGISTRYINDEX);
810 ref->uvL = ucv_this_to_uvL(vm);
811
812 uv = uc_resource_new(lv_type, ref);
813 }
814 }
815
816 lua_settop(L, oldtop);
817
818 return uv;
819 }
820
821 static uc_value_t *
822 uc_lua_lv_value(uc_vm_t *vm, size_t nargs)
823 {
824 lua_resource_t **lv = uc_fn_this("lua.value");
825 lua_State *L = uc_lua_lv_to_L(lv);
826 uc_value_t *uv;
827
828 if (!L)
829 return NULL;
830
831 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
832
833 uv = lua_to_ucv(L, lua_gettop(L), vm, NULL);
834
835 lua_pop(L, 1);
836
837 return uv;
838 }
839
840 static uc_value_t *
841 uc_lua_lv_tostring(uc_vm_t *vm, size_t nargs)
842 {
843 lua_resource_t **lv = uc_fn_this("lua.value");
844 lua_State *L = uc_lua_lv_to_L(lv);
845 uc_value_t *uv = NULL;
846 uc_stringbuf_t *buf;
847 const char *s;
848 size_t len;
849
850 if (!L)
851 return NULL;
852
853 lua_rawgeti(L, LUA_REGISTRYINDEX, (*lv)->ref);
854
855 if (luaL_callmeta(L, -1, "__tostring")) {
856 if (lua_isstring(L, -1)) {
857 s = lua_tolstring(L, -1, &len);
858 uv = ucv_string_new_length(s, len);
859 lua_pop(L, 2);
860
861 return uv;
862 }
863
864 lua_pop(L, 1);
865 }
866
867 buf = ucv_stringbuf_new();
868
869 switch (lua_type(L, lua_gettop(L))) {
870 case LUA_TNIL:
871 case LUA_TTABLE:
872 case LUA_TBOOLEAN:
873 case LUA_TNUMBER:
874 case LUA_TSTRING:
875 uv = lua_to_ucv(L, lua_gettop(L), vm, NULL);
876 ucv_to_stringbuf(vm, buf, uv, false);
877 ucv_put(uv);
878 break;
879
880 default:
881 ucv_stringbuf_printf(buf, "%s (%p)",
882 lua_typename(L, lua_type(L, lua_gettop(L))),
883 lua_topointer(L, lua_gettop(L)));
884 break;
885 }
886
887 lua_pop(L, 1);
888
889 return ucv_stringbuf_finish(buf);
890 }
891
892
893 static uc_value_t *
894 uc_lua_create(uc_vm_t *vm, size_t nargs)
895 {
896 lua_State *L = luaL_newstate();
897
898 luaL_openlibs(L);
899
900 luaL_newmetatable(L, "ucode.value");
901 luaL_register(L, NULL, ucode_ud_methods);
902 lua_pushvalue(L, -1);
903 lua_setfield(L, -2, "__index");
904 lua_pop(L, 1);
905
906 return uc_resource_new(vm_type, L);
907 }
908
909
910 static const uc_function_list_t vm_fns[] = {
911 { "invoke", uc_lua_vm_invoke },
912 { "eval", uc_lua_vm_eval },
913 { "include", uc_lua_vm_include },
914 { "set", uc_lua_vm_set },
915 { "get", uc_lua_vm_get },
916 };
917
918 static const uc_function_list_t lv_fns[] = {
919 { "call", uc_lua_lv_call },
920 { "invoke", uc_lua_lv_invoke },
921 { "get", uc_lua_lv_get },
922 { "getraw", uc_lua_lv_getraw },
923 { "getmt", uc_lua_lv_getmt },
924 { "value", uc_lua_lv_value },
925 { "tostring", uc_lua_lv_tostring },
926 };
927
928 static const uc_function_list_t lua_fns[] = {
929 { "create", uc_lua_create },
930 };
931
932 static void
933 free_vm(void *ud)
934 {
935 lua_State *L = ud;
936
937 if (L)
938 lua_close(L);
939 }
940
941 static void
942 free_lv(void *ud)
943 {
944 lua_resource_t *lv = ud;
945 lua_State **L = (lua_State **)ucv_resource_dataptr(lv->uvL, "lua.vm");
946
947 luaL_unref(*L, LUA_REGISTRYINDEX, lv->ref);
948 ucv_put(lv->uvL);
949 free(lv);
950 }
951
952 static void
953 dlopen_self(uc_vm_t *vm)
954 {
955 uc_value_t *search, *entry;
956 char *path, *wildcard;
957 void *dlh = NULL;
958 size_t i;
959
960 search = ucv_property_get(uc_vm_scope_get(vm), "REQUIRE_SEARCH_PATH");
961
962 for (i = 0; !dlh && i < ucv_array_length(search); i++) {
963 entry = ucv_array_get(search, i);
964 path = ucv_string_get(entry);
965 wildcard = path ? strchr(path, '*') : NULL;
966
967 if (wildcard) {
968 xasprintf(&path, "%.*slua%s", (int)(wildcard - path), path, wildcard + 1);
969 dlh = dlopen(path, RTLD_LAZY|RTLD_GLOBAL);
970 dlerror(); /* clear error */
971 free(path);
972 }
973 }
974 }
975
976 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
977 {
978 uc_function_list_register(scope, lua_fns);
979
980 vm_type = uc_type_declare(vm, "lua.vm", vm_fns, free_vm);
981 lv_type = uc_type_declare(vm, "lua.value", lv_fns, free_lv);
982
983 /* reopen ourself using dlopen(RTLD_GLOBAL) to make liblua symbols
984 * available to dynamic Lua extensions loaded by this module through
985 * Lua's require() */
986 dlopen_self(vm);
987 }