Browse Source

Better error messages for some polymorphic functions

New auxiliary functions/macros 'luaL_argexpected'/'luaL_typeerror'
ease the creation of error messages such as

  bad argument #2 to 'setmetatable' (nil or table expected, got boolean)

(The novelty being the "got boolean" part...)
Roberto Ierusalimschy 6 years ago
parent
commit
46beca5bed
7 changed files with 41 additions and 12 deletions
  1. 3 3
      lauxlib.c
  2. 5 0
      lauxlib.h
  3. 3 4
      lbaselib.c
  4. 1 1
      lcorolib.c
  5. 1 2
      ldblib.c
  6. 2 2
      lstrlib.c
  7. 26 0
      manual/manual.of

+ 3 - 3
lauxlib.c

@@ -185,7 +185,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
 }
 
 
-static int typeerror (lua_State *L, int arg, const char *tname) {
+int luaL_typeerror (lua_State *L, int arg, const char *tname) {
   const char *msg;
   const char *typearg;  /* name for the type of the actual argument */
   if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
@@ -200,7 +200,7 @@ static int typeerror (lua_State *L, int arg, const char *tname) {
 
 
 static void tag_error (lua_State *L, int arg, int tag) {
-  typeerror(L, arg, lua_typename(L, tag));
+  luaL_typeerror(L, arg, lua_typename(L, tag));
 }
 
 
@@ -339,7 +339,7 @@ LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
 
 LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
   void *p = luaL_testudata(L, ud, tname);
-  if (p == NULL) typeerror(L, ud, tname);
+  luaL_argexpected(L, p != NULL, ud, tname);
   return p;
 }
 

+ 5 - 0
lauxlib.h

@@ -48,6 +48,7 @@ LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
 LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
 LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
 LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
+LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname);
 LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
                                                           size_t *l);
 LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
@@ -126,6 +127,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
 
 #define luaL_argcheck(L, cond,arg,extramsg)	\
 		((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
+
+#define luaL_argexpected(L,cond,arg,tname)	\
+		((void)((cond) || luaL_typeerror(L, (arg), (tname))))
+
 #define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL))
 #define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL))
 

+ 3 - 4
lbaselib.c

@@ -125,8 +125,7 @@ static int luaB_getmetatable (lua_State *L) {
 static int luaB_setmetatable (lua_State *L) {
   int t = lua_type(L, 2);
   luaL_checktype(L, 1, LUA_TTABLE);
-  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
-                    "nil or table expected");
+  luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
   if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)
     return luaL_error(L, "cannot change a protected metatable");
   lua_settop(L, 2);
@@ -145,8 +144,8 @@ static int luaB_rawequal (lua_State *L) {
 
 static int luaB_rawlen (lua_State *L) {
   int t = lua_type(L, 1);
-  luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
-                   "table or string expected");
+  luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
+                      "table or string");
   lua_pushinteger(L, lua_rawlen(L, 1));
   return 1;
 }

+ 1 - 1
lcorolib.c

@@ -20,7 +20,7 @@
 
 static lua_State *getco (lua_State *L) {
   lua_State *co = lua_tothread(L, 1);
-  luaL_argcheck(L, co, 1, "thread expected");
+  luaL_argexpected(L, co, 1, "thread");
   return co;
 }
 

+ 1 - 2
ldblib.c

@@ -55,8 +55,7 @@ static int db_getmetatable (lua_State *L) {
 
 static int db_setmetatable (lua_State *L) {
   int t = lua_type(L, 2);
-  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
-                    "nil or table expected");
+  luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
   lua_settop(L, 2);
   lua_setmetatable(L, 1);
   return 1;  /* return 1st argument */

+ 2 - 2
lstrlib.c

@@ -857,9 +857,9 @@ static int str_gsub (lua_State *L) {
   lua_Integer n = 0;  /* replacement count */
   MatchState ms;
   luaL_Buffer b;
-  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
+  luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
                    tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
-                      "string/function/table expected");
+                      "string/function/table");
   luaL_buffinit(L, &b);
   if (anchor) {
     p++; lp--;  /* skip anchor character */

+ 26 - 0
manual/manual.of

@@ -4979,6 +4979,19 @@ This function never returns.
 
 }
 
+@APIEntry{
+void luaL_argexpected (lua_State *L,
+                       int cond,
+                       int arg,
+                       const char *tname);|
+@apii{0,0,v}
+
+Checks whether @id{cond} is true.
+If it is not, raises an error about the type of the argument @id{arg}
+with a standard message @seeF{luaL_typeerror}.
+
+}
+
 @APIEntry{typedef struct luaL_Buffer luaL_Buffer;|
 
 Type for a @def{string buffer}.
@@ -5713,6 +5726,19 @@ to start the traceback.
 
 }
 
+@APIEntry{const char *luaL_typeerror (lua_State *L,
+                                      int arg,
+                                      const char *tname);|
+@apii{0,0,v}
+
+Raises a type error for argument @id{arg}
+of the @N{C function} that called it,
+using a standard message;
+@id{tname} is a @Q{name} for the expected type.
+This function never returns.
+
+}
+
 @APIEntry{const char *luaL_typename (lua_State *L, int index);|
 @apii{0,0,-}