mirror of
https://github.com/lua/lua.git
synced 2024-11-27 04:03:54 +08:00
Added a warning system to Lua
The warning system is just a way for Lua to emit warnings, messages to the programmer that do not interfere with the running program.
This commit is contained in:
parent
ba7da13ec5
commit
437a5b07d4
18
lapi.c
18
lapi.c
@ -1267,6 +1267,24 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
|
||||
}
|
||||
|
||||
|
||||
void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud) {
|
||||
lua_lock(L);
|
||||
G(L)->ud_warn = ud;
|
||||
G(L)->warnf = f;
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
||||
void lua_warning (lua_State *L, const char *msg) {
|
||||
lua_WarnFunction wf = G(L)->warnf;
|
||||
lua_lock(L);
|
||||
if (wf != NULL)
|
||||
wf(&G(L)->ud_warn, msg);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
|
||||
Udata *u;
|
||||
lua_lock(L);
|
||||
|
28
lauxlib.c
28
lauxlib.c
@ -986,9 +986,35 @@ static int panic (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** checks whether 'message' ends with end-of-line
|
||||
** (and therefore is the last part of a warning)
|
||||
*/
|
||||
static int islast (const char *message) {
|
||||
size_t len = strlen(message);
|
||||
return (len > 0 && message[len - 1] == '\n');
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Emit a warning. If '*pud' is NULL, previous message was to be
|
||||
** 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) {
|
||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
||||
if (L) lua_atpanic(L, &panic);
|
||||
if (L) {
|
||||
lua_atpanic(L, &panic);
|
||||
lua_setwarnf(L, warnf, L);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,13 @@ static int luaB_print (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
static int luaB_warn (lua_State *L) {
|
||||
const char *msg = luaL_checkstring(L, 1);
|
||||
lua_warning(L, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define SPACECHARS " \f\n\r\t\v"
|
||||
|
||||
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
|
||||
@ -482,6 +489,7 @@ static const luaL_Reg base_funcs[] = {
|
||||
{"pairs", luaB_pairs},
|
||||
{"pcall", luaB_pcall},
|
||||
{"print", luaB_print},
|
||||
{"warn", luaB_warn},
|
||||
{"rawequal", luaB_rawequal},
|
||||
{"rawlen", luaB_rawlen},
|
||||
{"rawget", luaB_rawget},
|
||||
|
2
lstate.c
2
lstate.c
@ -365,6 +365,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||
L->next = NULL;
|
||||
g->frealloc = f;
|
||||
g->ud = ud;
|
||||
g->warnf = NULL;
|
||||
g->ud_warn = NULL;
|
||||
g->mainthread = L;
|
||||
g->seed = luai_makeseed(L);
|
||||
g->gcrunning = 0; /* no GC while building state */
|
||||
|
2
lstate.h
2
lstate.h
@ -231,6 +231,8 @@ typedef struct global_State {
|
||||
TString *tmname[TM_N]; /* array with tag-method names */
|
||||
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
|
||||
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
||||
lua_WarnFunction warnf; /* warning function */
|
||||
void *ud_warn; /* auxiliary data to 'warnf' */
|
||||
} global_State;
|
||||
|
||||
|
||||
|
33
ltests.c
33
ltests.c
@ -63,10 +63,36 @@ static void pushobject (lua_State *L, const TValue *o) {
|
||||
}
|
||||
|
||||
|
||||
static void badexit (void) {
|
||||
/* avoid assertion failures when exiting */
|
||||
l_memcontrol.numblocks = l_memcontrol.total = 0;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static int tpanic (lua_State *L) {
|
||||
fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
|
||||
lua_tostring(L, -1));
|
||||
return (exit(EXIT_FAILURE), 0); /* do not return to Lua */
|
||||
return (badexit(), 0); /* do not return to Lua */
|
||||
}
|
||||
|
||||
|
||||
static int islast (const char *message) {
|
||||
size_t len = strlen(message);
|
||||
return (len > 0 && message[len - 1] == '\n');
|
||||
}
|
||||
|
||||
|
||||
static void warnf (void **pud, const char *msg) {
|
||||
if (*pud == NULL) /* continuation line? */
|
||||
printf("%s", msg); /* print it */
|
||||
else if (msg[0] == '*') /* expected warning? */
|
||||
printf("Expected Lua warning: %s", msg + 1); /* print without the star */
|
||||
else { /* a real warning; should not happen during tests */
|
||||
fprintf(stderr, "Warning in test mode (%s), aborting...\n", msg);
|
||||
badexit();
|
||||
}
|
||||
*pud = islast(msg) ? pud : NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -1405,6 +1431,10 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
||||
const char *msg = getstring;
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
else if EQ("warning") {
|
||||
const char *msg = getstring;
|
||||
lua_warning(L1, msg);
|
||||
}
|
||||
else if EQ("pushbool") {
|
||||
lua_pushboolean(L1, getnum);
|
||||
}
|
||||
@ -1743,6 +1773,7 @@ static void checkfinalmem (void) {
|
||||
int luaB_opentests (lua_State *L) {
|
||||
void *ud;
|
||||
lua_atpanic(L, &tpanic);
|
||||
lua_setwarnf(L, &warnf, L);
|
||||
atexit(checkfinalmem);
|
||||
lua_assert(lua_getallocf(L, &ud) == debug_realloc);
|
||||
lua_assert(ud == cast_voidp(&l_memcontrol));
|
||||
|
14
lua.h
14
lua.h
@ -126,6 +126,13 @@ typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
|
||||
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
|
||||
|
||||
/*
|
||||
** Type for warning functions
|
||||
*/
|
||||
typedef void (*lua_WarnFunction) (void **pud, const char *msg);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** generic extra include file
|
||||
@ -299,6 +306,13 @@ LUA_API int (lua_isyieldable) (lua_State *L);
|
||||
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
|
||||
|
||||
|
||||
/*
|
||||
** Warning-related functions
|
||||
*/
|
||||
LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
|
||||
LUA_API void (lua_warning) (lua_State *L, const char *msg);
|
||||
|
||||
|
||||
/*
|
||||
** garbage-collection function and options
|
||||
*/
|
||||
|
@ -1795,7 +1795,7 @@ Functions with any detectable difference
|
||||
(different behavior, different definition) are always different.
|
||||
Functions created at different times but with no detectable differences
|
||||
may be classified as equal or not
|
||||
(depending on internal cashing details).
|
||||
(depending on internal caching details).
|
||||
|
||||
You can change the way that Lua compares tables and userdata
|
||||
by using the @idx{__eq} metamethod @see{metatable}.
|
||||
@ -4033,6 +4033,16 @@ for the @Q{newindex} event @see{metatable}.
|
||||
|
||||
}
|
||||
|
||||
@APIEntry{int lua_setiuservalue (lua_State *L, int index, int n);|
|
||||
@apii{1,0,-}
|
||||
|
||||
Pops a value from the stack and sets it as
|
||||
the new @id{n}-th user value associated to the
|
||||
full userdata at the given index.
|
||||
Returns 0 if the userdata does not have that value.
|
||||
|
||||
}
|
||||
|
||||
@APIEntry{void lua_setmetatable (lua_State *L, int index);|
|
||||
@apii{1,0,-}
|
||||
|
||||
@ -4066,13 +4076,13 @@ If @id{index} @N{is 0}, then all stack elements are removed.
|
||||
|
||||
}
|
||||
|
||||
@APIEntry{int lua_setiuservalue (lua_State *L, int index, int n);|
|
||||
@apii{1,0,-}
|
||||
@APIEntry{void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud);|
|
||||
@apii{0,0,-}
|
||||
|
||||
Pops a value from the stack and sets it as
|
||||
the new @id{n}-th user value associated to the
|
||||
full userdata at the given index.
|
||||
Returns 0 if the userdata does not have that value.
|
||||
Sets the @x{warning function} to be used by Lua to emit warnings
|
||||
@see{lua_WarnFunction}.
|
||||
The @id{ud} parameter initializes the slot @id{pud} passed to
|
||||
the warning function.
|
||||
|
||||
}
|
||||
|
||||
@ -4334,6 +4344,30 @@ Returns the version number of this core.
|
||||
|
||||
}
|
||||
|
||||
@APIEntry{
|
||||
typedef void (*lua_WarnFunction) (void **pud, const char *msg);|
|
||||
|
||||
The type of @x{warning function}s, called by Lua to emit warnings.
|
||||
The first parameter is the address of a writable slot,
|
||||
constant for a given Lua state and
|
||||
initialized by @Lid{lua_setwarnf}.
|
||||
The second parameter is the warning message.
|
||||
This function should assume that
|
||||
a message not ending with an end-of-line will be
|
||||
continued by the message in the next call.
|
||||
|
||||
}
|
||||
|
||||
@APIEntry{
|
||||
void lua_warning (lua_State *L, const char *msg);|
|
||||
@apii{0,0,-}
|
||||
|
||||
Emits a warning with the given message.
|
||||
A message not ending with an end-of-line should be
|
||||
continued in another call to this function.
|
||||
|
||||
}
|
||||
|
||||
@APIEntry{
|
||||
typedef int (*lua_Writer) (lua_State *L,
|
||||
const void* p,
|
||||
@ -4345,7 +4379,7 @@ Every time it produces another piece of chunk,
|
||||
@Lid{lua_dump} calls the writer,
|
||||
passing along the buffer to be written (@id{p}),
|
||||
its size (@id{sz}),
|
||||
and the @id{data} parameter supplied to @Lid{lua_dump}.
|
||||
and the @id{ud} parameter supplied to @Lid{lua_dump}.
|
||||
|
||||
The writer returns an error code:
|
||||
@N{0 means} no errors;
|
||||
@ -6261,6 +6295,12 @@ The current value of this variable is @St{Lua 5.4}.
|
||||
|
||||
}
|
||||
|
||||
@LibEntry{warn (message)|
|
||||
|
||||
Emits a warning with the given message.
|
||||
|
||||
}
|
||||
|
||||
@LibEntry{xpcall (f, msgh [, arg1, @Cdots])|
|
||||
|
||||
This function is similar to @Lid{pcall},
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
local version = "Lua 5.4"
|
||||
if _VERSION ~= version then
|
||||
io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION,
|
||||
"\nExiting tests\n")
|
||||
warn(string.format(
|
||||
"This test suite is for %s, not for %s\nExiting tests\n", version, _VERSION))
|
||||
return
|
||||
end
|
||||
|
||||
@ -190,11 +190,10 @@ assert(dofile('verybig.lua', true) == 10); collectgarbage()
|
||||
dofile('files.lua')
|
||||
|
||||
if #msgs > 0 then
|
||||
print("\ntests not performed:")
|
||||
warn("*tests not performed:\n ")
|
||||
for i=1,#msgs do
|
||||
print(msgs[i])
|
||||
warn(msgs[i]); warn("\n ")
|
||||
end
|
||||
print()
|
||||
end
|
||||
|
||||
-- no test module should define 'debug'
|
||||
@ -220,6 +219,10 @@ local _G, showmem, print, format, clock, time, difftime, assert, open =
|
||||
local fname = T and "time-debug.txt" or "time.txt"
|
||||
local lasttime
|
||||
|
||||
|
||||
warn("*This is "); warn("an expected"); warn(" warning\n")
|
||||
warn("*This is"); warn(" another one\n")
|
||||
|
||||
if not usertests then
|
||||
-- open file with time of last performed test
|
||||
local f = io.open(fname)
|
||||
|
@ -111,6 +111,20 @@ do -- testing 'rotate'
|
||||
tcheck(t, {10, 20, 30, 40})
|
||||
end
|
||||
|
||||
|
||||
-- testing warnings
|
||||
T.testC([[
|
||||
warning "*This "
|
||||
warning "warning "
|
||||
warning "should be in a"
|
||||
warning " single line
|
||||
"
|
||||
warning "*This should be "
|
||||
warning "another warning
|
||||
"
|
||||
]])
|
||||
|
||||
|
||||
-- testing message handlers
|
||||
do
|
||||
local f = T.makeCfunc[[
|
||||
|
Loading…
Reference in New Issue
Block a user