Merge pull request #9726 from jcarrano/lua-loader-fix

pkg/lua: Make the module searchers conform to the API.
This commit is contained in:
Leandro Lanzieri 2019-06-03 11:47:06 +02:00 committed by GitHub
commit f56709e0bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 235 additions and 10 deletions

View File

@ -42,12 +42,17 @@
/* ======================== 'searchers' functions =========================== */
/* A null address for table_len means the weak symbol was not overridden */
#define _SEARCH_BUILTINS(table, len, sname) \
((&(len) == NULL)? NULL : BINSEARCH_STR_P((table), (len), name, (sname), \
LUAR_MAX_MODULE_NAME))
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);
_SEARCH_BUILTINS(lua_riot_builtin_lua_table,
lua_riot_builtin_lua_table_len,
name);
if (lmodule != NULL) {
int load_result = luaL_loadbuffer(L, (const char *)lmodule->code,
@ -79,8 +84,8 @@ static int searcher_builtin_lua(lua_State *L)
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));
lua_pushliteral(L, "\n\tModule not found in Lua-builtins");
return 1;
default:
return luaL_error(L, "error loading module '%s' from Lua-builtins: \n%s",
lua_tostring(L, 1), lua_tostring(L, 2));
@ -90,9 +95,9 @@ static int searcher_builtin_lua(lua_State *L)
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);
_SEARCH_BUILTINS(lua_riot_builtin_c_table,
lua_riot_builtin_c_table_len,
name);
if (cmodule != NULL) {
lua_pushcfunction(L, cmodule->luaopen);
@ -119,8 +124,8 @@ static int searcher_builtin_c(lua_State *L)
return 2;
}
else {
return luaL_error(L, "Module '%s' not found in C-builtins",
lua_tostring(L, 1));
lua_pushliteral(L, "\n\tModule not found in C-builtins");
return 1;
}
}

16
tests/lua_loader/Makefile Normal file
View File

@ -0,0 +1,16 @@
include ../Makefile.tests_common
USEPKG += lua
BOARD_WHITELIST += native samr21-xpro
ifneq ($(BOARD),native)
# This stack size is large enough to run Lua print() functions of
# various lengths. Other functions untested.
CFLAGS += -DTHREAD_STACKSIZE_MAIN='(THREAD_STACKSIZE_DEFAULT+2048)'
endif
include $(RIOTBASE)/Makefile.include
test:
tests/01-run.py

8
tests/lua_loader/README Normal file
View File

@ -0,0 +1,8 @@
Test modified LUA module loader
===============================
This test defines a bunch of dummy modules, both in
pure lua and in C. The way modules are declares is not "nice"
in the sense that it is not the way it would be done in a big
application. The goal is to test the module loader code, and not
the build tooling.

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2019 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 Define a couple of dummy lua extension modules
*
* @author Juan Carrano <j.carrano@fu-berlin.de>
*
* Normally one would not define more than one module in a single file, but
* these modules are exacly the same: a single table with an integer value.
*
* @}
*/
#define LUA_LIB
#include "lprefix.h"
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static const luaL_Reg funcs[] = {
/* placeholder */
{ "X", NULL },
{ NULL, NULL }
};
static int _luaopen_X(lua_State *L, const char *xstring)
{
luaL_newlib(L, funcs);
lua_pushstring(L, xstring);
lua_setfield(L, -2, "X");
return 1;
}
int _luaopen_hello(lua_State *L)
{
return _luaopen_X(L, "E se deixa no céu,");
}
int _luaopen_world(lua_State *L)
{
return _luaopen_X(L, "como esquecida");
}

105
tests/lua_loader/main.c Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2019 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 Test custom lua loader ("require" module)
*
* @author Juan Carrano <j.carrano@fu-berlin.de>
*
* This application defines some pure-lua and some C-extension modules.
* First it tests running a module as a script (lua_riot_do_module).
*
* Then it goes into a loop reading single lines of input from stdin and
* executing them as lua source. The test script can use that to test module
* loading.
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "lua_run.h"
#include "lua_builtin.h"
static const uint8_t pure_module_1[] = "\n\
return {a='Quando uma lua'}\n\
";
static const uint8_t pure_module_2[] = "\n\
return {a='chega de repente'}\n\
";
static const uint8_t test_script[] = "\n\
print'I am a module, hi!'\n\
";
/* The -1 is because the final '\0' is not part of the source code that should
* be read by lua.
*/
const struct lua_riot_builtin_lua _lua_riot_builtin_lua_table[] = {
{ "m1", pure_module_1, sizeof(pure_module_1) - 1 },
{ "m2", pure_module_2, sizeof(pure_module_2) - 1 },
{ "test", test_script, sizeof(test_script) - 1 }
};
extern int _luaopen_hello(lua_State *L);
extern int _luaopen_world(lua_State *L);
const struct lua_riot_builtin_c _lua_riot_builtin_c_table[] = {
{ "c1", _luaopen_hello },
{ "c2", _luaopen_world }
};
const struct lua_riot_builtin_lua *const lua_riot_builtin_lua_table = _lua_riot_builtin_lua_table;
const struct lua_riot_builtin_c *const lua_riot_builtin_c_table = _lua_riot_builtin_c_table;
const size_t lua_riot_builtin_lua_table_len =
sizeof(_lua_riot_builtin_lua_table) / sizeof(*_lua_riot_builtin_lua_table);
const size_t lua_riot_builtin_c_table_len =
sizeof(_lua_riot_builtin_c_table) / sizeof(*_lua_riot_builtin_c_table);
#define LUA_MEM_SIZE (11000)
static char lua_mem[LUA_MEM_SIZE] __attribute__ ((aligned(__BIGGEST_ALIGNMENT__)));
#define LINEBUF_SZ (32)
static char linebuf[LINEBUF_SZ];
int main(void)
{
int status;
status = lua_riot_do_module("test", lua_mem, LUA_MEM_SIZE,
LUAR_LOAD_BASE, NULL);
assert(status == LUAR_EXIT);
while (fgets(linebuf, LINEBUF_SZ, stdin) != NULL) {
int status;
size_t linelen = strlen(linebuf);
if (!linelen) {
continue;
}
else if (linebuf[linelen - 1] != '\n') {
puts("[ERROR] could not read a complete line");
break;
}
status = lua_riot_do_buffer((unsigned char *)linebuf, linelen,
lua_mem, LUA_MEM_SIZE,
LUAR_LOAD_BASE | LUAR_LOAD_PACKAGE, NULL);
assert(status == LUAR_EXIT);
}
return 0;
}

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# Copyright (C) 2019 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.
# Tell the lua interpreter running in riot to load some modules and print
# the value of a variable inside that module.
import os
import sys
MODULE_QUERIES = [
("m1", "a", "Quando uma lua"),
("m2", "a", "chega de repente"),
("c1", "X", "E se deixa no céu,"),
("c2", "X", "como esquecida"),
]
def test(child):
# check startup message
child.expect_exact('I am a module, hi!')
# loop other defined commands and expected output
for mod, attr, val in MODULE_QUERIES:
child.sendline('print((require"{}").{})'.format(mod, attr))
child.expect_exact(val)
if __name__ == "__main__":
sys.path.append(os.path.join(os.environ['RIOTTOOLS'], 'testrunner'))
from testrunner import run
sys.exit(run(test))