diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-05-16 15:54:01 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-05-16 15:54:01 -0300 |
| commit | e2be310a85df0b8eb5c406aa0397088a66b98c47 (patch) | |
| tree | 350f6dd4911c9b9011e5e03a04d02b8c2056b8c4 | |
| parent | 17159b491c98e7da79b413d8b0ca770a1af116f3 (diff) | |
| download | lua-e2be310a85df0b8eb5c406aa0397088a66b98c47.tar.gz lua-e2be310a85df0b8eb5c406aa0397088a66b98c47.tar.bz2 lua-e2be310a85df0b8eb5c406aa0397088a66b98c47.zip | |
better(?) implementation for 'pcall'/'xpcall' (regarding the insertion
of the boolean first result)
| -rw-r--r-- | lbaselib.c | 55 |
1 files changed, 35 insertions, 20 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lbaselib.c,v 1.285 2014/03/12 20:57:40 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.286 2014/05/01 18:18:06 roberto Exp roberto $ |
| 3 | ** Basic library | 3 | ** Basic library |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -379,44 +379,59 @@ static int luaB_select (lua_State *L) { | |||
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | 381 | ||
| 382 | static int finishpcall (lua_State *L, int status) { | 382 | /* |
| 383 | if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */ | 383 | ** Finishes a 'pcall' or 'xpcall'. Both functions already pushed a |
| 384 | lua_settop(L, 0); /* create space for return values */ | 384 | ** 'true' before doing the call, so in case of sucess 'finishpcall' |
| 385 | lua_pushboolean(L, 0); | 385 | ** only has to return everything in the stack minus 'extra' values |
| 386 | lua_pushstring(L, "stack overflow"); | 386 | ** (where 'extra' is exactly the number of items to be ignored). |
| 387 | */ | ||
| 388 | static int finishpcall (lua_State *L, int ok, int extra) { | ||
| 389 | if (!ok) { /* error? */ | ||
| 390 | lua_pushboolean(L, 0); /* first result (false) */ | ||
| 391 | lua_pushvalue(L, -2); /* error message */ | ||
| 387 | return 2; /* return false, msg */ | 392 | return 2; /* return false, msg */ |
| 388 | } | 393 | } |
| 389 | lua_pushboolean(L, status); /* first result (status) */ | 394 | else |
| 390 | lua_replace(L, 1); /* put first result in first slot */ | 395 | return lua_gettop(L) - extra; /* return all results */ |
| 391 | return lua_gettop(L); | ||
| 392 | } | 396 | } |
| 393 | 397 | ||
| 394 | 398 | ||
| 399 | /* | ||
| 400 | ** Continuation function for 'pcall' and 'xpcall': get appropriate | ||
| 401 | ** state through 'lua_getctx' and call 'finishpcall' to finish the | ||
| 402 | ** original function. | ||
| 403 | */ | ||
| 395 | static int pcallcont (lua_State *L) { | 404 | static int pcallcont (lua_State *L) { |
| 396 | int status = lua_getctx(L, NULL); | 405 | int extra; |
| 397 | return finishpcall(L, (status == LUA_YIELD)); | 406 | int status = lua_getctx(L, &extra); |
| 407 | return finishpcall(L, (status == LUA_YIELD), extra); | ||
| 398 | } | 408 | } |
| 399 | 409 | ||
| 400 | 410 | ||
| 401 | static int luaB_pcall (lua_State *L) { | 411 | static int luaB_pcall (lua_State *L) { |
| 402 | int status; | 412 | int status; |
| 403 | luaL_checkany(L, 1); | 413 | luaL_checkany(L, 1); |
| 404 | lua_pushnil(L); | 414 | lua_pushboolean(L, 1); /* first result if no errors */ |
| 405 | lua_insert(L, 1); /* create space for status result */ | 415 | lua_insert(L, 1); /* put it in place */ |
| 406 | status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); | 416 | status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); |
| 407 | return finishpcall(L, (status == LUA_OK)); | 417 | return finishpcall(L, (status == LUA_OK), 0); |
| 408 | } | 418 | } |
| 409 | 419 | ||
| 410 | 420 | ||
| 421 | /* | ||
| 422 | ** Do a protected call with error handling. After 'lua_rotate', the | ||
| 423 | ** stack will have <f, err, true, f, [args...]>; so, the function passes | ||
| 424 | ** 2 to 'finishpcall' to skip the 2 first values when returning results. | ||
| 425 | */ | ||
| 411 | static int luaB_xpcall (lua_State *L) { | 426 | static int luaB_xpcall (lua_State *L) { |
| 412 | int status; | 427 | int status; |
| 413 | int n = lua_gettop(L); | 428 | int n = lua_gettop(L); |
| 414 | luaL_argcheck(L, n >= 2, 2, "value expected"); | 429 | luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ |
| 415 | lua_pushvalue(L, 1); /* exchange function... */ | 430 | lua_pushboolean(L, 1); /* first result */ |
| 416 | lua_copy(L, 2, 1); /* ...and error handler */ | 431 | lua_pushvalue(L, 1); /* function */ |
| 417 | lua_replace(L, 2); | 432 | lua_rotate(L, 3, 2); /* move them below function's arguments */ |
| 418 | status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont); | 433 | status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, pcallcont); |
| 419 | return finishpcall(L, (status == LUA_OK)); | 434 | return finishpcall(L, (status == LUA_OK), 2); |
| 420 | } | 435 | } |
| 421 | 436 | ||
| 422 | 437 | ||
