From 832f652a5abbb6c8a6bb4fa38adb84edfd7b5e22 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 3 Apr 2014 16:01:01 +0100 Subject: [PATCH] Elua: initial commit Elua is a LuaJIT based runtime for the EFL meant to provide facilities for rapid application development. The name is temporary. The EFL bindings will be generated with Eolian. @feature --- configure.ac | 46 +++++ src/Makefile.am | 5 +- src/Makefile_Elua.am | 22 +++ src/bin/elua/cache.c | 192 +++++++++++++++++++ src/bin/elua/elm.lua | 129 +++++++++++++ src/bin/elua/main.c | 328 +++++++++++++++++++++++++++++++++ src/bin/elua/main.h | 37 ++++ src/bin/elua/module.lua | 72 ++++++++ src/examples/elua/Makefile.am | 17 ++ src/examples/elua/elm_test.lua | 38 ++++ 10 files changed, 885 insertions(+), 1 deletion(-) create mode 100644 src/Makefile_Elua.am create mode 100644 src/bin/elua/cache.c create mode 100644 src/bin/elua/elm.lua create mode 100644 src/bin/elua/main.c create mode 100644 src/bin/elua/main.h create mode 100644 src/bin/elua/module.lua create mode 100644 src/examples/elua/Makefile.am create mode 100644 src/examples/elua/elm_test.lua diff --git a/configure.ac b/configure.ac index f4c4e860ef..d1d3507eb8 100644 --- a/configure.ac +++ b/configure.ac @@ -4307,6 +4307,51 @@ EFL_EVAL_PKGS([ETHUMB_CLIENT]) EFL_LIB_END_OPTIONAL([Ethumb_Client]) #### End of Ethumb_Client +#### Elua + +have_elua="yes" +if test "${want_lua_old}" = "yes"; then + have_elua="no" +fi + +EFL_LIB_START_OPTIONAL([Elua], [test "${have_elua}" = "yes"]) + +### Default values + +AM_CONDITIONAL([HAVE_ELUA], [test "x${have_elua}" = "xyes"]) + +### Additional options to configure + +### Checks for programs + +## Compatibility layers +EFL_PLATFORM_DEPEND([ELUA], [evil]) + +### Checks for libraries +EFL_INTERNAL_DEPEND_PKG([ELUA], [eina]) +EFL_INTERNAL_DEPEND_PKG([ELUA], [eo]) +EFL_INTERNAL_DEPEND_PKG([ELUA], [ecore]) + +EFL_DEPEND_PKG([ELUA], [LUAJIT], [luajit >= 2.0.0]) + +EFL_EVAL_PKGS([ELUA]) + +### Checks for header files + +### Checks for types + +### Checks for structures + +### Checks for compiler characteristics + +### Checks for linker characteristics + +### Checks for library functions + +### Check availability + +EFL_LIB_END_OPTIONAL([Elua]) +#### End of Elua AC_ARG_ENABLE([always-build-examples], [AC_HELP_STRING([--enable-always-build-examples], @@ -4567,6 +4612,7 @@ echo "Edje............: ${efl_lib_optional_edje} (${features_edje})" echo "Emotion.........: ${efl_lib_optional_emotion} (${features_emotion})" echo "Ethumb..........: ${efl_lib_optional_ethumb}" echo "Ethumb_Client...: ${efl_lib_optional_ethumb_client}" +echo "Elua............: $have_elua" if test "${build_tests}" = "none"; then echo "Tests...........: no" elif test "${build_tests}" = "auto"; then diff --git a/src/Makefile.am b/src/Makefile.am index 58124bbddb..7ccd43157c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,6 +79,8 @@ include Makefile_Eolian_Cxx.am include Makefile_Eet_Cxx.am include Makefile_Eo_Cxx.am +include Makefile_Elua.am + .PHONY: benchmark examples BENCHMARK_SUBDIRS = \ @@ -105,7 +107,8 @@ examples/eldbus \ examples/ephysics \ examples/edje \ examples/emotion \ -examples/ethumb_client +examples/ethumb_client \ +examples/elua if HAVE_CXX11 EXAMPLES_SUBDIRS += \ diff --git a/src/Makefile_Elua.am b/src/Makefile_Elua.am new file mode 100644 index 0000000000..4e3a14097d --- /dev/null +++ b/src/Makefile_Elua.am @@ -0,0 +1,22 @@ +if HAVE_ELUA + +bin_PROGRAMS += bin/elua/elua + +bin_elua_elua_SOURCES = \ + bin/elua/cache.c \ + bin/elua/main.c + +bin_elua_elua_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ + -DELUA_DATA_DIR="\"$(datadir)/elua\"" @ELUA_CFLAGS@ +bin_elua_elua_LDADD = @ELUA_LIBS@ +bin_elua_elua_DEPENDENCIES = @ELUA_INTERNAL_LIBS@ + +eluamodulesdir = $(datadir)/elua/modules +eluamodules_DATA = bin/elua/elm.lua +EXTRA_DIST += $(eluamodules_DATA) + +eluacoredir = $(datadir)/elua/core +eluacore_DATA = bin/elua/module.lua +EXTRA_DIST += $(eluacore_DATA) + +endif diff --git a/src/bin/elua/cache.c b/src/bin/elua/cache.c new file mode 100644 index 0000000000..be2699a459 --- /dev/null +++ b/src/bin/elua/cache.c @@ -0,0 +1,192 @@ +/* elua bytecode caching */ + +#include +#include +#include +#include +#include + +#include "main.h" + +/* bytecode caching */ + +static int check_bc(const char *fname, const char *mode, Eina_Bool *bc) { + const char *ext = strstr(fname, ".lua"); + if (ext && !ext[4] && (!mode || strchr(mode, 't'))) { + /* loading lua source file, try cached */ + char buf[PATH_MAX]; + snprintf(buf, sizeof(buf), "%sc", fname); + int fd = open(buf, O_RDONLY); + if (fd < 0) { + /* no cached bytecode */ + *bc = EINA_TRUE; + } else { + /* cached bytecode, check timestamp */ + struct stat s1, s2; + stat(fname, &s1); + stat(buf, &s2); + if (s2.st_ctime > s1.st_ctime) { + /* bytecode new enough, chunkname stays the same */ + return fd; + } else { + /* bytecode too old, remove old file */ + close(fd); + *bc = EINA_TRUE; + } + } + } + return -1; +} + +static int writef(lua_State *L EINA_UNUSED, const void *p, size_t size, +void *ud) { + FILE *f = ud; + return ferror(f) || (fwrite(p, 1, size, f) != size); +} + +static void write_bc(lua_State *L, const char *fname) { + char buf[PATH_MAX]; + snprintf(buf, sizeof(buf), "%sc", fname); + FILE *f = fopen(buf, "wb"); + if (f) { + if (lua_dump(L, writef, f)) { + fclose(f); + remove(buf); + } else fclose(f); + } +} + +/* loadfile - regular version */ + +typedef struct Cached_Stream { + FILE *f; + char buff[LUAL_BUFFERSIZE]; +} Cached_Stream; + +static const char *getf(lua_State *L EINA_UNUSED, void *ud, size_t *size) { + Cached_Stream *s = ud; + if (feof(s->f)) return NULL; + *size = fread(s->buff, 1, sizeof(s->buff), s->f); + return (*size > 0) ? s->buff : NULL; +} + +int elua_loadfilex(lua_State *L, const char *fname, const char *mode) { + Cached_Stream s; + int status; + const char *chname; + Eina_Bool bcache = EINA_FALSE; + if (!fname) { + s.f = stdin; + chname = "=stdin"; + } else { + if (!(s.f = fopen(fname, "rb"))) { + lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno)); + return LUA_ERRFILE; + } + chname = lua_pushfstring(L, "@%s", fname); + int fd = check_bc(fname, mode, &bcache); + if (fd >= 0) { + fclose(s.f); + s.f = fdopen(fd, "rb"); + } + } + status = lua_loadx(L, getf, &s, chname, mode); + if (ferror(s.f)) { + lua_pop(L, 1); + lua_pushfstring(L, "cannot read %s: %s", chname + 1, strerror(errno)); + if (fname) { + lua_remove(L, -2); + fclose(s.f); + } + return LUA_ERRFILE; + } + /* trigger bytecode writing */ + if (!status && bcache) write_bc(L, fname); + if (fname) { + lua_remove(L, -2); + fclose(s.f); + } + return status; +} + +int elua_loadfile(lua_State *L, const char *fname) { + return elua_loadfilex(L, fname, NULL); +} + +/* loadfile - mmap version */ + +typedef struct Map_Stream { + char *fmap; + size_t flen; +} Map_Stream; + +static const char *getf_map(lua_State *L EINA_UNUSED, void *ud, size_t *size) { + Map_Stream *s = ud; + *size = s->flen; + return s->fmap; +} + +int elua_loadfilex_mmap(lua_State *L, const char *fname, const char *mode) { + Map_Stream s; + int status, fd, nfd; + const char *chname; + Eina_Bool bcache = EINA_FALSE; + if (!fname) { + return elua_loadfilex(L, fname, mode); + } + if ((fd = open(fname, O_RDONLY, 0)) < 0) { + lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno)); + return LUA_ERRFILE; + } + chname = lua_pushfstring(L, "@%s", fname); + if ((nfd = check_bc(fname, mode, &bcache)) > 0) { + close(fd); + fd = nfd; + } + s.flen = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + if ((s.fmap = mmap(NULL, s.flen, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0)) + == MAP_FAILED) { + lua_pushfstring(L, "cannot read %s: %s", chname + 1, strerror(errno)); + lua_remove(L, -2); + return LUA_ERRFILE; + } + status = lua_loadx(L, getf_map, &s, chname, mode); + munmap(s.fmap, s.flen); + close(fd); + if (!status && bcache) write_bc(L, fname); + lua_remove(L, -2); + return status; +} + +int elua_loadfile_mmap(lua_State *L, const char *fname) { + return elua_loadfilex_mmap(L, fname, NULL); +} + +/* lua function */ + +static int loadfile(lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + const char *mode = luaL_optstring(L, 2, NULL); + int status, hasenv = (lua_gettop(L) >= 3); + if (lua_toboolean(L, 4)) { + status = elua_loadfilex_mmap(L, fname, mode); + } else { + status = elua_loadfilex(L, fname, mode); + } + if (!status) { + if (hasenv) { + lua_pushvalue(L, 3); + lua_setfenv(L, -2); + } + return 1; + } + lua_pushnil(L); + lua_insert(L, -2); + return 2; +} + +void elua_register_cache(lua_State *L) { + lua_pushcfunction(L, loadfile); + lua_setglobal(L, "loadfile"); +} \ No newline at end of file diff --git a/src/bin/elua/elm.lua b/src/bin/elua/elm.lua new file mode 100644 index 0000000000..54a67137c8 --- /dev/null +++ b/src/bin/elua/elm.lua @@ -0,0 +1,129 @@ +local ffi = require("ffi") +local util = erequire("util") + +local elm, evas + +local M = {} + +ffi.cdef [[ + typedef struct Evas_Object Evas_Object; + + typedef void(*Evas_Smart_Cb)(void *data, Evas_Object *obj, void *event_info); + + int elm_init(int argc, char **argv); + int elm_exit(void); + + Evas_Object *elm_win_add(Evas_Object *parent, const char *name, int type); + void elm_win_title_set(Evas_Object *obj, const char *title); + void elm_win_resize_object_add(Evas_Object *obj, Evas_Object *subobj); + + Evas_Object *elm_bg_add(Evas_Object *parent); + Evas_Object *elm_label_add(Evas_Object *parent); + Evas_Object *elm_button_add(Evas_Object *parent); + Evas_Object *elm_box_add(Evas_Object *parent); + void elm_box_pack_end(Evas_Object *obj, Evas_Object *subobj); + void elm_object_part_text_set(Evas_Object *obj, const char *part, const char *text); + + void evas_object_show(Evas_Object *obj); + void evas_object_size_hint_weight_set(Evas_Object *obj, double x, double y); + void evas_object_resize(Evas_Object *obj, int w, int h); + + void evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data); + void evas_object_smart_callback_del_full(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data); +]] + +local callbacks = {} + +local smart_cb_wrapper = ffi.cast("Evas_Smart_Cb", + util.register_callbacks(callbacks)) + +util.init_module(function() + elm, evas = ffi.load("elementary"), ffi.load("evas") + elm.elm_init(0, nil) +end, function() + elm.elm_exit() +end) + +local Evas_Object = { + resize = function(self, w, h) + evas.evas_object_resize(self.__o, w, h) + end, + show = function(self) evas.evas_object_show(self.__o) end, + size_hint_weight_set = function(self, x, y) + evas.evas_object_size_hint_weight_set(self.__o, x, y) + end, + smart_callback_add = function(self, ev, cb) + local cbt = callbacks[cb] + if not cbt then + callbacks[#callbacks + 1] = cb + cbt = { #callbacks, 0 } + callbacks[cb] = cbt + end + cbt[2] = cbt[2] + 1 + evas.evas_object_smart_callback_add(self.__o, ev, smart_cb_wrapper, + ffi.cast("void*", cbt[1])) + end, + smart_callback_del = function(self, ev, cb) + local cbt = callbacks[cb] + if not cbt then return end + local cbi = cbt[1] + evas.evas_object_smart_callback_del_full(self.__o, ev, smart_cb_wrapper, + ffi.cast("void*", cbi)) + local cnt = cbt[2] - 1 + if cnt == 0 then + callbacks[cbi], callbacks[cb] = nil, nil + else + cbt[2] = cnt + end + end +} + +M.Window = function(name, title) + local o = setmetatable({ + __o = elm.elm_win_add(nil, name, 0), + resize_object_add = function(self, o) + elm.elm_win_resize_object_add(self.__o, o.__o) + end + }, { __index = Evas_Object }) + elm.elm_win_title_set(o.__o, title) + return o +end + +M.Background = function(parent) + return setmetatable({ + __o = elm.elm_bg_add(parent.__o) + }, { __index = Evas_Object }) +end + +M.Label = function(parent) + return setmetatable({ + __o = elm.elm_label_add(parent.__o), + text_set = function(self, label) + elm.elm_object_part_text_set(self.__o, nil, label) + end + }, { __index = Evas_Object }) +end + +M.Button = function(parent) + return setmetatable({ + __o = elm.elm_button_add(parent.__o), + text_set = function(self, label) + elm.elm_object_part_text_set(self.__o, nil, label) + end + }, { __index = Evas_Object }) +end + +M.Box = function(parent) + return setmetatable({ + __o = elm.elm_box_add(parent.__o), + pack_end = function(self, obj) + elm.elm_box_pack_end(self.__o, obj.__o) + end + }, { __index = Evas_Object }) +end + +M.exit = function() + elm.elm_exit() +end + +_G["elm"] = M \ No newline at end of file diff --git a/src/bin/elua/main.c b/src/bin/elua/main.c new file mode 100644 index 0000000000..fea90746f2 --- /dev/null +++ b/src/bin/elua/main.c @@ -0,0 +1,328 @@ +/* The Lua runtime component of the EFL */ + +#include "main.h" + +static Eina_List *modlist = NULL; +static int require_ref = LUA_REFNIL; + +int el_log_domain = -1; + +enum { + ARG_CODE = 0, ARG_MODULE, ARG_LIBRARY +}; + +typedef struct Arg_Data { + int type; + const char *value; +} Arg_Data; + +static Eina_Bool append_cb(const Ecore_Getopt *parser EINA_UNUSED, + const Ecore_Getopt_Desc *desc EINA_UNUSED, + const char *str, + void *data, + Ecore_Getopt_Value *val) +{ + Eina_List **l = val->listp; + Arg_Data *v = malloc(sizeof(Arg_Data)); + v->type = (size_t)data; + v->value = str; + *l = eina_list_append(*l, v); + return EINA_TRUE; +} + +static Ecore_Getopt opt = { + "elua", "%prog [options] [script [args]]", "0.0.1", "See COPYING", + "See COPYING", "A main entry for all EFL/LuaJIT powered applications.", + 0, { + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('c', "copyright"), + ECORE_GETOPT_VERSION('v', "version"), + ECORE_GETOPT_HELP('h', "help"), + + ECORE_GETOPT_CALLBACK_ARGS('e', "execute", "Execute string " + "'code'.", "CODE", append_cb, (void*)ARG_CODE), + ECORE_GETOPT_CALLBACK_ARGS('m', "module", "Include module 'module'.", + "MODULE", append_cb, (void*)ARG_MODULE), + ECORE_GETOPT_CALLBACK_ARGS('l', "library", "Require library 'library'.", + "LIBRARY", append_cb, (void*)ARG_LIBRARY), + ECORE_GETOPT_STORE_TRUE('E', "noenv", "Ignore environment vars."), + + ECORE_GETOPT_SENTINEL + } +}; + +static void errmsg(const char *pname, const char *msg) { + ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg); +} + +static int report(lua_State *L, int status) { + if (status && !lua_isnil(L, -1)) { + const char *msg = lua_tostring(L, -1); + errmsg(opt.prog, msg ? msg : "(non-string error)"); + lua_pop(L, 1); + } + return status; +} + +static int traceback(lua_State *L) { + lua_getglobal(L, "debug"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 2); + return 1; + } + lua_pushvalue(L, 1); + lua_pushinteger(L, 2); + lua_call(L, 2, 1); + return 1; +} + +static int docall(lua_State *L, int narg) { + int status; + int bs = lua_gettop(L) - narg; + lua_pushcfunction(L, traceback); + lua_insert(L, bs); + status = lua_pcall(L, narg, 0, bs); + lua_remove(L, bs); + if (status) lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + +static int getargs(lua_State *L, int argc, char **argv, int n) { + int i; + int narg = argc - (n + 1); + luaL_checkstack(L, narg + 3, "too many arguments to script"); + for (i = n + 1; i < argc; ++i) lua_pushstring(L, argv[i]); + lua_createtable(L, narg, n + 1); + for (i = 0; i < argc; ++i) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - n); + } + return narg; +} + +static int init_module(lua_State *L) { + if (!lua_isnoneornil(L, 1)) { + lua_pushvalue(L, 1); + lua_call(L, 0, 0); + } + if (!lua_isnoneornil(L, 2)) { + lua_pushvalue(L, 2); + modlist = eina_list_append(modlist, + (void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX)); + } + return 0; +} + +static int register_require(lua_State *L) { + lua_pushvalue(L, 1); + require_ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushliteral(L, ELUA_DATA_DIR "/core/?.lua;"); + lua_pushliteral(L, ELUA_DATA_DIR "/modules/?.lua;"); + lua_pushvalue(L, 2); + lua_concat(L, 3); + return 1; +} + +static int dolib(lua_State *L, const char *libname) { + lua_rawgeti(L, LUA_REGISTRYINDEX, require_ref); + lua_pushstring(L, libname); + return report(L, lua_pcall(L, 1, 0, 0)); +} + +static int dofile(lua_State *L, const char *fname) { + return report(L, elua_loadfile(L, fname) || docall(L, 0)); +} + +static int dostr(lua_State *L, const char *chunk, const char *chname) { + return report(L, luaL_loadbuffer(L, chunk, strlen(chunk), chname) + || docall(L, 0)); +} + +static int doscript(lua_State *L, int argc, char **argv, int n) { + int status; + const char *fname = argv[n]; + int narg = getargs(L, argc, argv, n); + lua_setglobal(L, "arg"); + if (fname[0] == '-' && !fname[1]) { + fname = NULL; + } + status = elua_loadfile(L, fname); + lua_insert(L, -(narg + 1)); + if (!status) { + status = docall(L, narg); + } else { + lua_pop(L, narg); + } + return report(L, status); +} + +void shutdown(lua_State *L, int c) { + void *data; + INF("elua shutdown"); + + EINA_LIST_FREE(modlist, data) { + lua_rawgeti(L, LUA_REGISTRYINDEX, (size_t)data); + lua_call(L, 0, 0); + } + + if (L) lua_close(L); + eina_shutdown(); + exit(c); +} + +static int cb_ref = LUA_REFNIL; +static lua_State *LL = NULL; + +static void smart_cb_wrapper(void *data, void *obj EINA_UNUSED, +void *einfo EINA_UNUSED) { + int idx = (size_t)data; + lua_rawgeti(LL, LUA_REGISTRYINDEX, cb_ref); + lua_rawgeti(LL, -1, idx); + lua_call(LL, 0, 0); + lua_pop(LL, 1); +} + +static int register_callbacks(lua_State *L) { + union { void (*fptr)(void*, void*, void*); void *ptr; } u; + lua_pushvalue(L, 1); + cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + u.fptr = smart_cb_wrapper; + lua_pushlightuserdata(L, u.ptr); + return 1; +} + +struct Main_Data { + int argc; + char **argv; + int status; +}; + +const luaL_reg utillib[] = { + { "init_module", init_module }, + { "register_callbacks", register_callbacks }, + { NULL, NULL } +}; + +/* protected main */ +static int lua_main(lua_State *L) { + Eina_Bool quit = EINA_FALSE, + noenv = EINA_FALSE, + hasexec = EINA_FALSE; + Eina_List *largs = NULL, *l = NULL; + Arg_Data *data = NULL; + + int nonopt; + + struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1); + + int argc = m->argc; + char **argv = m->argv; + + if (argv[0] && argv[0][0]) opt.prog = argv[0]; + + lua_gc(L, LUA_GCSTOP, 0); + + luaL_openlibs(L); + + elua_loadfile(L, ELUA_DATA_DIR "/core/module.lua"); + lua_pushcfunction(L, register_require); + lua_createtable(L, 0, 0); + luaL_register(L, NULL, utillib); + lua_call(L, 2, 0); + + elua_register_cache(L); + lua_gc(L, LUA_GCRESTART, 0); + + INF("elua lua state initialized"); + + nonopt = ecore_getopt_parse(&opt, (Ecore_Getopt_Value[]){ + ECORE_GETOPT_VALUE_BOOL(quit), /* license */ + ECORE_GETOPT_VALUE_BOOL(quit), /* copyright */ + ECORE_GETOPT_VALUE_BOOL(quit), /* version */ + ECORE_GETOPT_VALUE_BOOL(quit), /* help */ + + ECORE_GETOPT_VALUE_LIST(largs), + ECORE_GETOPT_VALUE_LIST(largs), + ECORE_GETOPT_VALUE_LIST(largs), + ECORE_GETOPT_VALUE_BOOL(noenv) + }, argc, argv); + + INF("arguments parsed"); + + if (quit) return 0; + + /* load all the things */ + EINA_LIST_FOREACH(largs, l, data) { + switch (data->type) { + case ARG_CODE: + if (!hasexec) hasexec = EINA_TRUE; + if (dostr(L, data->value, "=(command line)")) { + m->status = 1; + return 0; + } + break; + case ARG_MODULE: + break; + case ARG_LIBRARY: + if (dolib(L, data->value)) { + m->status = 1; + return 0; + } + break; + default: + break; + } + } + + /* cleanup */ + EINA_LIST_FREE(largs, data) free(data); + + /* run script or execute sdin as file */ + if (nonopt >= 0 && nonopt < argc) { + if ((m->status = doscript(L, argc, argv, nonopt))) return 0; + } else if (!hasexec) { + dofile(L, NULL); + } + + ecore_main_loop_begin(); + + return 0; +} + +int main(int argc, char **argv) { + struct Main_Data m; + lua_State *L = NULL; + + eina_init(); + + if (!(el_log_domain = eina_log_domain_register("elua", + EINA_COLOR_ORANGE))) { + printf("cannot set elua log domain\n"); + ERR("could not set elua log domain."); + el_log_domain = EINA_LOG_DOMAIN_GLOBAL; + } + + INF("elua logging initialized: %d", el_log_domain); + + if (!(L = luaL_newstate())) { + ERR("could not initialize elua state."); + shutdown(L, 1); + } + + LL = L; + + INF("elua lua state created"); + + m.argc = argc; + m.argv = argv; + m.status = 0; + + shutdown(L, !!(lua_cpcall(L, lua_main, &m) || m.status)); + + return 0; /* never gets here */ +} \ No newline at end of file diff --git a/src/bin/elua/main.h b/src/bin/elua/main.h new file mode 100644 index 0000000000..ebf43887ad --- /dev/null +++ b/src/bin/elua/main.h @@ -0,0 +1,37 @@ +#ifndef LUAR_MAIN_H +#define LUAR_MAIN_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef ELUA_DATA_DIR +#define ELUA_DATA_DIR "." +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include + +extern int el_log_domain; + +#define DBG(...) EINA_LOG_DOM_DBG(el_log_domain, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(el_log_domain, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(el_log_domain, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(el_log_domain, __VA_ARGS__) +#define CRT(...) EINA_LOG_DOM_CRITICAL(el_log_domain, __VA_ARGS__) + +int elua_loadfilex(lua_State *L, const char *fname, const char *mode); +int elua_loadfile(lua_State *L, const char *fname); +int elua_loadfilex_mmap(lua_State *L, const char *fname, const char *mode); +int elua_loadfile_mmap(lua_State *L, const char *fname); +void elua_register_cache(lua_State *L); + +#endif \ No newline at end of file diff --git a/src/bin/elua/module.lua b/src/bin/elua/module.lua new file mode 100644 index 0000000000..ecac6bc753 --- /dev/null +++ b/src/bin/elua/module.lua @@ -0,0 +1,72 @@ +-- elua module system + +local M = {} + +local util = select(2, ...) + +local preload = { + util = function() return util end +} + +local loaded = { +} + +local path = "./?.lua;/?/init.lua" + +local loaders = { + function(modname) + local v = preload[modname] + if not v then + return ("\no field preload['%s']"):format(modname) + end + return v + end, + function(modname) + local fname, err = package.searchpath(modname, path) + if not fname then return err end + local f, err = loadfile(fname) + if not f then + error("error loading module '" .. modname .. "' from file '" + .. fname .. "':\n" .. err, 2) + end + return f + end +} +M.loaders = loaders + +local find_loader = function(modname, env) + env = env or _G + local err = { ("module '%s' not found\n"):format(modname) } + for i = 1, #loaders do + local v = loaders[i](modname) + if type(v) == "function" then + return setfenv(v, env) + elseif type(v) == "string" then + err[#err + 1] = v + end + end + return nil, table.concat(err) +end + +M.require = function(modname) + local v = loaded[modname] + if v ~= nil then return v end + local loader, err = find_loader(modname) + if not loader then error(err, 2) end + local ret = loader(modname) + if ret ~= nil then + loaded[modname] = ret + return ret + elseif loaded[modname] == nil then + loaded[modname] = true + return true + end + return loaded[modname] +end + +-- register require +path = (...)(M.require, path) + +_G["erequire"] = M.require + +return M \ No newline at end of file diff --git a/src/examples/elua/Makefile.am b/src/examples/elua/Makefile.am new file mode 100644 index 0000000000..63d102da45 --- /dev/null +++ b/src/examples/elua/Makefile.am @@ -0,0 +1,17 @@ +if HAVE_ELUA + +MAINTAINERCLEANFILES = Makefile.in + +DATA_FILES = Makefile.examples +EXTRA_DIST = $(DATA_FILES) + +install-examples: + mkdir -p $(datadir)/elua/examples + $(install_sh_DATA) -c $(DATA_FILES) $(datadir)/elua/examples + +uninstall-local: + for f in $(DATA_FILES); do \ + rm -f $(datadir)/elua/examples/$$f ; \ + done + +endif diff --git a/src/examples/elua/elm_test.lua b/src/examples/elua/elm_test.lua new file mode 100644 index 0000000000..77076d48ce --- /dev/null +++ b/src/examples/elua/elm_test.lua @@ -0,0 +1,38 @@ +local win = elm.Window("test", "Hello World") + +win:smart_callback_add("delete,request", function() + elm.exit() +end) + +local bg = elm.Background(win) +bg:size_hint_weight_set(1.0, 1.0) +win:resize_object_add(bg) +bg:show() + +local bx = elm.Box(win) +bx:size_hint_weight_set(1.0, 1.0) +win:resize_object_add(bx) +bx:show() + +local lbl = elm.Label(win) +lbl:text_set("Lua runtime test") +bx:pack_end(lbl) +lbl:show() + +local counter = nil +local step = 5 + +local btn = elm.Button(win) +btn:text_set("Reset counter") +bx:pack_end(btn) +btn:smart_callback_add("clicked", function() + if not counter then + btn:text_set("Add " .. step) + end + counter = counter and (counter + step) or 0 + lbl:text_set(tostring(counter)) +end) +btn:show() + +win:resize(360, 360) +win:show() \ No newline at end of file