mirror of
https://github.com/lua/lua
synced 2025-04-14 17:02:54 +03:00
Changes in the warning system
- The warning functions get an extra parameter that tells whether message is to be continued (instead of using end-of-lines as a signal). - The user data for the warning function is a regular value, instead of a writable slot inside the Lua state.
This commit is contained in:
parent
9eca305e75
commit
b56d4e570a
4
lapi.c
4
lapi.c
@ -1286,9 +1286,9 @@ void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void lua_warning (lua_State *L, const char *msg) {
|
void lua_warning (lua_State *L, const char *msg, int tocont) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
luaE_warning(L, msg);
|
luaE_warning(L, msg, tocont);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
lauxlib.c
34
lauxlib.c
@ -987,33 +987,29 @@ static int panic (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** checks whether 'message' ends with end-of-line
|
** Emit a warning. '*previoustocont' signals whether previous message
|
||||||
** (and therefore is the last part of a warning)
|
** was to be continued by the current one.
|
||||||
*/
|
*/
|
||||||
static int islast (const char *message) {
|
static void warnf (void *ud, const char *message, int tocont) {
|
||||||
size_t len = strlen(message);
|
int *previoustocont = (int *)ud;
|
||||||
return (len > 0 && message[len - 1] == '\n');
|
if (!*previoustocont) /* previous message was the last? */
|
||||||
}
|
lua_writestringerror("%s", "Lua warning: "); /* start a new warning */
|
||||||
|
lua_writestringerror("%s", message); /* write message */
|
||||||
|
if (!tocont) /* is this the last part? */
|
||||||
/*
|
lua_writestringerror("%s", "\n"); /* finish message with end-of-line */
|
||||||
** Emit a warning. If '*pud' is NULL, previous message was to be
|
*previoustocont = tocont;
|
||||||
** continued by the current one.
|
|
||||||
*/
|
|
||||||
static void warnf (void **pud, const char *message) {
|
|
||||||
if (*pud == NULL) /* previous message was not the last? */
|
|
||||||
lua_writestringerror("%s", message);
|
|
||||||
else /* start a new warning */
|
|
||||||
lua_writestringerror("Lua warning: %s", message);
|
|
||||||
*pud = (islast(message)) ? pud : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API lua_State *luaL_newstate (void) {
|
LUALIB_API lua_State *luaL_newstate (void) {
|
||||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
lua_State *L = lua_newstate(l_alloc, NULL);
|
||||||
if (L) {
|
if (L) {
|
||||||
|
int *previoustocont; /* space for warning state */
|
||||||
lua_atpanic(L, &panic);
|
lua_atpanic(L, &panic);
|
||||||
lua_setwarnf(L, warnf, L);
|
previoustocont = (int *)lua_newuserdatauv(L, sizeof(int), 0);
|
||||||
|
luaL_ref(L, LUA_REGISTRYINDEX); /* make sure it won't be collected */
|
||||||
|
*previoustocont = 0; /* next message starts a new warning */
|
||||||
|
lua_setwarnf(L, warnf, previoustocont);
|
||||||
}
|
}
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ static int luaB_print (lua_State *L) {
|
|||||||
|
|
||||||
static int luaB_warn (lua_State *L) {
|
static int luaB_warn (lua_State *L) {
|
||||||
const char *msg = luaL_checkstring(L, 1);
|
const char *msg = luaL_checkstring(L, 1);
|
||||||
lua_warning(L, msg);
|
lua_warning(L, msg, lua_toboolean(L, 2));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
lgc.c
8
lgc.c
@ -832,7 +832,7 @@ static void GCTM (lua_State *L) {
|
|||||||
lua_assert(!g->gcemergency);
|
lua_assert(!g->gcemergency);
|
||||||
setgcovalue(L, &v, udata2finalize(g));
|
setgcovalue(L, &v, udata2finalize(g));
|
||||||
tm = luaT_gettmbyobj(L, &v, TM_GC);
|
tm = luaT_gettmbyobj(L, &v, TM_GC);
|
||||||
if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */
|
if (ttisfunction(tm)) { /* is the finalizer a function? */
|
||||||
int status;
|
int status;
|
||||||
lu_byte oldah = L->allowhook;
|
lu_byte oldah = L->allowhook;
|
||||||
int running = g->gcrunning;
|
int running = g->gcrunning;
|
||||||
@ -850,9 +850,9 @@ static void GCTM (lua_State *L) {
|
|||||||
const char *msg = (ttisstring(s2v(L->top - 1)))
|
const char *msg = (ttisstring(s2v(L->top - 1)))
|
||||||
? svalue(s2v(L->top - 1))
|
? svalue(s2v(L->top - 1))
|
||||||
: "error object is not a string";
|
: "error object is not a string";
|
||||||
luaE_warning(L, "error in __gc metamethod (");
|
luaE_warning(L, "error in __gc metamethod (", 1);
|
||||||
luaE_warning(L, msg);
|
luaE_warning(L, msg, 1);
|
||||||
luaE_warning(L, ")\n");
|
luaE_warning(L, ")", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
lstate.c
4
lstate.c
@ -411,10 +411,10 @@ LUA_API void lua_close (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaE_warning (lua_State *L, const char *msg) {
|
void luaE_warning (lua_State *L, const char *msg, int tocont) {
|
||||||
lua_WarnFunction wf = G(L)->warnf;
|
lua_WarnFunction wf = G(L)->warnf;
|
||||||
if (wf != NULL)
|
if (wf != NULL)
|
||||||
wf(&G(L)->ud_warn, msg);
|
wf(G(L)->ud_warn, msg, tocont);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
2
lstate.h
2
lstate.h
@ -317,7 +317,7 @@ LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
|||||||
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_enterCcall (lua_State *L);
|
LUAI_FUNC void luaE_enterCcall (lua_State *L);
|
||||||
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg);
|
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
||||||
|
|
||||||
|
|
||||||
#define luaE_exitCcall(L) ((L)->nCcalls--)
|
#define luaE_exitCcall(L) ((L)->nCcalls--)
|
||||||
|
56
ltests.c
56
ltests.c
@ -63,11 +63,8 @@ static void pushobject (lua_State *L, const TValue *o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void badexit (const char *fmt, ...) {
|
static void badexit (const char *fmt, const char *s) {
|
||||||
va_list argp;
|
fprintf(stderr, fmt, s);
|
||||||
va_start(argp, fmt);
|
|
||||||
vfprintf(stderr, fmt, argp);
|
|
||||||
va_end(argp);
|
|
||||||
/* avoid assertion failures when exiting */
|
/* avoid assertion failures when exiting */
|
||||||
l_memcontrol.numblocks = l_memcontrol.total = 0;
|
l_memcontrol.numblocks = l_memcontrol.total = 0;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -81,52 +78,35 @@ static int tpanic (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int islast (const char *message) {
|
|
||||||
size_t len = strlen(message);
|
|
||||||
return (len > 0 && message[len - 1] == '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Warning function for tests. Fist, it concatenates all parts of
|
** Warning function for tests. Fist, it concatenates all parts of
|
||||||
** a warning in buffer 'buff'. Then:
|
** a warning in buffer 'buff'. Then:
|
||||||
** messages starting with '#' are shown on standard output (used to
|
** - messages starting with '#' are shown on standard output (used to
|
||||||
** test explicit warnings);
|
** test explicit warnings);
|
||||||
** messages containing '@' are stored in global '_WARN' (used to test
|
** - messages containing '@' are stored in global '_WARN' (used to test
|
||||||
** errors that generate warnings);
|
** errors that generate warnings);
|
||||||
** other messages abort the tests (they represent real warning conditions;
|
** - other messages abort the tests (they represent real warning
|
||||||
** the standard tests should not generate these conditions unexpectedly).
|
** conditions; the standard tests should not generate these conditions
|
||||||
|
** unexpectedly).
|
||||||
*/
|
*/
|
||||||
static void warnf (void **pud, const char *msg) {
|
static void warnf (void *ud, const char *msg, int tocont) {
|
||||||
static char buff[200]; /* should be enough for tests... */
|
static char buff[200] = ""; /* should be enough for tests... */
|
||||||
static int cont = 0; /* message to be continued */
|
|
||||||
if (cont) { /* continuation? */
|
|
||||||
if (strlen(msg) >= sizeof(buff) - strlen(buff))
|
if (strlen(msg) >= sizeof(buff) - strlen(buff))
|
||||||
badexit("warnf-buffer overflow");
|
badexit("%s", "warnf-buffer overflow");
|
||||||
strcat(buff, msg); /* add new message to current warning */
|
strcat(buff, msg); /* add new message to current warning */
|
||||||
}
|
if (!tocont) { /* message finished? */
|
||||||
else { /* new warning */
|
|
||||||
if (strlen(msg) >= sizeof(buff))
|
|
||||||
badexit("warnf-buffer overflow");
|
|
||||||
strcpy(buff, msg); /* start a new warning */
|
|
||||||
}
|
|
||||||
if (!islast(msg)) /* message not finished yet? */
|
|
||||||
cont = 1; /* wait for more */
|
|
||||||
else { /* handle message */
|
|
||||||
cont = 0; /* prepare for next message */
|
|
||||||
if (buff[0] == '#') /* expected warning? */
|
if (buff[0] == '#') /* expected warning? */
|
||||||
printf("Expected Lua warning: %s", buff); /* print it */
|
printf("Expected Lua warning: %s\n", buff); /* print it */
|
||||||
else if (strchr(buff, '@') != NULL) { /* warning for test purposes? */
|
else if (strchr(buff, '@') != NULL) { /* warning for test purposes? */
|
||||||
lua_State *L = cast(lua_State *, *pud);
|
lua_State *L = cast(lua_State *, ud);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
lua_pushstring(L, buff);
|
lua_pushstring(L, buff);
|
||||||
lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */
|
lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else { /* a real warning; should not happen during tests */
|
else /* a real warning; should not happen during tests */
|
||||||
badexit("Unexpected warning in test mode: %s\naborting...\n", buff);
|
badexit("Unexpected warning in test mode: %s\naborting...\n", buff);
|
||||||
}
|
buff[0] = '\0'; /* prepare buffer for next warning */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1466,9 +1446,13 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
|||||||
const char *msg = getstring;
|
const char *msg = getstring;
|
||||||
printf("%s\n", msg);
|
printf("%s\n", msg);
|
||||||
}
|
}
|
||||||
|
else if EQ("warningC") {
|
||||||
|
const char *msg = getstring;
|
||||||
|
lua_warning(L1, msg, 1);
|
||||||
|
}
|
||||||
else if EQ("warning") {
|
else if EQ("warning") {
|
||||||
const char *msg = getstring;
|
const char *msg = getstring;
|
||||||
lua_warning(L1, msg);
|
lua_warning(L1, msg, 0);
|
||||||
}
|
}
|
||||||
else if EQ("pushbool") {
|
else if EQ("pushbool") {
|
||||||
lua_pushboolean(L1, getnum);
|
lua_pushboolean(L1, getnum);
|
||||||
|
4
lua.h
4
lua.h
@ -128,7 +128,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
|||||||
/*
|
/*
|
||||||
** Type for warning functions
|
** Type for warning functions
|
||||||
*/
|
*/
|
||||||
typedef void (*lua_WarnFunction) (void **pud, const char *msg);
|
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -309,7 +309,7 @@ LUA_API int (lua_isyieldable) (lua_State *L);
|
|||||||
** Warning-related functions
|
** Warning-related functions
|
||||||
*/
|
*/
|
||||||
LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
|
LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
|
||||||
LUA_API void (lua_warning) (lua_State *L, const char *msg);
|
LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4061,7 +4061,7 @@ If @id{index} @N{is 0}, then all stack elements are removed.
|
|||||||
|
|
||||||
Sets the @x{warning function} to be used by Lua to emit warnings
|
Sets the @x{warning function} to be used by Lua to emit warnings
|
||||||
@see{lua_WarnFunction}.
|
@see{lua_WarnFunction}.
|
||||||
The @id{ud} parameter initializes the slot @id{pud} passed to
|
The @id{ud} parameter sets the value @id{ud} passed to
|
||||||
the warning function.
|
the warning function.
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -4325,25 +4325,24 @@ Returns the version number of this core.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@APIEntry{
|
@APIEntry{
|
||||||
typedef void (*lua_WarnFunction) (void **pud, const char *msg);|
|
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);|
|
||||||
|
|
||||||
The type of @x{warning function}s, called by Lua to emit warnings.
|
The type of @x{warning function}s, called by Lua to emit warnings.
|
||||||
The first parameter is the address of a writable slot,
|
The first parameter is an opaque pointer
|
||||||
constant for a given Lua state and
|
set by @Lid{lua_setwarnf}.
|
||||||
initialized by @Lid{lua_setwarnf}.
|
|
||||||
The second parameter is the warning message.
|
The second parameter is the warning message.
|
||||||
This function should assume that
|
The third parameter is a boolean that
|
||||||
a message not ending with an end-of-line will be
|
indicates whether the message is
|
||||||
continued by the message in the next call.
|
to be continued by the message in the next call.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@APIEntry{
|
@APIEntry{
|
||||||
void lua_warning (lua_State *L, const char *msg);|
|
void lua_warning (lua_State *L, const char *msg, int tocont);|
|
||||||
@apii{0,0,-}
|
@apii{0,0,-}
|
||||||
|
|
||||||
Emits a warning with the given message.
|
Emits a warning with the given message.
|
||||||
A message not ending with an end-of-line should be
|
A message in a call with @id{tocont} true should be
|
||||||
continued in another call to this function.
|
continued in another call to this function.
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6275,11 +6274,12 @@ The current value of this variable is @St{Lua 5.4}.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@LibEntry{warn (message)|
|
@LibEntry{warn (message [, tocont])|
|
||||||
|
|
||||||
Emits a warning with the given message.
|
Emits a warning with the given message.
|
||||||
Note that messages not ending with an end-of-line
|
A message in a call with @id{tocont} true should be
|
||||||
are assumed to be continued by the message in the next call.
|
continued in another call to this function.
|
||||||
|
The default for @id{tocont} is false.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
local version = "Lua 5.4"
|
local version = "Lua 5.4"
|
||||||
if _VERSION ~= version then
|
if _VERSION ~= version then
|
||||||
warn(string.format(
|
warn(string.format(
|
||||||
"This test suite is for %s, not for %s\nExiting tests\n", version, _VERSION))
|
"This test suite is for %s, not for %s\nExiting tests", version, _VERSION))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -190,16 +190,16 @@ assert(dofile('verybig.lua', true) == 10); collectgarbage()
|
|||||||
dofile('files.lua')
|
dofile('files.lua')
|
||||||
|
|
||||||
if #msgs > 0 then
|
if #msgs > 0 then
|
||||||
warn("#tests not performed:\n ")
|
warn("#tests not performed:", true)
|
||||||
for i=1,#msgs do
|
for i=1,#msgs do
|
||||||
warn(msgs[i]); warn("\n ")
|
warn("\n ", true); warn(msgs[i], true)
|
||||||
end
|
end
|
||||||
warn("\n")
|
warn("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
print("(there should be two warnings now)")
|
print("(there should be two warnings now)")
|
||||||
warn("#This is "); warn("an expected"); warn(" warning\n")
|
warn("#This is ", true); warn("an expected", true); warn(" warning")
|
||||||
warn("#This is"); warn(" another one\n")
|
warn("#This is", true); warn(" another one")
|
||||||
|
|
||||||
-- no test module should define 'debug'
|
-- no test module should define 'debug'
|
||||||
assert(debug == nil)
|
assert(debug == nil)
|
||||||
|
@ -114,13 +114,11 @@ end
|
|||||||
|
|
||||||
-- testing warnings
|
-- testing warnings
|
||||||
T.testC([[
|
T.testC([[
|
||||||
warning "#This shold be a"
|
warningC "#This shold be a"
|
||||||
warning " single "
|
warningC " single "
|
||||||
warning "warning
|
warning "warning"
|
||||||
"
|
warningC "#This should be "
|
||||||
warning "#This should be "
|
warning "another one"
|
||||||
warning "another one
|
|
||||||
"
|
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ assert(collectgarbage("incremental") == "generational")
|
|||||||
assert(collectgarbage("incremental") == "incremental")
|
assert(collectgarbage("incremental") == "incremental")
|
||||||
|
|
||||||
|
|
||||||
|
local function nop () end
|
||||||
|
|
||||||
local function gcinfo ()
|
local function gcinfo ()
|
||||||
return collectgarbage"count" * 1024
|
return collectgarbage"count" * 1024
|
||||||
end
|
end
|
||||||
@ -388,7 +390,7 @@ if T then
|
|||||||
collectgarbage()
|
collectgarbage()
|
||||||
for i = 1, 10 do assert(s[i]) end
|
for i = 1, 10 do assert(s[i]) end
|
||||||
|
|
||||||
getmetatable(u).__gc = false
|
getmetatable(u).__gc = nil
|
||||||
|
|
||||||
end
|
end
|
||||||
print '+'
|
print '+'
|
||||||
@ -604,8 +606,8 @@ if T then
|
|||||||
collectgarbage("stop")
|
collectgarbage("stop")
|
||||||
local x = T.newuserdata(0)
|
local x = T.newuserdata(0)
|
||||||
local y = T.newuserdata(0)
|
local y = T.newuserdata(0)
|
||||||
debug.setmetatable(y, {__gc = true}) -- bless the new udata before...
|
debug.setmetatable(y, {__gc = nop}) -- bless the new udata before...
|
||||||
debug.setmetatable(x, {__gc = true}) -- ...the old one
|
debug.setmetatable(x, {__gc = nop}) -- ...the old one
|
||||||
assert(T.gccolor(y) == "white")
|
assert(T.gccolor(y) == "white")
|
||||||
T.checkmemory()
|
T.checkmemory()
|
||||||
collectgarbage("restart")
|
collectgarbage("restart")
|
||||||
@ -631,6 +633,7 @@ if T then
|
|||||||
assert(T.totalmem("thread") == t + 1)
|
assert(T.totalmem("thread") == t + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- create an object to be collected when state is closed
|
-- create an object to be collected when state is closed
|
||||||
do
|
do
|
||||||
local setmetatable,assert,type,print,getmetatable =
|
local setmetatable,assert,type,print,getmetatable =
|
||||||
@ -650,7 +653,7 @@ end
|
|||||||
|
|
||||||
-- create several objects to raise errors when collected while closing state
|
-- create several objects to raise errors when collected while closing state
|
||||||
if T then
|
if T then
|
||||||
local error, assert, warn, find = error, assert, warn, string.find
|
local error, assert, find = error, assert, string.find
|
||||||
local n = 0
|
local n = 0
|
||||||
local lastmsg
|
local lastmsg
|
||||||
local mt = {__gc = function (o)
|
local mt = {__gc = function (o)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user