mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pkg/lua: Provide better integration with RIOT
- Remove file related functions from loader. * All packages must be builtin. - Remove os.tmpname. - Interface with TLSF. - Don't abort() when out of memory.
This commit is contained in:
parent
32e823acb2
commit
ed4411602c
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 FU Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup examples
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Basic lua example application
|
||||
*
|
||||
* @author Daniel Petry <daniel.petry@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "main.lua.h"
|
||||
|
||||
int lua_run_script(const char *buffer, size_t buffer_len)
|
||||
{
|
||||
|
||||
lua_State *L = luaL_newstate();
|
||||
|
||||
if (L == NULL) {
|
||||
puts("cannot create state: not enough memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
luaL_openlibs(L);
|
||||
luaL_loadbuffer(L, buffer, buffer_len, "lua input script");
|
||||
|
||||
if (lua_pcall(L, 0, 0, 0) != LUA_OK){
|
||||
puts("Lua script running failed");
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
lua_close(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Lua RIOT build");
|
||||
lua_run_script(main_lua, main_lua_len);
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
APPLICATION = lua
|
||||
APPLICATION = lua_basic
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
@ -29,12 +29,10 @@ DEVELHELP ?= 1
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
USEMODULE += ps
|
||||
|
||||
ifneq ($(BOARD),native)
|
||||
# This stack size is large enough to run Lua print() functions of
|
||||
# various lengths. Other functions untested.
|
||||
CFLAGS += -DTHREAD_STACKSIZE_MAIN=4096
|
||||
CFLAGS += -DTHREAD_STACKSIZE_MAIN='(THREAD_STACKSIZE_DEFAULT+2048)'
|
||||
endif
|
||||
|
||||
USEPKG += lua
|
||||
@ -61,6 +59,6 @@ $(LUA_PATH)/:
|
||||
$(LUA_H): | $(LUA_PATH)/
|
||||
$(LUA_H): $(LUA_PATH)/%.lua.h: %.lua
|
||||
|
||||
xxd -i $< | sed 's/^unsigned/const/g' > $@
|
||||
xxd -i $< | sed 's/^unsigned/const unsigned/g' > $@
|
||||
|
||||
$(RIOTBUILD_CONFIG_HEADER_C): $(LUA_H)
|
61
examples/lua_basic/main.c
Normal file
61
examples/lua_basic/main.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2018 FU Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup examples
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Basic lua example application
|
||||
*
|
||||
* @author Daniel Petry <daniel.petry@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
#include "lua_run.h"
|
||||
|
||||
#include "main.lua.h"
|
||||
|
||||
#define LUA_MEM_SIZE (11000)
|
||||
static char lua_mem[LUA_MEM_SIZE] __attribute__ ((aligned(__BIGGEST_ALIGNMENT__)));
|
||||
|
||||
int lua_run_script(const uint8_t *buffer, size_t buffer_len)
|
||||
{
|
||||
lua_State *L = lua_riot_newstate(lua_mem, sizeof(lua_mem), NULL);
|
||||
|
||||
if (L == NULL) {
|
||||
puts("cannot create state: not enough memory");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
lua_riot_openlibs(L, LUAR_LOAD_BASE);
|
||||
luaL_loadbuffer(L, (const char *)buffer, buffer_len, "lua input script");
|
||||
|
||||
if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
||||
puts("Lua script running failed");
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
lua_close(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Lua RIOT build");
|
||||
lua_run_script(main_lua, main_lua_len);
|
||||
puts("Lua interpreter exited");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
PKG_NAME=lua
|
||||
PKG_URL=https://github.com/lua/lua.git
|
||||
# tag: v5-3-4
|
||||
PKG_VERSION=e354c6355e7f48e087678ec49e340ca0696725b1
|
||||
PKG_LICENSE=MIT
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all:
|
||||
all: Makefile.lua
|
||||
@cp Makefile.lua $(PKG_BUILDDIR)
|
||||
"$(MAKE)" -C $(PKG_BUILDDIR) -f Makefile.lua
|
||||
|
||||
|
3
pkg/lua/Makefile.dep
Normal file
3
pkg/lua/Makefile.dep
Normal file
@ -0,0 +1,3 @@
|
||||
USEPKG += tlsf
|
||||
USEMODULE += lua-contrib
|
||||
USEMODULE += printf_float
|
@ -1 +1,3 @@
|
||||
INCLUDES += -I$(PKGDIRBASE)/lua
|
||||
INCLUDES += -I$(RIOTPKG)/lua/include
|
||||
DIRS += $(RIOTPKG)/lua/contrib
|
||||
|
@ -1,9 +1,9 @@
|
||||
SRC := $(filter-out lua.c luac.c,$(wildcard *.c))
|
||||
SRC := $(filter-out loadlib.c lua.c luac.c,$(wildcard *.c))
|
||||
|
||||
# This builds for native using POSIX system calls and some extra libraries, and
|
||||
# removes a compiler warning that warns against using tmpnam().
|
||||
ifeq ($(BOARD),native)
|
||||
CFLAGS += -DLUA_USE_LINUX
|
||||
endif
|
||||
CFLAGS += -fstack-usage -fconserve-stack \
|
||||
-DLUA_MAXCAPTURES=16 \
|
||||
-DL_MAXLENNUM=50
|
||||
# Enable these options to debug stack usage
|
||||
# -Wstack-usage=128 -Wno-error=stack-usage=128
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
3
pkg/lua/contrib/Makefile
Normal file
3
pkg/lua/contrib/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = lua-contrib
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
51
pkg/lua/contrib/binsearch.c
Normal file
51
pkg/lua/contrib/binsearch.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Generic binary search for tables containing strings.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "binsearch.h"
|
||||
|
||||
int binsearch_str(const void *start, size_t offset, size_t stride, size_t nmemb,
|
||||
const char *str, size_t n)
|
||||
{
|
||||
const uint8_t *cstart = (((const uint8_t *)start) + offset);
|
||||
size_t lo = 0, hi = nmemb;
|
||||
|
||||
while (lo < hi) {
|
||||
size_t mid = (lo + hi) / 2;
|
||||
const char *target = *((const char *const *)(cstart + mid * stride));
|
||||
int cmp = strncmp(str, target, n);
|
||||
|
||||
if (cmp == 0) {
|
||||
return mid;
|
||||
}
|
||||
else if (cmp < 0) {
|
||||
hi = mid;
|
||||
}
|
||||
else { /* (cmp > 0) */
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
return (-ENOENT);
|
||||
}
|
||||
|
||||
const void *binsearch_str_p(const void *start, size_t offset, size_t stride,
|
||||
size_t nmemb, const char *str, size_t n)
|
||||
{
|
||||
int ix = binsearch_str(start, offset, stride, nmemb, str, n);
|
||||
|
||||
return (ix == (-ENOENT)) ? NULL : (const uint8_t *)start + ix * stride;
|
||||
}
|
139
pkg/lua/contrib/binsearch.h
Normal file
139
pkg/lua/contrib/binsearch.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @brief Generic binary search for tables containing strings.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
*
|
||||
* It is often the case that one has an array of structs, where one of the
|
||||
* members of the struct is a string pointer containing a key that must be
|
||||
* searched. If the array is sorted by this key and of known length, a binary
|
||||
* search can be performed.
|
||||
*
|
||||
* To make the code generic we must reinterpret the structure array
|
||||
* as an array of pointers to string with a stride (separation in bytes between
|
||||
* elements) and offset (position of the first element relative to the start of
|
||||
* the array) given by the struct definition.
|
||||
*
|
||||
* For example, given the following struct and array definitions and assuming
|
||||
* a 32 bit platform with strict aligment:
|
||||
* struct s1 {
|
||||
* int a; // Takes up 4 bytes
|
||||
* char *name; // Takes up 4 bytes
|
||||
* char m; // Takes up 1 byte
|
||||
* };
|
||||
* struct s1 my_table[] = {......};
|
||||
*
|
||||
* Then each element of my_table will be aligned to 12 bytes. The address of the
|
||||
* "name" field of the first elements will be 4 bytes more than the address of
|
||||
* "my_table". With this two numbers we can compute the address of the i-th
|
||||
* "name" field as:
|
||||
* [address of my_table] + offset + i*stride
|
||||
* Where stride=12 bytes and offset = 4 bytes.
|
||||
*/
|
||||
|
||||
#ifndef BINSEARCH_H
|
||||
#define BINSEARCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Produce a compiler error if x is not an lvalue.
|
||||
*/
|
||||
#define _ENSURE_LVALUE(x) ((void)sizeof(&(x)))
|
||||
|
||||
/**
|
||||
* UNSAFE MACRO: Difference in bytes between the addresses of two consecutive
|
||||
* array elements.
|
||||
*/
|
||||
#define _ARRAY_STRIDE(arr) ((size_t)((uint8_t *)((arr) + 1) - (uint8_t *)(arr)))
|
||||
|
||||
/**
|
||||
* UNSAFE MACRO: Offset in bytes from the start of the array to member "member"
|
||||
* of the first element.
|
||||
*/
|
||||
#define _ARRAY_MEMBER_OFFS(arr, member) \
|
||||
((size_t)((uint8_t *)(&((arr)->member)) - (uint8_t *)(arr)))
|
||||
|
||||
/**
|
||||
* Find the index of the array element that contains "str" in
|
||||
* member "member".
|
||||
*
|
||||
* A compile-time error will be raised if arr is not an lvalue. This ensures the
|
||||
* macro is safe.
|
||||
*
|
||||
* @return Index of the array element containing the string.
|
||||
* @return (-ENOENT) if it is not found.
|
||||
*/
|
||||
#define BINSEARCH_STR(arr, nmemb, member, str, n) \
|
||||
(_ENSURE_LVALUE(arr), \
|
||||
(binsearch_str((arr), _ARRAY_MEMBER_OFFS(arr, member), _ARRAY_STRIDE(arr), \
|
||||
(nmemb), (str), (n))) \
|
||||
)
|
||||
|
||||
/**
|
||||
* Find a pointer of the array element that contains "str" in
|
||||
* member "member".
|
||||
*
|
||||
* @return Address of the element containing the string (as a void pointer).
|
||||
* @return Null if it is not found.
|
||||
*/
|
||||
#define BINSEARCH_STR_P(arr, nmemb, member, str, n) \
|
||||
(_ENSURE_LVALUE(arr), \
|
||||
(binsearch_str_p((arr), _ARRAY_MEMBER_OFFS(arr, member), _ARRAY_STRIDE(arr), \
|
||||
(nmemb), (str), (n))) \
|
||||
)
|
||||
|
||||
/**
|
||||
* Search for an array element containing a string.
|
||||
*
|
||||
* This does NOT check for NULL pointers, though start can be NULL of the size
|
||||
* (nmemb) is zero.
|
||||
*
|
||||
* @param start Pointer to start of array. The array must be ordered
|
||||
* according to the search string.
|
||||
* @param offset Offset of member containing string within structure. This
|
||||
* can be determined using offsetof.
|
||||
* @param stride Difference in bytes between the addresses of two consecutive
|
||||
* array elements.
|
||||
* @param nmemb Number of elements in the array.
|
||||
* @param str String that will be compared against.
|
||||
* @param n Compare up to n characters (see strncmp())
|
||||
*
|
||||
* @return Index of the array element containing the string.
|
||||
* @return (-ENOENT) if it is not found.
|
||||
*/
|
||||
int binsearch_str(const void *start, size_t offset, size_t stride, size_t nmemb,
|
||||
const char *str, size_t n);
|
||||
|
||||
/**
|
||||
* Like binsearch_str but returns the pointer to the element.
|
||||
*
|
||||
* @return Address of the element containing the string.
|
||||
* @return Null if it is not found.
|
||||
*/
|
||||
const void *binsearch_str_p(const void *start, size_t offset, size_t stride,
|
||||
size_t nmemb, const char *str, size_t n);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* BINSEARCH_H */
|
263
pkg/lua/contrib/lua_loadlib.c
Normal file
263
pkg/lua/contrib/lua_loadlib.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
/**
|
||||
* @ingroup pkg_lua
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @brief Replacement for the lua "package" module.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
* @author Roberto Ierusalimschy
|
||||
*
|
||||
* This file replaces the loadlib.c that comes with lua. It removes support
|
||||
* for files (both lua files and c shared objects) and dynamic loading since
|
||||
* none of these are present in RIOT.
|
||||
*
|
||||
* Instead, modules are searched in statically defined tables. In the case
|
||||
* of C modules, the table contains pointers to C functions that act as module
|
||||
* loaders. For pure Lua modules, the source code must be given as a string
|
||||
* embedded in the application binary.
|
||||
*
|
||||
*/
|
||||
|
||||
#define loadlib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include "binsearch.h"
|
||||
|
||||
#include "lua_builtin.h"
|
||||
#include "lua_loadlib.h"
|
||||
|
||||
/* ======================== 'searchers' functions =========================== */
|
||||
|
||||
static int _ll_searcher_builtin_lua(lua_State *L, const char *name)
|
||||
{
|
||||
const struct lua_riot_builtin_lua *lmodule =
|
||||
BINSEARCH_STR_P(lua_riot_builtin_lua_table,
|
||||
lua_riot_builtin_lua_table_len,
|
||||
name, name, LUAR_MAX_MODULE_NAME);
|
||||
|
||||
if (lmodule != NULL) {
|
||||
int load_result = luaL_loadbuffer(L, (const char *)lmodule->code,
|
||||
lmodule->code_size,
|
||||
lmodule->name);
|
||||
if (load_result == LUA_OK) {
|
||||
lua_pushstring(L, name); /* will be 2nd argument to module */
|
||||
}
|
||||
|
||||
return load_result;
|
||||
}
|
||||
else {
|
||||
return LUAR_MODULE_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search in the list of pure lua modules.
|
||||
*
|
||||
* If the module is found, the source code is compiled and the compiled chunk
|
||||
* is placed on the lua stack, followed by the module name (as a string).
|
||||
*/
|
||||
static int searcher_builtin_lua(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
int load_result = _ll_searcher_builtin_lua(L, name);
|
||||
|
||||
switch (load_result) {
|
||||
case LUA_OK:
|
||||
return 2; /* there are two elements in the stack */
|
||||
case LUAR_MODULE_NOTFOUND:
|
||||
return luaL_error(L, "Module '%s' not found in Lua-builtins",
|
||||
lua_tostring(L, 1));
|
||||
default:
|
||||
return luaL_error(L, "error loading module '%s' from Lua-builtins: \n%s",
|
||||
lua_tostring(L, 1), lua_tostring(L, 2));
|
||||
}
|
||||
}
|
||||
|
||||
static int _ll_searcher_builtin_c(lua_State *L, const char *name)
|
||||
{
|
||||
const struct lua_riot_builtin_c *cmodule =
|
||||
BINSEARCH_STR_P(lua_riot_builtin_c_table,
|
||||
lua_riot_builtin_c_table_len,
|
||||
name, name, LUAR_MAX_MODULE_NAME);
|
||||
|
||||
if (cmodule != NULL) {
|
||||
lua_pushcfunction(L, cmodule->luaopen);
|
||||
lua_pushstring(L, name); /* will be 2nd argument to module */
|
||||
return LUA_OK;
|
||||
}
|
||||
else {
|
||||
return LUAR_MODULE_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search in the list of C lua modules.
|
||||
*
|
||||
* If the module is found, the loader function is loaded with lua_pushcfunction
|
||||
* and is returned.
|
||||
*/
|
||||
static int searcher_builtin_c(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
int load_result = _ll_searcher_builtin_c(L, name);
|
||||
|
||||
if (load_result == LUA_OK) {
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
return luaL_error(L, "Module '%s' not found in C-builtins",
|
||||
lua_tostring(L, 1));
|
||||
}
|
||||
}
|
||||
|
||||
int lua_riot_getloader(lua_State *L, const char *name)
|
||||
{
|
||||
int load_result;
|
||||
|
||||
load_result = _ll_searcher_builtin_lua(L, name);
|
||||
|
||||
if (load_result == LUAR_MODULE_NOTFOUND) {
|
||||
load_result = _ll_searcher_builtin_c(L, name);
|
||||
}
|
||||
|
||||
return load_result;
|
||||
}
|
||||
|
||||
/* ======================== 'require' function ============================= */
|
||||
|
||||
static int searcher_preload(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
||||
if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */
|
||||
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void findloader(lua_State *L, const char *name)
|
||||
{
|
||||
int i;
|
||||
luaL_Buffer msg; /* to build error message */
|
||||
|
||||
luaL_buffinit(L, &msg);
|
||||
/* push 'package.searchers' to index 3 in the stack */
|
||||
if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) {
|
||||
luaL_error(L, "'package.searchers' must be a table");
|
||||
}
|
||||
/* iterate over available searchers to find a loader */
|
||||
for (i = 1;; i++) {
|
||||
if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */
|
||||
lua_pop(L, 1); /* remove nil */
|
||||
luaL_pushresult(&msg); /* create error message */
|
||||
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
|
||||
}
|
||||
lua_pushstring(L, name);
|
||||
lua_call(L, 1, 2); /* call it */
|
||||
if (lua_isfunction(L, -2)) { /* did it find a loader? */
|
||||
return; /* module loader found */
|
||||
}
|
||||
else if (lua_isstring(L, -2)) { /* searcher returned error message? */
|
||||
lua_pop(L, 1); /* remove extra return */
|
||||
luaL_addvalue(&msg); /* concatenate error message */
|
||||
}
|
||||
else {
|
||||
lua_pop(L, 2); /* remove both returns */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ll_require(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
|
||||
lua_settop(L, 1); /* LOADED table will be at index 2 */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||
lua_getfield(L, 2, name); /* LOADED[name] */
|
||||
if (lua_toboolean(L, -1)) { /* is it there? */
|
||||
return 1; /* package is already loaded */
|
||||
}
|
||||
/* else must load package */
|
||||
lua_pop(L, 1); /* remove 'getfield' result */
|
||||
findloader(L, name);
|
||||
lua_pushstring(L, name); /* pass name as argument to module loader */
|
||||
lua_insert(L, -2); /* name is 1st argument (before search data) */
|
||||
lua_call(L, 2, 1); /* run loader to load module */
|
||||
if (!lua_isnil(L, -1)) { /* non-nil return? */
|
||||
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
|
||||
}
|
||||
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
|
||||
lua_pushboolean(L, 1); /* use true as result */
|
||||
lua_pushvalue(L, -1); /* extra copy to be returned */
|
||||
lua_setfield(L, 2, name); /* LOADED[name] = true */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ====================== 'package' module loader =========================== */
|
||||
|
||||
static const luaL_Reg pk_funcs[] = {
|
||||
/* placeholders */
|
||||
{ "preload", NULL },
|
||||
{ "searchers", NULL },
|
||||
{ "loaded", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static const luaL_Reg ll_funcs[] = {
|
||||
{ "require", ll_require },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
LUAMOD_API int luaopen_package(lua_State *L)
|
||||
{
|
||||
static const lua_CFunction searchers[] =
|
||||
{ searcher_preload, searcher_builtin_lua, searcher_builtin_c, NULL };
|
||||
int i;
|
||||
|
||||
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
||||
|
||||
/* create 'searchers' table */
|
||||
lua_createtable(L, sizeof(searchers) / sizeof(searchers[0]) - 1, 0);
|
||||
/* fill it with predefined searchers */
|
||||
for (i = 0; searchers[i] != NULL; i++) {
|
||||
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
|
||||
lua_pushcclosure(L, searchers[i], 1);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */
|
||||
|
||||
/* set field 'loaded' */
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||
lua_setfield(L, -2, "loaded");
|
||||
|
||||
/* set field 'preload' */
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
||||
lua_setfield(L, -2, "preload");
|
||||
|
||||
|
||||
lua_pushglobaltable(L);
|
||||
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
|
||||
luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */
|
||||
lua_pop(L, 1); /* pop global table */
|
||||
return 1; /* return 'package' table */
|
||||
}
|
||||
|
||||
/** @} */
|
283
pkg/lua/contrib/lua_run.c
Normal file
283
pkg/lua/contrib/lua_run.c
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
/**
|
||||
* @ingroup pkg_lua
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @brief Convenience functions for running Lua code.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "tlsf.h"
|
||||
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "lua_run.h"
|
||||
#include "lua_loadlib.h"
|
||||
|
||||
const char *lua_riot_str_errors[] = {
|
||||
"No errors",
|
||||
"Error setting up the interpreter",
|
||||
"Error while loading a builtin library",
|
||||
"Cannot find the specified module",
|
||||
"Compilation / syntax error",
|
||||
"Unprotected error (uncaught exception)",
|
||||
"Out of memory",
|
||||
"Internal interpreter error",
|
||||
"Unknown error"
|
||||
};
|
||||
|
||||
/* The lua docs state the behavior in these cases:
|
||||
*
|
||||
* 1. ptr=?, size=0 -> free(ptr)
|
||||
therefore ptr=NULL, size=0 -> NOP
|
||||
* 2. ptr=? , size!=0 -> realloc(ptr, size)
|
||||
*
|
||||
* The TLSF code for realloc says:
|
||||
* / * Zero-size requests are treated as free. * /
|
||||
* if (ptr && size == 0)
|
||||
* {
|
||||
* tlsf_free(tlsf, ptr);
|
||||
* }
|
||||
* / * Requests with NULL pointers are treated as malloc. * /
|
||||
* else if (!ptr)
|
||||
* {
|
||||
* p = tlsf_malloc(tlsf, size);
|
||||
* }
|
||||
*
|
||||
* Therefore it is safe to use tlsf_realloc here.
|
||||
*/
|
||||
static void *lua_tlsf_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
|
||||
{
|
||||
tlsf_t tlsf = ud;
|
||||
|
||||
(void)osize;
|
||||
|
||||
return tlsf_realloc(tlsf, ptr, nsize);
|
||||
}
|
||||
|
||||
LUALIB_API lua_State *lua_riot_newstate(void *memory, size_t mem_size,
|
||||
lua_CFunction panicf)
|
||||
{
|
||||
lua_State *L;
|
||||
|
||||
#ifdef LUA_DEBUG
|
||||
Memcontrol *mc = memory;
|
||||
#endif
|
||||
|
||||
/* If we are using the lua debug module, let's reserve a space for the
|
||||
* memcontrol block directly. We don't use the allocator because we lose
|
||||
* the pointer, so we won't be able to free it and we will get a false
|
||||
* positive if we try to check for memory leaks.
|
||||
*/
|
||||
#ifdef LUA_DEBUG
|
||||
memory = (Memcontrol *)memory + 1;
|
||||
mem_size -= (uint8_t *)memory - (uint8_t *)mc;
|
||||
#endif
|
||||
|
||||
tlsf_t tlsf = tlsf_create_with_pool(memory, mem_size);
|
||||
|
||||
#ifdef LUA_DEBUG
|
||||
luaB_init_memcontrol(mc, lua_tlsf_alloc, tlsf);
|
||||
L = luaB_newstate(mc);
|
||||
#else
|
||||
L = lua_newstate(lua_tlsf_alloc, tlsf);
|
||||
#endif
|
||||
|
||||
if (L != NULL) {
|
||||
lua_atpanic(L, panicf);
|
||||
}
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
static const luaL_Reg loadedlibs[LUAR_LOAD_O_ALL] = {
|
||||
{ "_G", luaopen_base },
|
||||
{ LUA_LOADLIBNAME, luaopen_package },
|
||||
{ LUA_COLIBNAME, luaopen_coroutine },
|
||||
{ LUA_TABLIBNAME, luaopen_table },
|
||||
{ LUA_IOLIBNAME, luaopen_io },
|
||||
{ LUA_OSLIBNAME, luaopen_os },
|
||||
{ LUA_STRLIBNAME, luaopen_string },
|
||||
{ LUA_MATHLIBNAME, luaopen_math },
|
||||
{ LUA_UTF8LIBNAME, luaopen_utf8 },
|
||||
{ LUA_DBLIBNAME, luaopen_debug },
|
||||
};
|
||||
|
||||
LUALIB_API int lua_riot_openlibs(lua_State *L, uint16_t modmask)
|
||||
{
|
||||
int lib_index;
|
||||
|
||||
#ifdef LUA_DEBUG
|
||||
luaL_requiref(L, LUA_TESTLIBNAME, luaB_opentests, 1);
|
||||
lua_pop(L, 1);
|
||||
#endif
|
||||
|
||||
for (lib_index = 0; lib_index < LUAR_LOAD_O_ALL;
|
||||
lib_index++, modmask >>= 1) {
|
||||
const luaL_Reg *lib = loadedlibs + lib_index;
|
||||
|
||||
if (!(modmask & 1)) {
|
||||
continue;
|
||||
}
|
||||
/* TODO: how can the loading fail? */
|
||||
luaL_requiref(L, lib->name, lib->func, 1);
|
||||
lua_pop(L, 1); /* remove lib from stack (it is already global) */
|
||||
}
|
||||
|
||||
return lib_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump back to a save point (defined with setjmp).
|
||||
*
|
||||
* @note This function never returns!
|
||||
*/
|
||||
NORETURN static int _jump_back(lua_State *L)
|
||||
{
|
||||
jmp_buf *jump_buffer = *(jmp_buf **)lua_getextraspace(L);
|
||||
|
||||
/* FIXME: I dont think it's OK to print a message */
|
||||
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
||||
lua_tostring(L, -1));
|
||||
|
||||
/* TODO: try to return some info about the error object. */
|
||||
|
||||
longjmp(*jump_buffer, 1);
|
||||
}
|
||||
|
||||
static int lua_riot_do_module_or_buf(const uint8_t *buf, size_t buflen,
|
||||
const char *modname, void *memory, size_t mem_size,
|
||||
uint16_t modmask, int *retval)
|
||||
{
|
||||
jmp_buf jump_buffer;
|
||||
lua_State *volatile L = NULL;
|
||||
volatile int tmp_retval = 0; /* we need to make it volatile because of the
|
||||
setjmp/longjmp */
|
||||
volatile int status = LUAR_EXIT;
|
||||
int compilation_result;
|
||||
|
||||
if (setjmp(jump_buffer)) { /* We'll teleport back here if something goes wrong*/
|
||||
status = LUAR_INTERNAL_ERR;
|
||||
goto lua_riot_do_error;
|
||||
}
|
||||
|
||||
L = lua_riot_newstate(memory, mem_size, _jump_back);
|
||||
if (L == NULL) {
|
||||
status = LUAR_STARTUP_ERR;
|
||||
goto lua_riot_do_error;
|
||||
}
|
||||
|
||||
/* lua_getextraspace() gives us a pointer to an are large enough to hold a
|
||||
* pointer.
|
||||
*
|
||||
* We store a pointer to the jump buffer in that area.
|
||||
*
|
||||
* lua_getextraspace() is therefore a pointer to a pointer to jump_buffer.
|
||||
*/
|
||||
*(jmp_buf **)lua_getextraspace(L) = &jump_buffer;
|
||||
|
||||
tmp_retval = lua_riot_openlibs(L, modmask);
|
||||
if (tmp_retval != LUAR_LOAD_O_ALL) {
|
||||
status = LUAR_LOAD_ERR;
|
||||
goto lua_riot_do_error;
|
||||
}
|
||||
|
||||
if (buf == NULL) {
|
||||
compilation_result = lua_riot_getloader(L, modname);
|
||||
}
|
||||
else {
|
||||
compilation_result = luaL_loadbufferx(L, (const char *)buf,
|
||||
buflen, modname, "t");
|
||||
}
|
||||
|
||||
switch (compilation_result) {
|
||||
case LUAR_MODULE_NOTFOUND:
|
||||
status = LUAR_NOMODULE;
|
||||
goto lua_riot_do_error;
|
||||
case LUA_ERRSYNTAX:
|
||||
status = LUAR_COMPILE_ERR;
|
||||
goto lua_riot_do_error;
|
||||
case LUA_ERRMEM: /* fallthrough */
|
||||
case LUA_ERRGCMM: /* fallthrough */
|
||||
default:
|
||||
status = LUAR_MEMORY_ERR;
|
||||
goto lua_riot_do_error;
|
||||
case LUA_OK:
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf != NULL) {
|
||||
lua_pushstring(L, modname);
|
||||
}
|
||||
|
||||
switch (lua_pcall(L, 1, 1, 0)) {
|
||||
case LUA_ERRRUN: /* fallthrough */
|
||||
case LUA_ERRGCMM: /* fallthrough */
|
||||
default:
|
||||
status = LUAR_RUNTIME_ERR;
|
||||
puts(lua_tostring(L, -1));
|
||||
goto lua_riot_do_error;
|
||||
case LUA_ERRMEM:
|
||||
status = LUAR_MEMORY_ERR;
|
||||
goto lua_riot_do_error;
|
||||
case LUA_OK:
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_retval = lua_tonumber(L, 1);
|
||||
|
||||
lua_riot_do_error:
|
||||
|
||||
if (L != NULL) {
|
||||
lua_riot_close(L);
|
||||
}
|
||||
|
||||
if (retval != NULL) {
|
||||
*retval = tmp_retval;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int lua_riot_do_module(const char *modname, void *memory, size_t mem_size,
|
||||
uint16_t modmask, int *retval)
|
||||
{
|
||||
return lua_riot_do_module_or_buf(NULL, 0, modname, memory, mem_size, modmask,
|
||||
retval);
|
||||
}
|
||||
|
||||
LUALIB_API int lua_riot_do_buffer(const uint8_t *buf, size_t buflen, void *memory,
|
||||
size_t mem_size, uint16_t modmask, int *retval)
|
||||
{
|
||||
return lua_riot_do_module_or_buf(buf, buflen, "=BUFFER", memory, mem_size,
|
||||
modmask, retval);
|
||||
}
|
||||
|
||||
#define MAX_ERR_STRING ((sizeof(lua_riot_str_errors) / sizeof(*lua_riot_str_errors)) - 1)
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
LUALIB_API const char *lua_riot_strerror(int errn)
|
||||
{
|
||||
return lua_riot_str_errors[MIN((unsigned int)errn, MAX_ERR_STRING)];
|
||||
}
|
||||
|
||||
/** @} */
|
148
pkg/lua/doc.txt
148
pkg/lua/doc.txt
@ -1,6 +1,152 @@
|
||||
/**
|
||||
* @defgroup pkg_lua Lua ported to RIOT
|
||||
* @ingroup pkg
|
||||
* @brief Provides Lua support for RIOT
|
||||
* @brief Provides a Lua interpreter for RIOT
|
||||
* @see https://github.com/lua/lua
|
||||
* @see sys_lua
|
||||
*
|
||||
* # Lua programming language support
|
||||
*
|
||||
* ## Introduction
|
||||
*
|
||||
* This package embeds a [Lua 5.3](https://www.lua.org/) interpreter into RIOT.
|
||||
* With a few exceptions, all the APIs mentioned in the
|
||||
* [official documentation](https://www.lua.org/manual/5.3/) are available in
|
||||
* this package too.
|
||||
*
|
||||
* ## Running Lua code.
|
||||
*
|
||||
* lua_run.h contains functions that make it easy to setup the interpreter and
|
||||
* catch errors in a safe way. The functions from Lua's auxlib can still be used
|
||||
* but then you must supply your own allocator and panic routines, load the
|
||||
* builtin modules, etc.
|
||||
*
|
||||
* To run a chunk of code stored in an array use:
|
||||
* ```
|
||||
* lua_riot_do_buffer(const char *buf, size_t buflen, void *memory,
|
||||
* size_t mem_size, uint16_t modmask, int *retval);
|
||||
* ```
|
||||
* The interpreter will not use the global heap for allocations, instead the
|
||||
* user must supply a memory buffer.
|
||||
*
|
||||
* To save some memory, some builtin modules can be left out. `modmask` specifies
|
||||
* which builtins to load. Note that if a builtin is not loaded by C code, then
|
||||
* it cannot be loaded by Lua code later.
|
||||
*
|
||||
* `lua_riot_do_buffer` takes care of setting up the Lua state, registering a panic
|
||||
* handler that does not crash the application, configuring an allocator, loading
|
||||
* libraries, etc.
|
||||
*
|
||||
* To run a module as a script use `lua_riot_do_module`. This is roughly equivalent
|
||||
* to executing:
|
||||
* ```
|
||||
* require('modulename')
|
||||
* ```
|
||||
*
|
||||
* ## Memory requirements
|
||||
*
|
||||
* While generally efficient, the Lua interpreter was not really designed for
|
||||
* constrained devices.
|
||||
*
|
||||
* A basic interpreter session typically requires about 12kB RAM. The stack
|
||||
* but it depends on the functions used (string handling tends to use more stack).
|
||||
* It also depends on the platform.
|
||||
*
|
||||
* There is currently no easy way to determine the stack needs other than trial
|
||||
* and error. Future versions of the package will include instrumentation to
|
||||
* this end.
|
||||
*
|
||||
* ## Adding your own modules.
|
||||
*
|
||||
* `lua_loadlib.c` contains two loaders, one for modules written in Lua and
|
||||
* another one for C extensions.
|
||||
*
|
||||
* An index to the modules is stored in a table (there are two, one for each
|
||||
* kind of module). The tables are indexed by the module name and must be sorted
|
||||
* in ascending order by this key.
|
||||
*
|
||||
* The definitions for the table types are in `lua_builtin.h`. The loader module
|
||||
* containes empty tables, defined as weak symbols so they can be ovewritten
|
||||
* by the application. The variables that must be defined are:
|
||||
*
|
||||
* ```
|
||||
* /** Table containing all built in pure lua modules */
|
||||
* const struct lua_riot_builtin_lua *const lua_riot_builtin_lua_table;
|
||||
* /** Number of elements of lua_riot_builtin_lua_table */
|
||||
* const size_t lua_riot_builtin_lua_table_len;
|
||||
*
|
||||
* /** Table containing all built in c lua modules */
|
||||
* const struct lua_riot_builtin_c *const lua_riot_builtin_c_table;
|
||||
* /** Number of elements of lua_riot_builtin_c_table */
|
||||
* const size_t lua_riot_builtin_c_table_len;
|
||||
* ```
|
||||
*
|
||||
* Currently, these must be defined manually in the application code. In the
|
||||
* future a script will generate this tables, populating them with both RIOT
|
||||
* modules and the user modules.
|
||||
*
|
||||
*
|
||||
* ## Customizations
|
||||
*
|
||||
* The upstream Lua code is used without with the following modifications.
|
||||
*
|
||||
* Modifications that affect the API:
|
||||
*
|
||||
* - lua.c (the main interface to the interpreter) is replaced by our own
|
||||
* stripped-down version. The REPL is no longer included.
|
||||
* - loadlib.c (the "package" module) is replaced by our own (simplified)
|
||||
* loader. All the code dealing with files and dynamic loading has been
|
||||
* removed.
|
||||
* - os.tmpname() is removed as it caused compiler warnings and it is not
|
||||
* really possible to use it right. Use io.tmpfile() instead.
|
||||
* - The test module has been modified to allow it run in the RIOT environment.
|
||||
* This is not a public API, though.
|
||||
*
|
||||
* Other modifications:
|
||||
*
|
||||
* - There is a patch changing the Makefile. This updated makefile is not used
|
||||
* in the package, but is provided to aid development in a PC.
|
||||
* - Some patches to reduce stack and memory usage.
|
||||
*
|
||||
* ### Patches
|
||||
*
|
||||
* A version of Lua with the patches applied is available at
|
||||
* https://github.com/riot-appstore/lua. It can be downloaded and compiled in
|
||||
* desktop computer, and the official test suite (https://www.lua.org/tests/)
|
||||
* can then be run.
|
||||
*
|
||||
* Alternatively, the patches in this package can be directly applied to the
|
||||
* official distribution.
|
||||
*
|
||||
* The updated makefile creates two standalone executables. Tests should be run
|
||||
* with the debug executable.
|
||||
*
|
||||
* ## TODO
|
||||
*
|
||||
* The following features are missing and will be eventually added:
|
||||
*
|
||||
* - Load source code incrementally. It can be done now, but then the rest of the
|
||||
* interpreter setup must be loaded manually.
|
||||
* - Bindings to access RIOT functionality.
|
||||
* - Support in the build system for easily including application-specific
|
||||
* modules.
|
||||
* - Instrumentation to measure stack consumption (and maybe prevent overflow).
|
||||
* - Support for "frozen tables" (i.e. tables that live in ROM).
|
||||
* - Provide a better way of supplying data to a script and getting back results.
|
||||
* - Specify a function to call inside a module (????)
|
||||
* - Expand this readme into a proper manual.
|
||||
*
|
||||
*/
|
||||
|
||||
/* These are docs for the future (when we have the script to compile module tables) */
|
||||
/*
|
||||
* # Running Lua and C code
|
||||
*
|
||||
* see \ref sys_lua for information on how to access RIOT modules from within
|
||||
* Lua.
|
||||
*
|
||||
* While it is possible to include your application specific modules and run
|
||||
* arbitrary Lua code only just using this interpreter, the \ref sys_lua module
|
||||
* provides an automated way of handling Lua modules.
|
||||
*
|
||||
*/
|
||||
|
84
pkg/lua/include/lua_builtin.h
Normal file
84
pkg/lua/include/lua_builtin.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
/**
|
||||
* @ingroup pkg_lua
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @brief Definitions for including built-in modules.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
*
|
||||
* The modules must be placed in the tables lua_riot_builtin_lua_table (for lua
|
||||
* source code) and lua_riot_builtin_c_table (for C extensions) and the lengths
|
||||
* of these tables must be in lua_riot_builtin_lua_table_len and
|
||||
* lua_riot_builtin_c_table_len.
|
||||
*
|
||||
* These symbols are defined as weak, so there if they are not defined elsewhere
|
||||
* they will default to zero (or NULL), that is, empty tables.
|
||||
*/
|
||||
|
||||
#ifndef LUA_BUILTIN_H
|
||||
#define LUA_BUILTIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Avoid compilation errors where there are no external modules defined */
|
||||
/**
|
||||
* Attribute to make symbols weak.
|
||||
*
|
||||
* @todo This should be made part of RIOT.
|
||||
*/
|
||||
#define WEAK __attribute__((weak))
|
||||
|
||||
/**
|
||||
* Only the first `LUAR_MAX_MODULE_NAME` characters of a module name
|
||||
* will be considered when performing a lookup.
|
||||
*/
|
||||
#define LUAR_MAX_MODULE_NAME 64
|
||||
|
||||
/**
|
||||
* Entry describing a pure lua module whose source is built into the
|
||||
* application binary.
|
||||
*/
|
||||
struct lua_riot_builtin_lua {
|
||||
const char *name; /*!< Name of the module */
|
||||
const uint8_t *code; /*!< Lua source code buffer*/
|
||||
size_t code_size; /*!< Size of the source code buffer. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry describing a c lua module built into the
|
||||
* application binary.
|
||||
*/
|
||||
struct lua_riot_builtin_c {
|
||||
const char *name; /*!< Name of the module */
|
||||
int (*luaopen)(lua_State *); /*!< Loader function. It must place the module
|
||||
* table at the top of the lua stack.
|
||||
* @todo Add better docs.
|
||||
*/
|
||||
};
|
||||
|
||||
/** Table containing all built in pure lua modules */
|
||||
extern WEAK const struct lua_riot_builtin_lua *const lua_riot_builtin_lua_table;
|
||||
/** Number of elements of lua_riot_builtin_lua_table */
|
||||
extern WEAK const size_t lua_riot_builtin_lua_table_len;
|
||||
|
||||
/** Table containing all built in c lua modules */
|
||||
extern WEAK const struct lua_riot_builtin_c *const lua_riot_builtin_c_table;
|
||||
/** Number of elements of lua_riot_builtin_c_table */
|
||||
extern WEAK const size_t lua_riot_builtin_c_table_len;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" }
|
||||
#endif
|
||||
|
||||
#endif /* LUA_BUILTIN_H */
|
||||
|
||||
/** @} */
|
58
pkg/lua/include/lua_loadlib.h
Normal file
58
pkg/lua/include/lua_loadlib.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
/**
|
||||
* @ingroup pkg_lua
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @brief Lightweight C interface to the package loader.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LUA_LOADLIB_H
|
||||
#define LUA_LOADLIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Error code for when a modules is not found.
|
||||
*
|
||||
* The numeric value is chosen so that there is no collision with Lua's
|
||||
* own error codes.
|
||||
*/
|
||||
#define LUAR_MODULE_NOTFOUND 50
|
||||
|
||||
/**
|
||||
* Load a module as a chunk.
|
||||
*
|
||||
* This function is a lightweight "require". It does not require the "package"
|
||||
* module to be loaded and does not register the module.
|
||||
* Only the builtin tables are searched.
|
||||
*
|
||||
* Upon sucessful execution, the compiled chunk will be at the top of the lua
|
||||
* stack.
|
||||
*
|
||||
* @param L Initialized Lua interpreter state.
|
||||
* @param name Name of the module.
|
||||
*
|
||||
* @return Same as lua_load. If the module is a C-module, then this will
|
||||
* always succeed and return LUA_OK.
|
||||
*/
|
||||
int lua_riot_getloader(lua_State *L, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LUA_LOADLIB_H */
|
||||
|
||||
/** @} */
|
223
pkg/lua/include/lua_run.h
Normal file
223
pkg/lua/include/lua_run.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
/**
|
||||
* @ingroup pkg_lua
|
||||
* @file
|
||||
* @{
|
||||
*
|
||||
* @brief Convenience functions for running Lua code.
|
||||
* @author Juan Carrano <j.carrano@fu-berlin.de>
|
||||
*
|
||||
* This functions make it easy to create and use new Lua context:
|
||||
* It provides:
|
||||
*
|
||||
* - Easy to use routines for executing modules as scrips.
|
||||
* - Control over which modules get loaded.
|
||||
* - Support for using a local heap allocator.
|
||||
* - Out of memory handling via setjmp/longjmp.
|
||||
*
|
||||
* This library is not strictly required, as all of the functionality could be
|
||||
* implemented in terms of the public lua api, but it covers most of the use
|
||||
* cases, and thus avoids code repetition in applications.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LUA_RUN_H
|
||||
#define LUA_RUN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Convert a library index into a bit mask.
|
||||
*/
|
||||
#define LUAR_LOAD_FLAG(n) (((uint16_t)1) << (n))
|
||||
|
||||
/**
|
||||
* Order in which the builtin libraries are loaded.
|
||||
*/
|
||||
enum LUAR_LOAD_ORDER {
|
||||
LUAR_LOAD_O_BASE,
|
||||
LUAR_LOAD_O_PACKAGE,
|
||||
LUAR_LOAD_O_CORO,
|
||||
LUAR_LOAD_O_TABLE,
|
||||
LUAR_LOAD_O_IO,
|
||||
LUAR_LOAD_O_OS,
|
||||
LUAR_LOAD_O_STRING,
|
||||
LUAR_LOAD_O_MATH,
|
||||
LUAR_LOAD_O_UTF8,
|
||||
LUAR_LOAD_O_DEBUG,
|
||||
LUAR_LOAD_O_ALL,
|
||||
};
|
||||
|
||||
/** Load the base globals (_G) */
|
||||
#define LUAR_LOAD_BASE LUAR_LOAD_FLAG(LUAR_LOAD_O_BASE)
|
||||
/** Load ´package´ */
|
||||
#define LUAR_LOAD_PACKAGE LUAR_LOAD_FLAG(LUAR_LOAD_O_PACKAGE)
|
||||
/** Load ´coroutine´ */
|
||||
#define LUAR_LOAD_CORO LUAR_LOAD_FLAG(LUAR_LOAD_O_CORO)
|
||||
/** Load ´table´ */
|
||||
#define LUAR_LOAD_TABLE LUAR_LOAD_FLAG(LUAR_LOAD_O_TABLE)
|
||||
/** Load ´io´ */
|
||||
#define LUAR_LOAD_IO LUAR_LOAD_FLAG(LUAR_LOAD_O_IO)
|
||||
/** Load ´os´ */
|
||||
#define LUAR_LOAD_OS LUAR_LOAD_FLAG(LUAR_LOAD_O_OS)
|
||||
/** Load ´string´ */
|
||||
#define LUAR_LOAD_STRING LUAR_LOAD_FLAG(LUAR_LOAD_O_STRING)
|
||||
/** Load ´math´ */
|
||||
#define LUAR_LOAD_MATH LUAR_LOAD_FLAG(LUAR_LOAD_O_MATH)
|
||||
/** Load ´utf8´ */
|
||||
#define LUAR_LOAD_UTF8 LUAR_LOAD_FLAG(LUAR_LOAD_O_UTF8)
|
||||
/** Load ´debug´ */
|
||||
#define LUAR_LOAD_DEBUG LUAR_LOAD_FLAG(LUAR_LOAD_O_DEBUG)
|
||||
|
||||
/* TODO: maybe we can implement a "restricted base" package containing a subset
|
||||
* of base that is safe. */
|
||||
|
||||
#define LUAR_LOAD_ALL (0xFFFF) /** Load all standard modules */
|
||||
#define LUAR_LOAD_NONE (0x0000) /** Do not load any modules */
|
||||
|
||||
/** Errors that can be raised when running lua code. */
|
||||
enum LUAR_ERRORS {
|
||||
LUAR_EXIT, /** The program exited without error. */
|
||||
LUAR_STARTUP_ERR, /** Error setting up the interpreter. */
|
||||
LUAR_LOAD_ERR, /** Error while loading libraries. */
|
||||
LUAR_NOMODULE, /** The specified module could not be found. */
|
||||
LUAR_COMPILE_ERR, /** The Lua code failed to compile. */
|
||||
LUAR_RUNTIME_ERR, /** Error in code execution. */
|
||||
LUAR_MEMORY_ERR, /** Lua could not allocate enough memory */
|
||||
LUAR_INTERNAL_ERR /** Error inside the Lua VM.
|
||||
* Right now, if this happens, you may leak memory from
|
||||
* the heap. If your program is the only one using the
|
||||
* dynamic allocation, just clean the heap.
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Human-readable description of the errors
|
||||
*/
|
||||
extern const char *lua_riot_str_errors[];
|
||||
|
||||
/**
|
||||
* Return a string describing an error from LUAR_ERRORS.
|
||||
*
|
||||
* @param errn Error number as returned by lua_riot_do_buffer() or
|
||||
* lua_riot_do_buffer()
|
||||
*
|
||||
* @return A string describing the error, or "Unknown error".
|
||||
*/
|
||||
LUALIB_API const char *lua_riot_strerror(int errn);
|
||||
|
||||
/**
|
||||
* Initialize a lua state and set the panic handler.
|
||||
*
|
||||
* @todo Use a per-state allocator
|
||||
*
|
||||
* @param memory Pointer to memory region that will be used as heap for
|
||||
* the allocator. Currently this functionality is not
|
||||
* supported and this must be set to NULL.
|
||||
* @param mem_size Size of the memory region that will be used as heap.
|
||||
* Currently this functionality is not supported and this
|
||||
* must be set to 0.
|
||||
* @param panicf Function to be passed to lua_atpanic. If set to NULL,
|
||||
* a generic function that does nothing will be used.
|
||||
*
|
||||
* @return the new state, or NULL if there is a memory allocation error.
|
||||
*/
|
||||
LUALIB_API lua_State *lua_riot_newstate(void *memory, size_t mem_size,
|
||||
lua_CFunction panicf);
|
||||
|
||||
/**
|
||||
* Terminate the lua state.
|
||||
*
|
||||
* You must call this function if you want the finalizers (the __gc metamethods)
|
||||
* to be called.
|
||||
*/
|
||||
#ifndef LUA_DEBUG
|
||||
#define lua_riot_close lua_close
|
||||
#else
|
||||
#define lua_riot_close luaB_close
|
||||
#endif /* LUA_DEBUG */
|
||||
|
||||
/**
|
||||
* Open builtin libraries.
|
||||
*
|
||||
* This is like luaL_openlibs but it allows selecting which libraries will
|
||||
* be loaded.
|
||||
*
|
||||
* Libraries are loaded in the order specified by the LUAR_LOAD_ORDER enum. If
|
||||
* there is an error the load sequence is aborted and the index of the library
|
||||
* that failed is reported.
|
||||
*
|
||||
* If debuging is enabled (compile with the LUA_DEBUG macro), then the test
|
||||
* library will be unconditionally loaded.
|
||||
*
|
||||
* @param L Lua state
|
||||
* @param modmask Binary mask that indicates which modules should be
|
||||
* loaded. The mask is made from a combination of the
|
||||
* LUAR_LOAD_* macros.
|
||||
*
|
||||
* @return The index of the library that failed to load, or LUAR_LOAD_O_ALL
|
||||
* if all libraries were loaded.
|
||||
*/
|
||||
LUALIB_API int lua_riot_openlibs(lua_State *L, uint16_t modmask);
|
||||
|
||||
/**
|
||||
* Initialize the interpreter and run a built-in module in protected mode.
|
||||
*
|
||||
* In addition to running code in protected mode, this also sets a panic
|
||||
* function that long-jumps back to this function, in case there is an internal
|
||||
* interpreter error (LUAR_INTERNAL_ERR).
|
||||
* Right now the only things that the application can are either to abort(),
|
||||
* or to manually reset the heap (only if there's no other thread using it).
|
||||
*
|
||||
* @param modname name of the module.
|
||||
* @param memory @see lua_riot_newstate()
|
||||
* @param mem_size @see lua_riot_newstate()
|
||||
* @param modmask @see lua_riot_newstate()
|
||||
* @param[out] retval Value returned by the lua code, if it is a number,
|
||||
* or zero if no value is returned or the value is not
|
||||
* a number. If retval is null, the value is not stored.
|
||||
*
|
||||
* @return An error code ( @see LUAR_ERRORS). LUAR_EXIT indicates no error.
|
||||
*/
|
||||
LUALIB_API int lua_riot_do_module(const char *modname, void *memory, size_t mem_size,
|
||||
uint16_t modmask, int *retval);
|
||||
|
||||
/**
|
||||
* Initialize the interpreter and run a user supplied buffer in protected mode.
|
||||
*
|
||||
* Only text data (i.e. lua source code) can be loaded by this function. The
|
||||
* lua interpreter is not robust against corrupt binary code.
|
||||
*
|
||||
* @see lua_riot_do_module() for more information on internal errors.
|
||||
*
|
||||
* @param buf Text data (lua source code).
|
||||
* @param buflen Size of the text data in bytes. If buf is
|
||||
* a zero-terminated string, the zero must not be counted.
|
||||
* @param memory @see lua_riot_newstate()
|
||||
* @param mem_size @see lua_riot_newstate()
|
||||
* @param modmask @see lua_riot_newstate()
|
||||
* @param[out] retval @see lua_riot_do_module()
|
||||
* @return @see lua_riot_do_module().
|
||||
*/
|
||||
LUALIB_API int lua_riot_do_buffer(const uint8_t *buf, size_t buflen, void *memory,
|
||||
size_t mem_size, uint16_t modmask, int *retval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" }
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* LUA_RUN_H */
|
Binary file not shown.
BIN
pkg/lua/patches/0001-Remove-luaL_newstate.patch
Normal file
BIN
pkg/lua/patches/0001-Remove-luaL_newstate.patch
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
pkg/lua/patches/0004-Remove-os.tmpname.patch
Normal file
BIN
pkg/lua/patches/0004-Remove-os.tmpname.patch
Normal file
Binary file not shown.
BIN
pkg/lua/patches/0005-Do-not-allocate-buffers-on-the-stack.patch
Normal file
BIN
pkg/lua/patches/0005-Do-not-allocate-buffers-on-the-stack.patch
Normal file
Binary file not shown.
BIN
pkg/lua/patches/0006-Cleanup-test-module.patch
Normal file
BIN
pkg/lua/patches/0006-Cleanup-test-module.patch
Normal file
Binary file not shown.
BIN
pkg/lua/patches/0007-Add-a-proper-makefile.patch
Normal file
BIN
pkg/lua/patches/0007-Add-a-proper-makefile.patch
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user