* [tarantool-patches] [PATCH tarantool 1/2] Introduce luaT_tolstring
2018-08-06 7:16 [tarantool-patches] [PATCH tarantool 0/2] Using luaT_tolstring in error conversion function, instead lua_tostring Eugene Blikh
@ 2018-08-06 7:16 ` Eugene Blikh
2018-08-06 7:17 ` [tarantool-patches] [PATCH tarantool 2/2] Using luaT_tolstring in conversion function, instead lua_tostring Eugene Blikh
1 sibling, 0 replies; 3+ messages in thread
From: Eugene Blikh @ 2018-08-06 7:16 UTC (permalink / raw)
To: tarantool-patches; +Cc: Eugine Blikh
From: Eugine Blikh <bigbes@gmail.com>
`lua_tostring`/`lua_tolstring` ignores metatable/boolean/nil and return NULL,
but sometimes it's needed to have similar behaviour, like lua functions
tostring. Lua 5.1 and LuaJIT ignores it by default, Lua 5.2 introduced
auxilary function luaL_to(l)string with supporting of __tostring. This
function is backport of Lua 5.1 "lauxlib.h"s luaL_tostring in the luaT
namespace.
---
| 1 +
src/lua/init.h | 8 --------
src/lua/utils.c | 31 +++++++++++++++++++++++++++++++
src/lua/utils.h | 6 ++++++
test/app-tap/module_api.c | 39 +++++++++++++++++++++++++++++++++++++++
test/app-tap/module_api.test.lua | 13 +++++++++++--
6 files changed, 88 insertions(+), 10 deletions(-)
--git a/extra/exports b/extra/exports
index 61a2e0a54..a27722910 100644
--- a/extra/exports
+++ b/extra/exports
@@ -130,6 +130,7 @@ luaT_error
luaT_call
luaT_cpcall
luaT_state
+luaT_tolstring
box_txn
box_txn_begin
box_txn_commit
diff --git a/src/lua/init.h b/src/lua/init.h
index ddf3e9195..1257ef510 100644
--- a/src/lua/init.h
+++ b/src/lua/init.h
@@ -59,14 +59,6 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv);
void
tarantool_lua_free();
-/**
- * This function exists because lua_tostring does not use
- * __tostring metamethod, and this metamethod has to be used
- * if we want to print Lua userdata correctly.
- */
-const char *
-tarantool_lua_tostring(struct lua_State *L, int index);
-
/**
* Load and execute start-up file
*
diff --git a/src/lua/utils.c b/src/lua/utils.c
index 2f0f4dcf8..afc44b581 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -941,6 +941,37 @@ luaT_cpcall(lua_State *L, lua_CFunction func, void *ud)
return 0;
}
+/**
+ * This function exists because lua_tostring does not use
+ * __tostring metamethod, and this metamethod has to be used
+ * if we want to print Lua userdata correctly.
+ */
+const char *
+luaT_tolstring(lua_State *L, int idx, size_t *len)
+{
+ if (!luaL_callmeta(L, idx, "__tostring")) {
+ switch (lua_type(L, idx)) {
+ case LUA_TNUMBER:
+ case LUA_TSTRING:
+ lua_pushvalue(L, idx);
+ break;
+ case LUA_TBOOLEAN: {
+ int val = lua_toboolean(L, idx);
+ lua_pushstring(L, val ? "true" : "false");
+ break;
+ }
+ case LUA_TNIL:
+ lua_pushliteral(L, "nil");
+ break;
+ default:
+ lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
+ lua_topointer(L, idx));
+ }
+ }
+
+ return lua_tolstring(L, -1, len);
+}
+
lua_State *
luaT_state(void)
{
diff --git a/src/lua/utils.h b/src/lua/utils.h
index 6b057af3e..fdfa95805 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -430,6 +430,12 @@ luaT_cpcall(lua_State *L, lua_CFunction func, void *ud);
LUA_API lua_State *
luaT_state(void);
+/**
+ * Like lua_tolstring, but supports metatables, booleans and nil properly.
+ */
+LUA_API const char *
+luaT_tolstring(lua_State *L, int idx, size_t *ssize);
+
/** \endcond public */
void
diff --git a/test/app-tap/module_api.c b/test/app-tap/module_api.c
index 01c1ee35b..4abe1af48 100644
--- a/test/app-tap/module_api.c
+++ b/test/app-tap/module_api.c
@@ -402,6 +402,44 @@ test_state(lua_State *L)
return 1;
}
+static int table_tostring(lua_State *L) {
+ lua_pushstring(L, "123");
+ return 1;
+}
+
+static int
+test_tostring(lua_State *L)
+{
+ /* original table */
+ lua_createtable(L, 0, 0);
+ /* meta-table */
+ lua_createtable(L, 0, 0);
+ /* pushing __tostring function */
+ lua_pushcfunction(L, table_tostring);
+ lua_setfield(L, -2, "__tostring");
+ /* setting metatable */
+ lua_setmetatable(L, -2);
+ assert(strcmp(luaT_tolstring(L, -1, NULL), "123") == 0);
+
+ lua_pushnumber(L, 1);
+ assert(strcmp(luaT_tolstring(L, -1, NULL), "1") == 0);
+
+ lua_createtable(L, 0, 0);
+ assert(strncmp(luaT_tolstring(L, -1, NULL), "table: ", 7) == 0);
+
+ lua_pushboolean(L, true);
+ assert(strcmp(luaT_tolstring(L, -1, NULL), "true") == 0);
+
+ lua_pushboolean(L, false);
+ assert(strcmp(luaT_tolstring(L, -1, NULL), "false") == 0);
+
+ lua_pushnil(L);
+ assert(strcmp(luaT_tolstring(L, -1, NULL), "nil") == 0);
+
+ lua_pushboolean(L, true);
+ return 1;
+}
+
LUA_API int
luaopen_module_api(lua_State *L)
{
@@ -428,6 +466,7 @@ luaopen_module_api(lua_State *L)
{"test_call", test_call},
{"test_cpcall", test_cpcall},
{"test_state", test_state},
+ {"test_tostring", test_tostring},
{NULL, NULL}
};
luaL_register(L, "module_api", lib);
diff --git a/test/app-tap/module_api.test.lua b/test/app-tap/module_api.test.lua
index d55f67c3b..f93257236 100755
--- a/test/app-tap/module_api.test.lua
+++ b/test/app-tap/module_api.test.lua
@@ -1,8 +1,12 @@
#!/usr/bin/env tarantool
+local fio = require('fio')
+
box.cfg{log = "tarantool.log"}
build_path = os.getenv("BUILDDIR")
-package.cpath = build_path .. '/test/app-tap/?.so;' .. build_path .. '/test/app-tap/?.dylib;'
+package.cpath = fio.pathjoin(build_path, 'test/app-tap/?.so' ) .. ';' ..
+ fio.pathjoin(build_path, 'test/app-tap/?.dylib') .. ';' ..
+ package.cpath
local function test_pushcdata(test, module)
test:plan(6)
@@ -33,11 +37,15 @@ local function test_pushcdata(test, module)
end
local test = require('tap').test("module_api", function(test)
- test:plan(22)
+ test:plan(23)
local status, module = pcall(require, 'module_api')
test:is(status, true, "module")
test:ok(status, "module is loaded")
if not status then
+ test:diag("Failed to load library:")
+ for _, line in ipairs(module:split("\n")) do
+ test:diag("%s", line)
+ end
return
end
@@ -57,4 +65,5 @@ local test = require('tap').test("module_api", function(test)
space:drop()
end)
+
os.exit(0)
--
2.16.2
^ permalink raw reply [flat|nested] 3+ messages in thread
* [tarantool-patches] [PATCH tarantool 2/2] Using luaT_tolstring in conversion function, instead lua_tostring
2018-08-06 7:16 [tarantool-patches] [PATCH tarantool 0/2] Using luaT_tolstring in error conversion function, instead lua_tostring Eugene Blikh
2018-08-06 7:16 ` [tarantool-patches] [PATCH tarantool 1/2] Introduce luaT_tolstring Eugene Blikh
@ 2018-08-06 7:17 ` Eugene Blikh
1 sibling, 0 replies; 3+ messages in thread
From: Eugene Blikh @ 2018-08-06 7:17 UTC (permalink / raw)
To: tarantool-patches; +Cc: Eugine Blikh
From: Eugine Blikh <bigbes@gmail.com>
We can throw any Lua object as Lua error, but current behaviour won't
convert it to string. So diag error's object will have NULL, instead of
string.
luaT_tolstring honors __tostring metamethod and thus can convert table
to it's string representation.
For example, old behaviour is:
```
tarantool> fiber.create(error, 'help')
LuajitError: help
tarantool> fiber.create(error, { message = 'help' })
LuajitError:
tarantool> fiber.create(error, setmetatable({ message = 'help' }, {
__tostring = function(self) return self.message end
}))
LuajitError:
```
New behaviour is:
```
tarantool> fiber.create(error, 'help')
LuajitError: help
tarantool> fiber.create(error, { 'help' })
LuajitError: table: 0x0108fa2790
tarantool> fiber.create(error, setmetatable({ message = 'help' }, {
__tostring = function(self) return self.message end
}))
LuajitError: help
```
It won't break anything, but'll add new behaviour
---
src/lua/utils.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lua/utils.c b/src/lua/utils.c
index afc44b581..56df2bfb6 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -920,7 +920,7 @@ luaT_toerror(lua_State *L)
diag_add_error(&fiber()->diag, e);
} else {
/* Convert Lua error to a Tarantool exception. */
- diag_set(LuajitError, lua_tostring(L, -1));
+ diag_set(LuajitError, luaT_tolstring(L, -1, NULL));
}
return 1;
}
--
2.16.2
^ permalink raw reply [flat|nested] 3+ messages in thread