From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 284EA27344 for ; Mon, 6 Aug 2018 03:18:09 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Xae7mann_4BY for ; Mon, 6 Aug 2018 03:18:09 -0400 (EDT) Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id BB61022BE0 for ; Mon, 6 Aug 2018 03:18:08 -0400 (EDT) Received: by mail-wr1-f66.google.com with SMTP id c13-v6so11316546wrt.1 for ; Mon, 06 Aug 2018 00:18:08 -0700 (PDT) From: Eugene Blikh Subject: [tarantool-patches] [PATCH tarantool 1/2] Introduce luaT_tolstring Date: Mon, 6 Aug 2018 10:16:59 +0300 Message-Id: In-Reply-To: References: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: Eugine Blikh From: Eugine Blikh `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. --- extra/exports | 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(-) diff --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