aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-28 15:42:34 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-28 15:42:34 -0200
commit437a5b07d415e1a74160ddfd804017171d6cc5cb (patch)
tree861f9a56ae175eaed91c163409c33ab85bee7ff9
parentba7da13ec5938f978c37d63aa40a3e340b301f79 (diff)
downloadlua-437a5b07d415e1a74160ddfd804017171d6cc5cb.tar.gz
lua-437a5b07d415e1a74160ddfd804017171d6cc5cb.tar.bz2
lua-437a5b07d415e1a74160ddfd804017171d6cc5cb.zip
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.
-rw-r--r--lapi.c18
-rw-r--r--lauxlib.c28
-rw-r--r--lbaselib.c8
-rw-r--r--lstate.c2
-rw-r--r--lstate.h2
-rw-r--r--ltests.c33
-rw-r--r--lua.h14
-rw-r--r--manual/manual.of56
-rw-r--r--testes/all.lua13
-rw-r--r--testes/api.lua14
10 files changed, 173 insertions, 15 deletions
diff --git a/lapi.c b/lapi.c
index 2d10bb73..0f0166e5 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1267,6 +1267,24 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
1267} 1267}
1268 1268
1269 1269
1270void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud) {
1271 lua_lock(L);
1272 G(L)->ud_warn = ud;
1273 G(L)->warnf = f;
1274 lua_unlock(L);
1275}
1276
1277
1278void lua_warning (lua_State *L, const char *msg) {
1279 lua_WarnFunction wf = G(L)->warnf;
1280 lua_lock(L);
1281 if (wf != NULL)
1282 wf(&G(L)->ud_warn, msg);
1283 lua_unlock(L);
1284}
1285
1286
1287
1270LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { 1288LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
1271 Udata *u; 1289 Udata *u;
1272 lua_lock(L); 1290 lua_lock(L);
diff --git a/lauxlib.c b/lauxlib.c
index 769586b6..abf923f8 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -986,9 +986,35 @@ static int panic (lua_State *L) {
986} 986}
987 987
988 988
989/*
990** checks whether 'message' ends with end-of-line
991** (and therefore is the last part of a warning)
992*/
993static int islast (const char *message) {
994 size_t len = strlen(message);
995 return (len > 0 && message[len - 1] == '\n');
996}
997
998
999/*
1000** Emit a warning. If '*pud' is NULL, previous message was to be
1001** continued by the current one.
1002*/
1003static void warnf (void **pud, const char *message) {
1004 if (*pud == NULL) /* previous message was not the last? */
1005 lua_writestringerror("%s", message);
1006 else /* start a new warning */
1007 lua_writestringerror("Lua warning: %s", message);
1008 *pud = (islast(message)) ? pud : NULL;
1009}
1010
1011
989LUALIB_API lua_State *luaL_newstate (void) { 1012LUALIB_API lua_State *luaL_newstate (void) {
990 lua_State *L = lua_newstate(l_alloc, NULL); 1013 lua_State *L = lua_newstate(l_alloc, NULL);
991 if (L) lua_atpanic(L, &panic); 1014 if (L) {
1015 lua_atpanic(L, &panic);
1016 lua_setwarnf(L, warnf, L);
1017 }
992 return L; 1018 return L;
993} 1019}
994 1020
diff --git a/lbaselib.c b/lbaselib.c
index 7c0ebfec..26683a1d 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -43,6 +43,13 @@ static int luaB_print (lua_State *L) {
43} 43}
44 44
45 45
46static int luaB_warn (lua_State *L) {
47 const char *msg = luaL_checkstring(L, 1);
48 lua_warning(L, msg);
49 return 0;
50}
51
52
46#define SPACECHARS " \f\n\r\t\v" 53#define SPACECHARS " \f\n\r\t\v"
47 54
48static const char *b_str2int (const char *s, int base, lua_Integer *pn) { 55static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
@@ -482,6 +489,7 @@ static const luaL_Reg base_funcs[] = {
482 {"pairs", luaB_pairs}, 489 {"pairs", luaB_pairs},
483 {"pcall", luaB_pcall}, 490 {"pcall", luaB_pcall},
484 {"print", luaB_print}, 491 {"print", luaB_print},
492 {"warn", luaB_warn},
485 {"rawequal", luaB_rawequal}, 493 {"rawequal", luaB_rawequal},
486 {"rawlen", luaB_rawlen}, 494 {"rawlen", luaB_rawlen},
487 {"rawget", luaB_rawget}, 495 {"rawget", luaB_rawget},
diff --git a/lstate.c b/lstate.c
index 04a9e064..b3e9ec60 100644
--- a/lstate.c
+++ b/lstate.c
@@ -365,6 +365,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
365 L->next = NULL; 365 L->next = NULL;
366 g->frealloc = f; 366 g->frealloc = f;
367 g->ud = ud; 367 g->ud = ud;
368 g->warnf = NULL;
369 g->ud_warn = NULL;
368 g->mainthread = L; 370 g->mainthread = L;
369 g->seed = luai_makeseed(L); 371 g->seed = luai_makeseed(L);
370 g->gcrunning = 0; /* no GC while building state */ 372 g->gcrunning = 0; /* no GC while building state */
diff --git a/lstate.h b/lstate.h
index b069b390..f3793256 100644
--- a/lstate.h
+++ b/lstate.h
@@ -231,6 +231,8 @@ typedef struct global_State {
231 TString *tmname[TM_N]; /* array with tag-method names */ 231 TString *tmname[TM_N]; /* array with tag-method names */
232 struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ 232 struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
233 TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ 233 TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
234 lua_WarnFunction warnf; /* warning function */
235 void *ud_warn; /* auxiliary data to 'warnf' */
234} global_State; 236} global_State;
235 237
236 238
diff --git a/ltests.c b/ltests.c
index 0b5ed90b..5ea8b080 100644
--- a/ltests.c
+++ b/ltests.c
@@ -63,10 +63,36 @@ static void pushobject (lua_State *L, const TValue *o) {
63} 63}
64 64
65 65
66static void badexit (void) {
67 /* avoid assertion failures when exiting */
68 l_memcontrol.numblocks = l_memcontrol.total = 0;
69 exit(EXIT_FAILURE);
70}
71
72
66static int tpanic (lua_State *L) { 73static int tpanic (lua_State *L) {
67 fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", 74 fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
68 lua_tostring(L, -1)); 75 lua_tostring(L, -1));
69 return (exit(EXIT_FAILURE), 0); /* do not return to Lua */ 76 return (badexit(), 0); /* do not return to Lua */
77}
78
79
80static int islast (const char *message) {
81 size_t len = strlen(message);
82 return (len > 0 && message[len - 1] == '\n');
83}
84
85
86static void warnf (void **pud, const char *msg) {
87 if (*pud == NULL) /* continuation line? */
88 printf("%s", msg); /* print it */
89 else if (msg[0] == '*') /* expected warning? */
90 printf("Expected Lua warning: %s", msg + 1); /* print without the star */
91 else { /* a real warning; should not happen during tests */
92 fprintf(stderr, "Warning in test mode (%s), aborting...\n", msg);
93 badexit();
94 }
95 *pud = islast(msg) ? pud : NULL;
70} 96}
71 97
72 98
@@ -1405,6 +1431,10 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
1405 const char *msg = getstring; 1431 const char *msg = getstring;
1406 printf("%s\n", msg); 1432 printf("%s\n", msg);
1407 } 1433 }
1434 else if EQ("warning") {
1435 const char *msg = getstring;
1436 lua_warning(L1, msg);
1437 }
1408 else if EQ("pushbool") { 1438 else if EQ("pushbool") {
1409 lua_pushboolean(L1, getnum); 1439 lua_pushboolean(L1, getnum);
1410 } 1440 }
@@ -1743,6 +1773,7 @@ static void checkfinalmem (void) {
1743int luaB_opentests (lua_State *L) { 1773int luaB_opentests (lua_State *L) {
1744 void *ud; 1774 void *ud;
1745 lua_atpanic(L, &tpanic); 1775 lua_atpanic(L, &tpanic);
1776 lua_setwarnf(L, &warnf, L);
1746 atexit(checkfinalmem); 1777 atexit(checkfinalmem);
1747 lua_assert(lua_getallocf(L, &ud) == debug_realloc); 1778 lua_assert(lua_getallocf(L, &ud) == debug_realloc);
1748 lua_assert(ud == cast_voidp(&l_memcontrol)); 1779 lua_assert(ud == cast_voidp(&l_memcontrol));
diff --git a/lua.h b/lua.h
index 95ce5a2e..a6f8268b 100644
--- a/lua.h
+++ b/lua.h
@@ -126,6 +126,13 @@ typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
126typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); 126typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
127 127
128 128
129/*
130** Type for warning functions
131*/
132typedef void (*lua_WarnFunction) (void **pud, const char *msg);
133
134
135
129 136
130/* 137/*
131** generic extra include file 138** generic extra include file
@@ -300,6 +307,13 @@ LUA_API int (lua_isyieldable) (lua_State *L);
300 307
301 308
302/* 309/*
310** Warning-related functions
311*/
312LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
313LUA_API void (lua_warning) (lua_State *L, const char *msg);
314
315
316/*
303** garbage-collection function and options 317** garbage-collection function and options
304*/ 318*/
305 319
diff --git a/manual/manual.of b/manual/manual.of
index 044bd09c..196ea1ef 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1795,7 +1795,7 @@ Functions with any detectable difference
1795(different behavior, different definition) are always different. 1795(different behavior, different definition) are always different.
1796Functions created at different times but with no detectable differences 1796Functions created at different times but with no detectable differences
1797may be classified as equal or not 1797may be classified as equal or not
1798(depending on internal cashing details). 1798(depending on internal caching details).
1799 1799
1800You can change the way that Lua compares tables and userdata 1800You can change the way that Lua compares tables and userdata
1801by using the @idx{__eq} metamethod @see{metatable}. 1801by using the @idx{__eq} metamethod @see{metatable}.
@@ -4033,6 +4033,16 @@ for the @Q{newindex} event @see{metatable}.
4033 4033
4034} 4034}
4035 4035
4036@APIEntry{int lua_setiuservalue (lua_State *L, int index, int n);|
4037@apii{1,0,-}
4038
4039Pops a value from the stack and sets it as
4040the new @id{n}-th user value associated to the
4041full userdata at the given index.
4042Returns 0 if the userdata does not have that value.
4043
4044}
4045
4036@APIEntry{void lua_setmetatable (lua_State *L, int index);| 4046@APIEntry{void lua_setmetatable (lua_State *L, int index);|
4037@apii{1,0,-} 4047@apii{1,0,-}
4038 4048
@@ -4066,13 +4076,13 @@ If @id{index} @N{is 0}, then all stack elements are removed.
4066 4076
4067} 4077}
4068 4078
4069@APIEntry{int lua_setiuservalue (lua_State *L, int index, int n);| 4079@APIEntry{void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud);|
4070@apii{1,0,-} 4080@apii{0,0,-}
4071 4081
4072Pops a value from the stack and sets it as 4082Sets the @x{warning function} to be used by Lua to emit warnings
4073the new @id{n}-th user value associated to the 4083@see{lua_WarnFunction}.
4074full userdata at the given index. 4084The @id{ud} parameter initializes the slot @id{pud} passed to
4075Returns 0 if the userdata does not have that value. 4085the warning function.
4076 4086
4077} 4087}
4078 4088
@@ -4335,6 +4345,30 @@ Returns the version number of this core.
4335} 4345}
4336 4346
4337@APIEntry{ 4347@APIEntry{
4348typedef void (*lua_WarnFunction) (void **pud, const char *msg);|
4349
4350The type of @x{warning function}s, called by Lua to emit warnings.
4351The first parameter is the address of a writable slot,
4352constant for a given Lua state and
4353initialized by @Lid{lua_setwarnf}.
4354The second parameter is the warning message.
4355This function should assume that
4356a message not ending with an end-of-line will be
4357continued by the message in the next call.
4358
4359}
4360
4361@APIEntry{
4362void lua_warning (lua_State *L, const char *msg);|
4363@apii{0,0,-}
4364
4365Emits a warning with the given message.
4366A message not ending with an end-of-line should be
4367continued in another call to this function.
4368
4369}
4370
4371@APIEntry{
4338typedef int (*lua_Writer) (lua_State *L, 4372typedef int (*lua_Writer) (lua_State *L,
4339 const void* p, 4373 const void* p,
4340 size_t sz, 4374 size_t sz,
@@ -4345,7 +4379,7 @@ Every time it produces another piece of chunk,
4345@Lid{lua_dump} calls the writer, 4379@Lid{lua_dump} calls the writer,
4346passing along the buffer to be written (@id{p}), 4380passing along the buffer to be written (@id{p}),
4347its size (@id{sz}), 4381its size (@id{sz}),
4348and the @id{data} parameter supplied to @Lid{lua_dump}. 4382and the @id{ud} parameter supplied to @Lid{lua_dump}.
4349 4383
4350The writer returns an error code: 4384The writer returns an error code:
4351@N{0 means} no errors; 4385@N{0 means} no errors;
@@ -6261,6 +6295,12 @@ The current value of this variable is @St{Lua 5.4}.
6261 6295
6262} 6296}
6263 6297
6298@LibEntry{warn (message)|
6299
6300Emits a warning with the given message.
6301
6302}
6303
6264@LibEntry{xpcall (f, msgh [, arg1, @Cdots])| 6304@LibEntry{xpcall (f, msgh [, arg1, @Cdots])|
6265 6305
6266This function is similar to @Lid{pcall}, 6306This function is similar to @Lid{pcall},
diff --git a/testes/all.lua b/testes/all.lua
index 84ba80a6..bde4195e 100644
--- a/testes/all.lua
+++ b/testes/all.lua
@@ -5,8 +5,8 @@
5 5
6local version = "Lua 5.4" 6local version = "Lua 5.4"
7if _VERSION ~= version then 7if _VERSION ~= version then
8 io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, 8 warn(string.format(
9 "\nExiting tests\n") 9 "This test suite is for %s, not for %s\nExiting tests\n", version, _VERSION))
10 return 10 return
11end 11end
12 12
@@ -190,11 +190,10 @@ assert(dofile('verybig.lua', true) == 10); collectgarbage()
190dofile('files.lua') 190dofile('files.lua')
191 191
192if #msgs > 0 then 192if #msgs > 0 then
193 print("\ntests not performed:") 193 warn("*tests not performed:\n ")
194 for i=1,#msgs do 194 for i=1,#msgs do
195 print(msgs[i]) 195 warn(msgs[i]); warn("\n ")
196 end 196 end
197 print()
198end 197end
199 198
200-- no test module should define 'debug' 199-- no test module should define 'debug'
@@ -220,6 +219,10 @@ local _G, showmem, print, format, clock, time, difftime, assert, open =
220local fname = T and "time-debug.txt" or "time.txt" 219local fname = T and "time-debug.txt" or "time.txt"
221local lasttime 220local lasttime
222 221
222
223warn("*This is "); warn("an expected"); warn(" warning\n")
224warn("*This is"); warn(" another one\n")
225
223if not usertests then 226if not usertests then
224 -- open file with time of last performed test 227 -- open file with time of last performed test
225 local f = io.open(fname) 228 local f = io.open(fname)
diff --git a/testes/api.lua b/testes/api.lua
index 6f35e132..b4d63866 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -111,6 +111,20 @@ do -- testing 'rotate'
111 tcheck(t, {10, 20, 30, 40}) 111 tcheck(t, {10, 20, 30, 40})
112end 112end
113 113
114
115-- testing warnings
116T.testC([[
117 warning "*This "
118 warning "warning "
119 warning "should be in a"
120 warning " single line
121"
122 warning "*This should be "
123 warning "another warning
124"
125]])
126
127
114-- testing message handlers 128-- testing message handlers
115do 129do
116 local f = T.makeCfunc[[ 130 local f = T.makeCfunc[[