mirror of
https://github.com/lua/lua
synced 2026-06-08 15:34:49 +00:00
Compare commits
431 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 40b76de2d7 | |||
| 0465c23b3e | |||
| 53b41d0cdd | |||
| 36c1f6d949 | |||
| 0da6d320f7 | |||
| ae23e72601 | |||
| 4c5d5063a5 | |||
| 3228a97c6a | |||
| 0c16a42d61 | |||
| d0bd25d2e7 | |||
| 29cf284089 | |||
| c037162a1a | |||
| efddc2309c | |||
| f1bb2773bb | |||
| 51269bd783 | |||
| 377cbea61b | |||
| 36d5d2b284 | |||
| 9e501d9855 | |||
| 10eb89d114 | |||
| 7c40c5edb2 | |||
| b60e2bcd7c | |||
| c6b4848238 | |||
| efbc297545 | |||
| cfcaa9493b | |||
| 3360710bd3 | |||
| e992c6a959 | |||
| f5d1e8639b | |||
| 2a7cf4f319 | |||
| 5cfc725a8b | |||
| 45c7ae5b1b | |||
| 962f444a75 | |||
| c4e2c91973 | |||
| 632a71b24d | |||
| 578ae5745c | |||
| a5522f06d2 | |||
| 3d03ae5bd6 | |||
| 82d721a855 | |||
| 104b0fc700 | |||
| 8164d09338 | |||
| 985ef32248 | |||
| a07f6a8241 | |||
| f33cc4ddec | |||
| d94f7ba304 | |||
| 4cf498210e | |||
| 5b7d998764 | |||
| 81f4def54f | |||
| e44f3a2ffc | |||
| f791bb6906 | |||
| d342328e5b | |||
| 0149b781d4 | |||
| d4eff00234 | |||
| fca974486d | |||
| 26755cad99 | |||
| b352217b84 | |||
| 9c66903cc5 | |||
| 30a7b93439 | |||
| 7a92f3f99a | |||
| 3347c9d32d | |||
| 25c54fe60e | |||
| 0cc3c9447c | |||
| 8fb1af0e33 | |||
| 140b672e2e | |||
| 9ea06e61f2 | |||
| ffbcadfb41 | |||
| 0b73ed8f08 | |||
| f87416f1a3 | |||
| 03a3473687 | |||
| 9a3940380a | |||
| 711890624f | |||
| 13d2326a23 | |||
| 06c5d3825f | |||
| c345877e4c | |||
| 907d172c11 | |||
| 88aa4049ad | |||
| c688b00f73 | |||
| dd095677e3 | |||
| 53dc5a3bba | |||
| 5b179eaf6a | |||
| 8fddca81e7 | |||
| c33bb08ffe | |||
| e3716ee161 | |||
| 303f415559 | |||
| ccb8b307f1 | |||
| 60b6599e83 | |||
| c612685d4b | |||
| 85a3c1699c | |||
| f65d1f9e02 | |||
| 942c10a5e3 | |||
| 8485687908 | |||
| 03d672a95c | |||
| 03bf7fdd4f | |||
| 59a1adf194 | |||
| cfce6f4b20 | |||
| 1da89da62f | |||
| f6c627af20 | |||
| 270a58c062 | |||
| 30531c291b | |||
| 07b009c371 | |||
| f711567448 | |||
| 9386e49a31 | |||
| 8cd7ae7da0 | |||
| 0cecf1ab6d | |||
| e657a48ea5 | |||
| fd897027f1 | |||
| d05fe48bfd | |||
| 519c57d597 | |||
| c15543b9af | |||
| be05c44481 | |||
| 6d53701c7a | |||
| abbae57c78 | |||
| f2c1531e6c | |||
| ded2ad2d86 | |||
| 3fb7a77731 | |||
| fded0b4a84 | |||
| 3b9dd52be0 | |||
| 7dc6aae290 | |||
| 5b1ab8efdc | |||
| 7ade155762 | |||
| d827e96f33 | |||
| 3f0ea90aa8 | |||
| 4365a45d68 | |||
| be81209063 | |||
| e055905914 | |||
| 9b014d4bcd | |||
| 50fd8d03c3 | |||
| 3dbb1a4b89 | |||
| 3dd8ea54da | |||
| 620f49a7aa | |||
| 3f4f28010a | |||
| 93e347b519 | |||
| f4123b2fc2 | |||
| 37a1b72706 | |||
| ef5d171cc8 | |||
| b0f3df16a4 | |||
| cad5a4fdbb | |||
| fdbb4c2341 | |||
| 921832be8d | |||
| 205f9aa67b | |||
| 94d38560c3 | |||
| c2dc6e8e94 | |||
| 22974326ca | |||
| c931d86e98 | |||
| d9e0f64a5d | |||
| ab66652b32 | |||
| 4398e488e6 | |||
| 808976bb59 | |||
| b5b1995f29 | |||
| cb88c1cd5d | |||
| ee99452158 | |||
| 127a8e80fe | |||
| f9e35627ed | |||
| ceac82f78b | |||
| e5f4927a0b | |||
| cd38fe8cf3 | |||
| fa1382b5cd | |||
| d1e677c52b | |||
| f7439112a5 | |||
| 39a14ea7d7 | |||
| c4e7cdb541 | |||
| 7d7ae8781e | |||
| 724012d3d0 | |||
| 664bda02ba | |||
| 2d8d5c74b5 | |||
| 3cdd49c94a | |||
| 10e931da82 | |||
| 4b107a8776 | |||
| 429761d7d2 | |||
| 915c29f8bd | |||
| 7ca3c40b50 | |||
| 8a3a49250c | |||
| 1ec251e091 | |||
| 5894ca7b95 | |||
| abf8b1cd4a | |||
| 2a307f898b | |||
| f81d0bbd4f | |||
| 1c40ff9faa | |||
| 7538f3886d | |||
| 412e9a4d95 | |||
| 25a491fe34 | |||
| b4b616bdf2 | |||
| bb93f04d87 | |||
| 975d4e0592 | |||
| 04e495403b | |||
| 62afbc6bfc | |||
| 002beeebe7 | |||
| 9329eeac3b | |||
| 682efe2678 | |||
| 50c7c915ee | |||
| b117bdb344 | |||
| f12ce4029d | |||
| a4762b6ffe | |||
| d4247befa1 | |||
| ee6a4cd1ec | |||
| 8a4419b119 | |||
| 9a91fe1640 | |||
| 2491b87c10 | |||
| 0de8191152 | |||
| 853311e5b1 | |||
| 25a2dac2bc | |||
| e3ce88c9e8 | |||
| 5ffcd458f0 | |||
| 9b01da97e3 | |||
| 258355734d | |||
| d0815046d0 | |||
| 3d54b42d59 | |||
| e4f418f07c | |||
| 20d42ccaae | |||
| 70d6975018 | |||
| 00e34375ec | |||
| 45a8f1b593 | |||
| 8fac494509 | |||
| 9b72355f99 | |||
| ddfa1fbccf | |||
| b443145ff3 | |||
| 4901853c11 | |||
| a04e0ffdb9 | |||
| 007b8c7a01 | |||
| fd0e1f530d | |||
| 75620b45ae | |||
| 3e88b72b8e | |||
| 8b752ddf14 | |||
| 1bf4b80f1a | |||
| 4c6afbcb01 | |||
| f2206b2abe | |||
| 0acd55898d | |||
| 15231d4fb2 | |||
| f407b3c4a1 | |||
| a546138d15 | |||
| cd4de92762 | |||
| 6b45ccf4ed | |||
| 93fd6892f8 | |||
| 193bf7919e | |||
| 366c855648 | |||
| 781219dbe1 | |||
| d71fbc3175 | |||
| c403e456b6 | |||
| 6ac7219da3 | |||
| 9904c253da | |||
| fb7e5b76c9 | |||
| c1dc08e8e8 | |||
| 0f7025dcae | |||
| ef28e5f789 | |||
| ec65ab878e | |||
| e24ce8c2b3 | |||
| a08d82eb13 | |||
| 55ac40f859 | |||
| 97ef8e7bd4 | |||
| aaf3533653 | |||
| b529aefc53 | |||
| d51022bf9e | |||
| bb7bb5944c | |||
| 94b503d95e | |||
| bdc85357aa | |||
| b291008cc2 | |||
| 814213b65f | |||
| cbdf4969ec | |||
| 262dc5729a | |||
| 9d985db7bb | |||
| 0897c0a428 | |||
| 5edacafcfa | |||
| 3507c3380f | |||
| 88a50ffa71 | |||
| 86a8e74824 | |||
| 9fa63a6268 | |||
| 0593256707 | |||
| ce6f5502c9 | |||
| ba71060381 | |||
| 3823fc6c81 | |||
| 52aa2b5d24 | |||
| cc2b66c856 | |||
| 65b07dd53d | |||
| 7237eb3f1c | |||
| 165389b27b | |||
| c8121ce34b | |||
| 7360f8d0fd | |||
| 6063c47031 | |||
| 0c9bec0d38 | |||
| c31d6774ac | |||
| 108e0bdc84 | |||
| b34a97a4af | |||
| 3e9dbe143d | |||
| 4a8e480864 | |||
| 17e0c29d9b | |||
| 8eb0abc9db | |||
| d862da6d04 | |||
| e288c5a918 | |||
| 7827c40c49 | |||
| e7af9cdf0b | |||
| 12b6f610b0 | |||
| e81f586001 | |||
| e2cc179454 | |||
| 5853c37a83 | |||
| ad0ea7813b | |||
| 666e95a66d | |||
| 4eda1acafa | |||
| ad73b33224 | |||
| 925fe8a0f2 | |||
| 789e7acdea | |||
| 74b4013538 | |||
| b719ff9399 | |||
| 35a2fed2d1 | |||
| 63d68bd657 | |||
| 842a83f09c | |||
| 011850a8f8 | |||
| 52b899d60d | |||
| 25cd3d377e | |||
| 1028f296a8 | |||
| 6d042a178f | |||
| eabf425c76 | |||
| 3b57e37e48 | |||
| 024f9064f1 | |||
| 7f4906f565 | |||
| b8a9d14032 | |||
| 19afd91687 | |||
| 37c215b43f | |||
| 9e99f3071d | |||
| fa075b7953 | |||
| 08a077d673 | |||
| 7923dbbf72 | |||
| 43c8e5bded | |||
| b8b709b6d4 | |||
| 81e4fce530 | |||
| 6baee9ef9d | |||
| edd8589f47 | |||
| 14e416355f | |||
| f33cda8d6e | |||
| 96f7714237 | |||
| 0554581605 | |||
| 07a9eab23a | |||
| c815c2f0eb | |||
| 9363a8b990 | |||
| 5ab6a5756b | |||
| 9b4f39ab14 | |||
| f4211a5ea4 | |||
| 1b3f507f62 | |||
| 6b51133a98 | |||
| cbae016202 | |||
| ab6a949522 | |||
| ea39042e13 | |||
| 05ec55f16b | |||
| f623b96932 | |||
| 9be74ccc21 | |||
| 819bd51d87 | |||
| f8d30826dd | |||
| 351ccd7332 | |||
| 09f3c2372f | |||
| c197885cb0 | |||
| 934e77a286 | |||
| 6443185167 | |||
| e15f1f2bb7 | |||
| b5c65705ca | |||
| 7ca8105a2e | |||
| 94689ac3ad | |||
| 86e8039a72 | |||
| 5a04f1851e | |||
| ab859fe59b | |||
| c4b71b7ba0 | |||
| 1de2f31694 | |||
| 02bab9fc25 | |||
| 5e08b41567 | |||
| 8c064fdc23 | |||
| cf08915d62 | |||
| c888ae0aea | |||
| d69789da1c | |||
| 8dea54877a | |||
| b5ab31a475 | |||
| 314745ed84 | |||
| 140cdcced5 | |||
| 0825cf237d | |||
| 7d4c7ae2af | |||
| 873588dc5f | |||
| b2f7b3b79f | |||
| 540d805226 | |||
| 7d6a97e42b | |||
| d70a0c91ad | |||
| 3e6818ca87 | |||
| f874d37fa2 | |||
| 88e5c6b80b | |||
| 35e01ed21d | |||
| e33e1bda97 | |||
| 6aabf4b15e | |||
| 5d8b5b9290 | |||
| 40565b4a08 | |||
| ff106c028c | |||
| fa2f294dd1 | |||
| d738c8d18b | |||
| 0270c204c2 | |||
| 82fae58e25 | |||
| efc7c5d503 | |||
| d324a0ccf9 | |||
| 152b51955a | |||
| ec61be9a7e | |||
| f356d5acdd | |||
| 9a77f57edc | |||
| be908a7d4d | |||
| 76953316d1 | |||
| 3d2bd1359d | |||
| 9ede317c70 | |||
| 8047b2d03e | |||
| ee645472eb | |||
| 413a393e62 | |||
| ba089bcb08 | |||
| 1e64c1391f | |||
| b85816b9a8 | |||
| c954db3924 | |||
| 14d2803e55 | |||
| 7f12bf40c4 | |||
| 26be27459b | |||
| cfbe378f90 | |||
| a1089b415a | |||
| f8c4c4fcf2 | |||
| 71bc69c2af | |||
| cd56f222b7 | |||
| 69b77b6fde | |||
| 997f11f543 | |||
| 02060b7a37 | |||
| a1f77a234a | |||
| c6cea857a4 | |||
| d61b0c6028 | |||
| 196bb94d66 | |||
| 603b2c64ad | |||
| 4a00f61276 | |||
| 42d40581dd | |||
| e435aaabef | |||
| 315639d3bb | |||
| c764ca71a6 | |||
| 295cde9454 | |||
| f3cfd5bf2b | |||
| 8426d9b4d4 | |||
| 1f3c6f4534 | |||
| 25b143dd34 |
@@ -1,7 +1,7 @@
|
|||||||
make -s -j
|
make -s -j
|
||||||
cd testes/libs; make -s
|
cd testes/libs; make -s
|
||||||
cd .. # back to directory 'testes'
|
cd .. # back to directory 'testes'
|
||||||
ulimit -S -s 1000
|
ulimit -S -s 1100
|
||||||
if { ../lua -W all.lua; } then
|
if { ../lua -W all.lua; } then
|
||||||
echo -e "\n\n final OK!!!!\n\n"
|
echo -e "\n\n final OK!!!!\n\n"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -12,38 +12,54 @@
|
|||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
|
||||||
|
|
||||||
/* Increments 'L->top', checking for stack overflows */
|
#if defined(LUA_USE_APICHECK)
|
||||||
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
|
#include <assert.h>
|
||||||
"stack overflow");}
|
#define api_check(l,e,msg) assert(e)
|
||||||
|
#else /* for testing */
|
||||||
|
#define api_check(l,e,msg) ((void)(l), lua_assert((e) && msg))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Increments 'L->top.p', checking for stack overflows */
|
||||||
|
#define api_incr_top(L) \
|
||||||
|
(L->top.p++, api_check(L, L->top.p <= L->ci->top.p, "stack overflow"))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** macros that are executed whenever program enters the Lua core
|
||||||
|
** ('lua_lock') and leaves the core ('lua_unlock')
|
||||||
|
*/
|
||||||
|
#if !defined(lua_lock)
|
||||||
|
#define lua_lock(L) ((void) 0)
|
||||||
|
#define lua_unlock(L) ((void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If a call returns too many multiple returns, the callee may not have
|
** If a call returns too many multiple returns, the callee may not have
|
||||||
** stack space to accommodate all results. In this case, this macro
|
** stack space to accommodate all results. In this case, this macro
|
||||||
** increases its stack space ('L->ci->top').
|
** increases its stack space ('L->ci->top.p').
|
||||||
*/
|
*/
|
||||||
#define adjustresults(L,nres) \
|
#define adjustresults(L,nres) \
|
||||||
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
|
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
|
||||||
|
L->ci->top.p = L->top.p; }
|
||||||
|
|
||||||
|
|
||||||
/* Ensure the stack has at least 'n' elements */
|
/* Ensure the stack has at least 'n' elements */
|
||||||
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
|
#define api_checknelems(L,n) \
|
||||||
"not enough elements in the stack")
|
api_check(L, (n) < (L->top.p - L->ci->func.p), \
|
||||||
|
"not enough elements in the stack")
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* Ensure the stack has at least 'n' elements to be popped. (Some
|
||||||
** To reduce the overhead of returning from C functions, the presence of
|
** functions only update a slot after checking it for popping, but that
|
||||||
** to-be-closed variables in these functions is coded in the CallInfo's
|
** is only an optimization for a pop followed by a push.)
|
||||||
** field 'nresults', in a way that functions with no to-be-closed variables
|
|
||||||
** with zero, one, or "all" wanted results have no overhead. Functions
|
|
||||||
** with other number of wanted results, as well as functions with
|
|
||||||
** variables to be closed, have an extra check.
|
|
||||||
*/
|
*/
|
||||||
|
#define api_checkpop(L,n) \
|
||||||
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
|
api_check(L, (n) < L->top.p - L->ci->func.p && \
|
||||||
|
L->tbclist.p < L->top.p - (n), \
|
||||||
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
|
"not enough free elements in the stack")
|
||||||
#define codeNresults(n) (-(n) - 3)
|
|
||||||
#define decodeNresults(n) (-(n) - 3)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,12 +25,7 @@
|
|||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
#if !defined(MAX_SIZET)
|
|
||||||
/* maximum value for size_t */
|
|
||||||
#define MAX_SIZET ((size_t)(~(size_t)0))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -80,6 +75,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
|||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
lua_getinfo(L, "f", ar); /* push function */
|
lua_getinfo(L, "f", ar); /* push function */
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||||
|
luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */
|
||||||
if (findfield(L, top + 1, 2)) {
|
if (findfield(L, top + 1, 2)) {
|
||||||
const char *name = lua_tostring(L, -1);
|
const char *name = lua_tostring(L, -1);
|
||||||
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
|
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
|
||||||
@@ -98,14 +94,14 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
|||||||
|
|
||||||
|
|
||||||
static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
||||||
if (pushglobalfuncname(L, ar)) { /* try first a global name */
|
if (*ar->namewhat != '\0') /* is there a name from code? */
|
||||||
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
|
|
||||||
lua_remove(L, -2); /* remove name */
|
|
||||||
}
|
|
||||||
else if (*ar->namewhat != '\0') /* is there a name from code? */
|
|
||||||
lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
|
lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
|
||||||
else if (*ar->what == 'm') /* main? */
|
else if (*ar->what == 'm') /* main? */
|
||||||
lua_pushliteral(L, "main chunk");
|
lua_pushliteral(L, "main chunk");
|
||||||
|
else if (pushglobalfuncname(L, ar)) { /* try a global name */
|
||||||
|
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
|
||||||
|
lua_remove(L, -2); /* remove name */
|
||||||
|
}
|
||||||
else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
|
else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
|
||||||
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
||||||
else /* nothing left... */
|
else /* nothing left... */
|
||||||
@@ -174,19 +170,27 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
|||||||
|
|
||||||
LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
|
const char *argword;
|
||||||
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
||||||
return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
|
return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
|
||||||
lua_getinfo(L, "n", &ar);
|
lua_getinfo(L, "nt", &ar);
|
||||||
if (strcmp(ar.namewhat, "method") == 0) {
|
if (arg <= ar.extraargs) /* error in an extra argument? */
|
||||||
arg--; /* do not count 'self' */
|
argword = "extra argument";
|
||||||
if (arg == 0) /* error is in the self argument itself? */
|
else {
|
||||||
return luaL_error(L, "calling '%s' on bad self (%s)",
|
arg -= ar.extraargs; /* do not count extra arguments */
|
||||||
ar.name, extramsg);
|
if (strcmp(ar.namewhat, "method") == 0) { /* colon syntax? */
|
||||||
|
arg--; /* do not count (extra) self argument */
|
||||||
|
if (arg == 0) /* error in self argument? */
|
||||||
|
return luaL_error(L, "calling '%s' on bad self (%s)",
|
||||||
|
ar.name, extramsg);
|
||||||
|
/* else go through; error in a regular argument */
|
||||||
|
}
|
||||||
|
argword = "argument";
|
||||||
}
|
}
|
||||||
if (ar.name == NULL)
|
if (ar.name == NULL)
|
||||||
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
||||||
return luaL_error(L, "bad argument #%d to '%s' (%s)",
|
return luaL_error(L, "bad %s #%d to '%s' (%s)",
|
||||||
arg, ar.name, extramsg);
|
argword, arg, ar.name, extramsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
|
|||||||
/*
|
/*
|
||||||
** Again, the use of 'lua_pushvfstring' ensures this function does
|
** Again, the use of 'lua_pushvfstring' ensures this function does
|
||||||
** not need reserved stack space when called. (At worst, it generates
|
** not need reserved stack space when called. (At worst, it generates
|
||||||
** an error with "stack overflow" instead of the given message.)
|
** a memory error instead of the given message.)
|
||||||
*/
|
*/
|
||||||
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
||||||
va_list argp;
|
va_list argp;
|
||||||
@@ -249,11 +253,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const char *msg;
|
||||||
luaL_pushfail(L);
|
luaL_pushfail(L);
|
||||||
|
msg = (en != 0) ? strerror(en) : "(no extra info)";
|
||||||
if (fname)
|
if (fname)
|
||||||
lua_pushfstring(L, "%s: %s", fname, strerror(en));
|
lua_pushfstring(L, "%s: %s", fname, msg);
|
||||||
else
|
else
|
||||||
lua_pushstring(L, strerror(en));
|
lua_pushstring(L, msg);
|
||||||
lua_pushinteger(L, en);
|
lua_pushinteger(L, en);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
@@ -470,18 +476,27 @@ typedef struct UBox {
|
|||||||
} UBox;
|
} UBox;
|
||||||
|
|
||||||
|
|
||||||
|
/* Resize the buffer used by a box. Optimize for the common case of
|
||||||
|
** resizing to the old size. (For instance, __gc will resize the box
|
||||||
|
** to 0 even after it was closed. 'pushresult' may also resize it to a
|
||||||
|
** final size that is equal to the one set when the buffer was created.)
|
||||||
|
*/
|
||||||
static void *resizebox (lua_State *L, int idx, size_t newsize) {
|
static void *resizebox (lua_State *L, int idx, size_t newsize) {
|
||||||
void *ud;
|
|
||||||
lua_Alloc allocf = lua_getallocf(L, &ud);
|
|
||||||
UBox *box = (UBox *)lua_touserdata(L, idx);
|
UBox *box = (UBox *)lua_touserdata(L, idx);
|
||||||
void *temp = allocf(ud, box->box, box->bsize, newsize);
|
if (box->bsize == newsize) /* not changing size? */
|
||||||
if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */
|
return box->box; /* keep the buffer */
|
||||||
lua_pushliteral(L, "not enough memory");
|
else {
|
||||||
lua_error(L); /* raise a memory error */
|
void *ud;
|
||||||
|
lua_Alloc allocf = lua_getallocf(L, &ud);
|
||||||
|
void *temp = allocf(ud, box->box, box->bsize, newsize);
|
||||||
|
if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */
|
||||||
|
lua_pushliteral(L, "not enough memory");
|
||||||
|
lua_error(L); /* raise a memory error */
|
||||||
|
}
|
||||||
|
box->box = temp;
|
||||||
|
box->bsize = newsize;
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
box->box = temp;
|
|
||||||
box->bsize = newsize;
|
|
||||||
return temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -526,14 +541,17 @@ static void newbox (lua_State *L) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
|
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
|
||||||
** bytes.
|
** bytes plus one for a terminating zero.
|
||||||
*/
|
*/
|
||||||
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
||||||
size_t newsize = B->size * 2; /* double buffer size */
|
size_t newsize = B->size;
|
||||||
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
|
if (l_unlikely(sz >= MAX_SIZE - B->n))
|
||||||
return luaL_error(B->L, "buffer too large");
|
return cast_sizet(luaL_error(B->L, "resulting string too large"));
|
||||||
if (newsize < B->n + sz) /* double is not big enough? */
|
/* else B->n + sz + 1 <= MAX_SIZE */
|
||||||
newsize = B->n + sz;
|
if (newsize <= MAX_SIZE/3 * 2) /* no overflow? */
|
||||||
|
newsize += (newsize >> 1); /* new size *= 1.5 */
|
||||||
|
if (newsize < B->n + sz + 1) /* not big enough? */
|
||||||
|
newsize = B->n + sz + 1;
|
||||||
return newsize;
|
return newsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,9 +611,23 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
|||||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||||
lua_State *L = B->L;
|
lua_State *L = B->L;
|
||||||
checkbufferlevel(B, -1);
|
checkbufferlevel(B, -1);
|
||||||
lua_pushlstring(L, B->b, B->n);
|
if (!buffonstack(B)) /* using static buffer? */
|
||||||
if (buffonstack(B))
|
lua_pushlstring(L, B->b, B->n); /* save result as regular string */
|
||||||
|
else { /* reuse buffer already allocated */
|
||||||
|
UBox *box = (UBox *)lua_touserdata(L, -1);
|
||||||
|
void *ud;
|
||||||
|
lua_Alloc allocf = lua_getallocf(L, &ud); /* function to free buffer */
|
||||||
|
size_t len = B->n; /* final string length */
|
||||||
|
char *s;
|
||||||
|
resizebox(L, -1, len + 1); /* adjust box size to content size */
|
||||||
|
s = (char*)box->box; /* final buffer address */
|
||||||
|
s[len] = '\0'; /* add ending zero */
|
||||||
|
/* clear box, as Lua will take control of the buffer */
|
||||||
|
box->bsize = 0; box->box = NULL;
|
||||||
|
lua_pushexternalstring(L, s, len, allocf, ud);
|
||||||
lua_closeslot(L, -2); /* close the box */
|
lua_closeslot(L, -2); /* close the box */
|
||||||
|
lua_gc(L, LUA_GCSTEP, len);
|
||||||
|
}
|
||||||
lua_remove(L, -2); /* remove box or placeholder from the stack */
|
lua_remove(L, -2); /* remove box or placeholder from the stack */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,7 +643,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
|
|||||||
** box (if existent) is not on the top of the stack. So, instead of
|
** box (if existent) is not on the top of the stack. So, instead of
|
||||||
** calling 'luaL_addlstring', it replicates the code using -2 as the
|
** calling 'luaL_addlstring', it replicates the code using -2 as the
|
||||||
** last argument to 'prepbuffsize', signaling that the box is (or will
|
** last argument to 'prepbuffsize', signaling that the box is (or will
|
||||||
** be) bellow the string being added to the buffer. (Box creation can
|
** be) below the string being added to the buffer. (Box creation can
|
||||||
** trigger an emergency GC, so we should not remove the string from the
|
** trigger an emergency GC, so we should not remove the string from the
|
||||||
** stack before we have the space guaranteed.)
|
** stack before we have the space guaranteed.)
|
||||||
*/
|
*/
|
||||||
@@ -649,13 +681,10 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
|
|||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* index of free-list header (after the predefined values) */
|
|
||||||
#define freelist (LUA_RIDX_LAST + 1)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The previously freed references form a linked list:
|
** The previously freed references form a linked list: t[1] is the index
|
||||||
** t[freelist] is the index of a first free index, or zero if list is
|
** of a first free index, t[t[1]] is the index of the second element,
|
||||||
** empty; t[t[freelist]] is the index of the second element; etc.
|
** etc. A zero signals the end of the list.
|
||||||
*/
|
*/
|
||||||
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||||
int ref;
|
int ref;
|
||||||
@@ -664,19 +693,18 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
|
|||||||
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
||||||
}
|
}
|
||||||
t = lua_absindex(L, t);
|
t = lua_absindex(L, t);
|
||||||
if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */
|
if (lua_rawgeti(L, t, 1) == LUA_TNUMBER) /* already initialized? */
|
||||||
|
ref = (int)lua_tointeger(L, -1); /* ref = t[1] */
|
||||||
|
else { /* first access */
|
||||||
|
lua_assert(!lua_toboolean(L, -1)); /* must be nil or false */
|
||||||
ref = 0; /* list is empty */
|
ref = 0; /* list is empty */
|
||||||
lua_pushinteger(L, 0); /* initialize as an empty list */
|
lua_pushinteger(L, 0); /* initialize as an empty list */
|
||||||
lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */
|
lua_rawseti(L, t, 1); /* ref = t[1] = 0 */
|
||||||
}
|
|
||||||
else { /* already initialized */
|
|
||||||
lua_assert(lua_isinteger(L, -1));
|
|
||||||
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
|
|
||||||
}
|
}
|
||||||
lua_pop(L, 1); /* remove element from stack */
|
lua_pop(L, 1); /* remove element from stack */
|
||||||
if (ref != 0) { /* any free element? */
|
if (ref != 0) { /* any free element? */
|
||||||
lua_rawgeti(L, t, ref); /* remove it from list */
|
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||||
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
|
lua_rawseti(L, t, 1); /* (t[1] = t[ref]) */
|
||||||
}
|
}
|
||||||
else /* no free elements */
|
else /* no free elements */
|
||||||
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
|
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
|
||||||
@@ -688,11 +716,11 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
|
|||||||
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
||||||
if (ref >= 0) {
|
if (ref >= 0) {
|
||||||
t = lua_absindex(L, t);
|
t = lua_absindex(L, t);
|
||||||
lua_rawgeti(L, t, freelist);
|
lua_rawgeti(L, t, 1);
|
||||||
lua_assert(lua_isinteger(L, -1));
|
lua_assert(lua_isinteger(L, -1));
|
||||||
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
|
lua_rawseti(L, t, ref); /* t[ref] = t[1] */
|
||||||
lua_pushinteger(L, ref);
|
lua_pushinteger(L, ref);
|
||||||
lua_rawseti(L, t, freelist); /* t[freelist] = ref */
|
lua_rawseti(L, t, 1); /* t[1] = ref */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,7 +734,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct LoadF {
|
typedef struct LoadF {
|
||||||
int n; /* number of pre-read characters */
|
unsigned n; /* number of pre-read characters */
|
||||||
FILE *f; /* file being read */
|
FILE *f; /* file being read */
|
||||||
char buff[BUFSIZ]; /* area for reading file */
|
char buff[BUFSIZ]; /* area for reading file */
|
||||||
} LoadF;
|
} LoadF;
|
||||||
@@ -714,7 +742,7 @@ typedef struct LoadF {
|
|||||||
|
|
||||||
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||||
LoadF *lf = (LoadF *)ud;
|
LoadF *lf = (LoadF *)ud;
|
||||||
(void)L; /* not used */
|
UNUSED(L);
|
||||||
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
||||||
*size = lf->n; /* return them (chars already in buffer) */
|
*size = lf->n; /* return them (chars already in buffer) */
|
||||||
lf->n = 0; /* no more pre-read characters */
|
lf->n = 0; /* no more pre-read characters */
|
||||||
@@ -731,25 +759,29 @@ static const char *getF (lua_State *L, void *ud, size_t *size) {
|
|||||||
|
|
||||||
|
|
||||||
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
||||||
const char *serr = strerror(errno);
|
int err = errno;
|
||||||
const char *filename = lua_tostring(L, fnameindex) + 1;
|
const char *filename = lua_tostring(L, fnameindex) + 1;
|
||||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
if (err != 0)
|
||||||
|
lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err));
|
||||||
|
else
|
||||||
|
lua_pushfstring(L, "cannot %s %s", what, filename);
|
||||||
lua_remove(L, fnameindex);
|
lua_remove(L, fnameindex);
|
||||||
return LUA_ERRFILE;
|
return LUA_ERRFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int skipBOM (LoadF *lf) {
|
/*
|
||||||
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
|
** Skip an optional BOM at the start of a stream. If there is an
|
||||||
int c;
|
** incomplete BOM (the first character is correct but the rest is
|
||||||
lf->n = 0;
|
** not), returns the first character anyway to force an error
|
||||||
do {
|
** (as no chunk can start with 0xEF).
|
||||||
c = getc(lf->f);
|
*/
|
||||||
if (c == EOF || c != *(const unsigned char *)p++) return c;
|
static int skipBOM (FILE *f) {
|
||||||
lf->buff[lf->n++] = c; /* to be read by the parser */
|
int c = getc(f); /* read first character */
|
||||||
} while (*p != '\0');
|
if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
|
||||||
lf->n = 0; /* prefix matched; discard it */
|
return getc(f); /* ignore BOM and return next char */
|
||||||
return getc(lf->f); /* return next character */
|
else /* no (valid) BOM */
|
||||||
|
return c; /* return first character */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -760,13 +792,13 @@ static int skipBOM (LoadF *lf) {
|
|||||||
** first "valid" character of the file (after the optional BOM and
|
** first "valid" character of the file (after the optional BOM and
|
||||||
** a first-line comment).
|
** a first-line comment).
|
||||||
*/
|
*/
|
||||||
static int skipcomment (LoadF *lf, int *cp) {
|
static int skipcomment (FILE *f, int *cp) {
|
||||||
int c = *cp = skipBOM(lf);
|
int c = *cp = skipBOM(f);
|
||||||
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
||||||
do { /* skip first line */
|
do { /* skip first line */
|
||||||
c = getc(lf->f);
|
c = getc(f);
|
||||||
} while (c != EOF && c != '\n');
|
} while (c != EOF && c != '\n');
|
||||||
*cp = getc(lf->f); /* skip end-of-line, if present */
|
*cp = getc(f); /* next character after comment, if present */
|
||||||
return 1; /* there was a comment */
|
return 1; /* there was a comment */
|
||||||
}
|
}
|
||||||
else return 0; /* no comment */
|
else return 0; /* no comment */
|
||||||
@@ -785,20 +817,27 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushfstring(L, "@%s", filename);
|
lua_pushfstring(L, "@%s", filename);
|
||||||
|
errno = 0;
|
||||||
lf.f = fopen(filename, "r");
|
lf.f = fopen(filename, "r");
|
||||||
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
||||||
}
|
}
|
||||||
if (skipcomment(&lf, &c)) /* read initial portion */
|
lf.n = 0;
|
||||||
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
|
if (skipcomment(lf.f, &c)) /* read initial portion */
|
||||||
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
|
lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
|
||||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
if (c == LUA_SIGNATURE[0]) { /* binary file? */
|
||||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
lf.n = 0; /* remove possible newline */
|
||||||
skipcomment(&lf, &c); /* re-read initial portion */
|
if (filename) { /* "real" file? */
|
||||||
|
errno = 0;
|
||||||
|
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||||
|
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||||
|
skipcomment(lf.f, &c); /* re-read initial portion */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (c != EOF)
|
if (c != EOF)
|
||||||
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
|
lf.buff[lf.n++] = cast_char(c); /* 'c' is the first character */
|
||||||
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
|
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
|
||||||
readstatus = ferror(lf.f);
|
readstatus = ferror(lf.f);
|
||||||
|
errno = 0; /* no useful error number until here */
|
||||||
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
||||||
if (readstatus) {
|
if (readstatus) {
|
||||||
lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
|
lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
|
||||||
@@ -817,7 +856,7 @@ typedef struct LoadS {
|
|||||||
|
|
||||||
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
||||||
LoadS *ls = (LoadS *)ud;
|
LoadS *ls = (LoadS *)ud;
|
||||||
(void)L; /* not used */
|
UNUSED(L);
|
||||||
if (ls->size == 0) return NULL;
|
if (ls->size == 0) return NULL;
|
||||||
*size = ls->size;
|
*size = ls->size;
|
||||||
ls->size = 0;
|
ls->size = 0;
|
||||||
@@ -835,7 +874,7 @@ LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
|
|||||||
|
|
||||||
|
|
||||||
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
|
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
|
||||||
return luaL_loadbuffer(L, s, strlen(s), s);
|
return luaL_loadbufferx(L, s, strlen(s), s, "t");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
@@ -889,10 +928,9 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
|||||||
else {
|
else {
|
||||||
switch (lua_type(L, idx)) {
|
switch (lua_type(L, idx)) {
|
||||||
case LUA_TNUMBER: {
|
case LUA_TNUMBER: {
|
||||||
if (lua_isinteger(L, idx))
|
char buff[LUA_N2SBUFFSZ];
|
||||||
lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
|
lua_numbertocstring(L, idx, buff);
|
||||||
else
|
lua_pushstring(L, buff);
|
||||||
lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
@@ -927,7 +965,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
|||||||
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
||||||
luaL_checkstack(L, nup, "too many upvalues");
|
luaL_checkstack(L, nup, "too many upvalues");
|
||||||
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
||||||
if (l->func == NULL) /* place holder? */
|
if (l->func == NULL) /* placeholder? */
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
else {
|
else {
|
||||||
int i;
|
int i;
|
||||||
@@ -990,7 +1028,7 @@ LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
|
|||||||
const char *wild;
|
const char *wild;
|
||||||
size_t l = strlen(p);
|
size_t l = strlen(p);
|
||||||
while ((wild = strstr(s, p)) != NULL) {
|
while ((wild = strstr(s, p)) != NULL) {
|
||||||
luaL_addlstring(b, s, wild - s); /* push prefix */
|
luaL_addlstring(b, s, ct_diff2sz(wild - s)); /* push prefix */
|
||||||
luaL_addstring(b, r); /* push replacement in place of pattern */
|
luaL_addstring(b, r); /* push replacement in place of pattern */
|
||||||
s = wild + l; /* continue after 'p' */
|
s = wild + l; /* continue after 'p' */
|
||||||
}
|
}
|
||||||
@@ -1008,8 +1046,8 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
void *luaL_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
(void)ud; (void)osize; /* not used */
|
UNUSED(ud); UNUSED(osize);
|
||||||
if (nsize == 0) {
|
if (nsize == 0) {
|
||||||
free(ptr);
|
free(ptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1019,9 +1057,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Standard panic function just prints an error message. The test
|
||||||
|
** with 'lua_type' avoids possible memory errors in 'lua_tostring'.
|
||||||
|
*/
|
||||||
static int panic (lua_State *L) {
|
static int panic (lua_State *L) {
|
||||||
const char *msg = lua_tostring(L, -1);
|
const char *msg = (lua_type(L, -1) == LUA_TSTRING)
|
||||||
if (msg == NULL) msg = "error object is not a string";
|
? lua_tostring(L, -1)
|
||||||
|
: "error object is not a string";
|
||||||
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
||||||
msg);
|
msg);
|
||||||
return 0; /* return to Lua to abort */
|
return 0; /* return to Lua to abort */
|
||||||
@@ -1085,11 +1128,64 @@ static void warnfon (void *ud, const char *message, int tocont) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API lua_State *luaL_newstate (void) {
|
|
||||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
/*
|
||||||
|
** A function to compute an unsigned int with some level of
|
||||||
|
** randomness. Rely on Address Space Layout Randomization (if present)
|
||||||
|
** and the current time.
|
||||||
|
*/
|
||||||
|
#if !defined(luai_makeseed)
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Size for the buffer, in bytes */
|
||||||
|
#define BUFSEEDB (sizeof(void*) + sizeof(time_t))
|
||||||
|
|
||||||
|
/* Size for the buffer in int's, rounded up */
|
||||||
|
#define BUFSEED ((BUFSEEDB + sizeof(int) - 1) / sizeof(int))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copy the contents of variable 'v' into the buffer pointed by 'b'.
|
||||||
|
** (The '&b[0]' disguises 'b' to fix an absurd warning from clang.)
|
||||||
|
*/
|
||||||
|
#define addbuff(b,v) (memcpy(&b[0], &(v), sizeof(v)), b += sizeof(v))
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int luai_makeseed (void) {
|
||||||
|
unsigned int buff[BUFSEED];
|
||||||
|
unsigned int res;
|
||||||
|
unsigned int i;
|
||||||
|
time_t t = time(NULL);
|
||||||
|
char *b = (char*)buff;
|
||||||
|
addbuff(b, b); /* local variable's address */
|
||||||
|
addbuff(b, t); /* time */
|
||||||
|
/* fill (rare but possible) remain of the buffer with zeros */
|
||||||
|
memset(b, 0, sizeof(buff) - BUFSEEDB);
|
||||||
|
res = buff[0];
|
||||||
|
for (i = 1; i < BUFSEED; i++)
|
||||||
|
res ^= (res >> 3) + (res << 7) + buff[i];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API unsigned int luaL_makeseed (lua_State *L) {
|
||||||
|
UNUSED(L);
|
||||||
|
return luai_makeseed();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Use the name with parentheses so that headers can redefine it
|
||||||
|
** as a macro.
|
||||||
|
*/
|
||||||
|
LUALIB_API lua_State *(luaL_newstate) (void) {
|
||||||
|
lua_State *L = lua_newstate(luaL_alloc, NULL, luaL_makeseed(NULL));
|
||||||
if (l_likely(L)) {
|
if (l_likely(L)) {
|
||||||
lua_atpanic(L, &panic);
|
lua_atpanic(L, &panic);
|
||||||
lua_setwarnf(L, warnfoff, L); /* default is warnings off */
|
lua_setwarnf(L, warnfon, L);
|
||||||
}
|
}
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
|
|||||||
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
||||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
||||||
|
|
||||||
|
LUALIB_API void *(luaL_alloc) (void *ud, void *ptr, size_t osize,
|
||||||
|
size_t nsize);
|
||||||
|
|
||||||
|
|
||||||
/* predefined references */
|
/* predefined references */
|
||||||
#define LUA_NOREF (-2)
|
#define LUA_NOREF (-2)
|
||||||
@@ -100,6 +103,8 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
|||||||
|
|
||||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||||
|
|
||||||
|
LUALIB_API unsigned (luaL_makeseed) (lua_State *L);
|
||||||
|
|
||||||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||||
|
|
||||||
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
|
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
|
||||||
@@ -163,21 +168,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
|||||||
|
|
||||||
|
|
||||||
/* push the value used to represent failure/error */
|
/* push the value used to represent failure/error */
|
||||||
#define luaL_pushfail(L) lua_pushnil(L)
|
#if defined(LUA_FAILISFALSE)
|
||||||
|
#define luaL_pushfail(L) lua_pushboolean(L, 0)
|
||||||
|
|
||||||
/*
|
|
||||||
** Internal assertions for in-house debugging
|
|
||||||
*/
|
|
||||||
#if !defined(lua_assert)
|
|
||||||
|
|
||||||
#if defined LUAI_ASSERT
|
|
||||||
#include <assert.h>
|
|
||||||
#define lua_assert(c) assert(c)
|
|
||||||
#else
|
#else
|
||||||
#define lua_assert(c) ((void)0)
|
#define luaL_pushfail(L) lua_pushnil(L)
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -249,30 +243,6 @@ typedef struct luaL_Stream {
|
|||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
||||||
/*
|
|
||||||
** {==================================================================
|
|
||||||
** "Abstraction Layer" for basic report of messages and errors
|
|
||||||
** ===================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* print a string */
|
|
||||||
#if !defined(lua_writestring)
|
|
||||||
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* print a newline and flush the output */
|
|
||||||
#if !defined(lua_writeline)
|
|
||||||
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* print an error message */
|
|
||||||
#if !defined(lua_writestringerror)
|
|
||||||
#define lua_writestringerror(s,p) \
|
|
||||||
(fprintf(stderr, (s), (p)), fflush(stderr))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* }================================================================== */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {============================================================
|
** {============================================================
|
||||||
|
|||||||
+59
-56
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
static int luaB_print (lua_State *L) {
|
static int luaB_print (lua_State *L) {
|
||||||
@@ -57,21 +58,22 @@ static int luaB_warn (lua_State *L) {
|
|||||||
|
|
||||||
#define SPACECHARS " \f\n\r\t\v"
|
#define SPACECHARS " \f\n\r\t\v"
|
||||||
|
|
||||||
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
|
static const char *b_str2int (const char *s, unsigned base, lua_Integer *pn) {
|
||||||
lua_Unsigned n = 0;
|
lua_Unsigned n = 0;
|
||||||
int neg = 0;
|
int neg = 0;
|
||||||
s += strspn(s, SPACECHARS); /* skip initial spaces */
|
s += strspn(s, SPACECHARS); /* skip initial spaces */
|
||||||
if (*s == '-') { s++; neg = 1; } /* handle sign */
|
if (*s == '-') { s++; neg = 1; } /* handle sign */
|
||||||
else if (*s == '+') s++;
|
else if (*s == '+') s++;
|
||||||
if (!isalnum((unsigned char)*s)) /* no digit? */
|
if (!isalnum(cast_uchar(*s))) /* no digit? */
|
||||||
return NULL;
|
return NULL;
|
||||||
do {
|
do {
|
||||||
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
|
unsigned digit = cast_uint(isdigit(cast_uchar(*s))
|
||||||
: (toupper((unsigned char)*s) - 'A') + 10;
|
? *s - '0'
|
||||||
|
: (toupper(cast_uchar(*s)) - 'A') + 10);
|
||||||
if (digit >= base) return NULL; /* invalid numeral */
|
if (digit >= base) return NULL; /* invalid numeral */
|
||||||
n = n * base + digit;
|
n = n * base + digit;
|
||||||
s++;
|
s++;
|
||||||
} while (isalnum((unsigned char)*s));
|
} while (isalnum(cast_uchar(*s)));
|
||||||
s += strspn(s, SPACECHARS); /* skip trailing spaces */
|
s += strspn(s, SPACECHARS); /* skip trailing spaces */
|
||||||
*pn = (lua_Integer)((neg) ? (0u - n) : n);
|
*pn = (lua_Integer)((neg) ? (0u - n) : n);
|
||||||
return s;
|
return s;
|
||||||
@@ -101,7 +103,7 @@ static int luaB_tonumber (lua_State *L) {
|
|||||||
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
|
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
|
||||||
s = lua_tolstring(L, 1, &l);
|
s = lua_tolstring(L, 1, &l);
|
||||||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
||||||
if (b_str2int(s, (int)base, &n) == s + l) {
|
if (b_str2int(s, cast_uint(base), &n) == s + l) {
|
||||||
lua_pushinteger(L, n);
|
lua_pushinteger(L, n);
|
||||||
return 1;
|
return 1;
|
||||||
} /* else not a number */
|
} /* else not a number */
|
||||||
@@ -158,7 +160,7 @@ static int luaB_rawlen (lua_State *L) {
|
|||||||
int t = lua_type(L, 1);
|
int t = lua_type(L, 1);
|
||||||
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
|
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
|
||||||
"table or string");
|
"table or string");
|
||||||
lua_pushinteger(L, lua_rawlen(L, 1));
|
lua_pushinteger(L, l_castU2S(lua_rawlen(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,11 +200,11 @@ static int pushmode (lua_State *L, int oldmode) {
|
|||||||
|
|
||||||
static int luaB_collectgarbage (lua_State *L) {
|
static int luaB_collectgarbage (lua_State *L) {
|
||||||
static const char *const opts[] = {"stop", "restart", "collect",
|
static const char *const opts[] = {"stop", "restart", "collect",
|
||||||
"count", "step", "setpause", "setstepmul",
|
"count", "step", "isrunning", "generational", "incremental",
|
||||||
"isrunning", "generational", "incremental", NULL};
|
"param", NULL};
|
||||||
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
static const char optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
||||||
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
|
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC,
|
||||||
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
|
LUA_GCPARAM};
|
||||||
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
|
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case LUA_GCCOUNT: {
|
case LUA_GCCOUNT: {
|
||||||
@@ -213,20 +215,12 @@ static int luaB_collectgarbage (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_GCSTEP: {
|
case LUA_GCSTEP: {
|
||||||
int step = (int)luaL_optinteger(L, 2, 0);
|
lua_Integer n = luaL_optinteger(L, 2, 0);
|
||||||
int res = lua_gc(L, o, step);
|
int res = lua_gc(L, o, cast_sizet(n));
|
||||||
checkvalres(res);
|
checkvalres(res);
|
||||||
lua_pushboolean(L, res);
|
lua_pushboolean(L, res);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_GCSETPAUSE:
|
|
||||||
case LUA_GCSETSTEPMUL: {
|
|
||||||
int p = (int)luaL_optinteger(L, 2, 0);
|
|
||||||
int previous = lua_gc(L, o, p);
|
|
||||||
checkvalres(previous);
|
|
||||||
lua_pushinteger(L, previous);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case LUA_GCISRUNNING: {
|
case LUA_GCISRUNNING: {
|
||||||
int res = lua_gc(L, o);
|
int res = lua_gc(L, o);
|
||||||
checkvalres(res);
|
checkvalres(res);
|
||||||
@@ -234,15 +228,22 @@ static int luaB_collectgarbage (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_GCGEN: {
|
case LUA_GCGEN: {
|
||||||
int minormul = (int)luaL_optinteger(L, 2, 0);
|
return pushmode(L, lua_gc(L, o));
|
||||||
int majormul = (int)luaL_optinteger(L, 3, 0);
|
|
||||||
return pushmode(L, lua_gc(L, o, minormul, majormul));
|
|
||||||
}
|
}
|
||||||
case LUA_GCINC: {
|
case LUA_GCINC: {
|
||||||
int pause = (int)luaL_optinteger(L, 2, 0);
|
return pushmode(L, lua_gc(L, o));
|
||||||
int stepmul = (int)luaL_optinteger(L, 3, 0);
|
}
|
||||||
int stepsize = (int)luaL_optinteger(L, 4, 0);
|
case LUA_GCPARAM: {
|
||||||
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
|
static const char *const params[] = {
|
||||||
|
"minormul", "majorminor", "minormajor",
|
||||||
|
"pause", "stepmul", "stepsize", NULL};
|
||||||
|
static const char pnum[] = {
|
||||||
|
LUA_GCPMINORMUL, LUA_GCPMAJORMINOR, LUA_GCPMINORMAJOR,
|
||||||
|
LUA_GCPPAUSE, LUA_GCPSTEPMUL, LUA_GCPSTEPSIZE};
|
||||||
|
int p = pnum[luaL_checkoption(L, 2, NULL, params)];
|
||||||
|
lua_Integer value = luaL_optinteger(L, 3, -1);
|
||||||
|
lua_pushinteger(L, lua_gc(L, o, p, (int)value));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
int res = lua_gc(L, o);
|
int res = lua_gc(L, o);
|
||||||
@@ -278,21 +279,22 @@ static int luaB_next (lua_State *L) {
|
|||||||
|
|
||||||
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
||||||
(void)L; (void)status; (void)k; /* unused */
|
(void)L; (void)status; (void)k; /* unused */
|
||||||
return 3;
|
return 4; /* __pairs did all the work, just return its results */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int luaB_pairs (lua_State *L) {
|
static int luaB_pairs (lua_State *L) {
|
||||||
luaL_checkany(L, 1);
|
luaL_checkany(L, 1);
|
||||||
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
||||||
lua_pushcfunction(L, luaB_next); /* will return generator, */
|
lua_pushcfunction(L, luaB_next); /* will return generator and */
|
||||||
lua_pushvalue(L, 1); /* state, */
|
lua_pushvalue(L, 1); /* state */
|
||||||
lua_pushnil(L); /* and initial value */
|
lua_pushnil(L); /* initial value */
|
||||||
|
lua_pushnil(L); /* to-be-closed object */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
||||||
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
|
lua_callk(L, 1, 4, 0, pairscont); /* get 4 values from metamethod */
|
||||||
}
|
}
|
||||||
return 3;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -337,9 +339,19 @@ static int load_aux (lua_State *L, int status, int envidx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *getMode (lua_State *L, int idx) {
|
||||||
|
const char *mode = luaL_optstring(L, idx, NULL);
|
||||||
|
if (mode != NULL && strchr(mode, 'B') != NULL) {
|
||||||
|
/* Lua code cannot use fixed buffers */
|
||||||
|
luaL_argerror(L, idx, "invalid mode");
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaB_loadfile (lua_State *L) {
|
static int luaB_loadfile (lua_State *L) {
|
||||||
const char *fname = luaL_optstring(L, 1, NULL);
|
const char *fname = luaL_optstring(L, 1, NULL);
|
||||||
const char *mode = luaL_optstring(L, 2, NULL);
|
const char *mode = getMode(L, 2);
|
||||||
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
||||||
int status = luaL_loadfilex(L, fname, mode);
|
int status = luaL_loadfilex(L, fname, mode);
|
||||||
return load_aux(L, status, env);
|
return load_aux(L, status, env);
|
||||||
@@ -354,33 +366,24 @@ static int luaB_loadfile (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** reserved slot, above all arguments, to hold a copy of the returned
|
** Reader for generic 'load' function.
|
||||||
** string to avoid it being collected while parsed. 'load' has four
|
|
||||||
** optional arguments (chunk, source name, mode, and environment).
|
|
||||||
*/
|
|
||||||
#define RESERVEDSLOT 5
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Reader for generic 'load' function: 'lua_load' uses the
|
|
||||||
** stack for internal stuff, so the reader cannot change the
|
|
||||||
** stack top. Instead, it keeps its resulting string in a
|
|
||||||
** reserved slot inside the stack.
|
|
||||||
*/
|
*/
|
||||||
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
||||||
(void)(ud); /* not used */
|
int *firstcall = cast(int *, ud);
|
||||||
luaL_checkstack(L, 2, "too many nested functions");
|
luaL_checkstack(L, 2, "too many nested functions");
|
||||||
|
if (*firstcall)
|
||||||
|
*firstcall = 0;
|
||||||
|
else
|
||||||
|
lua_pop(L, 1); /* remove previous result */
|
||||||
lua_pushvalue(L, 1); /* get function */
|
lua_pushvalue(L, 1); /* get function */
|
||||||
lua_call(L, 0, 1); /* call it */
|
lua_call(L, 0, 1); /* call it */
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1)) {
|
||||||
lua_pop(L, 1); /* pop result */
|
|
||||||
*size = 0;
|
*size = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||||
luaL_error(L, "reader function must return a string");
|
luaL_error(L, "reader function must return a string");
|
||||||
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
|
return lua_tolstring(L, -1, size);
|
||||||
return lua_tolstring(L, RESERVEDSLOT, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -388,17 +391,17 @@ static int luaB_load (lua_State *L) {
|
|||||||
int status;
|
int status;
|
||||||
size_t l;
|
size_t l;
|
||||||
const char *s = lua_tolstring(L, 1, &l);
|
const char *s = lua_tolstring(L, 1, &l);
|
||||||
const char *mode = luaL_optstring(L, 3, "bt");
|
const char *mode = getMode(L, 3);
|
||||||
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
||||||
if (s != NULL) { /* loading a string? */
|
if (s != NULL) { /* loading a string? */
|
||||||
const char *chunkname = luaL_optstring(L, 2, s);
|
const char *chunkname = luaL_optstring(L, 2, s);
|
||||||
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
||||||
}
|
}
|
||||||
else { /* loading from a reader function */
|
else { /* loading from a reader function */
|
||||||
|
int firstcall = 1; /* userdata for generic_reader */
|
||||||
const char *chunkname = luaL_optstring(L, 2, "=(load)");
|
const char *chunkname = luaL_optstring(L, 2, "=(load)");
|
||||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||||
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
|
status = lua_load(L, generic_reader, &firstcall, chunkname, mode);
|
||||||
status = lua_load(L, generic_reader, NULL, chunkname, mode);
|
|
||||||
}
|
}
|
||||||
return load_aux(L, status, env);
|
return load_aux(L, status, env);
|
||||||
}
|
}
|
||||||
@@ -415,7 +418,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
|
|||||||
static int luaB_dofile (lua_State *L) {
|
static int luaB_dofile (lua_State *L) {
|
||||||
const char *fname = luaL_optstring(L, 1, NULL);
|
const char *fname = luaL_optstring(L, 1, NULL);
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
|
if (l_unlikely(luaL_loadfilex(L, fname, "bt") != LUA_OK))
|
||||||
return lua_error(L);
|
return lua_error(L);
|
||||||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
||||||
return dofilecont(L, 0, 0);
|
return dofilecont(L, 0, 0);
|
||||||
|
|||||||
@@ -60,27 +60,28 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
|||||||
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
|
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
|
||||||
|
|
||||||
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
|
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
|
||||||
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, int Bx);
|
||||||
LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
|
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C,
|
||||||
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
|
int k);
|
||||||
int B, int C, int k);
|
LUAI_FUNC int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C,
|
||||||
LUAI_FUNC int luaK_isKint (expdesc *e);
|
int k);
|
||||||
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
||||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
||||||
|
LUAI_FUNC void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k,
|
||||||
|
int line);
|
||||||
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
||||||
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
||||||
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
|
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
|
||||||
|
LUAI_FUNC void luaK_vapar2local (FuncState *fs, expdesc *var);
|
||||||
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
|
|
||||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||||
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
|
|
||||||
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||||
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
||||||
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
||||||
@@ -98,7 +99,7 @@ LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
|
|||||||
int ra, int asize, int hsize);
|
int ra, int asize, int hsize);
|
||||||
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
||||||
LUAI_FUNC void luaK_finish (FuncState *fs);
|
LUAI_FUNC void luaK_finish (FuncState *fs);
|
||||||
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
|
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+20
-5
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
static lua_State *getco (lua_State *L) {
|
static lua_State *getco (lua_State *L) {
|
||||||
@@ -76,7 +77,7 @@ static int luaB_auxwrap (lua_State *L) {
|
|||||||
if (l_unlikely(r < 0)) { /* error? */
|
if (l_unlikely(r < 0)) { /* error? */
|
||||||
int stat = lua_status(co);
|
int stat = lua_status(co);
|
||||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
||||||
stat = lua_resetthread(co); /* close its tbc variables */
|
stat = lua_closethread(co, L); /* close its tbc variables */
|
||||||
lua_assert(stat != LUA_OK);
|
lua_assert(stat != LUA_OK);
|
||||||
lua_xmove(co, L, 1); /* move error message to the caller */
|
lua_xmove(co, L, 1); /* move error message to the caller */
|
||||||
}
|
}
|
||||||
@@ -153,8 +154,13 @@ static int luaB_costatus (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lua_State *getoptco (lua_State *L) {
|
||||||
|
return (lua_isnone(L, 1) ? L : getco(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaB_yieldable (lua_State *L) {
|
static int luaB_yieldable (lua_State *L) {
|
||||||
lua_State *co = lua_isnone(L, 1) ? L : getco(L);
|
lua_State *co = getoptco(L);
|
||||||
lua_pushboolean(L, lua_isyieldable(co));
|
lua_pushboolean(L, lua_isyieldable(co));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -168,11 +174,11 @@ static int luaB_corunning (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
static int luaB_close (lua_State *L) {
|
static int luaB_close (lua_State *L) {
|
||||||
lua_State *co = getco(L);
|
lua_State *co = getoptco(L);
|
||||||
int status = auxstatus(L, co);
|
int status = auxstatus(L, co);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case COS_DEAD: case COS_YIELD: {
|
case COS_DEAD: case COS_YIELD: {
|
||||||
status = lua_resetthread(co);
|
status = lua_closethread(co, L);
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -183,8 +189,17 @@ static int luaB_close (lua_State *L) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: /* normal or running coroutine */
|
case COS_NORM:
|
||||||
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
||||||
|
case COS_RUN:
|
||||||
|
lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); /* get main */
|
||||||
|
if (lua_tothread(L, -1) == co)
|
||||||
|
return luaL_error(L, "cannot close main thread");
|
||||||
|
lua_closethread(co, L); /* close itself */
|
||||||
|
/* previous call does not return *//* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
lua_assert(0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
|
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
|
||||||
/* consider all non-ascii codepoints to be alphabetic */
|
/* consider all non-ASCII codepoints to be alphabetic */
|
||||||
#define NONA 0x01
|
#define NONA 0x01
|
||||||
#else
|
#else
|
||||||
#define NONA 0x00 /* default */
|
#define NONA 0x00 /* default */
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -190,8 +191,10 @@ static int db_getinfo (lua_State *L) {
|
|||||||
settabsi(L, "ftransfer", ar.ftransfer);
|
settabsi(L, "ftransfer", ar.ftransfer);
|
||||||
settabsi(L, "ntransfer", ar.ntransfer);
|
settabsi(L, "ntransfer", ar.ntransfer);
|
||||||
}
|
}
|
||||||
if (strchr(options, 't'))
|
if (strchr(options, 't')) {
|
||||||
settabsb(L, "istailcall", ar.istailcall);
|
settabsb(L, "istailcall", ar.istailcall);
|
||||||
|
settabsi(L, "extraargs", ar.extraargs);
|
||||||
|
}
|
||||||
if (strchr(options, 'L'))
|
if (strchr(options, 'L'))
|
||||||
treatstackoption(L, L1, "activelines");
|
treatstackoption(L, L1, "activelines");
|
||||||
if (strchr(options, 'f'))
|
if (strchr(options, 'f'))
|
||||||
@@ -424,7 +427,7 @@ static int db_debug (lua_State *L) {
|
|||||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
|
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
|
||||||
strcmp(buffer, "cont\n") == 0)
|
strcmp(buffer, "cont\n") == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
if (luaL_loadbufferx(L, buffer, strlen(buffer), "=(debug command)", "t") ||
|
||||||
lua_pcall(L, 0, 0, 0))
|
lua_pcall(L, 0, 0, 0))
|
||||||
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
|
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
|
||||||
lua_settop(L, 0); /* remove eventual returns */
|
lua_settop(L, 0); /* remove eventual returns */
|
||||||
@@ -446,14 +449,6 @@ static int db_traceback (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int db_setcstacklimit (lua_State *L) {
|
|
||||||
int limit = (int)luaL_checkinteger(L, 1);
|
|
||||||
int res = lua_setcstacklimit(L, limit);
|
|
||||||
lua_pushinteger(L, res);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const luaL_Reg dblib[] = {
|
static const luaL_Reg dblib[] = {
|
||||||
{"debug", db_debug},
|
{"debug", db_debug},
|
||||||
{"getuservalue", db_getuservalue},
|
{"getuservalue", db_getuservalue},
|
||||||
@@ -471,7 +466,6 @@ static const luaL_Reg dblib[] = {
|
|||||||
{"setmetatable", db_setmetatable},
|
{"setmetatable", db_setmetatable},
|
||||||
{"setupvalue", db_setupvalue},
|
{"setupvalue", db_setupvalue},
|
||||||
{"traceback", db_traceback},
|
{"traceback", db_traceback},
|
||||||
{"setcstacklimit", db_setcstacklimit},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
|
#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
|
||||||
|
|
||||||
|
static const char strlocal[] = "local";
|
||||||
|
static const char strupval[] = "upvalue";
|
||||||
|
|
||||||
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||||
const char **name);
|
const char **name);
|
||||||
@@ -63,7 +65,7 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
|
|||||||
return f->linedefined;
|
return f->linedefined;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
|
int i = pc / MAXIWTHABS - 1; /* get an estimate */
|
||||||
/* estimate must be a lower bound of the correct base */
|
/* estimate must be a lower bound of the correct base */
|
||||||
lua_assert(i < 0 ||
|
lua_assert(i < 0 ||
|
||||||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
|
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
|
||||||
@@ -182,10 +184,10 @@ static const char *upvalname (const Proto *p, int uv) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||||
if (clLvalue(s2v(ci->func))->p->is_vararg) {
|
if (clLvalue(s2v(ci->func.p))->p->flag & PF_VAHID) {
|
||||||
int nextra = ci->u.l.nextraargs;
|
int nextra = ci->u.l.nextraargs;
|
||||||
if (n >= -nextra) { /* 'n' is negative */
|
if (n >= -nextra) { /* 'n' is negative */
|
||||||
*pos = ci->func - nextra - (n + 1);
|
*pos = ci->func.p - nextra - (n + 1);
|
||||||
return "(vararg)"; /* generic name for any vararg */
|
return "(vararg)"; /* generic name for any vararg */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +196,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
|||||||
|
|
||||||
|
|
||||||
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
||||||
StkId base = ci->func + 1;
|
StkId base = ci->func.p + 1;
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
if (isLua(ci)) {
|
if (isLua(ci)) {
|
||||||
if (n < 0) /* access to vararg values? */
|
if (n < 0) /* access to vararg values? */
|
||||||
@@ -203,7 +205,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
|||||||
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
||||||
}
|
}
|
||||||
if (name == NULL) { /* no 'standard' name? */
|
if (name == NULL) { /* no 'standard' name? */
|
||||||
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
|
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
|
||||||
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
|
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
|
||||||
/* generic name for any valid slot */
|
/* generic name for any valid slot */
|
||||||
name = isLua(ci) ? "(temporary)" : "(C temporary)";
|
name = isLua(ci) ? "(temporary)" : "(C temporary)";
|
||||||
@@ -221,16 +223,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
const char *name;
|
const char *name;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
if (ar == NULL) { /* information about non-active function? */
|
if (ar == NULL) { /* information about non-active function? */
|
||||||
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
|
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
|
||||||
name = NULL;
|
name = NULL;
|
||||||
else /* consider live variables at function start (parameters) */
|
else /* consider live variables at function start (parameters) */
|
||||||
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
|
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
|
||||||
}
|
}
|
||||||
else { /* active function; get information through 'ar' */
|
else { /* active function; get information through 'ar' */
|
||||||
StkId pos = NULL; /* to avoid warnings */
|
StkId pos = NULL; /* to avoid warnings */
|
||||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||||
if (name) {
|
if (name) {
|
||||||
setobjs2s(L, L->top, pos);
|
setobjs2s(L, L->top.p, pos);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,8 +247,9 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||||
if (name) {
|
if (name) {
|
||||||
setobjs2s(L, pos, L->top - 1);
|
api_checkpop(L, 1);
|
||||||
L->top--; /* pop value */
|
setobjs2s(L, pos, L->top.p - 1);
|
||||||
|
L->top.p--; /* pop value */
|
||||||
}
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return name;
|
return name;
|
||||||
@@ -254,7 +257,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
|
|
||||||
|
|
||||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||||
if (noLuaClosure(cl)) {
|
if (!LuaClosure(cl)) {
|
||||||
ar->source = "=[C]";
|
ar->source = "=[C]";
|
||||||
ar->srclen = LL("=[C]");
|
ar->srclen = LL("=[C]");
|
||||||
ar->linedefined = -1;
|
ar->linedefined = -1;
|
||||||
@@ -264,8 +267,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
|
|||||||
else {
|
else {
|
||||||
const Proto *p = cl->l.p;
|
const Proto *p = cl->l.p;
|
||||||
if (p->source) {
|
if (p->source) {
|
||||||
ar->source = getstr(p->source);
|
ar->source = getlstr(p->source, ar->srclen);
|
||||||
ar->srclen = tsslen(p->source);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ar->source = "=?";
|
ar->source = "=?";
|
||||||
@@ -288,29 +290,31 @@ static int nextline (const Proto *p, int currentline, int pc) {
|
|||||||
|
|
||||||
|
|
||||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||||
if (noLuaClosure(f)) {
|
if (!LuaClosure(f)) {
|
||||||
setnilvalue(s2v(L->top));
|
setnilvalue2s(L->top.p);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int i;
|
|
||||||
TValue v;
|
|
||||||
const Proto *p = f->l.p;
|
const Proto *p = f->l.p;
|
||||||
int currentline = p->linedefined;
|
int currentline = p->linedefined;
|
||||||
Table *t = luaH_new(L); /* new table to store active lines */
|
Table *t = luaH_new(L); /* new table to store active lines */
|
||||||
sethvalue2s(L, L->top, t); /* push it on stack */
|
sethvalue2s(L, L->top.p, t); /* push it on stack */
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
if (p->lineinfo != NULL) { /* proto with debug information? */
|
||||||
if (!p->is_vararg) /* regular function? */
|
int i;
|
||||||
i = 0; /* consider all instructions */
|
TValue v;
|
||||||
else { /* vararg function */
|
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
if (!(isvararg(p))) /* regular function? */
|
||||||
currentline = nextline(p, currentline, 0);
|
i = 0; /* consider all instructions */
|
||||||
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
else { /* vararg function */
|
||||||
}
|
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||||
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
currentline = nextline(p, currentline, 0);
|
||||||
currentline = nextline(p, currentline, i); /* get its line */
|
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
||||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
}
|
||||||
|
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
||||||
|
currentline = nextline(p, currentline, i); /* get its line */
|
||||||
|
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,18 +343,26 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
|||||||
}
|
}
|
||||||
case 'u': {
|
case 'u': {
|
||||||
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
||||||
if (noLuaClosure(f)) {
|
if (!LuaClosure(f)) {
|
||||||
ar->isvararg = 1;
|
ar->isvararg = 1;
|
||||||
ar->nparams = 0;
|
ar->nparams = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ar->isvararg = f->l.p->is_vararg;
|
ar->isvararg = (isvararg(f->l.p)) ? 1 : 0;
|
||||||
ar->nparams = f->l.p->numparams;
|
ar->nparams = f->l.p->numparams;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 't': {
|
case 't': {
|
||||||
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
|
if (ci != NULL) {
|
||||||
|
ar->istailcall = !!(ci->callstatus & CIST_TAIL);
|
||||||
|
ar->extraargs =
|
||||||
|
cast_uchar((ci->callstatus & MAX_CCMT) >> CIST_CCMT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ar->istailcall = 0;
|
||||||
|
ar->extraargs = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'n': {
|
case 'n': {
|
||||||
@@ -362,11 +374,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'r': {
|
case 'r': {
|
||||||
if (ci == NULL || !(ci->callstatus & CIST_TRAN))
|
if (ci == NULL || !(ci->callstatus & CIST_HOOKED))
|
||||||
ar->ftransfer = ar->ntransfer = 0;
|
ar->ftransfer = ar->ntransfer = 0;
|
||||||
else {
|
else {
|
||||||
ar->ftransfer = ci->u2.transferinfo.ftransfer;
|
ar->ftransfer = L->transferinfo.ftransfer;
|
||||||
ar->ntransfer = ci->u2.transferinfo.ntransfer;
|
ar->ntransfer = L->transferinfo.ntransfer;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -388,20 +400,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
if (*what == '>') {
|
if (*what == '>') {
|
||||||
ci = NULL;
|
ci = NULL;
|
||||||
func = s2v(L->top - 1);
|
func = s2v(L->top.p - 1);
|
||||||
api_check(L, ttisfunction(func), "function expected");
|
api_check(L, ttisfunction(func), "function expected");
|
||||||
what++; /* skip the '>' */
|
what++; /* skip the '>' */
|
||||||
L->top--; /* pop function */
|
L->top.p--; /* pop function */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ci = ar->i_ci;
|
ci = ar->i_ci;
|
||||||
func = s2v(ci->func);
|
func = s2v(ci->func.p);
|
||||||
lua_assert(ttisfunction(func));
|
lua_assert(ttisfunction(func));
|
||||||
}
|
}
|
||||||
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
||||||
status = auxgetinfo(L, what, ar, cl, ci);
|
status = auxgetinfo(L, what, ar, cl, ci);
|
||||||
if (strchr(what, 'f')) {
|
if (strchr(what, 'f')) {
|
||||||
setobj2s(L, L->top, func);
|
setobj2s(L, L->top.p, func);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
if (strchr(what, 'L'))
|
if (strchr(what, 'L'))
|
||||||
@@ -417,40 +429,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|
||||||
const char **name);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find a "name" for the constant 'c'.
|
|
||||||
*/
|
|
||||||
static void kname (const Proto *p, int c, const char **name) {
|
|
||||||
TValue *kvalue = &p->k[c];
|
|
||||||
*name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find a "name" for the register 'c'.
|
|
||||||
*/
|
|
||||||
static void rname (const Proto *p, int pc, int c, const char **name) {
|
|
||||||
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
|
|
||||||
if (!(what && *what == 'c')) /* did not find a constant name? */
|
|
||||||
*name = "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find a "name" for a 'C' value in an RK instruction.
|
|
||||||
*/
|
|
||||||
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
|
|
||||||
int c = GETARG_C(i); /* key index */
|
|
||||||
if (GETARG_k(i)) /* is 'c' a constant? */
|
|
||||||
kname(p, c, name);
|
|
||||||
else /* 'c' is a register */
|
|
||||||
rname(p, pc, c, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int filterpc (int pc, int jmptarget) {
|
static int filterpc (int pc, int jmptarget) {
|
||||||
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
||||||
@@ -509,28 +487,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether table being indexed by instruction 'i' is the
|
** Find a "name" for the constant 'c'.
|
||||||
** environment '_ENV'
|
|
||||||
*/
|
*/
|
||||||
static const char *gxf (const Proto *p, int pc, Instruction i, int isup) {
|
static const char *kname (const Proto *p, int index, const char **name) {
|
||||||
int t = GETARG_B(i); /* table index */
|
TValue *kvalue = &p->k[index];
|
||||||
const char *name; /* name of indexed variable */
|
if (ttisstring(kvalue)) {
|
||||||
if (isup) /* is an upvalue? */
|
*name = getstr(tsvalue(kvalue));
|
||||||
name = upvalname(p, t);
|
return "constant";
|
||||||
else
|
}
|
||||||
getobjname(p, pc, t, &name);
|
else {
|
||||||
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
*name = "?";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
|
||||||
const char **name) {
|
const char **name) {
|
||||||
int pc;
|
int pc = *ppc;
|
||||||
*name = luaF_getlocalname(p, reg + 1, lastpc);
|
*name = luaF_getlocalname(p, reg + 1, pc);
|
||||||
if (*name) /* is a local? */
|
if (*name) /* is a local? */
|
||||||
return "local";
|
return strlocal;
|
||||||
/* else try symbolic execution */
|
/* else try symbolic execution */
|
||||||
pc = findsetreg(p, lastpc, reg);
|
*ppc = pc = findsetreg(p, pc, reg);
|
||||||
if (pc != -1) { /* could find instruction? */
|
if (pc != -1) { /* could find instruction? */
|
||||||
Instruction i = p->code[pc];
|
Instruction i = p->code[pc];
|
||||||
OpCode op = GET_OPCODE(i);
|
OpCode op = GET_OPCODE(i);
|
||||||
@@ -538,18 +517,73 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|||||||
case OP_MOVE: {
|
case OP_MOVE: {
|
||||||
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
||||||
if (b < GETARG_A(i))
|
if (b < GETARG_A(i))
|
||||||
return getobjname(p, pc, b, name); /* get name for 'b' */
|
return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_GETUPVAL: {
|
||||||
|
*name = upvalname(p, GETARG_B(i));
|
||||||
|
return strupval;
|
||||||
|
}
|
||||||
|
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
|
||||||
|
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; /* could not find reasonable name */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Find a "name" for the register 'c'.
|
||||||
|
*/
|
||||||
|
static void rname (const Proto *p, int pc, int c, const char **name) {
|
||||||
|
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
|
||||||
|
if (!(what && *what == 'c')) /* did not find a constant name? */
|
||||||
|
*name = "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check whether table being indexed by instruction 'i' is the
|
||||||
|
** environment '_ENV'
|
||||||
|
*/
|
||||||
|
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
|
||||||
|
int t = GETARG_B(i); /* table index */
|
||||||
|
const char *name; /* name of indexed variable */
|
||||||
|
if (isup) /* is 't' an upvalue? */
|
||||||
|
name = upvalname(p, t);
|
||||||
|
else { /* 't' is a register */
|
||||||
|
const char *what = basicgetobjname(p, &pc, t, &name);
|
||||||
|
/* 'name' must be the name of a local variable (at the current
|
||||||
|
level or an upvalue) */
|
||||||
|
if (what != strlocal && what != strupval)
|
||||||
|
name = NULL; /* cannot be the variable _ENV */
|
||||||
|
}
|
||||||
|
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Extend 'basicgetobjname' to handle table accesses
|
||||||
|
*/
|
||||||
|
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||||
|
const char **name) {
|
||||||
|
const char *kind = basicgetobjname(p, &lastpc, reg, name);
|
||||||
|
if (kind != NULL)
|
||||||
|
return kind;
|
||||||
|
else if (lastpc != -1) { /* could find instruction? */
|
||||||
|
Instruction i = p->code[lastpc];
|
||||||
|
OpCode op = GET_OPCODE(i);
|
||||||
|
switch (op) {
|
||||||
case OP_GETTABUP: {
|
case OP_GETTABUP: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
kname(p, k, name);
|
kname(p, k, name);
|
||||||
return gxf(p, pc, i, 1);
|
return isEnv(p, lastpc, i, 1);
|
||||||
}
|
}
|
||||||
case OP_GETTABLE: {
|
case OP_GETTABLE: case OP_GETVARG: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
rname(p, pc, k, name);
|
rname(p, lastpc, k, name);
|
||||||
return gxf(p, pc, i, 0);
|
return isEnv(p, lastpc, i, 0);
|
||||||
}
|
}
|
||||||
case OP_GETI: {
|
case OP_GETI: {
|
||||||
*name = "integer index";
|
*name = "integer index";
|
||||||
@@ -558,24 +592,11 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|||||||
case OP_GETFIELD: {
|
case OP_GETFIELD: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
kname(p, k, name);
|
kname(p, k, name);
|
||||||
return gxf(p, pc, i, 0);
|
return isEnv(p, lastpc, i, 0);
|
||||||
}
|
|
||||||
case OP_GETUPVAL: {
|
|
||||||
*name = upvalname(p, GETARG_B(i));
|
|
||||||
return "upvalue";
|
|
||||||
}
|
|
||||||
case OP_LOADK:
|
|
||||||
case OP_LOADKX: {
|
|
||||||
int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
|
||||||
: GETARG_Ax(p->code[pc + 1]);
|
|
||||||
if (ttisstring(&p->k[b])) {
|
|
||||||
*name = svalue(&p->k[b]);
|
|
||||||
return "constant";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case OP_SELF: {
|
case OP_SELF: {
|
||||||
rkname(p, pc, i, name);
|
int k = GETARG_C(i); /* key index */
|
||||||
|
kname(p, k, name);
|
||||||
return "method";
|
return "method";
|
||||||
}
|
}
|
||||||
default: break; /* go through to return NULL */
|
default: break; /* go through to return NULL */
|
||||||
@@ -627,7 +648,7 @@ static const char *funcnamefromcode (lua_State *L, const Proto *p,
|
|||||||
default:
|
default:
|
||||||
return NULL; /* cannot find a reasonable name */
|
return NULL; /* cannot find a reasonable name */
|
||||||
}
|
}
|
||||||
*name = getstr(G(L)->tmname[tm]) + 2;
|
*name = getshrstr(G(L)->tmname[tm]) + 2;
|
||||||
return "metamethod";
|
return "metamethod";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,18 +677,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether pointer 'o' points to some value in the stack
|
** Check whether pointer 'o' points to some value in the stack frame of
|
||||||
** frame of the current function. Because 'o' may not point to a
|
** the current function and, if so, returns its index. Because 'o' may
|
||||||
** value in this stack, we cannot compare it with the region
|
** not point to a value in this stack, we cannot compare it with the
|
||||||
** boundaries (undefined behaviour in ISO C).
|
** region boundaries (undefined behavior in ISO C).
|
||||||
*/
|
*/
|
||||||
static int isinstack (CallInfo *ci, const TValue *o) {
|
static int instack (CallInfo *ci, const TValue *o) {
|
||||||
StkId pos;
|
int pos;
|
||||||
for (pos = ci->func + 1; pos < ci->top; pos++) {
|
StkId base = ci->func.p + 1;
|
||||||
if (o == s2v(pos))
|
for (pos = 0; base + pos < ci->top.p; pos++) {
|
||||||
return 1;
|
if (o == s2v(base + pos))
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
return 0; /* not found */
|
return -1; /* not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -681,9 +703,9 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
|
|||||||
LClosure *c = ci_func(ci);
|
LClosure *c = ci_func(ci);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < c->nupvalues; i++) {
|
for (i = 0; i < c->nupvalues; i++) {
|
||||||
if (c->upvals[i]->v == o) {
|
if (c->upvals[i]->v.p == o) {
|
||||||
*name = upvalname(c->p, i);
|
*name = upvalname(c->p, i);
|
||||||
return "upvalue";
|
return strupval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -708,9 +730,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
|
|||||||
const char *kind = NULL;
|
const char *kind = NULL;
|
||||||
if (isLua(ci)) {
|
if (isLua(ci)) {
|
||||||
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
||||||
if (!kind && isinstack(ci, o)) /* no? try a register */
|
if (!kind) { /* not an upvalue? */
|
||||||
kind = getobjname(ci_func(ci)->p, currentpc(ci),
|
int reg = instack(ci, o); /* try a register */
|
||||||
cast_int(cast(StkId, o) - (ci->func + 1)), &name);
|
if (reg >= 0) /* is 'o' a register? */
|
||||||
|
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return formatvarinfo(L, kind, name);
|
return formatvarinfo(L, kind, name);
|
||||||
}
|
}
|
||||||
@@ -790,16 +814,26 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k) {
|
||||||
|
const char *globalname = "?"; /* default name if k == 0 */
|
||||||
|
if (k > 0)
|
||||||
|
kname(cl->p, k - 1, &globalname);
|
||||||
|
luaG_runerror(L, "global '%s' already defined", globalname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* add src:line information to 'msg' */
|
/* add src:line information to 'msg' */
|
||||||
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
||||||
int line) {
|
int line) {
|
||||||
char buff[LUA_IDSIZE];
|
if (src == NULL) /* no debug information? */
|
||||||
if (src)
|
return luaO_pushfstring(L, "?:?: %s", msg);
|
||||||
luaO_chunkid(buff, getstr(src), tsslen(src));
|
else {
|
||||||
else { /* no source available; use "?" instead */
|
char buff[LUA_IDSIZE];
|
||||||
buff[0] = '?'; buff[1] = '\0';
|
size_t idlen;
|
||||||
|
const char *id = getlstr(src, idlen);
|
||||||
|
luaO_chunkid(buff, id, idlen);
|
||||||
|
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
||||||
}
|
}
|
||||||
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -807,10 +841,14 @@ l_noret luaG_errormsg (lua_State *L) {
|
|||||||
if (L->errfunc != 0) { /* is there an error handling function? */
|
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||||
StkId errfunc = restorestack(L, L->errfunc);
|
StkId errfunc = restorestack(L, L->errfunc);
|
||||||
lua_assert(ttisfunction(s2v(errfunc)));
|
lua_assert(ttisfunction(s2v(errfunc)));
|
||||||
setobjs2s(L, L->top, L->top - 1); /* move argument */
|
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
|
||||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
|
||||||
L->top++; /* assume EXTRA_STACK */
|
L->top.p++; /* assume EXTRA_STACK */
|
||||||
luaD_callnoyield(L, L->top - 2, 1); /* call it */
|
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
|
||||||
|
}
|
||||||
|
if (ttisnil(s2v(L->top.p - 1))) { /* error object is nil? */
|
||||||
|
/* change it to a proper message */
|
||||||
|
setsvalue2s(L, L->top.p - 1, luaS_newliteral(L, "<no error object>"));
|
||||||
}
|
}
|
||||||
luaD_throw(L, LUA_ERRRUN);
|
luaD_throw(L, LUA_ERRRUN);
|
||||||
}
|
}
|
||||||
@@ -821,11 +859,13 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
|||||||
const char *msg;
|
const char *msg;
|
||||||
va_list argp;
|
va_list argp;
|
||||||
luaC_checkGC(L); /* error message uses memory */
|
luaC_checkGC(L); /* error message uses memory */
|
||||||
va_start(argp, fmt);
|
pushvfstring(L, argp, fmt, msg);
|
||||||
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
|
if (isLua(ci)) { /* Lua function? */
|
||||||
va_end(argp);
|
/* add source:line information */
|
||||||
if (isLua(ci)) /* if Lua function, add source:line information */
|
|
||||||
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
|
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
|
||||||
|
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
|
||||||
|
L->top.p--;
|
||||||
|
}
|
||||||
luaG_errormsg(L);
|
luaG_errormsg(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,7 +882,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
|||||||
if (p->lineinfo == NULL) /* no debug information? */
|
if (p->lineinfo == NULL) /* no debug information? */
|
||||||
return 0;
|
return 0;
|
||||||
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
|
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
|
||||||
int delta = 0; /* line diference */
|
int delta = 0; /* line difference */
|
||||||
int pc = oldpc;
|
int pc = oldpc;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int lineinfo = p->lineinfo[++pc];
|
int lineinfo = p->lineinfo[++pc];
|
||||||
@@ -859,6 +899,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Traces Lua calls. If code is running the first instruction of a function,
|
||||||
|
** and function is not vararg, and it is not coming from an yield,
|
||||||
|
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
|
||||||
|
** after adjusting its variable arguments; otherwise, they could call
|
||||||
|
** a line/count hook before the call hook. Functions coming from
|
||||||
|
** an yield already called 'luaD_hookcall' before yielding.)
|
||||||
|
*/
|
||||||
|
int luaG_tracecall (lua_State *L) {
|
||||||
|
CallInfo *ci = L->ci;
|
||||||
|
Proto *p = ci_func(ci)->p;
|
||||||
|
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
||||||
|
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
||||||
|
if (isvararg(p))
|
||||||
|
return 0; /* hooks will start at VARARGPREP instruction */
|
||||||
|
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yielded? */
|
||||||
|
luaD_hookcall(L, ci); /* check 'call' hook */
|
||||||
|
}
|
||||||
|
return 1; /* keep 'trap' on */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Traces the execution of a Lua function. Called before the execution
|
** Traces the execution of a Lua function. Called before the execution
|
||||||
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
||||||
@@ -869,11 +931,11 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
|||||||
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
||||||
** at most causes an extra call to a line hook.)
|
** at most causes an extra call to a line hook.)
|
||||||
** This function is not "Protected" when called, so it should correct
|
** This function is not "Protected" when called, so it should correct
|
||||||
** 'L->top' before calling anything that can run the GC.
|
** 'L->top.p' before calling anything that can run the GC.
|
||||||
*/
|
*/
|
||||||
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
lu_byte mask = L->hookmask;
|
lu_byte mask = cast_byte(L->hookmask);
|
||||||
const Proto *p = ci_func(ci)->p;
|
const Proto *p = ci_func(ci)->p;
|
||||||
int counthook;
|
int counthook;
|
||||||
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
|
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
|
||||||
@@ -882,17 +944,17 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
|||||||
}
|
}
|
||||||
pc++; /* reference is always next instruction */
|
pc++; /* reference is always next instruction */
|
||||||
ci->u.l.savedpc = pc; /* save 'pc' */
|
ci->u.l.savedpc = pc; /* save 'pc' */
|
||||||
counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
|
counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
|
||||||
if (counthook)
|
if (counthook)
|
||||||
resethookcount(L); /* reset count */
|
resethookcount(L); /* reset count */
|
||||||
else if (!(mask & LUA_MASKLINE))
|
else if (!(mask & LUA_MASKLINE))
|
||||||
return 1; /* no line hook and count != 0; nothing to be done now */
|
return 1; /* no line hook and count != 0; nothing to be done now */
|
||||||
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
|
if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
|
||||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||||
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
||||||
}
|
}
|
||||||
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
if (!luaP_isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
||||||
L->top = ci->top; /* correct top */
|
L->top.p = ci->top.p; /* correct top */
|
||||||
if (counthook)
|
if (counthook)
|
||||||
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
||||||
if (mask & LUA_MASKLINE) {
|
if (mask & LUA_MASKLINE) {
|
||||||
@@ -909,7 +971,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
|||||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||||
if (counthook)
|
if (counthook)
|
||||||
L->hookcount = 1; /* undo decrement to zero */
|
L->hookcount = 1; /* undo decrement to zero */
|
||||||
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
|
|
||||||
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
||||||
luaD_throw(L, LUA_YIELD);
|
luaD_throw(L, LUA_YIELD);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Active Lua function (given call info) */
|
/* Active Lua function (given call info) */
|
||||||
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
|
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
|
||||||
|
|
||||||
|
|
||||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||||
@@ -53,11 +53,13 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
|
|||||||
const TValue *p2);
|
const TValue *p2);
|
||||||
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
||||||
const TValue *p2);
|
const TValue *p2);
|
||||||
|
LUAI_FUNC l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k);
|
||||||
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||||
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
||||||
TString *src, int line);
|
TString *src, int line);
|
||||||
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
||||||
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
|
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
|
||||||
|
LUAI_FUNC int luaG_tracecall (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#define ldo_h
|
#define ldo_h
|
||||||
|
|
||||||
|
|
||||||
|
#include "llimits.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
@@ -22,58 +23,77 @@
|
|||||||
** 'condmovestack' is used in heavy tests to force a stack reallocation
|
** 'condmovestack' is used in heavy tests to force a stack reallocation
|
||||||
** at every check.
|
** at every check.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !defined(HARDSTACKTESTS)
|
||||||
|
#define condmovestack(L,pre,pos) ((void)0)
|
||||||
|
#else
|
||||||
|
/* realloc stack keeping its size */
|
||||||
|
#define condmovestack(L,pre,pos) \
|
||||||
|
{ int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
|
||||||
|
#endif
|
||||||
|
|
||||||
#define luaD_checkstackaux(L,n,pre,pos) \
|
#define luaD_checkstackaux(L,n,pre,pos) \
|
||||||
if (l_unlikely(L->stack_last - L->top <= (n))) \
|
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
|
||||||
{ pre; luaD_growstack(L, n, 1); pos; } \
|
{ pre; luaD_growstack(L, n, 1); pos; } \
|
||||||
else { condmovestack(L,pre,pos); }
|
else { condmovestack(L,pre,pos); }
|
||||||
|
|
||||||
/* In general, 'pre'/'pos' are empty (nothing to save) */
|
/* In general, 'pre'/'pos' are empty (nothing to save) */
|
||||||
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
|
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
|
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
|
||||||
#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
|
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
|
||||||
|
|
||||||
|
|
||||||
/* macro to check stack size, preserving 'p' */
|
/* macro to check stack size, preserving 'p' */
|
||||||
#define checkstackGCp(L,n,p) \
|
#define checkstackp(L,n,p) \
|
||||||
luaD_checkstackaux(L, n, \
|
luaD_checkstackaux(L, n, \
|
||||||
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
|
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
|
||||||
luaC_checkGC(L), /* stack grow uses memory */ \
|
|
||||||
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
||||||
|
|
||||||
|
|
||||||
/* macro to check stack size and GC */
|
/*
|
||||||
#define checkstackGC(L,fsize) \
|
** Maximum depth for nested C calls, syntactical nested non-terminals,
|
||||||
luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
|
** and other features implemented through recursion in C. (Value must
|
||||||
|
** fit in a 16-bit unsigned integer. It must also be compatible with
|
||||||
|
** the size of the C stack.)
|
||||||
|
*/
|
||||||
|
#if !defined(LUAI_MAXCCALLS)
|
||||||
|
#define LUAI_MAXCCALLS 200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* type of protected functions, to be ran by 'runprotected' */
|
/* type of protected functions, to be ran by 'runprotected' */
|
||||||
typedef void (*Pfunc) (lua_State *L, void *ud);
|
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||||
|
|
||||||
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
|
LUAI_FUNC l_noret luaD_errerr (lua_State *L);
|
||||||
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
LUAI_FUNC void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop);
|
||||||
|
LUAI_FUNC TStatus luaD_protectedparser (lua_State *L, ZIO *z,
|
||||||
|
const char *name,
|
||||||
const char *mode);
|
const char *mode);
|
||||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
||||||
int fTransfer, int nTransfer);
|
int fTransfer, int nTransfer);
|
||||||
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
||||||
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
|
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||||
|
int narg1, int delta);
|
||||||
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
|
LUAI_FUNC TStatus luaD_closeprotected (lua_State *L, ptrdiff_t level,
|
||||||
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
|
TStatus status);
|
||||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
LUAI_FUNC TStatus luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||||
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
|
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
|
||||||
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
|
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
|
||||||
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
||||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
||||||
LUAI_FUNC void luaD_inctop (lua_State *L);
|
LUAI_FUNC int luaD_checkminstack (lua_State *L);
|
||||||
|
LUAI_FUNC void luaD_anchorobj (lua_State *L, Table *anchor, GCObject *obj);
|
||||||
|
|
||||||
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
|
LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode);
|
||||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);
|
||||||
|
LUAI_FUNC TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,16 @@
|
|||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lapi.h"
|
||||||
|
#include "lgc.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
#include "ltable.h"
|
||||||
#include "lundump.h"
|
#include "lundump.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -23,8 +27,11 @@ typedef struct {
|
|||||||
lua_State *L;
|
lua_State *L;
|
||||||
lua_Writer writer;
|
lua_Writer writer;
|
||||||
void *data;
|
void *data;
|
||||||
|
size_t offset; /* current position relative to beginning of dump */
|
||||||
int strip;
|
int strip;
|
||||||
int status;
|
int status;
|
||||||
|
Table *h; /* table to track saved strings */
|
||||||
|
lua_Unsigned nstr; /* counter for counting saved strings */
|
||||||
} DumpState;
|
} DumpState;
|
||||||
|
|
||||||
|
|
||||||
@@ -37,15 +44,36 @@ typedef struct {
|
|||||||
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
|
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Dump the block of memory pointed by 'b' with given 'size'.
|
||||||
|
** 'b' should not be NULL, except for the last call signaling the end
|
||||||
|
** of the dump.
|
||||||
|
*/
|
||||||
static void dumpBlock (DumpState *D, const void *b, size_t size) {
|
static void dumpBlock (DumpState *D, const void *b, size_t size) {
|
||||||
if (D->status == 0 && size > 0) {
|
if (D->status == 0) { /* do not write anything after an error */
|
||||||
lua_unlock(D->L);
|
lua_unlock(D->L);
|
||||||
D->status = (*D->writer)(D->L, b, size, D->data);
|
D->status = (*D->writer)(D->L, b, size, D->data);
|
||||||
lua_lock(D->L);
|
lua_lock(D->L);
|
||||||
|
D->offset += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Dump enough zeros to ensure that current position is a multiple of
|
||||||
|
** 'align'.
|
||||||
|
*/
|
||||||
|
static void dumpAlign (DumpState *D, unsigned align) {
|
||||||
|
unsigned padding = align - cast_uint(D->offset % align);
|
||||||
|
if (padding < align) { /* padding == align means no padding */
|
||||||
|
static lua_Integer paddingContent = 0;
|
||||||
|
lua_assert(align <= sizeof(lua_Integer));
|
||||||
|
dumpBlock(D, &paddingContent, padding);
|
||||||
|
}
|
||||||
|
lua_assert(D->offset % align == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define dumpVar(D,x) dumpVector(D,&x,1)
|
#define dumpVar(D,x) dumpVector(D,&x,1)
|
||||||
|
|
||||||
|
|
||||||
@@ -55,23 +83,33 @@ static void dumpByte (DumpState *D, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* dumpInt Buff Size */
|
/*
|
||||||
#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
|
** size for 'dumpVarint' buffer: each byte can store up to 7 bits.
|
||||||
|
** (The "+6" rounds up the division.)
|
||||||
|
*/
|
||||||
|
#define DIBS ((l_numbits(lua_Unsigned) + 6) / 7)
|
||||||
|
|
||||||
static void dumpSize (DumpState *D, size_t x) {
|
/*
|
||||||
|
** Dumps an unsigned integer using the MSB Varint encoding
|
||||||
|
*/
|
||||||
|
static void dumpVarint (DumpState *D, lua_Unsigned x) {
|
||||||
lu_byte buff[DIBS];
|
lu_byte buff[DIBS];
|
||||||
int n = 0;
|
unsigned n = 1;
|
||||||
do {
|
buff[DIBS - 1] = x & 0x7f; /* fill least-significant byte */
|
||||||
buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */
|
while ((x >>= 7) != 0) /* fill other bytes in reverse order */
|
||||||
x >>= 7;
|
buff[DIBS - (++n)] = cast_byte((x & 0x7f) | 0x80);
|
||||||
} while (x != 0);
|
|
||||||
buff[DIBS - 1] |= 0x80; /* mark last byte */
|
|
||||||
dumpVector(D, buff + DIBS - n, n);
|
dumpVector(D, buff + DIBS - n, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpSize (DumpState *D, size_t sz) {
|
||||||
|
dumpVarint(D, cast(lua_Unsigned, sz));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dumpInt (DumpState *D, int x) {
|
static void dumpInt (DumpState *D, int x) {
|
||||||
dumpSize(D, x);
|
lua_assert(x >= 0);
|
||||||
|
dumpVarint(D, cast_uint(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -80,30 +118,65 @@ static void dumpNumber (DumpState *D, lua_Number x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Signed integers are coded to keep small values small. (Coding -1 as
|
||||||
|
** 0xfff...fff would use too many bytes to save a quite common value.)
|
||||||
|
** A non-negative x is coded as 2x; a negative x is coded as -2x - 1.
|
||||||
|
** (0 => 0; -1 => 1; 1 => 2; -2 => 3; 2 => 4; ...)
|
||||||
|
*/
|
||||||
static void dumpInteger (DumpState *D, lua_Integer x) {
|
static void dumpInteger (DumpState *D, lua_Integer x) {
|
||||||
dumpVar(D, x);
|
lua_Unsigned cx = (x >= 0) ? 2u * l_castS2U(x)
|
||||||
|
: (2u * ~l_castS2U(x)) + 1;
|
||||||
|
dumpVarint(D, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dumpString (DumpState *D, const TString *s) {
|
/*
|
||||||
if (s == NULL)
|
** Dump a String. First dump its "size":
|
||||||
dumpSize(D, 0);
|
** size==0 is followed by an index and means "reuse saved string with
|
||||||
|
** that index"; index==0 means NULL.
|
||||||
|
** size>=1 is followed by the string contents with real size==size-1 and
|
||||||
|
** means that string, which will be saved with the next available index.
|
||||||
|
** The real size does not include the ending '\0' (which is not dumped),
|
||||||
|
** so adding 1 to it cannot overflow a size_t.
|
||||||
|
*/
|
||||||
|
static void dumpString (DumpState *D, TString *ts) {
|
||||||
|
if (ts == NULL) {
|
||||||
|
dumpVarint(D, 0); /* will "reuse" NULL */
|
||||||
|
dumpVarint(D, 0); /* special index for NULL */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
size_t size = tsslen(s);
|
TValue idx;
|
||||||
const char *str = getstr(s);
|
int tag = luaH_getstr(D->h, ts, &idx);
|
||||||
dumpSize(D, size + 1);
|
if (!tagisempty(tag)) { /* string already saved? */
|
||||||
dumpVector(D, str, size);
|
dumpVarint(D, 0); /* reuse a saved string */
|
||||||
|
dumpVarint(D, l_castS2U(ivalue(&idx))); /* index of saved string */
|
||||||
|
}
|
||||||
|
else { /* must write and save the string */
|
||||||
|
TValue key, value; /* to save the string in the hash */
|
||||||
|
size_t size;
|
||||||
|
const char *s = getlstr(ts, size);
|
||||||
|
dumpSize(D, size + 1);
|
||||||
|
dumpVector(D, s, size + 1); /* include ending '\0' */
|
||||||
|
D->nstr++; /* one more saved string */
|
||||||
|
setsvalue(D->L, &key, ts); /* the string is the key */
|
||||||
|
setivalue(&value, l_castU2S(D->nstr)); /* its index is the value */
|
||||||
|
luaH_set(D->L, D->h, &key, &value); /* h[ts] = nstr */
|
||||||
|
/* integer value does not need barrier */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dumpCode (DumpState *D, const Proto *f) {
|
static void dumpCode (DumpState *D, const Proto *f) {
|
||||||
dumpInt(D, f->sizecode);
|
dumpInt(D, f->sizecode);
|
||||||
dumpVector(D, f->code, f->sizecode);
|
dumpAlign(D, sizeof(f->code[0]));
|
||||||
|
lua_assert(f->code != NULL);
|
||||||
|
dumpVector(D, f->code, cast_uint(f->sizecode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dumpFunction(DumpState *D, const Proto *f, TString *psource);
|
static void dumpFunction (DumpState *D, const Proto *f);
|
||||||
|
|
||||||
static void dumpConstants (DumpState *D, const Proto *f) {
|
static void dumpConstants (DumpState *D, const Proto *f) {
|
||||||
int i;
|
int i;
|
||||||
@@ -136,7 +209,7 @@ static void dumpProtos (DumpState *D, const Proto *f) {
|
|||||||
int n = f->sizep;
|
int n = f->sizep;
|
||||||
dumpInt(D, n);
|
dumpInt(D, n);
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
dumpFunction(D, f->p[i], f->source);
|
dumpFunction(D, f->p[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -155,12 +228,14 @@ static void dumpDebug (DumpState *D, const Proto *f) {
|
|||||||
int i, n;
|
int i, n;
|
||||||
n = (D->strip) ? 0 : f->sizelineinfo;
|
n = (D->strip) ? 0 : f->sizelineinfo;
|
||||||
dumpInt(D, n);
|
dumpInt(D, n);
|
||||||
dumpVector(D, f->lineinfo, n);
|
if (f->lineinfo != NULL)
|
||||||
|
dumpVector(D, f->lineinfo, cast_uint(n));
|
||||||
n = (D->strip) ? 0 : f->sizeabslineinfo;
|
n = (D->strip) ? 0 : f->sizeabslineinfo;
|
||||||
dumpInt(D, n);
|
dumpInt(D, n);
|
||||||
for (i = 0; i < n; i++) {
|
if (n > 0) {
|
||||||
dumpInt(D, f->abslineinfo[i].pc);
|
/* 'abslineinfo' is an array of structures of int's */
|
||||||
dumpInt(D, f->abslineinfo[i].line);
|
dumpAlign(D, sizeof(int));
|
||||||
|
dumpVector(D, f->abslineinfo, cast_uint(n));
|
||||||
}
|
}
|
||||||
n = (D->strip) ? 0 : f->sizelocvars;
|
n = (D->strip) ? 0 : f->sizelocvars;
|
||||||
dumpInt(D, n);
|
dumpInt(D, n);
|
||||||
@@ -176,51 +251,57 @@ static void dumpDebug (DumpState *D, const Proto *f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dumpFunction (DumpState *D, const Proto *f, TString *psource) {
|
static void dumpFunction (DumpState *D, const Proto *f) {
|
||||||
if (D->strip || f->source == psource)
|
|
||||||
dumpString(D, NULL); /* no debug info or same source as its parent */
|
|
||||||
else
|
|
||||||
dumpString(D, f->source);
|
|
||||||
dumpInt(D, f->linedefined);
|
dumpInt(D, f->linedefined);
|
||||||
dumpInt(D, f->lastlinedefined);
|
dumpInt(D, f->lastlinedefined);
|
||||||
dumpByte(D, f->numparams);
|
dumpByte(D, f->numparams);
|
||||||
dumpByte(D, f->is_vararg);
|
dumpByte(D, f->flag);
|
||||||
dumpByte(D, f->maxstacksize);
|
dumpByte(D, f->maxstacksize);
|
||||||
dumpCode(D, f);
|
dumpCode(D, f);
|
||||||
dumpConstants(D, f);
|
dumpConstants(D, f);
|
||||||
dumpUpvalues(D, f);
|
dumpUpvalues(D, f);
|
||||||
dumpProtos(D, f);
|
dumpProtos(D, f);
|
||||||
|
dumpString(D, D->strip ? NULL : f->source);
|
||||||
dumpDebug(D, f);
|
dumpDebug(D, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define dumpNumInfo(D, tvar, value) \
|
||||||
|
{ tvar i = value; dumpByte(D, sizeof(tvar)); dumpVar(D, i); }
|
||||||
|
|
||||||
|
|
||||||
static void dumpHeader (DumpState *D) {
|
static void dumpHeader (DumpState *D) {
|
||||||
dumpLiteral(D, LUA_SIGNATURE);
|
dumpLiteral(D, LUA_SIGNATURE);
|
||||||
dumpByte(D, LUAC_VERSION);
|
dumpByte(D, LUAC_VERSION);
|
||||||
dumpByte(D, LUAC_FORMAT);
|
dumpByte(D, LUAC_FORMAT);
|
||||||
dumpLiteral(D, LUAC_DATA);
|
dumpLiteral(D, LUAC_DATA);
|
||||||
dumpByte(D, sizeof(Instruction));
|
dumpNumInfo(D, int, LUAC_INT);
|
||||||
dumpByte(D, sizeof(lua_Integer));
|
dumpNumInfo(D, Instruction, LUAC_INST);
|
||||||
dumpByte(D, sizeof(lua_Number));
|
dumpNumInfo(D, lua_Integer, LUAC_INT);
|
||||||
dumpInteger(D, LUAC_INT);
|
dumpNumInfo(D, lua_Number, LUAC_NUM);
|
||||||
dumpNumber(D, LUAC_NUM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** dump Lua function as precompiled chunk
|
** dump Lua function as precompiled chunk
|
||||||
*/
|
*/
|
||||||
int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
|
int luaU_dump (lua_State *L, const Proto *f, lua_Writer w, void *data,
|
||||||
int strip) {
|
int strip) {
|
||||||
DumpState D;
|
DumpState D;
|
||||||
|
D.h = luaH_new(L); /* aux. table to keep strings already dumped */
|
||||||
|
sethvalue2s(L, L->top.p, D.h); /* anchor it */
|
||||||
|
L->top.p++;
|
||||||
D.L = L;
|
D.L = L;
|
||||||
D.writer = w;
|
D.writer = w;
|
||||||
|
D.offset = 0;
|
||||||
D.data = data;
|
D.data = data;
|
||||||
D.strip = strip;
|
D.strip = strip;
|
||||||
D.status = 0;
|
D.status = 0;
|
||||||
|
D.nstr = 0;
|
||||||
dumpHeader(&D);
|
dumpHeader(&D);
|
||||||
dumpByte(&D, f->sizeupvalues);
|
dumpByte(&D, f->sizeupvalues);
|
||||||
dumpFunction(&D, f, NULL);
|
dumpFunction(&D, f);
|
||||||
|
dumpBlock(&D, NULL, 0); /* signal end of dump */
|
||||||
return D.status;
|
return D.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
|||||||
for (i = 0; i < cl->nupvalues; i++) {
|
for (i = 0; i < cl->nupvalues; i++) {
|
||||||
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
||||||
UpVal *uv = gco2upv(o);
|
UpVal *uv = gco2upv(o);
|
||||||
uv->v = &uv->u.value; /* make it closed */
|
uv->v.p = &uv->u.value; /* make it closed */
|
||||||
setnilvalue(uv->v);
|
setnilvalue(uv->v.p);
|
||||||
cl->upvals[i] = uv;
|
cl->upvals[i] = uv;
|
||||||
luaC_objbarrier(L, cl, uv);
|
luaC_objbarrier(L, cl, uv);
|
||||||
}
|
}
|
||||||
@@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
|||||||
** Create a new upvalue at the given level, and link it to the list of
|
** Create a new upvalue at the given level, and link it to the list of
|
||||||
** open upvalues of 'L' after entry 'prev'.
|
** open upvalues of 'L' after entry 'prev'.
|
||||||
**/
|
**/
|
||||||
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
|
static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
|
||||||
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
||||||
UpVal *uv = gco2upv(o);
|
UpVal *uv = gco2upv(o);
|
||||||
UpVal *next = *prev;
|
UpVal *next = *prev;
|
||||||
uv->v = s2v(level); /* current value lives in the stack */
|
uv->v.p = s2v(level); /* current value lives in the stack */
|
||||||
uv->tbc = tbc;
|
|
||||||
uv->u.open.next = next; /* link it to list of open upvalues */
|
uv->u.open.next = next; /* link it to list of open upvalues */
|
||||||
uv->u.open.previous = prev;
|
uv->u.open.previous = prev;
|
||||||
if (next)
|
if (next)
|
||||||
@@ -96,26 +95,28 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||||||
pp = &p->u.open.next;
|
pp = &p->u.open.next;
|
||||||
}
|
}
|
||||||
/* not found: create a new upvalue after 'pp' */
|
/* not found: create a new upvalue after 'pp' */
|
||||||
return newupval(L, 0, level, pp);
|
return newupval(L, level, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Call closing method for object 'obj' with error message 'err'. The
|
** Call closing method for object 'obj' with error object 'err'. The
|
||||||
** boolean 'yy' controls whether the call is yieldable.
|
** boolean 'yy' controls whether the call is yieldable.
|
||||||
** (This function assumes EXTRA_STACK.)
|
** (This function assumes EXTRA_STACK.)
|
||||||
*/
|
*/
|
||||||
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
||||||
StkId top = L->top;
|
StkId top = L->top.p;
|
||||||
|
StkId func = top;
|
||||||
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
||||||
setobj2s(L, top, tm); /* will call metamethod... */
|
setobj2s(L, top++, tm); /* will call metamethod... */
|
||||||
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
|
setobj2s(L, top++, obj); /* with 'self' as the 1st argument */
|
||||||
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
|
if (err != NULL) /* if there was an error... */
|
||||||
L->top = top + 3; /* add function and arguments */
|
setobj2s(L, top++, err); /* then error object will be 2nd argument */
|
||||||
|
L->top.p = top; /* add function and arguments */
|
||||||
if (yy)
|
if (yy)
|
||||||
luaD_call(L, top, 0);
|
luaD_call(L, func, 0);
|
||||||
else
|
else
|
||||||
luaD_callnoyield(L, top, 0);
|
luaD_callnoyield(L, func, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
|||||||
static void checkclosemth (lua_State *L, StkId level) {
|
static void checkclosemth (lua_State *L, StkId level) {
|
||||||
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
|
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
|
||||||
if (ttisnil(tm)) { /* no metamethod? */
|
if (ttisnil(tm)) { /* no metamethod? */
|
||||||
int idx = cast_int(level - L->ci->func); /* variable index */
|
int idx = cast_int(level - L->ci->func.p); /* variable index */
|
||||||
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
|
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
|
||||||
if (vname == NULL) vname = "?";
|
if (vname == NULL) vname = "?";
|
||||||
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
|
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
|
||||||
@@ -141,42 +142,44 @@ static void checkclosemth (lua_State *L, StkId level) {
|
|||||||
** the 'level' of the upvalue being closed, as everything after that
|
** the 'level' of the upvalue being closed, as everything after that
|
||||||
** won't be used again.
|
** won't be used again.
|
||||||
*/
|
*/
|
||||||
static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
|
static void prepcallclosemth (lua_State *L, StkId level, TStatus status,
|
||||||
|
int yy) {
|
||||||
TValue *uv = s2v(level); /* value being closed */
|
TValue *uv = s2v(level); /* value being closed */
|
||||||
TValue *errobj;
|
TValue *errobj;
|
||||||
if (status == CLOSEKTOP)
|
switch (status) {
|
||||||
errobj = &G(L)->nilvalue; /* error object is nil */
|
case LUA_OK:
|
||||||
else { /* 'luaD_seterrorobj' will set top to level + 2 */
|
L->top.p = level + 1; /* call will be at this level */
|
||||||
errobj = s2v(level + 1); /* error object goes after 'uv' */
|
/* FALLTHROUGH */
|
||||||
luaD_seterrorobj(L, status, level + 1); /* set error object */
|
case CLOSEKTOP: /* don't need to change top */
|
||||||
|
errobj = NULL; /* no error object */
|
||||||
|
break;
|
||||||
|
default: /* 'luaD_seterrorobj' will set top to level + 2 */
|
||||||
|
errobj = s2v(level + 1); /* error object goes after 'uv' */
|
||||||
|
luaD_seterrorobj(L, status, level + 1); /* set error object */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
callclosemethod(L, uv, errobj, yy);
|
callclosemethod(L, uv, errobj, yy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* Maximum value for deltas in 'tbclist' */
|
||||||
** Maximum value for deltas in 'tbclist', dependent on the type
|
#define MAXDELTA USHRT_MAX
|
||||||
** of delta. (This macro assumes that an 'L' is in scope where it
|
|
||||||
** is used.)
|
|
||||||
*/
|
|
||||||
#define MAXDELTA \
|
|
||||||
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Insert a variable in the list of to-be-closed variables.
|
** Insert a variable in the list of to-be-closed variables.
|
||||||
*/
|
*/
|
||||||
void luaF_newtbcupval (lua_State *L, StkId level) {
|
void luaF_newtbcupval (lua_State *L, StkId level) {
|
||||||
lua_assert(level > L->tbclist);
|
lua_assert(level > L->tbclist.p);
|
||||||
if (l_isfalse(s2v(level)))
|
if (l_isfalse(s2v(level)))
|
||||||
return; /* false doesn't need to be closed */
|
return; /* false doesn't need to be closed */
|
||||||
checkclosemth(L, level); /* value must have a close method */
|
checkclosemth(L, level); /* value must have a close method */
|
||||||
while (cast_uint(level - L->tbclist) > MAXDELTA) {
|
while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
|
||||||
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
|
L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
|
||||||
L->tbclist->tbclist.delta = 0;
|
L->tbclist.p->tbclist.delta = 0;
|
||||||
}
|
}
|
||||||
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
|
level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
|
||||||
L->tbclist = level;
|
L->tbclist.p = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -193,13 +196,12 @@ void luaF_unlinkupval (UpVal *uv) {
|
|||||||
*/
|
*/
|
||||||
void luaF_closeupval (lua_State *L, StkId level) {
|
void luaF_closeupval (lua_State *L, StkId level) {
|
||||||
UpVal *uv;
|
UpVal *uv;
|
||||||
StkId upl; /* stack index pointed by 'uv' */
|
while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
|
||||||
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
|
|
||||||
TValue *slot = &uv->u.value; /* new position for value */
|
TValue *slot = &uv->u.value; /* new position for value */
|
||||||
lua_assert(uplevel(uv) < L->top);
|
lua_assert(uplevel(uv) < L->top.p);
|
||||||
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
||||||
setobj(L, slot, uv->v); /* move value to upvalue slot */
|
setobj(L, slot, uv->v.p); /* move value to upvalue slot */
|
||||||
uv->v = slot; /* now current value lives here */
|
uv->v.p = slot; /* now current value lives here */
|
||||||
if (!iswhite(uv)) { /* neither white nor dead? */
|
if (!iswhite(uv)) { /* neither white nor dead? */
|
||||||
nw2black(uv); /* closed upvalues cannot be gray */
|
nw2black(uv); /* closed upvalues cannot be gray */
|
||||||
luaC_barrier(L, uv, slot);
|
luaC_barrier(L, uv, slot);
|
||||||
@@ -209,31 +211,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Remove firt element from the tbclist plus its dummy nodes.
|
** Remove first element from the tbclist plus its dummy nodes.
|
||||||
*/
|
*/
|
||||||
static void poptbclist (lua_State *L) {
|
static void poptbclist (lua_State *L) {
|
||||||
StkId tbc = L->tbclist;
|
StkId tbc = L->tbclist.p;
|
||||||
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
||||||
tbc -= tbc->tbclist.delta;
|
tbc -= tbc->tbclist.delta;
|
||||||
while (tbc > L->stack && tbc->tbclist.delta == 0)
|
while (tbc > L->stack.p && tbc->tbclist.delta == 0)
|
||||||
tbc -= MAXDELTA; /* remove dummy nodes */
|
tbc -= MAXDELTA; /* remove dummy nodes */
|
||||||
L->tbclist = tbc;
|
L->tbclist.p = tbc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Close all upvalues and to-be-closed variables up to the given stack
|
** Close all upvalues and to-be-closed variables up to the given stack
|
||||||
** level.
|
** level. Return restored 'level'.
|
||||||
*/
|
*/
|
||||||
void luaF_close (lua_State *L, StkId level, int status, int yy) {
|
StkId luaF_close (lua_State *L, StkId level, TStatus status, int yy) {
|
||||||
ptrdiff_t levelrel = savestack(L, level);
|
ptrdiff_t levelrel = savestack(L, level);
|
||||||
luaF_closeupval(L, level); /* first, close the upvalues */
|
luaF_closeupval(L, level); /* first, close the upvalues */
|
||||||
while (L->tbclist >= level) { /* traverse tbc's down to that level */
|
while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
|
||||||
StkId tbc = L->tbclist; /* get variable index */
|
StkId tbc = L->tbclist.p; /* get variable index */
|
||||||
poptbclist(L); /* remove it from list */
|
poptbclist(L); /* remove it from list */
|
||||||
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
||||||
level = restorestack(L, levelrel);
|
level = restorestack(L, levelrel);
|
||||||
}
|
}
|
||||||
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -253,7 +256,7 @@ Proto *luaF_newproto (lua_State *L) {
|
|||||||
f->upvalues = NULL;
|
f->upvalues = NULL;
|
||||||
f->sizeupvalues = 0;
|
f->sizeupvalues = 0;
|
||||||
f->numparams = 0;
|
f->numparams = 0;
|
||||||
f->is_vararg = 0;
|
f->flag = 0;
|
||||||
f->maxstacksize = 0;
|
f->maxstacksize = 0;
|
||||||
f->locvars = NULL;
|
f->locvars = NULL;
|
||||||
f->sizelocvars = 0;
|
f->sizelocvars = 0;
|
||||||
@@ -264,14 +267,31 @@ Proto *luaF_newproto (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lu_mem luaF_protosize (Proto *p) {
|
||||||
|
lu_mem sz = cast(lu_mem, sizeof(Proto))
|
||||||
|
+ cast_uint(p->sizep) * sizeof(Proto*)
|
||||||
|
+ cast_uint(p->sizek) * sizeof(TValue)
|
||||||
|
+ cast_uint(p->sizelocvars) * sizeof(LocVar)
|
||||||
|
+ cast_uint(p->sizeupvalues) * sizeof(Upvaldesc);
|
||||||
|
if (!(p->flag & PF_FIXED)) {
|
||||||
|
sz += cast_uint(p->sizecode) * sizeof(Instruction);
|
||||||
|
sz += cast_uint(p->sizelineinfo) * sizeof(lu_byte);
|
||||||
|
sz += cast_uint(p->sizeabslineinfo) * sizeof(AbsLineInfo);
|
||||||
|
}
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||||
luaM_freearray(L, f->code, f->sizecode);
|
if (!(f->flag & PF_FIXED)) {
|
||||||
luaM_freearray(L, f->p, f->sizep);
|
luaM_freearray(L, f->code, cast_sizet(f->sizecode));
|
||||||
luaM_freearray(L, f->k, f->sizek);
|
luaM_freearray(L, f->lineinfo, cast_sizet(f->sizelineinfo));
|
||||||
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
|
luaM_freearray(L, f->abslineinfo, cast_sizet(f->sizeabslineinfo));
|
||||||
luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo);
|
}
|
||||||
luaM_freearray(L, f->locvars, f->sizelocvars);
|
luaM_freearray(L, f->p, cast_sizet(f->sizep));
|
||||||
luaM_freearray(L, f->upvalues, f->sizeupvalues);
|
luaM_freearray(L, f->k, cast_sizet(f->sizek));
|
||||||
|
luaM_freearray(L, f->locvars, cast_sizet(f->sizelocvars));
|
||||||
|
luaM_freearray(L, f->upvalues, cast_sizet(f->sizeupvalues));
|
||||||
luaM_free(L, f);
|
luaM_free(L, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
#define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \
|
#define sizeCclosure(n) \
|
||||||
cast_int(sizeof(TValue)) * (n))
|
(offsetof(CClosure, upvalue) + sizeof(TValue) * cast_uint(n))
|
||||||
|
|
||||||
#define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \
|
#define sizeLclosure(n) \
|
||||||
cast_int(sizeof(TValue *)) * (n))
|
(offsetof(LClosure, upvals) + sizeof(UpVal *) * cast_uint(n))
|
||||||
|
|
||||||
|
|
||||||
/* test whether thread is in 'twups' list */
|
/* test whether thread is in 'twups' list */
|
||||||
@@ -29,10 +29,10 @@
|
|||||||
#define MAXUPVAL 255
|
#define MAXUPVAL 255
|
||||||
|
|
||||||
|
|
||||||
#define upisopen(up) ((up)->v != &(up)->u.value)
|
#define upisopen(up) ((up)->v.p != &(up)->u.value)
|
||||||
|
|
||||||
|
|
||||||
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
|
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* special status to close upvalues preserving the top of the stack */
|
/* special status to close upvalues preserving the top of the stack */
|
||||||
#define CLOSEKTOP (-1)
|
#define CLOSEKTOP (LUA_ERRERR + 1)
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||||
@@ -54,8 +54,9 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
|
|||||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||||
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
|
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
|
||||||
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
|
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
|
||||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
|
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, TStatus status, int yy);
|
||||||
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
|
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
|
||||||
|
LUAI_FUNC lu_mem luaF_protosize (Proto *p);
|
||||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||||
int pc);
|
int pc);
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#define lgc_h
|
#define lgc_h
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
|
||||||
@@ -20,8 +23,9 @@
|
|||||||
** never point to a white one. Moreover, any gray object must be in a
|
** never point to a white one. Moreover, any gray object must be in a
|
||||||
** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
|
** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
|
||||||
** can be visited again before finishing the collection cycle. (Open
|
** can be visited again before finishing the collection cycle. (Open
|
||||||
** upvalues are an exception to this rule.) These lists have no meaning
|
** upvalues are an exception to this rule, as they are attached to
|
||||||
** when the invariant is not being enforced (e.g., sweep phase).
|
** a corresponding thread.) These lists have no meaning when the
|
||||||
|
** invariant is not being enforced (e.g., sweep phase).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -45,10 +49,10 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** macro to tell when main invariant (white objects cannot point to black
|
** macro to tell when main invariant (white objects cannot point to black
|
||||||
** ones) must be kept. During a collection, the sweep
|
** ones) must be kept. During a collection, the sweep phase may break
|
||||||
** phase may break the invariant, as objects turned white may point to
|
** the invariant, as objects turned white may point to still-black
|
||||||
** still-black objects. The invariant is restored when sweep ends and
|
** objects. The invariant is restored when sweep ends and all objects
|
||||||
** all objects are white again.
|
** are white again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
|
#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
|
||||||
@@ -117,36 +121,90 @@
|
|||||||
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
|
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
|
||||||
#define isold(o) (getage(o) > G_SURVIVAL)
|
#define isold(o) (getage(o) > G_SURVIVAL)
|
||||||
|
|
||||||
#define changeage(o,f,t) \
|
|
||||||
check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
|
/*
|
||||||
|
** In generational mode, objects are created 'new'. After surviving one
|
||||||
|
** cycle, they become 'survival'. Both 'new' and 'survival' can point
|
||||||
|
** to any other object, as they are traversed at the end of the cycle.
|
||||||
|
** We call them both 'young' objects.
|
||||||
|
** If a survival object survives another cycle, it becomes 'old1'.
|
||||||
|
** 'old1' objects can still point to survival objects (but not to
|
||||||
|
** new objects), so they still must be traversed. After another cycle
|
||||||
|
** (that, being old, 'old1' objects will "survive" no matter what)
|
||||||
|
** finally the 'old1' object becomes really 'old', and then they
|
||||||
|
** are no more traversed.
|
||||||
|
**
|
||||||
|
** To keep its invariants, the generational mode uses the same barriers
|
||||||
|
** also used by the incremental mode. If a young object is caught in a
|
||||||
|
** forward barrier, it cannot become old immediately, because it can
|
||||||
|
** still point to other young objects. Instead, it becomes 'old0',
|
||||||
|
** which in the next cycle becomes 'old1'. So, 'old0' objects is
|
||||||
|
** old but can point to new and survival objects; 'old1' is old
|
||||||
|
** but cannot point to new objects; and 'old' cannot point to any
|
||||||
|
** young object.
|
||||||
|
**
|
||||||
|
** If any old object ('old0', 'old1', 'old') is caught in a back
|
||||||
|
** barrier, it becomes 'touched1' and goes into a gray list, to be
|
||||||
|
** visited at the end of the cycle. There it evolves to 'touched2',
|
||||||
|
** which can point to survivals but not to new objects. In yet another
|
||||||
|
** cycle then it becomes 'old' again.
|
||||||
|
**
|
||||||
|
** The generational mode must also control the colors of objects,
|
||||||
|
** because of the barriers. While the mutator is running, young objects
|
||||||
|
** are kept white. 'old', 'old1', and 'touched2' objects are kept black,
|
||||||
|
** as they cannot point to new objects; exceptions are threads and open
|
||||||
|
** upvalues, which age to 'old1' and 'old' but are kept gray. 'old0'
|
||||||
|
** objects may be gray or black, as in the incremental mode. 'touched1'
|
||||||
|
** objects are kept gray, as they must be visited again at the end of
|
||||||
|
** the cycle.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Default Values for GC parameters */
|
/*
|
||||||
#define LUAI_GENMAJORMUL 100
|
** {======================================================
|
||||||
|
** Default Values for GC parameters
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Minor collections will shift to major ones after LUAI_MINORMAJOR%
|
||||||
|
** bytes become old.
|
||||||
|
*/
|
||||||
|
#define LUAI_MINORMAJOR 70
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Major collections will shift to minor ones after a collection
|
||||||
|
** collects at least LUAI_MAJORMINOR% of the new bytes.
|
||||||
|
*/
|
||||||
|
#define LUAI_MAJORMINOR 50
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A young (minor) collection will run after creating LUAI_GENMINORMUL%
|
||||||
|
** new bytes.
|
||||||
|
*/
|
||||||
#define LUAI_GENMINORMUL 20
|
#define LUAI_GENMINORMUL 20
|
||||||
|
|
||||||
/* wait memory to double before starting new cycle */
|
|
||||||
#define LUAI_GCPAUSE 200
|
/* incremental */
|
||||||
|
|
||||||
|
/* Number of bytes must be LUAI_GCPAUSE% before starting new cycle */
|
||||||
|
#define LUAI_GCPAUSE 250
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** some gc parameters are stored divided by 4 to allow a maximum value
|
** Step multiplier: The collector handles LUAI_GCMUL% work units for
|
||||||
** up to 1023 in a 'lu_byte'.
|
** each new allocated word. (Each "work unit" corresponds roughly to
|
||||||
|
** sweeping one object or traversing one slot.)
|
||||||
*/
|
*/
|
||||||
#define getgcparam(p) ((p) * 4)
|
#define LUAI_GCMUL 200
|
||||||
#define setgcparam(p,v) ((p) = (v) / 4)
|
|
||||||
|
|
||||||
#define LUAI_GCMUL 100
|
/* How many bytes to allocate before next GC step */
|
||||||
|
#define LUAI_GCSTEPSIZE (200 * sizeof(Table))
|
||||||
/* how much to allocate before next GC step (log2) */
|
|
||||||
#define LUAI_GCSTEPSIZE 13 /* 8 KB */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
#define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v))
|
||||||
** Check whether the declared GC mode is generational. While in
|
#define applygcparam(g,p,x) luaO_applyparam(g->gcparams[LUA_GCP##p], x)
|
||||||
** generational mode, the collector can go temporarily to incremental
|
|
||||||
** mode to improve performance. This is signaled by 'g->lastatomic != 0'.
|
/* }====================================================== */
|
||||||
*/
|
|
||||||
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -159,37 +217,48 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Does one step of collection when debt becomes positive. 'pre'/'pos'
|
** Does one step of collection when debt becomes zero. 'pre'/'pos'
|
||||||
** allows some adjustments to be done only when needed. macro
|
** allows some adjustments to be done only when needed. macro
|
||||||
** 'condchangemem' is used only for heavy tests (forcing a full
|
** 'condchangemem' is used only for heavy tests (forcing a full
|
||||||
** GC cycle on every opportunity)
|
** GC cycle on every opportunity)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !defined(HARDMEMTESTS)
|
||||||
|
#define condchangemem(L,pre,pos,emg) ((void)0)
|
||||||
|
#else
|
||||||
|
#define condchangemem(L,pre,pos,emg) \
|
||||||
|
{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, emg); pos; } }
|
||||||
|
#endif
|
||||||
|
|
||||||
#define luaC_condGC(L,pre,pos) \
|
#define luaC_condGC(L,pre,pos) \
|
||||||
{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
|
{ if (G(L)->GCdebt <= 0) { pre; luaC_step(L); pos;}; \
|
||||||
condchangemem(L,pre,pos); }
|
condchangemem(L,pre,pos,0); }
|
||||||
|
|
||||||
/* more often than not, 'pre'/'pos' are empty */
|
/* more often than not, 'pre'/'pos' are empty */
|
||||||
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
|
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
|
||||||
|
|
||||||
|
|
||||||
#define luaC_barrier(L,p,v) ( \
|
|
||||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
|
||||||
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
|
|
||||||
|
|
||||||
#define luaC_barrierback(L,p,v) ( \
|
|
||||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
|
||||||
luaC_barrierback_(L,p) : cast_void(0))
|
|
||||||
|
|
||||||
#define luaC_objbarrier(L,p,o) ( \
|
#define luaC_objbarrier(L,p,o) ( \
|
||||||
(isblack(p) && iswhite(o)) ? \
|
(isblack(p) && iswhite(o)) ? \
|
||||||
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_barrier(L,p,v) ( \
|
||||||
|
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_objbarrierback(L,p,o) ( \
|
||||||
|
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_barrierback(L,p,v) ( \
|
||||||
|
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
|
||||||
|
|
||||||
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
||||||
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
||||||
LUAI_FUNC void luaC_step (lua_State *L);
|
LUAI_FUNC void luaC_step (lua_State *L);
|
||||||
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
|
LUAI_FUNC void luaC_runtilstate (lua_State *L, int state, int fast);
|
||||||
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
||||||
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
|
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz);
|
||||||
|
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz,
|
||||||
|
size_t offset);
|
||||||
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
||||||
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
|
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
|
||||||
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
||||||
|
|||||||
@@ -8,21 +8,6 @@
|
|||||||
#define linit_c
|
#define linit_c
|
||||||
#define LUA_LIB
|
#define LUA_LIB
|
||||||
|
|
||||||
/*
|
|
||||||
** If you embed Lua in your program and need to open the standard
|
|
||||||
** libraries, call luaL_openlibs in your program. If you need a
|
|
||||||
** different set of libraries, copy this file to your project and edit
|
|
||||||
** it to suit your needs.
|
|
||||||
**
|
|
||||||
** You can also *preload* libraries, so that a later 'require' can
|
|
||||||
** open the library, which is already linked to the application.
|
|
||||||
** For that, do the following code:
|
|
||||||
**
|
|
||||||
** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
|
||||||
** lua_pushcfunction(L, luaopen_modname);
|
|
||||||
** lua_setfield(L, -2, modname);
|
|
||||||
** lua_pop(L, 1); // remove PRELOAD table
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
@@ -33,33 +18,46 @@
|
|||||||
|
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** these libs are loaded by lua.c and are readily available to any Lua
|
** Standard Libraries. (Must be listed in the same ORDER of their
|
||||||
** program
|
** respective constants LUA_<libname>K.)
|
||||||
*/
|
*/
|
||||||
static const luaL_Reg loadedlibs[] = {
|
static const luaL_Reg stdlibs[] = {
|
||||||
{LUA_GNAME, luaopen_base},
|
{LUA_GNAME, luaopen_base},
|
||||||
{LUA_LOADLIBNAME, luaopen_package},
|
{LUA_LOADLIBNAME, luaopen_package},
|
||||||
{LUA_COLIBNAME, luaopen_coroutine},
|
{LUA_COLIBNAME, luaopen_coroutine},
|
||||||
{LUA_TABLIBNAME, luaopen_table},
|
{LUA_DBLIBNAME, luaopen_debug},
|
||||||
{LUA_IOLIBNAME, luaopen_io},
|
{LUA_IOLIBNAME, luaopen_io},
|
||||||
|
{LUA_MATHLIBNAME, luaopen_math},
|
||||||
{LUA_OSLIBNAME, luaopen_os},
|
{LUA_OSLIBNAME, luaopen_os},
|
||||||
{LUA_STRLIBNAME, luaopen_string},
|
{LUA_STRLIBNAME, luaopen_string},
|
||||||
{LUA_MATHLIBNAME, luaopen_math},
|
{LUA_TABLIBNAME, luaopen_table},
|
||||||
{LUA_UTF8LIBNAME, luaopen_utf8},
|
{LUA_UTF8LIBNAME, luaopen_utf8},
|
||||||
{LUA_DBLIBNAME, luaopen_debug},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_openlibs (lua_State *L) {
|
/*
|
||||||
|
** require and preload selected standard libraries
|
||||||
|
*/
|
||||||
|
LUALIB_API void luaL_openselectedlibs (lua_State *L, int load, int preload) {
|
||||||
|
int mask;
|
||||||
const luaL_Reg *lib;
|
const luaL_Reg *lib;
|
||||||
/* "require" functions from 'loadedlibs' and set results to global table */
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
||||||
for (lib = loadedlibs; lib->func; lib++) {
|
for (lib = stdlibs, mask = 1; lib->name != NULL; lib++, mask <<= 1) {
|
||||||
luaL_requiref(L, lib->name, lib->func, 1);
|
if (load & mask) { /* selected? */
|
||||||
lua_pop(L, 1); /* remove lib */
|
luaL_requiref(L, lib->name, lib->func, 1); /* require library */
|
||||||
|
lua_pop(L, 1); /* remove result from the stack */
|
||||||
|
}
|
||||||
|
else if (preload & mask) { /* selected? */
|
||||||
|
lua_pushcfunction(L, lib->func);
|
||||||
|
lua_setfield(L, -2, lib->name); /* add library to PRELOAD table */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
lua_assert((mask >> 1) == LUA_UTF8LIBK);
|
||||||
|
lua_pop(L, 1); /* remove PRELOAD table */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -115,7 +114,7 @@ static int l_checkmode (const char *mode) {
|
|||||||
|
|
||||||
#if !defined(l_fseek) /* { */
|
#if !defined(l_fseek) /* { */
|
||||||
|
|
||||||
#if defined(LUA_USE_POSIX) /* { */
|
#if defined(LUA_USE_POSIX) || defined(LUA_USE_OFF_T) /* { */
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@@ -245,8 +244,8 @@ static int f_gc (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
static int io_fclose (lua_State *L) {
|
static int io_fclose (lua_State *L) {
|
||||||
LStream *p = tolstream(L);
|
LStream *p = tolstream(L);
|
||||||
int res = fclose(p->f);
|
errno = 0;
|
||||||
return luaL_fileresult(L, (res == 0), NULL);
|
return luaL_fileresult(L, (fclose(p->f) == 0), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -272,6 +271,7 @@ static int io_open (lua_State *L) {
|
|||||||
LStream *p = newfile(L);
|
LStream *p = newfile(L);
|
||||||
const char *md = mode; /* to traverse/check mode */
|
const char *md = mode; /* to traverse/check mode */
|
||||||
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
|
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
|
||||||
|
errno = 0;
|
||||||
p->f = fopen(filename, mode);
|
p->f = fopen(filename, mode);
|
||||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||||
}
|
}
|
||||||
@@ -292,6 +292,7 @@ static int io_popen (lua_State *L) {
|
|||||||
const char *mode = luaL_optstring(L, 2, "r");
|
const char *mode = luaL_optstring(L, 2, "r");
|
||||||
LStream *p = newprefile(L);
|
LStream *p = newprefile(L);
|
||||||
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
|
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
|
||||||
|
errno = 0;
|
||||||
p->f = l_popen(L, filename, mode);
|
p->f = l_popen(L, filename, mode);
|
||||||
p->closef = &io_pclose;
|
p->closef = &io_pclose;
|
||||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||||
@@ -300,6 +301,7 @@ static int io_popen (lua_State *L) {
|
|||||||
|
|
||||||
static int io_tmpfile (lua_State *L) {
|
static int io_tmpfile (lua_State *L) {
|
||||||
LStream *p = newfile(L);
|
LStream *p = newfile(L);
|
||||||
|
errno = 0;
|
||||||
p->f = tmpfile();
|
p->f = tmpfile();
|
||||||
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
|
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
|
||||||
}
|
}
|
||||||
@@ -441,7 +443,7 @@ static int nextc (RN *rn) {
|
|||||||
return 0; /* fail */
|
return 0; /* fail */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rn->buff[rn->n++] = rn->c; /* save current char */
|
rn->buff[rn->n++] = cast_char(rn->c); /* save current char */
|
||||||
rn->c = l_getc(rn->f); /* read next one */
|
rn->c = l_getc(rn->f); /* read next one */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -522,15 +524,15 @@ static int read_line (lua_State *L, FILE *f, int chop) {
|
|||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
do { /* may need to read several chunks to get whole line */
|
do { /* may need to read several chunks to get whole line */
|
||||||
char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */
|
char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */
|
||||||
int i = 0;
|
unsigned i = 0;
|
||||||
l_lockfile(f); /* no memory errors can happen inside the lock */
|
l_lockfile(f); /* no memory errors can happen inside the lock */
|
||||||
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
|
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
|
||||||
buff[i++] = c; /* read up to end of line or buffer limit */
|
buff[i++] = cast_char(c); /* read up to end of line or buffer limit */
|
||||||
l_unlockfile(f);
|
l_unlockfile(f);
|
||||||
luaL_addsize(&b, i);
|
luaL_addsize(&b, i);
|
||||||
} while (c != EOF && c != '\n'); /* repeat until end of line */
|
} while (c != EOF && c != '\n'); /* repeat until end of line */
|
||||||
if (!chop && c == '\n') /* want a newline and have one? */
|
if (!chop && c == '\n') /* want a newline and have one? */
|
||||||
luaL_addchar(&b, c); /* add ending newline to result */
|
luaL_addchar(&b, '\n'); /* add ending newline to result */
|
||||||
luaL_pushresult(&b); /* close buffer */
|
luaL_pushresult(&b); /* close buffer */
|
||||||
/* return ok if read something (either a newline or something else) */
|
/* return ok if read something (either a newline or something else) */
|
||||||
return (c == '\n' || lua_rawlen(L, -1) > 0);
|
return (c == '\n' || lua_rawlen(L, -1) > 0);
|
||||||
@@ -567,6 +569,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
|
|||||||
int nargs = lua_gettop(L) - 1;
|
int nargs = lua_gettop(L) - 1;
|
||||||
int n, success;
|
int n, success;
|
||||||
clearerr(f);
|
clearerr(f);
|
||||||
|
errno = 0;
|
||||||
if (nargs == 0) { /* no arguments? */
|
if (nargs == 0) { /* no arguments? */
|
||||||
success = read_line(L, f, 1);
|
success = read_line(L, f, 1);
|
||||||
n = first + 1; /* to return 1 result */
|
n = first + 1; /* to return 1 result */
|
||||||
@@ -659,26 +662,28 @@ static int io_readline (lua_State *L) {
|
|||||||
|
|
||||||
static int g_write (lua_State *L, FILE *f, int arg) {
|
static int g_write (lua_State *L, FILE *f, int arg) {
|
||||||
int nargs = lua_gettop(L) - arg;
|
int nargs = lua_gettop(L) - arg;
|
||||||
int status = 1;
|
size_t totalbytes = 0; /* total number of bytes written */
|
||||||
for (; nargs--; arg++) {
|
errno = 0;
|
||||||
if (lua_type(L, arg) == LUA_TNUMBER) {
|
for (; nargs--; arg++) { /* for each argument */
|
||||||
/* optimization: could be done exactly as for strings */
|
char buff[LUA_N2SBUFFSZ];
|
||||||
int len = lua_isinteger(L, arg)
|
const char *s;
|
||||||
? fprintf(f, LUA_INTEGER_FMT,
|
size_t numbytes; /* bytes written in one call to 'fwrite' */
|
||||||
(LUAI_UACINT)lua_tointeger(L, arg))
|
size_t len = lua_numbertocstring(L, arg, buff); /* try as a number */
|
||||||
: fprintf(f, LUA_NUMBER_FMT,
|
if (len > 0) { /* did conversion work (value was a number)? */
|
||||||
(LUAI_UACNUMBER)lua_tonumber(L, arg));
|
s = buff;
|
||||||
status = status && (len > 0);
|
len--;
|
||||||
}
|
}
|
||||||
else {
|
else /* must be a string */
|
||||||
size_t l;
|
s = luaL_checklstring(L, arg, &len);
|
||||||
const char *s = luaL_checklstring(L, arg, &l);
|
numbytes = fwrite(s, sizeof(char), len, f);
|
||||||
status = status && (fwrite(s, sizeof(char), l, f) == l);
|
totalbytes += numbytes;
|
||||||
|
if (numbytes < len) { /* write error? */
|
||||||
|
int n = luaL_fileresult(L, 0, NULL);
|
||||||
|
lua_pushinteger(L, cast_st2S(totalbytes));
|
||||||
|
return n + 1; /* return fail, error msg., error code, and counter */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (l_likely(status))
|
return 1; /* no errors; file handle already on stack top */
|
||||||
return 1; /* file handle already on stack top */
|
|
||||||
else return luaL_fileresult(L, status, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -703,6 +708,7 @@ static int f_seek (lua_State *L) {
|
|||||||
l_seeknum offset = (l_seeknum)p3;
|
l_seeknum offset = (l_seeknum)p3;
|
||||||
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
||||||
"not an integer in proper range");
|
"not an integer in proper range");
|
||||||
|
errno = 0;
|
||||||
op = l_fseek(f, offset, mode[op]);
|
op = l_fseek(f, offset, mode[op]);
|
||||||
if (l_unlikely(op))
|
if (l_unlikely(op))
|
||||||
return luaL_fileresult(L, 0, NULL); /* error */
|
return luaL_fileresult(L, 0, NULL); /* error */
|
||||||
@@ -719,19 +725,26 @@ static int f_setvbuf (lua_State *L) {
|
|||||||
FILE *f = tofile(L);
|
FILE *f = tofile(L);
|
||||||
int op = luaL_checkoption(L, 2, NULL, modenames);
|
int op = luaL_checkoption(L, 2, NULL, modenames);
|
||||||
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
|
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
|
||||||
int res = setvbuf(f, NULL, mode[op], (size_t)sz);
|
int res;
|
||||||
|
errno = 0;
|
||||||
|
res = setvbuf(f, NULL, mode[op], (size_t)sz);
|
||||||
return luaL_fileresult(L, res == 0, NULL);
|
return luaL_fileresult(L, res == 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int aux_flush (lua_State *L, FILE *f) {
|
||||||
static int io_flush (lua_State *L) {
|
errno = 0;
|
||||||
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
|
return luaL_fileresult(L, fflush(f) == 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_flush (lua_State *L) {
|
static int f_flush (lua_State *L) {
|
||||||
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
|
return aux_flush(L, tofile(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int io_flush (lua_State *L) {
|
||||||
|
return aux_flush(L, getiofile(L, IO_OUTPUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -773,7 +786,7 @@ static const luaL_Reg meth[] = {
|
|||||||
** metamethods for file handles
|
** metamethods for file handles
|
||||||
*/
|
*/
|
||||||
static const luaL_Reg metameth[] = {
|
static const luaL_Reg metameth[] = {
|
||||||
{"__index", NULL}, /* place holder */
|
{"__index", NULL}, /* placeholder */
|
||||||
{"__gc", f_gc},
|
{"__gc", f_gc},
|
||||||
{"__close", f_gc},
|
{"__close", f_gc},
|
||||||
{"__tostring", f_tostring},
|
{"__tostring", f_tostring},
|
||||||
|
|||||||
+4
-2
@@ -21,7 +21,7 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
#if 0
|
#if 0
|
||||||
** you can update the following list with this command:
|
** you can update the following list with this command:
|
||||||
**
|
**
|
||||||
** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h
|
** sed -n '/^OP_/!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h
|
||||||
**
|
**
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -57,8 +57,8 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
&&L_OP_BANDK,
|
&&L_OP_BANDK,
|
||||||
&&L_OP_BORK,
|
&&L_OP_BORK,
|
||||||
&&L_OP_BXORK,
|
&&L_OP_BXORK,
|
||||||
&&L_OP_SHRI,
|
|
||||||
&&L_OP_SHLI,
|
&&L_OP_SHLI,
|
||||||
|
&&L_OP_SHRI,
|
||||||
&&L_OP_ADD,
|
&&L_OP_ADD,
|
||||||
&&L_OP_SUB,
|
&&L_OP_SUB,
|
||||||
&&L_OP_MUL,
|
&&L_OP_MUL,
|
||||||
@@ -106,6 +106,8 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
&&L_OP_SETLIST,
|
&&L_OP_SETLIST,
|
||||||
&&L_OP_CLOSURE,
|
&&L_OP_CLOSURE,
|
||||||
&&L_OP_VARARG,
|
&&L_OP_VARARG,
|
||||||
|
&&L_OP_GETVARG,
|
||||||
|
&&L_OP_ERRNNIL,
|
||||||
&&L_OP_VARARGPREP,
|
&&L_OP_VARARGPREP,
|
||||||
&&L_OP_EXTRAARG
|
&&L_OP_EXTRAARG
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
#define next(ls) (ls->current = zgetc(ls->z))
|
#define next(ls) (ls->current = zgetc(ls->z))
|
||||||
|
|
||||||
|
|
||||||
|
/* minimum size for string buffer */
|
||||||
|
#if !defined(LUA_MINBUFFER)
|
||||||
|
#define LUA_MINBUFFER 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
|
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
|
||||||
|
|
||||||
@@ -39,7 +44,7 @@
|
|||||||
/* ORDER RESERVED */
|
/* ORDER RESERVED */
|
||||||
static const char *const luaX_tokens [] = {
|
static const char *const luaX_tokens [] = {
|
||||||
"and", "break", "do", "else", "elseif",
|
"and", "break", "do", "else", "elseif",
|
||||||
"end", "false", "for", "function", "goto", "if",
|
"end", "false", "for", "function", "global", "goto", "if",
|
||||||
"in", "local", "nil", "not", "or", "repeat",
|
"in", "local", "nil", "not", "or", "repeat",
|
||||||
"return", "then", "true", "until", "while",
|
"return", "then", "true", "until", "while",
|
||||||
"//", "..", "...", "==", ">=", "<=", "~=",
|
"//", "..", "...", "==", ">=", "<=", "~=",
|
||||||
@@ -57,10 +62,10 @@ static l_noret lexerror (LexState *ls, const char *msg, int token);
|
|||||||
static void save (LexState *ls, int c) {
|
static void save (LexState *ls, int c) {
|
||||||
Mbuffer *b = ls->buff;
|
Mbuffer *b = ls->buff;
|
||||||
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
|
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
|
||||||
size_t newsize;
|
size_t newsize = luaZ_sizebuffer(b); /* get old size */;
|
||||||
if (luaZ_sizebuffer(b) >= MAX_SIZE/2)
|
if (newsize >= (MAX_SIZE/3 * 2)) /* larger than MAX_SIZE/1.5 ? */
|
||||||
lexerror(ls, "lexical element too long", 0);
|
lexerror(ls, "lexical element too long", 0);
|
||||||
newsize = luaZ_sizebuffer(b) * 2;
|
newsize += (newsize >> 1); /* new size is 1.5 times the old one */
|
||||||
luaZ_resizebuffer(ls->L, b, newsize);
|
luaZ_resizebuffer(ls->L, b, newsize);
|
||||||
}
|
}
|
||||||
b->buffer[luaZ_bufflen(b)++] = cast_char(c);
|
b->buffer[luaZ_bufflen(b)++] = cast_char(c);
|
||||||
@@ -122,30 +127,34 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Creates a new string and anchors it in scanner's table so that it
|
** Anchors a string in scanner's table so that it will not be collected
|
||||||
** will not be collected until the end of the compilation; by that time
|
** until the end of the compilation; by that time it should be anchored
|
||||||
** it should be anchored somewhere. It also internalizes long strings,
|
** somewhere. It also internalizes long strings, ensuring there is only
|
||||||
** ensuring there is only one copy of each unique string. The table
|
** one copy of each unique string.
|
||||||
** here is used as a set: the string enters as the key, while its value
|
|
||||||
** is irrelevant. We use the string itself as the value only because it
|
|
||||||
** is a TValue readly available. Later, the code generation can change
|
|
||||||
** this value.
|
|
||||||
*/
|
*/
|
||||||
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
static TString *anchorstr (LexState *ls, TString *ts) {
|
||||||
lua_State *L = ls->L;
|
lua_State *L = ls->L;
|
||||||
TString *ts = luaS_newlstr(L, str, l); /* create new string */
|
TValue oldts;
|
||||||
const TValue *o = luaH_getstr(ls->h, ts);
|
int tag = luaH_getstr(ls->h, ts, &oldts);
|
||||||
if (!ttisnil(o)) /* string already present? */
|
if (!tagisempty(tag)) /* string already present? */
|
||||||
ts = keystrval(nodefromval(o)); /* get saved copy */
|
return tsvalue(&oldts); /* use stored value */
|
||||||
else { /* not in use yet */
|
else { /* create a new entry */
|
||||||
TValue *stv = s2v(L->top++); /* reserve stack space for string */
|
TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
|
||||||
setsvalue(L, stv, ts); /* temporarily anchor the string */
|
setsvalue(L, stv, ts); /* push (anchor) the string on the stack */
|
||||||
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
|
luaH_set(L, ls->h, stv, stv); /* t[string] = string */
|
||||||
/* table is not a metatable, so it does not need to invalidate cache */
|
/* table is not a metatable, so it does not need to invalidate cache */
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
L->top--; /* remove string from stack */
|
L->top.p--; /* remove string from stack */
|
||||||
|
return ts;
|
||||||
}
|
}
|
||||||
return ts;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Creates a new string and anchors it in scanner's table.
|
||||||
|
*/
|
||||||
|
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
||||||
|
return anchorstr(ls, luaS_newlstr(ls->L, str, l));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -159,7 +168,7 @@ static void inclinenumber (LexState *ls) {
|
|||||||
next(ls); /* skip '\n' or '\r' */
|
next(ls); /* skip '\n' or '\r' */
|
||||||
if (currIsNewline(ls) && ls->current != old)
|
if (currIsNewline(ls) && ls->current != old)
|
||||||
next(ls); /* skip '\n\r' or '\r\n' */
|
next(ls); /* skip '\n\r' or '\r\n' */
|
||||||
if (++ls->linenumber >= MAX_INT)
|
if (++ls->linenumber >= INT_MAX)
|
||||||
lexerror(ls, "chunk has too many lines", 0);
|
lexerror(ls, "chunk has too many lines", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +184,15 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
|
|||||||
ls->linenumber = 1;
|
ls->linenumber = 1;
|
||||||
ls->lastline = 1;
|
ls->lastline = 1;
|
||||||
ls->source = source;
|
ls->source = source;
|
||||||
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
|
/* all three strings here ("_ENV", "break", "global") were fixed,
|
||||||
|
so they cannot be collected */
|
||||||
|
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */
|
||||||
|
ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */
|
||||||
|
#if LUA_COMPAT_GLOBAL
|
||||||
|
/* compatibility mode: "global" is not a reserved word */
|
||||||
|
ls->glbn = luaS_newliteral(L, "global"); /* get "global" string */
|
||||||
|
ls->glbn->extra = 0; /* mark it as not reserved */
|
||||||
|
#endif
|
||||||
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
|
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,12 +357,17 @@ static int readhexaesc (LexState *ls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned long readutf8esc (LexState *ls) {
|
/*
|
||||||
unsigned long r;
|
** When reading a UTF-8 escape sequence, save everything to the buffer
|
||||||
int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */
|
** for error reporting in case of errors; 'i' counts the number of
|
||||||
|
** saved characters, so that they can be removed if case of success.
|
||||||
|
*/
|
||||||
|
static l_uint32 readutf8esc (LexState *ls) {
|
||||||
|
l_uint32 r;
|
||||||
|
int i = 4; /* number of chars to be removed: start with #"\u{X" */
|
||||||
save_and_next(ls); /* skip 'u' */
|
save_and_next(ls); /* skip 'u' */
|
||||||
esccheck(ls, ls->current == '{', "missing '{'");
|
esccheck(ls, ls->current == '{', "missing '{'");
|
||||||
r = gethexa(ls); /* must have at least one digit */
|
r = cast_uint(gethexa(ls)); /* must have at least one digit */
|
||||||
while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) {
|
while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) {
|
||||||
i++;
|
i++;
|
||||||
esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large");
|
esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large");
|
||||||
@@ -542,12 +564,13 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
|||||||
do {
|
do {
|
||||||
save_and_next(ls);
|
save_and_next(ls);
|
||||||
} while (lislalnum(ls->current));
|
} while (lislalnum(ls->current));
|
||||||
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
/* find or create string */
|
||||||
luaZ_bufflen(ls->buff));
|
ts = luaS_newlstr(ls->L, luaZ_buffer(ls->buff),
|
||||||
seminfo->ts = ts;
|
luaZ_bufflen(ls->buff));
|
||||||
if (isreserved(ts)) /* reserved word? */
|
if (isreserved(ts)) /* reserved word? */
|
||||||
return ts->extra - 1 + FIRST_RESERVED;
|
return ts->extra - 1 + FIRST_RESERVED;
|
||||||
else {
|
else {
|
||||||
|
seminfo->ts = anchorstr(ls, ts);
|
||||||
return TK_NAME;
|
return TK_NAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ enum RESERVED {
|
|||||||
/* terminal symbols denoted by reserved words */
|
/* terminal symbols denoted by reserved words */
|
||||||
TK_AND = FIRST_RESERVED, TK_BREAK,
|
TK_AND = FIRST_RESERVED, TK_BREAK,
|
||||||
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
||||||
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
|
TK_GLOBAL, TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR,
|
||||||
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
||||||
/* other terminal symbols */
|
/* other terminal symbols */
|
||||||
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
|
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
|
||||||
TK_SHL, TK_SHR,
|
TK_SHL, TK_SHR,
|
||||||
@@ -59,7 +59,7 @@ typedef struct Token {
|
|||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
|
|
||||||
/* state of the lexer plus state of the parser when shared by all
|
/* state of the scanner plus state of the parser when shared by all
|
||||||
functions */
|
functions */
|
||||||
typedef struct LexState {
|
typedef struct LexState {
|
||||||
int current; /* current character (charint) */
|
int current; /* current character (charint) */
|
||||||
@@ -75,6 +75,8 @@ typedef struct LexState {
|
|||||||
struct Dyndata *dyd; /* dynamic structures used by the parser */
|
struct Dyndata *dyd; /* dynamic structures used by the parser */
|
||||||
TString *source; /* current source name */
|
TString *source; /* current source name */
|
||||||
TString *envn; /* environment variable name */
|
TString *envn; /* environment variable name */
|
||||||
|
TString *brkn; /* "break" name (used as a label) */
|
||||||
|
TString *glbn; /* "global" name (when not a reserved word) */
|
||||||
} LexState;
|
} LexState;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,50 +15,49 @@
|
|||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define l_numbits(t) cast_int(sizeof(t) * CHAR_BIT)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count
|
** 'l_mem' is a signed integer big enough to count the total memory
|
||||||
** the total memory used by Lua (in bytes). Usually, 'size_t' and
|
** used by Lua. (It is signed due to the use of debt in several
|
||||||
|
** computations.) 'lu_mem' is a corresponding unsigned type. Usually,
|
||||||
** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
|
** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
|
||||||
*/
|
*/
|
||||||
#if defined(LUAI_MEM) /* { external definitions? */
|
#if defined(LUAI_MEM) /* { external definitions? */
|
||||||
typedef LUAI_UMEM lu_mem;
|
|
||||||
typedef LUAI_MEM l_mem;
|
typedef LUAI_MEM l_mem;
|
||||||
|
typedef LUAI_UMEM lu_mem;
|
||||||
#elif LUAI_IS32INT /* }{ */
|
#elif LUAI_IS32INT /* }{ */
|
||||||
typedef size_t lu_mem;
|
|
||||||
typedef ptrdiff_t l_mem;
|
typedef ptrdiff_t l_mem;
|
||||||
|
typedef size_t lu_mem;
|
||||||
#else /* 16-bit ints */ /* }{ */
|
#else /* 16-bit ints */ /* }{ */
|
||||||
typedef unsigned long lu_mem;
|
|
||||||
typedef long l_mem;
|
typedef long l_mem;
|
||||||
|
typedef unsigned long lu_mem;
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
#define MAX_LMEM \
|
||||||
|
cast(l_mem, (cast(lu_mem, 1) << (l_numbits(l_mem) - 1)) - 1)
|
||||||
|
|
||||||
|
|
||||||
/* chars used as small naturals (so that 'char' is reserved for characters) */
|
/* chars used as small naturals (so that 'char' is reserved for characters) */
|
||||||
typedef unsigned char lu_byte;
|
typedef unsigned char lu_byte;
|
||||||
typedef signed char ls_byte;
|
typedef signed char ls_byte;
|
||||||
|
|
||||||
|
|
||||||
|
/* Type for thread status/error codes */
|
||||||
|
typedef lu_byte TStatus;
|
||||||
|
|
||||||
|
/* The C API still uses 'int' for status/error codes */
|
||||||
|
#define APIstatus(st) cast_int(st)
|
||||||
|
|
||||||
/* maximum value for size_t */
|
/* maximum value for size_t */
|
||||||
#define MAX_SIZET ((size_t)(~(size_t)0))
|
#define MAX_SIZET ((size_t)(~(size_t)0))
|
||||||
|
|
||||||
/* maximum size visible for Lua (must be representable in a lua_Integer) */
|
|
||||||
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
|
|
||||||
: (size_t)(LUA_MAXINTEGER))
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0))
|
|
||||||
|
|
||||||
#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1))
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_INT INT_MAX /* maximum value of an int */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** floor of the log2 of the maximum signed value for integral type 't'.
|
** Maximum size for strings and userdata visible for Lua; should be
|
||||||
** (That is, maximum 'n' such that '2^n' fits in the given signed type.)
|
** representable as a lua_Integer and as a size_t.
|
||||||
*/
|
*/
|
||||||
#define log2maxs(t) (sizeof(t) * 8 - 2)
|
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
|
||||||
|
: cast_sizet(LUA_MAXINTEGER))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** test whether an unsigned value is a power of 2 (or zero)
|
** test whether an unsigned value is a power of 2 (or zero)
|
||||||
@@ -71,11 +70,24 @@ typedef signed char ls_byte;
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** conversion of pointer to unsigned integer:
|
** conversion of pointer to unsigned integer: this is for hashing only;
|
||||||
** this is for hashing only; there is no problem if the integer
|
** there is no problem if the integer cannot hold the whole pointer
|
||||||
** cannot hold the whole pointer value
|
** value. (In strict ISO C this may cause undefined behavior, but no
|
||||||
|
** actual machine seems to bother.)
|
||||||
*/
|
*/
|
||||||
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
|
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
|
||||||
|
__STDC_VERSION__ >= 199901L
|
||||||
|
#include <stdint.h>
|
||||||
|
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
|
||||||
|
#define L_P2I uintptr_t
|
||||||
|
#else /* no 'intptr'? */
|
||||||
|
#define L_P2I uintmax_t /* use the largest available integer */
|
||||||
|
#endif
|
||||||
|
#else /* C89 option */
|
||||||
|
#define L_P2I size_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define point2uint(p) cast_uint((L_P2I)(p) & UINT_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -91,26 +103,18 @@ typedef LUAI_UACINT l_uacInt;
|
|||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define lua_assert(c) assert(c)
|
#define lua_assert(c) assert(c)
|
||||||
|
#define assert_code(c) c
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(lua_assert)
|
#if defined(lua_assert)
|
||||||
#define check_exp(c,e) (lua_assert(c), (e))
|
|
||||||
/* to avoid problems with conditions too long */
|
|
||||||
#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
|
|
||||||
#else
|
#else
|
||||||
#define lua_assert(c) ((void)0)
|
#define lua_assert(c) ((void)0)
|
||||||
#define check_exp(c,e) (e)
|
#define assert_code(c) ((void)0)
|
||||||
#define lua_longassert(c) ((void)0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
#define check_exp(c,e) (lua_assert(c), (e))
|
||||||
** assertion for checking API calls
|
/* to avoid problems with conditions too long */
|
||||||
*/
|
#define lua_longassert(c) assert_code((c) ? (void)0 : lua_assert(0))
|
||||||
#if !defined(luai_apicheck)
|
|
||||||
#define luai_apicheck(l,e) ((void)l, lua_assert(e))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
|
|
||||||
|
|
||||||
|
|
||||||
/* macro to avoid warnings about unused variables */
|
/* macro to avoid warnings about unused variables */
|
||||||
@@ -126,12 +130,15 @@ typedef LUAI_UACINT l_uacInt;
|
|||||||
#define cast_voidp(i) cast(void *, (i))
|
#define cast_voidp(i) cast(void *, (i))
|
||||||
#define cast_num(i) cast(lua_Number, (i))
|
#define cast_num(i) cast(lua_Number, (i))
|
||||||
#define cast_int(i) cast(int, (i))
|
#define cast_int(i) cast(int, (i))
|
||||||
|
#define cast_short(i) cast(short, (i))
|
||||||
#define cast_uint(i) cast(unsigned int, (i))
|
#define cast_uint(i) cast(unsigned int, (i))
|
||||||
#define cast_byte(i) cast(lu_byte, (i))
|
#define cast_byte(i) cast(lu_byte, (i))
|
||||||
#define cast_uchar(i) cast(unsigned char, (i))
|
#define cast_uchar(i) cast(unsigned char, (i))
|
||||||
#define cast_char(i) cast(char, (i))
|
#define cast_char(i) cast(char, (i))
|
||||||
#define cast_charp(i) cast(char *, (i))
|
#define cast_charp(i) cast(char *, (i))
|
||||||
#define cast_sizet(i) cast(size_t, (i))
|
#define cast_sizet(i) cast(size_t, (i))
|
||||||
|
#define cast_Integer(i) cast(lua_Integer, (i))
|
||||||
|
#define cast_Inst(i) cast(Instruction, (i))
|
||||||
|
|
||||||
|
|
||||||
/* cast a signed lua_Integer to lua_Unsigned */
|
/* cast a signed lua_Integer to lua_Unsigned */
|
||||||
@@ -148,6 +155,38 @@ typedef LUAI_UACINT l_uacInt;
|
|||||||
#define l_castU2S(i) ((lua_Integer)(i))
|
#define l_castU2S(i) ((lua_Integer)(i))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** cast a size_t to lua_Integer: These casts are always valid for
|
||||||
|
** sizes of Lua objects (see MAX_SIZE)
|
||||||
|
*/
|
||||||
|
#define cast_st2S(sz) ((lua_Integer)(sz))
|
||||||
|
|
||||||
|
/* Cast a ptrdiff_t to size_t, when it is known that the minuend
|
||||||
|
** comes from the subtrahend (the base)
|
||||||
|
*/
|
||||||
|
#define ct_diff2sz(df) ((size_t)(df))
|
||||||
|
|
||||||
|
/* ptrdiff_t to lua_Integer */
|
||||||
|
#define ct_diff2S(df) cast_st2S(ct_diff2sz(df))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Special type equivalent to '(void*)' for functions (to suppress some
|
||||||
|
** warnings when converting function pointers)
|
||||||
|
*/
|
||||||
|
typedef void (*voidf)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macro to convert pointer-to-void* to pointer-to-function. This cast
|
||||||
|
** is undefined according to ISO C, but POSIX assumes that it works.
|
||||||
|
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define cast_func(p) (__extension__ (voidf)(p))
|
||||||
|
#else
|
||||||
|
#define cast_func(p) ((voidf)(p))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** non-return type
|
** non-return type
|
||||||
@@ -180,8 +219,7 @@ typedef LUAI_UACINT l_uacInt;
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** type for virtual-machine instructions;
|
** An unsigned with (at least) 4 bytes
|
||||||
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
|
|
||||||
*/
|
*/
|
||||||
#if LUAI_IS32INT
|
#if LUAI_IS32INT
|
||||||
typedef unsigned int l_uint32;
|
typedef unsigned int l_uint32;
|
||||||
@@ -189,107 +227,6 @@ typedef unsigned int l_uint32;
|
|||||||
typedef unsigned long l_uint32;
|
typedef unsigned long l_uint32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef l_uint32 Instruction;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Maximum length for short strings, that is, strings that are
|
|
||||||
** internalized. (Cannot be smaller than reserved words or tags for
|
|
||||||
** metamethods, as these strings must be internalized;
|
|
||||||
** #("function") = 8, #("__newindex") = 10.)
|
|
||||||
*/
|
|
||||||
#if !defined(LUAI_MAXSHORTLEN)
|
|
||||||
#define LUAI_MAXSHORTLEN 40
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Initial size for the string table (must be power of 2).
|
|
||||||
** The Lua core alone registers ~50 strings (reserved words +
|
|
||||||
** metaevent keys + a few others). Libraries would typically add
|
|
||||||
** a few dozens more.
|
|
||||||
*/
|
|
||||||
#if !defined(MINSTRTABSIZE)
|
|
||||||
#define MINSTRTABSIZE 128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Size of cache for strings in the API. 'N' is the number of
|
|
||||||
** sets (better be a prime) and "M" is the size of each set (M == 1
|
|
||||||
** makes a direct cache.)
|
|
||||||
*/
|
|
||||||
#if !defined(STRCACHE_N)
|
|
||||||
#define STRCACHE_N 53
|
|
||||||
#define STRCACHE_M 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* minimum size for string buffer */
|
|
||||||
#if !defined(LUA_MINBUFFER)
|
|
||||||
#define LUA_MINBUFFER 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Maximum depth for nested C calls, syntactical nested non-terminals,
|
|
||||||
** and other features implemented through recursion in C. (Value must
|
|
||||||
** fit in a 16-bit unsigned integer. It must also be compatible with
|
|
||||||
** the size of the C stack.)
|
|
||||||
*/
|
|
||||||
#if !defined(LUAI_MAXCCALLS)
|
|
||||||
#define LUAI_MAXCCALLS 200
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** macros that are executed whenever program enters the Lua core
|
|
||||||
** ('lua_lock') and leaves the core ('lua_unlock')
|
|
||||||
*/
|
|
||||||
#if !defined(lua_lock)
|
|
||||||
#define lua_lock(L) ((void) 0)
|
|
||||||
#define lua_unlock(L) ((void) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** macro executed during Lua functions at points where the
|
|
||||||
** function can yield.
|
|
||||||
*/
|
|
||||||
#if !defined(luai_threadyield)
|
|
||||||
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** these macros allow user-specific actions when a thread is
|
|
||||||
** created/deleted/resumed/yielded.
|
|
||||||
*/
|
|
||||||
#if !defined(luai_userstateopen)
|
|
||||||
#define luai_userstateopen(L) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstateclose)
|
|
||||||
#define luai_userstateclose(L) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstatethread)
|
|
||||||
#define luai_userstatethread(L,L1) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstatefree)
|
|
||||||
#define luai_userstatefree(L,L1) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstateresume)
|
|
||||||
#define luai_userstateresume(L,n) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstateyield)
|
|
||||||
#define luai_userstateyield(L,n) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The luai_num* macros define the primitive operations over numbers.
|
** The luai_num* macros define the primitive operations over numbers.
|
||||||
@@ -297,12 +234,12 @@ typedef l_uint32 Instruction;
|
|||||||
|
|
||||||
/* floor division (defined as 'floor(a/b)') */
|
/* floor division (defined as 'floor(a/b)') */
|
||||||
#if !defined(luai_numidiv)
|
#if !defined(luai_numidiv)
|
||||||
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
|
#define luai_numidiv(L,a,b) l_floor(luai_numdiv(L,a,b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* float division */
|
/* float division */
|
||||||
#if !defined(luai_numdiv)
|
#if !defined(luai_numdiv)
|
||||||
#define luai_numdiv(L,a,b) ((a)/(b))
|
#define luai_numdiv(L,a,b) ((void)L, (a)/(b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -330,10 +267,10 @@ typedef l_uint32 Instruction;
|
|||||||
|
|
||||||
/* the others are quite standard operations */
|
/* the others are quite standard operations */
|
||||||
#if !defined(luai_numadd)
|
#if !defined(luai_numadd)
|
||||||
#define luai_numadd(L,a,b) ((a)+(b))
|
#define luai_numadd(L,a,b) ((void)L, (a)+(b))
|
||||||
#define luai_numsub(L,a,b) ((a)-(b))
|
#define luai_numsub(L,a,b) ((void)L, (a)-(b))
|
||||||
#define luai_nummul(L,a,b) ((a)*(b))
|
#define luai_nummul(L,a,b) ((void)L, (a)*(b))
|
||||||
#define luai_numunm(L,a) (-(a))
|
#define luai_numunm(L,a) ((void)L, -(a))
|
||||||
#define luai_numeq(a,b) ((a)==(b))
|
#define luai_numeq(a,b) ((a)==(b))
|
||||||
#define luai_numlt(a,b) ((a)<(b))
|
#define luai_numlt(a,b) ((a)<(b))
|
||||||
#define luai_numle(a,b) ((a)<=(b))
|
#define luai_numle(a,b) ((a)<=(b))
|
||||||
@@ -344,24 +281,77 @@ typedef l_uint32 Instruction;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** lua_numbertointeger converts a float number with an integral value
|
||||||
|
** to an integer, or returns 0 if the float is not within the range of
|
||||||
|
** a lua_Integer. (The range comparisons are tricky because of
|
||||||
|
** rounding. The tests here assume a two-complement representation,
|
||||||
|
** where MININTEGER always has an exact representation as a float;
|
||||||
|
** MAXINTEGER may not have one, and therefore its conversion to float
|
||||||
|
** may have an ill-defined value.)
|
||||||
|
*/
|
||||||
|
#define lua_numbertointeger(n,p) \
|
||||||
|
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
|
||||||
|
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
|
||||||
|
(*(p) = (LUA_INTEGER)(n), 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** macro to control inclusion of some hard tests on stack reallocation
|
** LUAI_FUNC is a mark for all extern functions that are not to be
|
||||||
|
** exported to outside modules.
|
||||||
|
** LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables,
|
||||||
|
** none of which to be exported to outside modules (LUAI_DDEF for
|
||||||
|
** definitions and LUAI_DDEC for declarations).
|
||||||
|
** Elf and MACH/gcc (versions 3.2 and later) mark them as "hidden" to
|
||||||
|
** optimize access when Lua is compiled as a shared library. Not all elf
|
||||||
|
** targets support this attribute. Unfortunately, gcc does not offer
|
||||||
|
** a way to check whether the target offers that support, and those
|
||||||
|
** without support give a warning about it. To avoid these warnings,
|
||||||
|
** change to the default definition.
|
||||||
*/
|
*/
|
||||||
#if !defined(HARDSTACKTESTS)
|
#if !defined(LUAI_FUNC)
|
||||||
#define condmovestack(L,pre,pos) ((void)0)
|
|
||||||
|
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
|
||||||
|
(defined(__ELF__) || defined(__MACH__))
|
||||||
|
#define LUAI_FUNC __attribute__((visibility("internal"))) extern
|
||||||
#else
|
#else
|
||||||
/* realloc stack keeping its size */
|
#define LUAI_FUNC extern
|
||||||
#define condmovestack(L,pre,pos) \
|
|
||||||
{ int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HARDMEMTESTS)
|
#define LUAI_DDEC(dec) LUAI_FUNC dec
|
||||||
#define condchangemem(L,pre,pos) ((void)0)
|
#define LUAI_DDEF /* empty */
|
||||||
#else
|
|
||||||
#define condchangemem(L,pre,pos) \
|
|
||||||
{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Give these macros simpler names for internal use */
|
||||||
|
#define l_likely(x) luai_likely(x)
|
||||||
|
#define l_unlikely(x) luai_unlikely(x)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {==================================================================
|
||||||
|
** "Abstraction Layer" for basic report of messages and errors
|
||||||
|
** ===================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* print a string */
|
||||||
|
#if !defined(lua_writestring)
|
||||||
|
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* print a newline and flush the output */
|
||||||
|
#if !defined(lua_writeline)
|
||||||
|
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* print an error message */
|
||||||
|
#if !defined(lua_writestringerror)
|
||||||
|
#define lua_writestringerror(s,p) \
|
||||||
|
(fprintf(stderr, (s), (p)), fflush(stderr))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* }================================================================== */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+86
-85
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
#undef PI
|
#undef PI
|
||||||
@@ -37,31 +38,37 @@ static int math_abs (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_sin (lua_State *L) {
|
static int math_sin (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_cos (lua_State *L) {
|
static int math_cos (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_tan (lua_State *L) {
|
static int math_tan (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_asin (lua_State *L) {
|
static int math_asin (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_acos (lua_State *L) {
|
static int math_acos (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_atan (lua_State *L) {
|
static int math_atan (lua_State *L) {
|
||||||
lua_Number y = luaL_checknumber(L, 1);
|
lua_Number y = luaL_checknumber(L, 1);
|
||||||
lua_Number x = luaL_optnumber(L, 2, 1);
|
lua_Number x = luaL_optnumber(L, 2, 1);
|
||||||
@@ -105,7 +112,7 @@ static int math_floor (lua_State *L) {
|
|||||||
|
|
||||||
static int math_ceil (lua_State *L) {
|
static int math_ceil (lua_State *L) {
|
||||||
if (lua_isinteger(L, 1))
|
if (lua_isinteger(L, 1))
|
||||||
lua_settop(L, 1); /* integer is its own ceil */
|
lua_settop(L, 1); /* integer is its own ceiling */
|
||||||
else {
|
else {
|
||||||
lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));
|
lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));
|
||||||
pushnumint(L, d);
|
pushnumint(L, d);
|
||||||
@@ -166,6 +173,7 @@ static int math_ult (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_log (lua_State *L) {
|
static int math_log (lua_State *L) {
|
||||||
lua_Number x = luaL_checknumber(L, 1);
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
lua_Number res;
|
lua_Number res;
|
||||||
@@ -187,22 +195,42 @@ static int math_log (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_exp (lua_State *L) {
|
static int math_exp (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_deg (lua_State *L) {
|
static int math_deg (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
|
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_rad (lua_State *L) {
|
static int math_rad (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
|
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int math_frexp (lua_State *L) {
|
||||||
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
|
int ep;
|
||||||
|
lua_pushnumber(L, l_mathop(frexp)(x, &ep));
|
||||||
|
lua_pushinteger(L, ep);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int math_ldexp (lua_State *L) {
|
||||||
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
|
int ep = (int)luaL_checkinteger(L, 2);
|
||||||
|
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_min (lua_State *L) {
|
static int math_min (lua_State *L) {
|
||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
int imin = 1; /* index of current minimum value */
|
int imin = 1; /* index of current minimum value */
|
||||||
@@ -249,6 +277,15 @@ static int math_type (lua_State *L) {
|
|||||||
** ===================================================================
|
** ===================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This code uses lots of shifts. ISO C does not allow shifts greater
|
||||||
|
** than or equal to the width of the type being shifted, so some shifts
|
||||||
|
** are written in convoluted ways to match that restriction. For
|
||||||
|
** preprocessor tests, it assumes a width of 32 bits, so the maximum
|
||||||
|
** shift there is 31 bits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* number of binary digits in the mantissa of a float */
|
/* number of binary digits in the mantissa of a float */
|
||||||
#define FIGS l_floatatt(MANT_DIG)
|
#define FIGS l_floatatt(MANT_DIG)
|
||||||
|
|
||||||
@@ -267,20 +304,23 @@ static int math_type (lua_State *L) {
|
|||||||
|
|
||||||
/* try to find an integer type with at least 64 bits */
|
/* try to find an integer type with at least 64 bits */
|
||||||
|
|
||||||
#if (ULONG_MAX >> 31 >> 31) >= 3
|
#if ((ULONG_MAX >> 31) >> 31) >= 3
|
||||||
|
|
||||||
/* 'long' has at least 64 bits */
|
/* 'long' has at least 64 bits */
|
||||||
#define Rand64 unsigned long
|
#define Rand64 unsigned long
|
||||||
|
#define SRand64 long
|
||||||
|
|
||||||
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
|
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
|
||||||
|
|
||||||
/* there is a 'long long' type (which must have at least 64 bits) */
|
/* there is a 'long long' type (which must have at least 64 bits) */
|
||||||
#define Rand64 unsigned long long
|
#define Rand64 unsigned long long
|
||||||
|
#define SRand64 long long
|
||||||
|
|
||||||
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
|
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
|
||||||
|
|
||||||
/* 'lua_Integer' has at least 64 bits */
|
/* 'lua_Unsigned' has at least 64 bits */
|
||||||
#define Rand64 lua_Unsigned
|
#define Rand64 lua_Unsigned
|
||||||
|
#define SRand64 lua_Integer
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -319,23 +359,30 @@ static Rand64 nextrand (Rand64 *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* must take care to not shift stuff by more than 63 slots */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Convert bits from a random integer into a float in the
|
** Convert bits from a random integer into a float in the
|
||||||
** interval [0,1), getting the higher FIG bits from the
|
** interval [0,1), getting the higher FIG bits from the
|
||||||
** random unsigned integer and converting that to a float.
|
** random unsigned integer and converting that to a float.
|
||||||
|
** Some old Microsoft compilers cannot cast an unsigned long
|
||||||
|
** to a floating-point number, so we use a signed long as an
|
||||||
|
** intermediary. When lua_Number is float or double, the shift ensures
|
||||||
|
** that 'sx' is non negative; in that case, a good compiler will remove
|
||||||
|
** the correction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* must throw out the extra (64 - FIGS) bits */
|
/* must throw out the extra (64 - FIGS) bits */
|
||||||
#define shift64_FIG (64 - FIGS)
|
#define shift64_FIG (64 - FIGS)
|
||||||
|
|
||||||
/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
|
/* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */
|
||||||
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
|
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
|
||||||
|
|
||||||
static lua_Number I2d (Rand64 x) {
|
static lua_Number I2d (Rand64 x) {
|
||||||
return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG;
|
SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
|
||||||
|
lua_Number res = (lua_Number)(sx) * scaleFIG;
|
||||||
|
if (sx < 0)
|
||||||
|
res += l_mathop(1.0); /* correct the two's complement if negative */
|
||||||
|
lua_assert(0 <= res && res < 1);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
||||||
@@ -347,25 +394,17 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
|
|
||||||
#else /* no 'Rand64' }{ */
|
#else /* no 'Rand64' }{ */
|
||||||
|
|
||||||
/* get an integer with at least 32 bits */
|
|
||||||
#if LUAI_IS32INT
|
|
||||||
typedef unsigned int lu_int32;
|
|
||||||
#else
|
|
||||||
typedef unsigned long lu_int32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Use two 32-bit integers to represent a 64-bit quantity.
|
** Use two 32-bit integers to represent a 64-bit quantity.
|
||||||
*/
|
*/
|
||||||
typedef struct Rand64 {
|
typedef struct Rand64 {
|
||||||
lu_int32 h; /* higher half */
|
l_uint32 h; /* higher half */
|
||||||
lu_int32 l; /* lower half */
|
l_uint32 l; /* lower half */
|
||||||
} Rand64;
|
} Rand64;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If 'lu_int32' has more than 32 bits, the extra bits do not interfere
|
** If 'l_uint32' has more than 32 bits, the extra bits do not interfere
|
||||||
** with the 32 initial bits, except in a right shift and comparisons.
|
** with the 32 initial bits, except in a right shift and comparisons.
|
||||||
** Moreover, the final result has to discard the extra bits.
|
** Moreover, the final result has to discard the extra bits.
|
||||||
*/
|
*/
|
||||||
@@ -379,7 +418,7 @@ typedef struct Rand64 {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* build a new Rand64 value */
|
/* build a new Rand64 value */
|
||||||
static Rand64 packI (lu_int32 h, lu_int32 l) {
|
static Rand64 packI (l_uint32 h, l_uint32 l) {
|
||||||
Rand64 result;
|
Rand64 result;
|
||||||
result.h = h;
|
result.h = h;
|
||||||
result.l = l;
|
result.l = l;
|
||||||
@@ -452,7 +491,7 @@ static Rand64 nextrand (Rand64 *state) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* an unsigned 1 with proper type */
|
/* an unsigned 1 with proper type */
|
||||||
#define UONE ((lu_int32)1)
|
#define UONE ((l_uint32)1)
|
||||||
|
|
||||||
|
|
||||||
#if FIGS <= 32
|
#if FIGS <= 32
|
||||||
@@ -471,8 +510,6 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
|
|
||||||
#else /* 32 < FIGS <= 64 */
|
#else /* 32 < FIGS <= 64 */
|
||||||
|
|
||||||
/* must take care to not shift stuff by more than 31 slots */
|
|
||||||
|
|
||||||
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
|
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
|
||||||
#define scaleFIG \
|
#define scaleFIG \
|
||||||
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
|
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
|
||||||
@@ -500,12 +537,12 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
|
|
||||||
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
||||||
static lua_Unsigned I2UInt (Rand64 x) {
|
static lua_Unsigned I2UInt (Rand64 x) {
|
||||||
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
|
return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert a 'lua_Unsigned' to a 'Rand64' */
|
/* convert a 'lua_Unsigned' to a 'Rand64' */
|
||||||
static Rand64 Int2I (lua_Unsigned n) {
|
static Rand64 Int2I (lua_Unsigned n) {
|
||||||
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
|
return packI((l_uint32)((n >> 31) >> 1), (l_uint32)n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
@@ -523,7 +560,7 @@ typedef struct {
|
|||||||
** Project the random integer 'ran' into the interval [0, n].
|
** Project the random integer 'ran' into the interval [0, n].
|
||||||
** Because 'ran' has 2^B possible values, the projection can only be
|
** Because 'ran' has 2^B possible values, the projection can only be
|
||||||
** uniform when the size of the interval is a power of 2 (exact
|
** uniform when the size of the interval is a power of 2 (exact
|
||||||
** division). Otherwise, to get a uniform projection into [0, n], we
|
** division). So, to get a uniform projection into [0, n], we
|
||||||
** first compute 'lim', the smallest Mersenne number not smaller than
|
** first compute 'lim', the smallest Mersenne number not smaller than
|
||||||
** 'n'. We then project 'ran' into the interval [0, lim]. If the result
|
** 'n'. We then project 'ran' into the interval [0, lim]. If the result
|
||||||
** is inside [0, n], we are done. Otherwise, we try with another 'ran',
|
** is inside [0, n], we are done. Otherwise, we try with another 'ran',
|
||||||
@@ -531,26 +568,14 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
|
static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
|
||||||
RanState *state) {
|
RanState *state) {
|
||||||
if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */
|
lua_Unsigned lim = n; /* to compute the Mersenne number */
|
||||||
return ran & n; /* no bias */
|
int sh; /* how much to spread bits to the right in 'lim' */
|
||||||
else {
|
/* spread '1' bits in 'lim' until it becomes a Mersenne number */
|
||||||
lua_Unsigned lim = n;
|
for (sh = 1; (lim & (lim + 1)) != 0; sh *= 2)
|
||||||
/* compute the smallest (2^b - 1) not smaller than 'n' */
|
lim |= (lim >> sh); /* spread '1's to the right */
|
||||||
lim |= (lim >> 1);
|
while ((ran &= lim) > n) /* project 'ran' into [0..lim] and test */
|
||||||
lim |= (lim >> 2);
|
ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */
|
||||||
lim |= (lim >> 4);
|
return ran;
|
||||||
lim |= (lim >> 8);
|
|
||||||
lim |= (lim >> 16);
|
|
||||||
#if (LUA_MAXUNSIGNED >> 31) >= 3
|
|
||||||
lim |= (lim >> 32); /* integer type has more than 32 bits */
|
|
||||||
#endif
|
|
||||||
lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */
|
|
||||||
&& lim >= n /* not smaller than 'n', */
|
|
||||||
&& (lim >> 1) < n); /* and it is the smallest one */
|
|
||||||
while ((ran &= lim) > n) /* project 'ran' into [0..lim] */
|
|
||||||
ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */
|
|
||||||
return ran;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -568,7 +593,7 @@ static int math_random (lua_State *L) {
|
|||||||
low = 1;
|
low = 1;
|
||||||
up = luaL_checkinteger(L, 1);
|
up = luaL_checkinteger(L, 1);
|
||||||
if (up == 0) { /* single 0 as argument? */
|
if (up == 0) { /* single 0 as argument? */
|
||||||
lua_pushinteger(L, I2UInt(rv)); /* full random integer */
|
lua_pushinteger(L, l_castU2S(I2UInt(rv))); /* full random integer */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -583,8 +608,8 @@ static int math_random (lua_State *L) {
|
|||||||
/* random integer in the interval [low, up] */
|
/* random integer in the interval [low, up] */
|
||||||
luaL_argcheck(L, low <= up, 1, "interval is empty");
|
luaL_argcheck(L, low <= up, 1, "interval is empty");
|
||||||
/* project random integer into the interval [0, up - low] */
|
/* project random integer into the interval [0, up - low] */
|
||||||
p = project(I2UInt(rv), (lua_Unsigned)up - (lua_Unsigned)low, state);
|
p = project(I2UInt(rv), l_castS2U(up) - l_castS2U(low), state);
|
||||||
lua_pushinteger(L, p + (lua_Unsigned)low);
|
lua_pushinteger(L, l_castU2S(p + l_castS2U(low)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,33 +623,23 @@ static void setseed (lua_State *L, Rand64 *state,
|
|||||||
state[3] = Int2I(0);
|
state[3] = Int2I(0);
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
nextrand(state); /* discard initial values to "spread" seed */
|
nextrand(state); /* discard initial values to "spread" seed */
|
||||||
lua_pushinteger(L, n1);
|
lua_pushinteger(L, l_castU2S(n1));
|
||||||
lua_pushinteger(L, n2);
|
lua_pushinteger(L, l_castU2S(n2));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Set a "random" seed. To get some randomness, use the current time
|
|
||||||
** and the address of 'L' (in case the machine does address space layout
|
|
||||||
** randomization).
|
|
||||||
*/
|
|
||||||
static void randseed (lua_State *L, RanState *state) {
|
|
||||||
lua_Unsigned seed1 = (lua_Unsigned)time(NULL);
|
|
||||||
lua_Unsigned seed2 = (lua_Unsigned)(size_t)L;
|
|
||||||
setseed(L, state->s, seed1, seed2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_randomseed (lua_State *L) {
|
static int math_randomseed (lua_State *L) {
|
||||||
RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
|
RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_Unsigned n1, n2;
|
||||||
if (lua_isnone(L, 1)) {
|
if (lua_isnone(L, 1)) {
|
||||||
randseed(L, state);
|
n1 = luaL_makeseed(L); /* "random" seed */
|
||||||
|
n2 = I2UInt(nextrand(state->s)); /* in case seed is not that random... */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_Integer n1 = luaL_checkinteger(L, 1);
|
n1 = l_castS2U(luaL_checkinteger(L, 1));
|
||||||
lua_Integer n2 = luaL_optinteger(L, 2, 0);
|
n2 = l_castS2U(luaL_optinteger(L, 2, 0));
|
||||||
setseed(L, state->s, n1, n2);
|
|
||||||
}
|
}
|
||||||
|
setseed(L, state->s, n1, n2);
|
||||||
return 2; /* return seeds */
|
return 2; /* return seeds */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,7 +656,7 @@ static const luaL_Reg randfuncs[] = {
|
|||||||
*/
|
*/
|
||||||
static void setrandfunc (lua_State *L) {
|
static void setrandfunc (lua_State *L) {
|
||||||
RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
|
RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
|
||||||
randseed(L, state); /* initialize with a "random" seed */
|
setseed(L, state->s, luaL_makeseed(L), 0); /* initialize with random seed */
|
||||||
lua_pop(L, 2); /* remove pushed seeds */
|
lua_pop(L, 2); /* remove pushed seeds */
|
||||||
luaL_setfuncs(L, randfuncs, 1);
|
luaL_setfuncs(L, randfuncs, 1);
|
||||||
}
|
}
|
||||||
@@ -678,20 +693,6 @@ static int math_pow (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_frexp (lua_State *L) {
|
|
||||||
int e;
|
|
||||||
lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
|
|
||||||
lua_pushinteger(L, e);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int math_ldexp (lua_State *L) {
|
|
||||||
lua_Number x = luaL_checknumber(L, 1);
|
|
||||||
int ep = (int)luaL_checkinteger(L, 2);
|
|
||||||
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int math_log10 (lua_State *L) {
|
static int math_log10 (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
@@ -714,7 +715,9 @@ static const luaL_Reg mathlib[] = {
|
|||||||
{"tointeger", math_toint},
|
{"tointeger", math_toint},
|
||||||
{"floor", math_floor},
|
{"floor", math_floor},
|
||||||
{"fmod", math_fmod},
|
{"fmod", math_fmod},
|
||||||
|
{"frexp", math_frexp},
|
||||||
{"ult", math_ult},
|
{"ult", math_ult},
|
||||||
|
{"ldexp", math_ldexp},
|
||||||
{"log", math_log},
|
{"log", math_log},
|
||||||
{"max", math_max},
|
{"max", math_max},
|
||||||
{"min", math_min},
|
{"min", math_min},
|
||||||
@@ -730,8 +733,6 @@ static const luaL_Reg mathlib[] = {
|
|||||||
{"sinh", math_sinh},
|
{"sinh", math_sinh},
|
||||||
{"tanh", math_tanh},
|
{"tanh", math_tanh},
|
||||||
{"pow", math_pow},
|
{"pow", math_pow},
|
||||||
{"frexp", math_frexp},
|
|
||||||
{"ldexp", math_ldexp},
|
|
||||||
{"log10", math_log10},
|
{"log10", math_log10},
|
||||||
#endif
|
#endif
|
||||||
/* placeholders */
|
/* placeholders */
|
||||||
|
|||||||
@@ -22,25 +22,6 @@
|
|||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(EMERGENCYGCTESTS)
|
|
||||||
/*
|
|
||||||
** First allocation will fail whenever not building initial state.
|
|
||||||
** (This fail will trigger 'tryagain' and a full GC cycle at every
|
|
||||||
** allocation.)
|
|
||||||
*/
|
|
||||||
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
|
||||||
if (completestate(g) && ns > 0) /* frees never fail */
|
|
||||||
return NULL; /* fail */
|
|
||||||
else /* normal allocation */
|
|
||||||
return (*g->frealloc)(g->ud, block, os, ns);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** About the realloc function:
|
** About the realloc function:
|
||||||
@@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macro to call the allocation function.
|
||||||
|
*/
|
||||||
|
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When an allocation fails, it will try again after an emergency
|
||||||
|
** collection, except when it cannot run a collection. The GC should
|
||||||
|
** not be called while the state is not fully built, as the collector
|
||||||
|
** is not yet fully initialized. Also, it should not be called when
|
||||||
|
** 'gcstopem' is true, because then the interpreter is in the middle of
|
||||||
|
** a collection step.
|
||||||
|
*/
|
||||||
|
#define cantryagain(g) (completestate(g) && !g->gcstopem)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(EMERGENCYGCTESTS)
|
||||||
|
/*
|
||||||
|
** First allocation will fail except when freeing a block (frees never
|
||||||
|
** fail) and when it cannot try again; this fail will trigger 'tryagain'
|
||||||
|
** and a full GC cycle at every allocation.
|
||||||
|
*/
|
||||||
|
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
||||||
|
if (ns > 0 && cantryagain(g))
|
||||||
|
return NULL; /* fail */
|
||||||
|
else /* normal allocation */
|
||||||
|
return callfrealloc(g, block, os, ns);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,7 +95,7 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
|||||||
|
|
||||||
|
|
||||||
void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
||||||
int size_elems, int limit, const char *what) {
|
unsigned size_elems, int limit, const char *what) {
|
||||||
void *newblock;
|
void *newblock;
|
||||||
int size = *psize;
|
int size = *psize;
|
||||||
if (nelems + 1 <= size) /* does one extra element still fit? */
|
if (nelems + 1 <= size) /* does one extra element still fit? */
|
||||||
@@ -108,10 +126,10 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
|||||||
** error.
|
** error.
|
||||||
*/
|
*/
|
||||||
void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
|
void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
|
||||||
int final_n, int size_elem) {
|
int final_n, unsigned size_elem) {
|
||||||
void *newblock;
|
void *newblock;
|
||||||
size_t oldsize = cast_sizet((*size) * size_elem);
|
size_t oldsize = cast_sizet(*size) * size_elem;
|
||||||
size_t newsize = cast_sizet(final_n * size_elem);
|
size_t newsize = cast_sizet(final_n) * size_elem;
|
||||||
lua_assert(newsize <= oldsize);
|
lua_assert(newsize <= oldsize);
|
||||||
newblock = luaM_saferealloc_(L, block, oldsize, newsize);
|
newblock = luaM_saferealloc_(L, block, oldsize, newsize);
|
||||||
*size = final_n;
|
*size = final_n;
|
||||||
@@ -132,27 +150,23 @@ l_noret luaM_toobig (lua_State *L) {
|
|||||||
void luaM_free_ (lua_State *L, void *block, size_t osize) {
|
void luaM_free_ (lua_State *L, void *block, size_t osize) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
lua_assert((osize == 0) == (block == NULL));
|
lua_assert((osize == 0) == (block == NULL));
|
||||||
(*g->frealloc)(g->ud, block, osize, 0);
|
callfrealloc(g, block, osize, 0);
|
||||||
g->GCdebt -= osize;
|
g->GCdebt += cast(l_mem, osize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** In case of allocation fail, this function will do an emergency
|
** In case of allocation fail, this function will do an emergency
|
||||||
** collection to free some memory and then try the allocation again.
|
** collection to free some memory and then try the allocation again.
|
||||||
** The GC should not be called while state is not fully built, as the
|
|
||||||
** collector is not yet fully initialized. Also, it should not be called
|
|
||||||
** when 'gcstopem' is true, because then the interpreter is in the
|
|
||||||
** middle of a collection step.
|
|
||||||
*/
|
*/
|
||||||
static void *tryagain (lua_State *L, void *block,
|
static void *tryagain (lua_State *L, void *block,
|
||||||
size_t osize, size_t nsize) {
|
size_t osize, size_t nsize) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
if (completestate(g) && !g->gcstopem) {
|
if (cantryagain(g)) {
|
||||||
luaC_fullgc(L, 1); /* try to free some memory... */
|
luaC_fullgc(L, 1); /* try to free some memory... */
|
||||||
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
|
return callfrealloc(g, block, osize, nsize); /* try again */
|
||||||
}
|
}
|
||||||
else return NULL; /* cannot free any memory without a full state */
|
else return NULL; /* cannot run an emergency collection */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,7 +184,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
|
|||||||
return NULL; /* do not update 'GCdebt' */
|
return NULL; /* do not update 'GCdebt' */
|
||||||
}
|
}
|
||||||
lua_assert((nsize == 0) == (newblock == NULL));
|
lua_assert((nsize == 0) == (newblock == NULL));
|
||||||
g->GCdebt = (g->GCdebt + nsize) - osize;
|
g->GCdebt -= cast(l_mem, nsize) - cast(l_mem, osize);
|
||||||
return newblock;
|
return newblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,13 +203,13 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
|
|||||||
return NULL; /* that's all */
|
return NULL; /* that's all */
|
||||||
else {
|
else {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
void *newblock = firsttry(g, NULL, tag, size);
|
void *newblock = firsttry(g, NULL, cast_sizet(tag), size);
|
||||||
if (l_unlikely(newblock == NULL)) {
|
if (l_unlikely(newblock == NULL)) {
|
||||||
newblock = tryagain(L, NULL, tag, size);
|
newblock = tryagain(L, NULL, cast_sizet(tag), size);
|
||||||
if (newblock == NULL)
|
if (newblock == NULL)
|
||||||
luaM_error(L);
|
luaM_error(L);
|
||||||
}
|
}
|
||||||
g->GCdebt += size;
|
g->GCdebt -= cast(l_mem, size);
|
||||||
return newblock;
|
return newblock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,11 @@
|
|||||||
** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that
|
** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that
|
||||||
** the result is not larger than 'n' and cannot overflow a 'size_t'
|
** the result is not larger than 'n' and cannot overflow a 'size_t'
|
||||||
** when multiplied by the size of type 't'. (Assumes that 'n' is an
|
** when multiplied by the size of type 't'. (Assumes that 'n' is an
|
||||||
** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.)
|
** 'int' and that 'int' is not larger than 'size_t'.)
|
||||||
*/
|
*/
|
||||||
#define luaM_limitN(n,t) \
|
#define luaM_limitN(n,t) \
|
||||||
((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \
|
((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \
|
||||||
cast_uint((MAX_SIZET/sizeof(t))))
|
cast_int((MAX_SIZET/sizeof(t))))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -57,12 +57,15 @@
|
|||||||
#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
|
#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
|
||||||
|
|
||||||
#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0))
|
#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0))
|
||||||
#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0))
|
#define luaM_newvector(L,n,t) \
|
||||||
|
cast(t*, luaM_malloc_(L, cast_sizet(n)*sizeof(t), 0))
|
||||||
#define luaM_newvectorchecked(L,n,t) \
|
#define luaM_newvectorchecked(L,n,t) \
|
||||||
(luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
|
(luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
|
||||||
|
|
||||||
#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
|
#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
|
||||||
|
|
||||||
|
#define luaM_newblock(L, size) luaM_newvector(L, size, char)
|
||||||
|
|
||||||
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
|
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
|
||||||
((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
|
((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
|
||||||
luaM_limitN(limit,t),e)))
|
luaM_limitN(limit,t),e)))
|
||||||
@@ -83,10 +86,10 @@ LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize,
|
|||||||
size_t size);
|
size_t size);
|
||||||
LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
|
LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
|
||||||
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
|
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
|
||||||
int *size, int size_elem, int limit,
|
int *size, unsigned size_elem, int limit,
|
||||||
const char *what);
|
const char *what);
|
||||||
LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
|
LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
|
||||||
int final_n, int size_elem);
|
int final_n, unsigned size_elem);
|
||||||
LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
|
LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,15 +22,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
/*
|
|
||||||
** LUA_IGMARK is a mark to ignore all before it when building the
|
|
||||||
** luaopen_ function name.
|
|
||||||
*/
|
|
||||||
#if !defined (LUA_IGMARK)
|
|
||||||
#define LUA_IGMARK "-"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -67,11 +59,8 @@ static const char *const CLIBS = "_CLIBS";
|
|||||||
#define setprogdir(L) ((void)0)
|
#define setprogdir(L) ((void)0)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* cast void* to a Lua function */
|
||||||
** Special type equivalent to '(void*)' for functions in gcc
|
#define cast_Lfunc(p) cast(lua_CFunction, cast_func(p))
|
||||||
** (to suppress warnings when converting function pointers)
|
|
||||||
*/
|
|
||||||
typedef void (*voidf)(void);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -104,26 +93,13 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
|
|||||||
#if defined(LUA_USE_DLOPEN) /* { */
|
#if defined(LUA_USE_DLOPEN) /* { */
|
||||||
/*
|
/*
|
||||||
** {========================================================================
|
** {========================================================================
|
||||||
** This is an implementation of loadlib based on the dlfcn interface.
|
** This is an implementation of loadlib based on the dlfcn interface,
|
||||||
** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
|
** which is available in all POSIX systems.
|
||||||
** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
|
|
||||||
** as an emulation layer on top of native functions.
|
|
||||||
** =========================================================================
|
** =========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
/*
|
|
||||||
** Macro to convert pointer-to-void* to pointer-to-function. This cast
|
|
||||||
** is undefined according to ISO C, but POSIX assumes that it works.
|
|
||||||
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
|
||||||
*/
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define cast_func(p) (__extension__ (lua_CFunction)(p))
|
|
||||||
#else
|
|
||||||
#define cast_func(p) ((lua_CFunction)(p))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static void lsys_unloadlib (void *lib) {
|
static void lsys_unloadlib (void *lib) {
|
||||||
dlclose(lib);
|
dlclose(lib);
|
||||||
@@ -139,7 +115,7 @@ static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|||||||
|
|
||||||
|
|
||||||
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
lua_CFunction f = cast_func(dlsym(lib, sym));
|
lua_CFunction f = cast_Lfunc(dlsym(lib, sym));
|
||||||
if (l_unlikely(f == NULL))
|
if (l_unlikely(f == NULL))
|
||||||
lua_pushstring(L, dlerror());
|
lua_pushstring(L, dlerror());
|
||||||
return f;
|
return f;
|
||||||
@@ -215,7 +191,7 @@ static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|||||||
|
|
||||||
|
|
||||||
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym);
|
lua_CFunction f = cast_Lfunc(GetProcAddress((HMODULE)lib, sym));
|
||||||
if (f == NULL) pusherror(L);
|
if (f == NULL) pusherror(L);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@@ -292,7 +268,8 @@ static int noenv (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Set a path
|
** Set a path. (If using the default path, assume it is a string
|
||||||
|
** literal in C and create it as an external string.)
|
||||||
*/
|
*/
|
||||||
static void setpath (lua_State *L, const char *fieldname,
|
static void setpath (lua_State *L, const char *fieldname,
|
||||||
const char *envname,
|
const char *envname,
|
||||||
@@ -303,7 +280,7 @@ static void setpath (lua_State *L, const char *fieldname,
|
|||||||
if (path == NULL) /* no versioned environment variable? */
|
if (path == NULL) /* no versioned environment variable? */
|
||||||
path = getenv(envname); /* try unversioned name */
|
path = getenv(envname); /* try unversioned name */
|
||||||
if (path == NULL || noenv(L)) /* no environment variable? */
|
if (path == NULL || noenv(L)) /* no environment variable? */
|
||||||
lua_pushstring(L, dft); /* use default */
|
lua_pushexternalstring(L, dft, strlen(dft), NULL, NULL); /* use default */
|
||||||
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL)
|
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL)
|
||||||
lua_pushstring(L, path); /* nothing to change */
|
lua_pushstring(L, path); /* nothing to change */
|
||||||
else { /* path contains a ";;": insert default path in its place */
|
else { /* path contains a ";;": insert default path in its place */
|
||||||
@@ -311,13 +288,13 @@ static void setpath (lua_State *L, const char *fieldname,
|
|||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
if (path < dftmark) { /* is there a prefix before ';;'? */
|
if (path < dftmark) { /* is there a prefix before ';;'? */
|
||||||
luaL_addlstring(&b, path, dftmark - path); /* add it */
|
luaL_addlstring(&b, path, ct_diff2sz(dftmark - path)); /* add it */
|
||||||
luaL_addchar(&b, *LUA_PATH_SEP);
|
luaL_addchar(&b, *LUA_PATH_SEP);
|
||||||
}
|
}
|
||||||
luaL_addstring(&b, dft); /* add default */
|
luaL_addstring(&b, dft); /* add default */
|
||||||
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */
|
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */
|
||||||
luaL_addchar(&b, *LUA_PATH_SEP);
|
luaL_addchar(&b, *LUA_PATH_SEP);
|
||||||
luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark);
|
luaL_addlstring(&b, dftmark + 2, ct_diff2sz((path + len - 2) - dftmark));
|
||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
}
|
}
|
||||||
@@ -329,6 +306,16 @@ static void setpath (lua_State *L, const char *fieldname,
|
|||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** External strings created by DLLs may need the DLL code to be
|
||||||
|
** deallocated. This implies that a DLL can only be unloaded after all
|
||||||
|
** its strings were deallocated. To ensure that, we create a 'library
|
||||||
|
** string' to represent each DLL, and when this string is deallocated
|
||||||
|
** it closes its corresponding DLL.
|
||||||
|
** (The string itself is irrelevant; its userdata is the DLL pointer.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** return registry.CLIBS[path]
|
** return registry.CLIBS[path]
|
||||||
*/
|
*/
|
||||||
@@ -343,34 +330,41 @@ static void *checkclib (lua_State *L, const char *path) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** registry.CLIBS[path] = plib -- for queries
|
** Deallocate function for library strings.
|
||||||
** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries
|
** Unload the DLL associated with the string being deallocated.
|
||||||
*/
|
*/
|
||||||
static void addtoclib (lua_State *L, const char *path, void *plib) {
|
static void *freelib (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
/* string itself is irrelevant and static */
|
||||||
lua_pushlightuserdata(L, plib);
|
(void)ptr; (void)osize; (void)nsize;
|
||||||
lua_pushvalue(L, -1);
|
lsys_unloadlib(ud); /* unload library represented by the string */
|
||||||
lua_setfield(L, -3, path); /* CLIBS[path] = plib */
|
return NULL;
|
||||||
lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
|
|
||||||
lua_pop(L, 1); /* pop CLIBS table */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib
|
** Create a library string that, when deallocated, will unload 'plib'
|
||||||
** handles in list CLIBS
|
|
||||||
*/
|
*/
|
||||||
static int gctm (lua_State *L) {
|
static void createlibstr (lua_State *L, void *plib) {
|
||||||
lua_Integer n = luaL_len(L, 1);
|
/* common content for all library strings */
|
||||||
for (; n >= 1; n--) { /* for each handle, in reverse order */
|
static const char dummy[] = "01234567890";
|
||||||
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
|
lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib);
|
||||||
lsys_unloadlib(lua_touserdata(L, -1));
|
|
||||||
lua_pop(L, 1); /* pop handle */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** registry.CLIBS[path] = plib -- for queries.
|
||||||
|
** Also create a reference to strlib, so that the library string will
|
||||||
|
** only be collected when registry.CLIBS is collected.
|
||||||
|
*/
|
||||||
|
static void addtoclib (lua_State *L, const char *path, void *plib) {
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
||||||
|
lua_pushlightuserdata(L, plib);
|
||||||
|
lua_setfield(L, -2, path); /* CLIBS[path] = plib */
|
||||||
|
createlibstr(L, plib);
|
||||||
|
luaL_ref(L, -2); /* keep library string in CLIBS */
|
||||||
|
lua_pop(L, 1); /* pop CLIBS table */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* error codes for 'lookforfunc' */
|
/* error codes for 'lookforfunc' */
|
||||||
#define ERRLIB 1
|
#define ERRLIB 1
|
||||||
@@ -384,8 +378,8 @@ static int gctm (lua_State *L) {
|
|||||||
** Then, if 'sym' is '*', return true (as library has been loaded).
|
** Then, if 'sym' is '*', return true (as library has been loaded).
|
||||||
** Otherwise, look for symbol 'sym' in the library and push a
|
** Otherwise, look for symbol 'sym' in the library and push a
|
||||||
** C function with that symbol.
|
** C function with that symbol.
|
||||||
** Return 0 and 'true' or a function in the stack; in case of
|
** Return 0 with 'true' or a function in the stack; in case of
|
||||||
** errors, return an error code and an error message in the stack.
|
** errors, return an error code with an error message in the stack.
|
||||||
*/
|
*/
|
||||||
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
||||||
void *reg = checkclib(L, path); /* check loaded C libraries */
|
void *reg = checkclib(L, path); /* check loaded C libraries */
|
||||||
@@ -547,7 +541,7 @@ static int searcher_Lua (lua_State *L) {
|
|||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
filename = findfile(L, name, "path", LUA_LSUBSEP);
|
filename = findfile(L, name, "path", LUA_LSUBSEP);
|
||||||
if (filename == NULL) return 1; /* module not found in this path */
|
if (filename == NULL) return 1; /* module not found in this path */
|
||||||
return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
|
return checkload(L, (luaL_loadfilex(L, filename, "bt") == LUA_OK), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -566,7 +560,7 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {
|
|||||||
mark = strchr(modname, *LUA_IGMARK);
|
mark = strchr(modname, *LUA_IGMARK);
|
||||||
if (mark) {
|
if (mark) {
|
||||||
int stat;
|
int stat;
|
||||||
openfunc = lua_pushlstring(L, modname, mark - modname);
|
openfunc = lua_pushlstring(L, modname, ct_diff2sz(mark - modname));
|
||||||
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
|
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
|
||||||
stat = lookforfunc(L, filename, openfunc);
|
stat = lookforfunc(L, filename, openfunc);
|
||||||
if (stat != ERRFUNC) return stat;
|
if (stat != ERRFUNC) return stat;
|
||||||
@@ -591,7 +585,7 @@ static int searcher_Croot (lua_State *L) {
|
|||||||
const char *p = strchr(name, '.');
|
const char *p = strchr(name, '.');
|
||||||
int stat;
|
int stat;
|
||||||
if (p == NULL) return 0; /* is root */
|
if (p == NULL) return 0; /* is root */
|
||||||
lua_pushlstring(L, name, p - name);
|
lua_pushlstring(L, name, ct_diff2sz(p - name));
|
||||||
filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
|
filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
|
||||||
if (filename == NULL) return 1; /* root not found */
|
if (filename == NULL) return 1; /* root not found */
|
||||||
if ((stat = loadfunc(L, filename, name)) != 0) {
|
if ((stat = loadfunc(L, filename, name)) != 0) {
|
||||||
@@ -629,12 +623,12 @@ static void findloader (lua_State *L, const char *name) {
|
|||||||
!= LUA_TTABLE))
|
!= LUA_TTABLE))
|
||||||
luaL_error(L, "'package.searchers' must be a table");
|
luaL_error(L, "'package.searchers' must be a table");
|
||||||
luaL_buffinit(L, &msg);
|
luaL_buffinit(L, &msg);
|
||||||
|
luaL_addstring(&msg, "\n\t"); /* error-message prefix for first message */
|
||||||
/* iterate over available searchers to find a loader */
|
/* iterate over available searchers to find a loader */
|
||||||
for (i = 1; ; i++) {
|
for (i = 1; ; i++) {
|
||||||
luaL_addstring(&msg, "\n\t"); /* error-message prefix */
|
|
||||||
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
|
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
|
||||||
lua_pop(L, 1); /* remove nil */
|
lua_pop(L, 1); /* remove nil */
|
||||||
luaL_buffsub(&msg, 2); /* remove prefix */
|
luaL_buffsub(&msg, 2); /* remove last prefix */
|
||||||
luaL_pushresult(&msg); /* create error message */
|
luaL_pushresult(&msg); /* create error message */
|
||||||
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
|
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
|
||||||
}
|
}
|
||||||
@@ -645,11 +639,10 @@ static void findloader (lua_State *L, const char *name) {
|
|||||||
else if (lua_isstring(L, -2)) { /* searcher returned error message? */
|
else if (lua_isstring(L, -2)) { /* searcher returned error message? */
|
||||||
lua_pop(L, 1); /* remove extra return */
|
lua_pop(L, 1); /* remove extra return */
|
||||||
luaL_addvalue(&msg); /* concatenate error message */
|
luaL_addvalue(&msg); /* concatenate error message */
|
||||||
|
luaL_addstring(&msg, "\n\t"); /* prefix for next message */
|
||||||
}
|
}
|
||||||
else { /* no error message */
|
else /* no error message */
|
||||||
lua_pop(L, 2); /* remove both returns */
|
lua_pop(L, 2); /* remove both returns */
|
||||||
luaL_buffsub(&msg, 2); /* remove prefix */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,8 +701,13 @@ static const luaL_Reg ll_funcs[] = {
|
|||||||
|
|
||||||
|
|
||||||
static void createsearcherstable (lua_State *L) {
|
static void createsearcherstable (lua_State *L) {
|
||||||
static const lua_CFunction searchers[] =
|
static const lua_CFunction searchers[] = {
|
||||||
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
|
searcher_preload,
|
||||||
|
searcher_Lua,
|
||||||
|
searcher_C,
|
||||||
|
searcher_Croot,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
int i;
|
int i;
|
||||||
/* create 'searchers' table */
|
/* create 'searchers' table */
|
||||||
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
||||||
@@ -723,21 +721,9 @@ static void createsearcherstable (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** create table CLIBS to keep track of loaded C libraries,
|
|
||||||
** setting a finalizer to close all libraries when closing state.
|
|
||||||
*/
|
|
||||||
static void createclibstable (lua_State *L) {
|
|
||||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
|
|
||||||
lua_createtable(L, 0, 1); /* create metatable for CLIBS */
|
|
||||||
lua_pushcfunction(L, gctm);
|
|
||||||
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUAMOD_API int luaopen_package (lua_State *L) {
|
LUAMOD_API int luaopen_package (lua_State *L) {
|
||||||
createclibstable(L);
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
|
||||||
|
lua_pop(L, 1); /* will not use it now */
|
||||||
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
||||||
createsearcherstable(L);
|
createsearcherstable(L);
|
||||||
/* set paths */
|
/* set paths */
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -30,10 +31,11 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Computes ceil(log2(x))
|
** Computes ceil(log2(x)), which is the smallest integer n such that
|
||||||
|
** x <= (1 << n).
|
||||||
*/
|
*/
|
||||||
int luaO_ceillog2 (unsigned int x) {
|
lu_byte luaO_ceillog2 (unsigned int x) {
|
||||||
static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
|
static const lu_byte log_2[256] = { /* log_2[i - 1] = ceil(log2(i)) */
|
||||||
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||||
@@ -46,7 +48,67 @@ int luaO_ceillog2 (unsigned int x) {
|
|||||||
int l = 0;
|
int l = 0;
|
||||||
x--;
|
x--;
|
||||||
while (x >= 256) { l += 8; x >>= 8; }
|
while (x >= 256) { l += 8; x >>= 8; }
|
||||||
return l + log_2[x];
|
return cast_byte(l + log_2[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Encodes 'p'% as a floating-point byte, represented as (eeeexxxx).
|
||||||
|
** The exponent is represented using excess-7. Mimicking IEEE 754, the
|
||||||
|
** representation normalizes the number when possible, assuming an extra
|
||||||
|
** 1 before the mantissa (xxxx) and adding one to the exponent (eeee)
|
||||||
|
** to signal that. So, the real value is (1xxxx) * 2^(eeee - 7 - 1) if
|
||||||
|
** eeee != 0, and (xxxx) * 2^-7 otherwise (subnormal numbers).
|
||||||
|
*/
|
||||||
|
lu_byte luaO_codeparam (unsigned int p) {
|
||||||
|
if (p >= (cast(lu_mem, 0x1F) << (0xF - 7 - 1)) * 100u) /* overflow? */
|
||||||
|
return 0xFF; /* return maximum value */
|
||||||
|
else {
|
||||||
|
p = (cast(l_uint32, p) * 128 + 99) / 100; /* round up the division */
|
||||||
|
if (p < 0x10) { /* subnormal number? */
|
||||||
|
/* exponent bits are already zero; nothing else to do */
|
||||||
|
return cast_byte(p);
|
||||||
|
}
|
||||||
|
else { /* p >= 0x10 implies ceil(log2(p + 1)) >= 5 */
|
||||||
|
/* preserve 5 bits in 'p' */
|
||||||
|
unsigned log = luaO_ceillog2(p + 1) - 5u;
|
||||||
|
return cast_byte(((p >> log) - 0x10) | ((log + 1) << 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Computes 'p' times 'x', where 'p' is a floating-point byte. Roughly,
|
||||||
|
** we have to multiply 'x' by the mantissa and then shift accordingly to
|
||||||
|
** the exponent. If the exponent is positive, both the multiplication
|
||||||
|
** and the shift increase 'x', so we have to care only about overflows.
|
||||||
|
** For negative exponents, however, multiplying before the shift keeps
|
||||||
|
** more significant bits, as long as the multiplication does not
|
||||||
|
** overflow, so we check which order is best.
|
||||||
|
*/
|
||||||
|
l_mem luaO_applyparam (lu_byte p, l_mem x) {
|
||||||
|
int m = p & 0xF; /* mantissa */
|
||||||
|
int e = (p >> 4); /* exponent */
|
||||||
|
if (e > 0) { /* normalized? */
|
||||||
|
e--; /* correct exponent */
|
||||||
|
m += 0x10; /* correct mantissa; maximum value is 0x1F */
|
||||||
|
}
|
||||||
|
e -= 7; /* correct excess-7 */
|
||||||
|
if (e >= 0) {
|
||||||
|
if (x < (MAX_LMEM / 0x1F) >> e) /* no overflow? */
|
||||||
|
return (x * m) << e; /* order doesn't matter here */
|
||||||
|
else /* real overflow */
|
||||||
|
return MAX_LMEM;
|
||||||
|
}
|
||||||
|
else { /* negative exponent */
|
||||||
|
e = -e;
|
||||||
|
if (x < MAX_LMEM / 0x1F) /* multiplication cannot overflow? */
|
||||||
|
return (x * m) >> e; /* multiplying first gives more precision */
|
||||||
|
else if ((x >> e) < MAX_LMEM / 0x1F) /* cannot overflow after shift? */
|
||||||
|
return (x >> e) * m;
|
||||||
|
else /* real overflow */
|
||||||
|
return MAX_LMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +124,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
|
|||||||
case LUA_OPBOR: return intop(|, v1, v2);
|
case LUA_OPBOR: return intop(|, v1, v2);
|
||||||
case LUA_OPBXOR: return intop(^, v1, v2);
|
case LUA_OPBXOR: return intop(^, v1, v2);
|
||||||
case LUA_OPSHL: return luaV_shiftl(v1, v2);
|
case LUA_OPSHL: return luaV_shiftl(v1, v2);
|
||||||
case LUA_OPSHR: return luaV_shiftl(v1, -v2);
|
case LUA_OPSHR: return luaV_shiftr(v1, v2);
|
||||||
case LUA_OPUNM: return intop(-, 0, v1);
|
case LUA_OPUNM: return intop(-, 0, v1);
|
||||||
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
|
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
|
||||||
default: lua_assert(0); return 0;
|
default: lua_assert(0); return 0;
|
||||||
@@ -132,9 +194,10 @@ void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaO_hexavalue (int c) {
|
lu_byte luaO_hexavalue (int c) {
|
||||||
if (lisdigit(c)) return c - '0';
|
lua_assert(lisxdigit(c));
|
||||||
else return (ltolower(c) - 'a') + 10;
|
if (lisdigit(c)) return cast_byte(c - '0');
|
||||||
|
else return cast_byte((ltolower(c) - 'a') + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -185,7 +248,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
|||||||
nosigdig++;
|
nosigdig++;
|
||||||
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
|
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
|
||||||
r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
|
r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
|
||||||
else e++; /* too many digits; ignore, but still count for exponent */
|
else e++; /* too many digits; ignore, but still count for exponent */
|
||||||
if (hasdot) e--; /* decimal digit? correct exponent */
|
if (hasdot) e--; /* decimal digit? correct exponent */
|
||||||
}
|
}
|
||||||
else break; /* neither a dot nor a digit */
|
else break; /* neither a dot nor a digit */
|
||||||
@@ -292,7 +355,7 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
|
|||||||
int d = *s - '0';
|
int d = *s - '0';
|
||||||
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
|
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
|
||||||
return NULL; /* do not accept it (as integer) */
|
return NULL; /* do not accept it (as integer) */
|
||||||
a = a * 10 + d;
|
a = a * 10 + cast_uint(d);
|
||||||
empty = 0;
|
empty = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,14 +379,14 @@ size_t luaO_str2num (const char *s, TValue *o) {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0; /* conversion failed */
|
return 0; /* conversion failed */
|
||||||
return (e - s) + 1; /* success; return string size */
|
return ct_diff2sz(e - s) + 1; /* success; return string size */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaO_utf8esc (char *buff, unsigned long x) {
|
int luaO_utf8esc (char *buff, l_uint32 x) {
|
||||||
int n = 1; /* number of bytes put in buffer (backwards) */
|
int n = 1; /* number of bytes put in buffer (backwards) */
|
||||||
lua_assert(x <= 0x7FFFFFFFu);
|
lua_assert(x <= 0x7FFFFFFFu);
|
||||||
if (x < 0x80) /* ascii? */
|
if (x < 0x80) /* ASCII? */
|
||||||
buff[UTF8BUFFSZ - 1] = cast_char(x);
|
buff[UTF8BUFFSZ - 1] = cast_char(x);
|
||||||
else { /* need continuation bytes */
|
else { /* need continuation bytes */
|
||||||
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
|
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
|
||||||
@@ -339,32 +402,59 @@ int luaO_utf8esc (char *buff, unsigned long x) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Maximum length of the conversion of a number to a string. Must be
|
** The size of the buffer for the conversion of a number to a string
|
||||||
** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
|
** 'LUA_N2SBUFFSZ' must be enough to accommodate both LUA_INTEGER_FMT
|
||||||
** (For a long long int, this is 19 digits plus a sign and a final '\0',
|
** and LUA_NUMBER_FMT. For a long long int, this is 19 digits plus a
|
||||||
** adding to 21. For a long double, it can go to a sign, 33 digits,
|
** sign and a final '\0', adding to 21. For a long double, it can go to
|
||||||
** the dot, an exponent letter, an exponent sign, 5 exponent digits,
|
** a sign, the dot, an exponent letter, an exponent sign, 4 exponent
|
||||||
** and a final '\0', adding to 43.)
|
** digits, the final '\0', plus the significant digits, which are
|
||||||
|
** approximately the *_DIG attribute.
|
||||||
*/
|
*/
|
||||||
#define MAXNUMBER2STR 44
|
#if LUA_N2SBUFFSZ < (20 + l_floatatt(DIG))
|
||||||
|
#error "invalid value for LUA_N2SBUFFSZ"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Convert a number object to a string, adding it to a buffer
|
** Convert a float to a string, adding it to a buffer. First try with
|
||||||
|
** a not too large number of digits, to avoid noise (for instance,
|
||||||
|
** 1.1 going to "1.1000000000000001"). If that lose precision, so
|
||||||
|
** that reading the result back gives a different number, then do the
|
||||||
|
** conversion again with extra precision. Moreover, if the numeral looks
|
||||||
|
** like an integer (without a decimal point or an exponent), add ".0" to
|
||||||
|
** its end.
|
||||||
*/
|
*/
|
||||||
static int tostringbuff (TValue *obj, char *buff) {
|
static int tostringbuffFloat (lua_Number n, char *buff) {
|
||||||
|
/* first conversion */
|
||||||
|
int len = l_sprintf(buff, LUA_N2SBUFFSZ, LUA_NUMBER_FMT,
|
||||||
|
(LUAI_UACNUMBER)n);
|
||||||
|
lua_Number check = lua_str2number(buff, NULL); /* read it back */
|
||||||
|
if (check != n) { /* not enough precision? */
|
||||||
|
/* convert again with more precision */
|
||||||
|
len = l_sprintf(buff, LUA_N2SBUFFSZ, LUA_NUMBER_FMT_N,
|
||||||
|
(LUAI_UACNUMBER)n);
|
||||||
|
}
|
||||||
|
/* looks like an integer? */
|
||||||
|
if (buff[strspn(buff, "-0123456789")] == '\0') {
|
||||||
|
buff[len++] = lua_getlocaledecpoint();
|
||||||
|
buff[len++] = '0'; /* adds '.0' to result */
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert a number object to a string, adding it to a buffer.
|
||||||
|
*/
|
||||||
|
unsigned luaO_tostringbuff (const TValue *obj, char *buff) {
|
||||||
int len;
|
int len;
|
||||||
lua_assert(ttisnumber(obj));
|
lua_assert(ttisnumber(obj));
|
||||||
if (ttisinteger(obj))
|
if (ttisinteger(obj))
|
||||||
len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
|
len = lua_integer2str(buff, LUA_N2SBUFFSZ, ivalue(obj));
|
||||||
else {
|
else
|
||||||
len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj));
|
len = tostringbuffFloat(fltvalue(obj), buff);
|
||||||
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
|
lua_assert(len < LUA_N2SBUFFSZ);
|
||||||
buff[len++] = lua_getlocaledecpoint();
|
return cast_uint(len);
|
||||||
buff[len++] = '0'; /* adds '.0' to result */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -372,8 +462,8 @@ static int tostringbuff (TValue *obj, char *buff) {
|
|||||||
** Convert a number object to a Lua string, replacing the value at 'obj'
|
** Convert a number object to a Lua string, replacing the value at 'obj'
|
||||||
*/
|
*/
|
||||||
void luaO_tostring (lua_State *L, TValue *obj) {
|
void luaO_tostring (lua_State *L, TValue *obj) {
|
||||||
char buff[MAXNUMBER2STR];
|
char buff[LUA_N2SBUFFSZ];
|
||||||
int len = tostringbuff(obj, buff);
|
unsigned len = luaO_tostringbuff(obj, buff);
|
||||||
setsvalue(L, obj, luaS_newlstr(L, buff, len));
|
setsvalue(L, obj, luaS_newlstr(L, buff, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,80 +476,116 @@ void luaO_tostring (lua_State *L, TValue *obj) {
|
|||||||
** ===================================================================
|
** ===================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* size for buffer space used by 'luaO_pushvfstring' */
|
/*
|
||||||
#define BUFVFS 200
|
** Size for buffer space used by 'luaO_pushvfstring'. It should be
|
||||||
|
** (LUA_IDSIZE + LUA_N2SBUFFSZ) + a minimal space for basic messages,
|
||||||
|
** so that 'luaG_addinfo' can work directly on the static buffer.
|
||||||
|
*/
|
||||||
|
#define BUFVFS cast_uint(LUA_IDSIZE + LUA_N2SBUFFSZ + 95)
|
||||||
|
|
||||||
/* buffer used by 'luaO_pushvfstring' */
|
/*
|
||||||
|
** Buffer used by 'luaO_pushvfstring'. 'err' signals an error while
|
||||||
|
** building result (memory error [1] or buffer overflow [2]).
|
||||||
|
*/
|
||||||
typedef struct BuffFS {
|
typedef struct BuffFS {
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
int pushed; /* number of string pieces already on the stack */
|
char *b;
|
||||||
int blen; /* length of partial string in 'space' */
|
size_t buffsize;
|
||||||
char space[BUFVFS]; /* holds last part of the result */
|
size_t blen; /* length of string in 'buff' */
|
||||||
|
int err;
|
||||||
|
char space[BUFVFS]; /* initial buffer */
|
||||||
} BuffFS;
|
} BuffFS;
|
||||||
|
|
||||||
|
|
||||||
|
static void initbuff (lua_State *L, BuffFS *buff) {
|
||||||
|
buff->L = L;
|
||||||
|
buff->b = buff->space;
|
||||||
|
buff->buffsize = sizeof(buff->space);
|
||||||
|
buff->blen = 0;
|
||||||
|
buff->err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Push given string to the stack, as part of the buffer, and
|
** Push final result from 'luaO_pushvfstring'. This function may raise
|
||||||
** join the partial strings in the stack into one.
|
** errors explicitly or through memory errors, so it must run protected.
|
||||||
*/
|
*/
|
||||||
static void pushstr (BuffFS *buff, const char *str, size_t l) {
|
static void pushbuff (lua_State *L, void *ud) {
|
||||||
|
BuffFS *buff = cast(BuffFS*, ud);
|
||||||
|
switch (buff->err) {
|
||||||
|
case 1: /* memory error */
|
||||||
|
luaD_throw(L, LUA_ERRMEM);
|
||||||
|
break;
|
||||||
|
case 2: /* length overflow: Add "..." at the end of result */
|
||||||
|
if (buff->buffsize - buff->blen < 3)
|
||||||
|
strcpy(buff->b + buff->blen - 3, "..."); /* 'blen' must be > 3 */
|
||||||
|
else { /* there is enough space left for the "..." */
|
||||||
|
strcpy(buff->b + buff->blen, "...");
|
||||||
|
buff->blen += 3;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default: { /* no errors, but it can raise one creating the new string */
|
||||||
|
TString *ts = luaS_newlstr(L, buff->b, buff->blen);
|
||||||
|
setsvalue2s(L, L->top.p, ts);
|
||||||
|
L->top.p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *clearbuff (BuffFS *buff) {
|
||||||
lua_State *L = buff->L;
|
lua_State *L = buff->L;
|
||||||
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
|
const char *res;
|
||||||
L->top++; /* may use one extra slot */
|
if (luaD_rawrunprotected(L, pushbuff, buff) != LUA_OK) /* errors? */
|
||||||
buff->pushed++;
|
res = NULL; /* error message is on the top of the stack */
|
||||||
luaV_concat(L, buff->pushed); /* join partial results into one */
|
else
|
||||||
buff->pushed = 1;
|
res = getstr(tsvalue(s2v(L->top.p - 1)));
|
||||||
|
if (buff->b != buff->space) /* using dynamic buffer? */
|
||||||
|
luaM_freearray(L, buff->b, buff->buffsize); /* free it */
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** empty the buffer space into the stack
|
|
||||||
*/
|
|
||||||
static void clearbuff (BuffFS *buff) {
|
|
||||||
pushstr(buff, buff->space, buff->blen); /* push buffer contents */
|
|
||||||
buff->blen = 0; /* space now is empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Get a space of size 'sz' in the buffer. If buffer has not enough
|
|
||||||
** space, empty it. 'sz' must fit in an empty buffer.
|
|
||||||
*/
|
|
||||||
static char *getbuff (BuffFS *buff, int sz) {
|
|
||||||
lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS);
|
|
||||||
if (sz > BUFVFS - buff->blen) /* not enough space? */
|
|
||||||
clearbuff(buff);
|
|
||||||
return buff->space + buff->blen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define addsize(b,sz) ((b)->blen += (sz))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Add 'str' to the buffer. If string is larger than the buffer space,
|
|
||||||
** push the string directly to the stack.
|
|
||||||
*/
|
|
||||||
static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
|
static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
|
||||||
if (slen <= BUFVFS) { /* does string fit into buffer? */
|
size_t left = buff->buffsize - buff->blen; /* space left in the buffer */
|
||||||
char *bf = getbuff(buff, cast_int(slen));
|
if (buff->err) /* do nothing else after an error */
|
||||||
memcpy(bf, str, slen); /* add string to buffer */
|
return;
|
||||||
addsize(buff, cast_int(slen));
|
if (slen > left) { /* new string doesn't fit into current buffer? */
|
||||||
}
|
if (slen > ((MAX_SIZE/2) - buff->blen)) { /* overflow? */
|
||||||
else { /* string larger than buffer */
|
memcpy(buff->b + buff->blen, str, left); /* copy what it can */
|
||||||
clearbuff(buff); /* string comes after buffer's content */
|
buff->blen = buff->buffsize;
|
||||||
pushstr(buff, str, slen); /* push string */
|
buff->err = 2; /* doesn't add anything else */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size_t newsize = buff->buffsize + slen; /* limited to MAX_SIZE/2 */
|
||||||
|
char *newb =
|
||||||
|
(buff->b == buff->space) /* still using static space? */
|
||||||
|
? luaM_reallocvector(buff->L, NULL, 0, newsize, char)
|
||||||
|
: luaM_reallocvector(buff->L, buff->b, buff->buffsize, newsize,
|
||||||
|
char);
|
||||||
|
if (newb == NULL) { /* allocation error? */
|
||||||
|
buff->err = 1; /* signal a memory error */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buff->b == buff->space) /* new buffer (not reallocated)? */
|
||||||
|
memcpy(newb, buff->b, buff->blen); /* copy previous content */
|
||||||
|
buff->b = newb; /* set new (larger) buffer... */
|
||||||
|
buff->buffsize = newsize; /* ...and its new size */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
memcpy(buff->b + buff->blen, str, slen); /* copy new content */
|
||||||
|
buff->blen += slen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Add a number to the buffer.
|
** Add a numeral to the buffer.
|
||||||
*/
|
*/
|
||||||
static void addnum2buff (BuffFS *buff, TValue *num) {
|
static void addnum2buff (BuffFS *buff, TValue *num) {
|
||||||
char *numbuff = getbuff(buff, MAXNUMBER2STR);
|
char numbuff[LUA_N2SBUFFSZ];
|
||||||
int len = tostringbuff(num, numbuff); /* format number into 'numbuff' */
|
unsigned len = luaO_tostringbuff(num, numbuff);
|
||||||
addsize(buff, len);
|
addstr2buff(buff, numbuff, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -470,10 +596,9 @@ static void addnum2buff (BuffFS *buff, TValue *num) {
|
|||||||
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||||
BuffFS buff; /* holds last part of the result */
|
BuffFS buff; /* holds last part of the result */
|
||||||
const char *e; /* points to next '%' */
|
const char *e; /* points to next '%' */
|
||||||
buff.pushed = buff.blen = 0;
|
initbuff(L, &buff);
|
||||||
buff.L = L;
|
|
||||||
while ((e = strchr(fmt, '%')) != NULL) {
|
while ((e = strchr(fmt, '%')) != NULL) {
|
||||||
addstr2buff(&buff, fmt, e - fmt); /* add 'fmt' up to '%' */
|
addstr2buff(&buff, fmt, ct_diff2sz(e - fmt)); /* add 'fmt' up to '%' */
|
||||||
switch (*(e + 1)) { /* conversion specifier */
|
switch (*(e + 1)) { /* conversion specifier */
|
||||||
case 's': { /* zero-terminated string */
|
case 's': { /* zero-terminated string */
|
||||||
const char *s = va_arg(argp, char *);
|
const char *s = va_arg(argp, char *);
|
||||||
@@ -482,7 +607,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c': { /* an 'int' as a character */
|
case 'c': { /* an 'int' as a character */
|
||||||
char c = cast_uchar(va_arg(argp, int));
|
char c = cast_char(va_arg(argp, int));
|
||||||
addstr2buff(&buff, &c, sizeof(char));
|
addstr2buff(&buff, &c, sizeof(char));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -494,7 +619,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
}
|
}
|
||||||
case 'I': { /* a 'lua_Integer' */
|
case 'I': { /* a 'lua_Integer' */
|
||||||
TValue num;
|
TValue num;
|
||||||
setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt)));
|
setivalue(&num, cast_Integer(va_arg(argp, l_uacInt)));
|
||||||
addnum2buff(&buff, &num);
|
addnum2buff(&buff, &num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -505,17 +630,17 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p': { /* a pointer */
|
case 'p': { /* a pointer */
|
||||||
const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */
|
char bf[LUA_N2SBUFFSZ]; /* enough space for '%p' */
|
||||||
char *bf = getbuff(&buff, sz);
|
|
||||||
void *p = va_arg(argp, void *);
|
void *p = va_arg(argp, void *);
|
||||||
int len = lua_pointer2str(bf, sz, p);
|
int len = lua_pointer2str(bf, LUA_N2SBUFFSZ, p);
|
||||||
addsize(&buff, len);
|
addstr2buff(&buff, bf, cast_uint(len));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'U': { /* a 'long' as a UTF-8 sequence */
|
case 'U': { /* an 'unsigned long' as a UTF-8 sequence */
|
||||||
char bf[UTF8BUFFSZ];
|
char bf[UTF8BUFFSZ];
|
||||||
int len = luaO_utf8esc(bf, va_arg(argp, long));
|
unsigned long arg = va_arg(argp, unsigned long);
|
||||||
addstr2buff(&buff, bf + UTF8BUFFSZ - len, len);
|
int len = luaO_utf8esc(bf, cast(l_uint32, arg));
|
||||||
|
addstr2buff(&buff, bf + UTF8BUFFSZ - len, cast_uint(len));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '%': {
|
case '%': {
|
||||||
@@ -523,16 +648,14 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'",
|
addstr2buff(&buff, e, 2); /* keep unknown format in the result */
|
||||||
*(e + 1));
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt = e + 2; /* skip '%' and the specifier */
|
fmt = e + 2; /* skip '%' and the specifier */
|
||||||
}
|
}
|
||||||
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
||||||
clearbuff(&buff); /* empty buffer into the stack */
|
return clearbuff(&buff); /* empty buffer into a new string */
|
||||||
lua_assert(buff.pushed == 1);
|
|
||||||
return svalue(s2v(L->top - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -542,6 +665,8 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
|
|||||||
va_start(argp, fmt);
|
va_start(argp, fmt);
|
||||||
msg = luaO_pushvfstring(L, fmt, argp);
|
msg = luaO_pushvfstring(L, fmt, argp);
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
|
if (msg == NULL) /* error? */
|
||||||
|
luaD_throw(L, LUA_ERRMEM);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,7 +706,8 @@ void luaO_chunkid (char *out, const char *source, size_t srclen) {
|
|||||||
addstr(out, source, srclen); /* keep it */
|
addstr(out, source, srclen); /* keep it */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (nl != NULL) srclen = nl - source; /* stop at first newline */
|
if (nl != NULL)
|
||||||
|
srclen = ct_diff2sz(nl - source); /* stop at first newline */
|
||||||
if (srclen > bufflen) srclen = bufflen;
|
if (srclen > bufflen) srclen = bufflen;
|
||||||
addstr(out, source, srclen);
|
addstr(out, source, srclen);
|
||||||
addstr(out, RETS, LL(RETS));
|
addstr(out, RETS, LL(RETS));
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ typedef union Value {
|
|||||||
lua_CFunction f; /* light C functions */
|
lua_CFunction f; /* light C functions */
|
||||||
lua_Integer i; /* integer numbers */
|
lua_Integer i; /* integer numbers */
|
||||||
lua_Number n; /* float numbers */
|
lua_Number n; /* float numbers */
|
||||||
|
/* not used, but may avoid warnings for uninitialized value */
|
||||||
|
lu_byte ub;
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
|
|
||||||
@@ -155,6 +157,17 @@ typedef union StackValue {
|
|||||||
/* index to stack elements */
|
/* index to stack elements */
|
||||||
typedef StackValue *StkId;
|
typedef StackValue *StkId;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When reallocating the stack, change all pointers to the stack into
|
||||||
|
** proper offsets.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
StkId p; /* actual pointer */
|
||||||
|
ptrdiff_t offset; /* used while the stack is being reallocated */
|
||||||
|
} StkIdRel;
|
||||||
|
|
||||||
|
|
||||||
/* convert a 'StackValue' to a 'TValue' */
|
/* convert a 'StackValue' to a 'TValue' */
|
||||||
#define s2v(o) (&(o)->val)
|
#define s2v(o) (&(o)->val)
|
||||||
|
|
||||||
@@ -175,16 +188,28 @@ typedef StackValue *StkId;
|
|||||||
/* Value returned for a key not found in a table (absent key) */
|
/* Value returned for a key not found in a table (absent key) */
|
||||||
#define LUA_VABSTKEY makevariant(LUA_TNIL, 2)
|
#define LUA_VABSTKEY makevariant(LUA_TNIL, 2)
|
||||||
|
|
||||||
|
/* Special variant to signal that a fast get is accessing a non-table */
|
||||||
|
#define LUA_VNOTABLE makevariant(LUA_TNIL, 3)
|
||||||
|
|
||||||
|
|
||||||
/* macro to test for (any kind of) nil */
|
/* macro to test for (any kind of) nil */
|
||||||
#define ttisnil(v) checktype((v), LUA_TNIL)
|
#define ttisnil(v) checktype((v), LUA_TNIL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macro to test the result of a table access. Formally, it should
|
||||||
|
** distinguish between LUA_VEMPTY/LUA_VABSTKEY/LUA_VNOTABLE and
|
||||||
|
** other tags. As currently nil is equivalent to LUA_VEMPTY, it is
|
||||||
|
** simpler to just test whether the value is nil.
|
||||||
|
*/
|
||||||
|
#define tagisempty(tag) (novariant(tag) == LUA_TNIL)
|
||||||
|
|
||||||
|
|
||||||
/* macro to test for a standard nil */
|
/* macro to test for a standard nil */
|
||||||
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
|
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
|
||||||
|
|
||||||
|
|
||||||
#define setnilvalue(obj) settt_(obj, LUA_VNIL)
|
#define setnilvalue(obj) settt_(obj, LUA_VNIL)
|
||||||
|
#define setnilvalue2s(stk) setnilvalue(s2v(stk))
|
||||||
|
|
||||||
|
|
||||||
#define isabstkey(v) checktag((v), LUA_VABSTKEY)
|
#define isabstkey(v) checktag((v), LUA_VABSTKEY)
|
||||||
@@ -232,6 +257,8 @@ typedef StackValue *StkId;
|
|||||||
|
|
||||||
|
|
||||||
#define l_isfalse(o) (ttisfalse(o) || ttisnil(o))
|
#define l_isfalse(o) (ttisfalse(o) || ttisnil(o))
|
||||||
|
#define tagisfalse(t) ((t) == LUA_VFALSE || novariant(t) == LUA_TNIL)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define setbfvalue(obj) settt_(obj, LUA_VFALSE)
|
#define setbfvalue(obj) settt_(obj, LUA_VFALSE)
|
||||||
@@ -367,37 +394,54 @@ typedef struct GCObject {
|
|||||||
#define setsvalue2n setsvalue
|
#define setsvalue2n setsvalue
|
||||||
|
|
||||||
|
|
||||||
|
/* Kinds of long strings (stored in 'shrlen') */
|
||||||
|
#define LSTRREG -1 /* regular long string */
|
||||||
|
#define LSTRFIX -2 /* fixed external long string */
|
||||||
|
#define LSTRMEM -3 /* external long string with deallocation */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Header for a string value.
|
** Header for a string value.
|
||||||
*/
|
*/
|
||||||
typedef struct TString {
|
typedef struct TString {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
||||||
lu_byte shrlen; /* length for short strings */
|
ls_byte shrlen; /* length for short strings, negative for long strings */
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
union {
|
union {
|
||||||
size_t lnglen; /* length for long strings */
|
size_t lnglen; /* length for long strings */
|
||||||
struct TString *hnext; /* linked list for hash table */
|
struct TString *hnext; /* linked list for hash table */
|
||||||
} u;
|
} u;
|
||||||
char contents[1];
|
char *contents; /* pointer to content in long strings */
|
||||||
|
lua_Alloc falloc; /* deallocation function for external strings */
|
||||||
|
void *ud; /* user data for external strings */
|
||||||
} TString;
|
} TString;
|
||||||
|
|
||||||
|
|
||||||
|
#define strisshr(ts) ((ts)->shrlen >= 0)
|
||||||
|
#define isextstr(ts) (ttislngstring(ts) && tsvalue(ts)->shrlen != LSTRREG)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Get the actual string (array of bytes) from a 'TString'.
|
** Get the actual string (array of bytes) from a 'TString'. (Generic
|
||||||
|
** version and specialized versions for long and short strings.)
|
||||||
*/
|
*/
|
||||||
#define getstr(ts) ((ts)->contents)
|
#define rawgetshrstr(ts) (cast_charp(&(ts)->contents))
|
||||||
|
#define getshrstr(ts) check_exp(strisshr(ts), rawgetshrstr(ts))
|
||||||
|
#define getlngstr(ts) check_exp(!strisshr(ts), (ts)->contents)
|
||||||
|
#define getstr(ts) (strisshr(ts) ? rawgetshrstr(ts) : (ts)->contents)
|
||||||
|
|
||||||
|
|
||||||
/* get the actual string (array of bytes) from a Lua value */
|
/* get string length from 'TString *ts' */
|
||||||
#define svalue(o) getstr(tsvalue(o))
|
#define tsslen(ts) \
|
||||||
|
(strisshr(ts) ? cast_sizet((ts)->shrlen) : (ts)->u.lnglen)
|
||||||
|
|
||||||
/* get string length from 'TString *s' */
|
/*
|
||||||
#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)
|
** Get string and length */
|
||||||
|
#define getlstr(ts, len) \
|
||||||
/* get string length from 'TValue *o' */
|
(strisshr(ts) \
|
||||||
#define vslen(o) tsslen(tsvalue(o))
|
? (cast_void((len) = cast_sizet((ts)->shrlen)), rawgetshrstr(ts)) \
|
||||||
|
: (cast_void((len) = (ts)->u.lnglen), (ts)->contents))
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -475,8 +519,8 @@ typedef struct Udata0 {
|
|||||||
|
|
||||||
/* compute the offset of the memory area of a userdata */
|
/* compute the offset of the memory area of a userdata */
|
||||||
#define udatamemoffset(nuv) \
|
#define udatamemoffset(nuv) \
|
||||||
((nuv) == 0 ? offsetof(Udata0, bindata) \
|
((nuv) == 0 ? offsetof(Udata0, bindata) \
|
||||||
: offsetof(Udata, uv) + (sizeof(UValue) * (nuv)))
|
: offsetof(Udata, uv) + (sizeof(UValue) * (nuv)))
|
||||||
|
|
||||||
/* get the address of the memory block inside 'Udata' */
|
/* get the address of the memory block inside 'Udata' */
|
||||||
#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue))
|
#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue))
|
||||||
@@ -496,6 +540,9 @@ typedef struct Udata0 {
|
|||||||
#define LUA_VPROTO makevariant(LUA_TPROTO, 0)
|
#define LUA_VPROTO makevariant(LUA_TPROTO, 0)
|
||||||
|
|
||||||
|
|
||||||
|
typedef l_uint32 Instruction;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Description of an upvalue for function prototypes
|
** Description of an upvalue for function prototypes
|
||||||
*/
|
*/
|
||||||
@@ -533,13 +580,30 @@ typedef struct AbsLineInfo {
|
|||||||
int line;
|
int line;
|
||||||
} AbsLineInfo;
|
} AbsLineInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Flags in Prototypes
|
||||||
|
*/
|
||||||
|
#define PF_VAHID 1 /* function has hidden vararg arguments */
|
||||||
|
#define PF_VATAB 2 /* function has vararg table */
|
||||||
|
#define PF_FIXED 4 /* prototype has parts in fixed memory */
|
||||||
|
|
||||||
|
/* a vararg function either has hidden args. or a vararg table */
|
||||||
|
#define isvararg(p) ((p)->flag & (PF_VAHID | PF_VATAB))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** mark that a function needs a vararg table. (The flag PF_VAHID will
|
||||||
|
** be cleared later.)
|
||||||
|
*/
|
||||||
|
#define needvatab(p) ((p)->flag |= PF_VATAB)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function Prototypes
|
** Function Prototypes
|
||||||
*/
|
*/
|
||||||
typedef struct Proto {
|
typedef struct Proto {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte numparams; /* number of fixed (named) parameters */
|
lu_byte numparams; /* number of fixed (named) parameters */
|
||||||
lu_byte is_vararg;
|
lu_byte flag;
|
||||||
lu_byte maxstacksize; /* number of registers needed by this function */
|
lu_byte maxstacksize; /* number of registers needed by this function */
|
||||||
int sizeupvalues; /* size of 'upvalues' */
|
int sizeupvalues; /* size of 'upvalues' */
|
||||||
int sizek; /* size of 'k' */
|
int sizek; /* size of 'k' */
|
||||||
@@ -615,8 +679,10 @@ typedef struct Proto {
|
|||||||
*/
|
*/
|
||||||
typedef struct UpVal {
|
typedef struct UpVal {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte tbc; /* true if it represents a to-be-closed variable */
|
union {
|
||||||
TValue *v; /* points to stack or to its own value */
|
TValue *p; /* points to stack or to its own value */
|
||||||
|
ptrdiff_t offset; /* used while the stack is being reallocated */
|
||||||
|
} v;
|
||||||
union {
|
union {
|
||||||
struct { /* (when open) */
|
struct { /* (when open) */
|
||||||
struct UpVal *next; /* linked list */
|
struct UpVal *next; /* linked list */
|
||||||
@@ -695,10 +761,9 @@ typedef union Node {
|
|||||||
|
|
||||||
|
|
||||||
/* copy a value into a key */
|
/* copy a value into a key */
|
||||||
#define setnodekey(L,node,obj) \
|
#define setnodekey(node,obj) \
|
||||||
{ Node *n_=(node); const TValue *io_=(obj); \
|
{ Node *n_=(node); const TValue *io_=(obj); \
|
||||||
n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
|
n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; }
|
||||||
checkliveness(L,io_); }
|
|
||||||
|
|
||||||
|
|
||||||
/* copy a value from a key */
|
/* copy a value from a key */
|
||||||
@@ -708,27 +773,14 @@ typedef union Node {
|
|||||||
checkliveness(L,io_); }
|
checkliveness(L,io_); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** About 'alimit': if 'isrealasize(t)' is true, then 'alimit' is the
|
|
||||||
** real size of 'array'. Otherwise, the real size of 'array' is the
|
|
||||||
** smallest power of two not smaller than 'alimit' (or zero iff 'alimit'
|
|
||||||
** is zero); 'alimit' is then used as a hint for #t.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define BITRAS (1 << 7)
|
|
||||||
#define isrealasize(t) (!((t)->flags & BITRAS))
|
|
||||||
#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS))
|
|
||||||
#define setnorealasize(t) ((t)->flags |= BITRAS)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct Table {
|
typedef struct Table {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
|
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
|
||||||
lu_byte lsizenode; /* log2 of size of 'node' array */
|
lu_byte lsizenode; /* log2 of number of slots of 'node' array */
|
||||||
unsigned int alimit; /* "limit" of 'array' array */
|
unsigned int asize; /* number of slots in 'array' array */
|
||||||
TValue *array; /* array part */
|
Value *array; /* array part */
|
||||||
Node *node;
|
Node *node;
|
||||||
Node *lastfree; /* any free position is before this position */
|
|
||||||
struct Table *metatable;
|
struct Table *metatable;
|
||||||
GCObject *gclist;
|
GCObject *gclist;
|
||||||
} Table;
|
} Table;
|
||||||
@@ -771,24 +823,37 @@ typedef struct Table {
|
|||||||
** 'module' operation for hashing (size is always a power of 2)
|
** 'module' operation for hashing (size is always a power of 2)
|
||||||
*/
|
*/
|
||||||
#define lmod(s,size) \
|
#define lmod(s,size) \
|
||||||
(check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1)))))
|
(check_exp((size&(size-1))==0, (cast_uint(s) & cast_uint((size)-1))))
|
||||||
|
|
||||||
|
|
||||||
#define twoto(x) (1<<(x))
|
#define twoto(x) (1u<<(x))
|
||||||
#define sizenode(t) (twoto((t)->lsizenode))
|
#define sizenode(t) (twoto((t)->lsizenode))
|
||||||
|
|
||||||
|
|
||||||
/* size of buffer for 'luaO_utf8esc' function */
|
/* size of buffer for 'luaO_utf8esc' function */
|
||||||
#define UTF8BUFFSZ 8
|
#define UTF8BUFFSZ 8
|
||||||
|
|
||||||
LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
|
|
||||||
LUAI_FUNC int luaO_ceillog2 (unsigned int x);
|
/* macro to call 'luaO_pushvfstring' correctly */
|
||||||
|
#define pushvfstring(L, argp, fmt, msg) \
|
||||||
|
{ va_start(argp, fmt); \
|
||||||
|
msg = luaO_pushvfstring(L, fmt, argp); \
|
||||||
|
va_end(argp); \
|
||||||
|
if (msg == NULL) luaD_throw(L, LUA_ERRMEM); /* only after 'va_end' */ }
|
||||||
|
|
||||||
|
|
||||||
|
LUAI_FUNC int luaO_utf8esc (char *buff, l_uint32 x);
|
||||||
|
LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x);
|
||||||
|
LUAI_FUNC lu_byte luaO_codeparam (unsigned int p);
|
||||||
|
LUAI_FUNC l_mem luaO_applyparam (lu_byte p, l_mem x);
|
||||||
|
|
||||||
LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
|
LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
|
||||||
const TValue *p2, TValue *res);
|
const TValue *p2, TValue *res);
|
||||||
LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
|
LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
|
||||||
const TValue *p2, StkId res);
|
const TValue *p2, StkId res);
|
||||||
LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
|
LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
|
||||||
LUAI_FUNC int luaO_hexavalue (int c);
|
LUAI_FUNC unsigned luaO_tostringbuff (const TValue *obj, char *buff);
|
||||||
|
LUAI_FUNC lu_byte luaO_hexavalue (int c);
|
||||||
LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
|
LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
|
||||||
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
|
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
|
||||||
va_list argp);
|
va_list argp);
|
||||||
|
|||||||
+33
-6
@@ -13,6 +13,10 @@
|
|||||||
#include "lopcodes.h"
|
#include "lopcodes.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define opmode(mm,ot,it,t,a,m) \
|
||||||
|
(((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
|
||||||
|
|
||||||
|
|
||||||
/* ORDER OP */
|
/* ORDER OP */
|
||||||
|
|
||||||
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
||||||
@@ -36,7 +40,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */
|
||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */
|
||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */
|
,opmode(0, 0, 0, 0, 1, ivABC) /* OP_NEWTABLE */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */
|
||||||
@@ -49,8 +53,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */
|
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */
|
||||||
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
|
||||||
@@ -64,8 +68,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */
|
||||||
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */
|
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */
|
||||||
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI*/
|
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI */
|
||||||
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK*/
|
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */
|
||||||
@@ -95,10 +99,33 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */
|
,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */
|
||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */
|
||||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
|
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
|
||||||
,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */
|
,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */
|
||||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
||||||
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
||||||
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */
|
||||||
|
,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */
|
||||||
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_VARARGPREP */
|
||||||
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
|
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define testITMode(m) (luaP_opmodes[m] & (1 << 5))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check whether instruction uses top. That happens for OP_VARARGPREP
|
||||||
|
** and for instructions that use multiple values set by the previous
|
||||||
|
** instruction.
|
||||||
|
*/
|
||||||
|
int luaP_isIT (Instruction i) {
|
||||||
|
OpCode op = GET_OPCODE(i);
|
||||||
|
switch (op) {
|
||||||
|
case OP_SETLIST:
|
||||||
|
return GETARG_vB(i) == 0;
|
||||||
|
case OP_VARARGPREP:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+108
-69
@@ -8,6 +8,7 @@
|
|||||||
#define lopcodes_h
|
#define lopcodes_h
|
||||||
|
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
@@ -18,25 +19,30 @@
|
|||||||
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
|
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
|
||||||
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||||
iABC C(8) | B(8) |k| A(8) | Op(7) |
|
iABC C(8) | B(8) |k| A(8) | Op(7) |
|
||||||
|
ivABC vC(10) | vB(6) |k| A(8) | Op(7) |
|
||||||
iABx Bx(17) | A(8) | Op(7) |
|
iABx Bx(17) | A(8) | Op(7) |
|
||||||
iAsBx sBx (signed)(17) | A(8) | Op(7) |
|
iAsBx sBx (signed)(17) | A(8) | Op(7) |
|
||||||
iAx Ax(25) | Op(7) |
|
iAx Ax(25) | Op(7) |
|
||||||
isJ sJ(25) | Op(7) |
|
isJ sJ (signed)(25) | Op(7) |
|
||||||
|
|
||||||
A signed argument is represented in excess K: the represented value is
|
('v' stands for "variant", 's' for "signed", 'x' for "extended".)
|
||||||
the written unsigned value minus K, where K is half the maximum for the
|
A signed argument is represented in excess K: The represented value is
|
||||||
corresponding unsigned argument.
|
the written unsigned value minus K, where K is half (rounded down) the
|
||||||
|
maximum value for the corresponding unsigned argument.
|
||||||
===========================================================================*/
|
===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
/* basic instruction formats */
|
||||||
|
enum OpMode {iABC, ivABC, iABx, iAsBx, iAx, isJ};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** size and position of opcode arguments.
|
** size and position of opcode arguments.
|
||||||
*/
|
*/
|
||||||
#define SIZE_C 8
|
#define SIZE_C 8
|
||||||
|
#define SIZE_vC 10
|
||||||
#define SIZE_B 8
|
#define SIZE_B 8
|
||||||
|
#define SIZE_vB 6
|
||||||
#define SIZE_Bx (SIZE_C + SIZE_B + 1)
|
#define SIZE_Bx (SIZE_C + SIZE_B + 1)
|
||||||
#define SIZE_A 8
|
#define SIZE_A 8
|
||||||
#define SIZE_Ax (SIZE_Bx + SIZE_A)
|
#define SIZE_Ax (SIZE_Bx + SIZE_A)
|
||||||
@@ -49,7 +55,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
#define POS_A (POS_OP + SIZE_OP)
|
#define POS_A (POS_OP + SIZE_OP)
|
||||||
#define POS_k (POS_A + SIZE_A)
|
#define POS_k (POS_A + SIZE_A)
|
||||||
#define POS_B (POS_k + 1)
|
#define POS_B (POS_k + 1)
|
||||||
|
#define POS_vB (POS_k + 1)
|
||||||
#define POS_C (POS_B + SIZE_B)
|
#define POS_C (POS_B + SIZE_B)
|
||||||
|
#define POS_vC (POS_vB + SIZE_vB)
|
||||||
|
|
||||||
#define POS_Bx POS_k
|
#define POS_Bx POS_k
|
||||||
|
|
||||||
@@ -64,14 +72,17 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
** so they must fit in ints.
|
** so they must fit in ints.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Check whether type 'int' has at least 'b' bits ('b' < 32) */
|
/*
|
||||||
#define L_INTHASBITS(b) ((UINT_MAX >> ((b) - 1)) >= 1)
|
** Check whether type 'int' has at least 'b' + 1 bits.
|
||||||
|
** 'b' < 32; +1 for the sign bit.
|
||||||
|
*/
|
||||||
|
#define L_INTHASBITS(b) ((UINT_MAX >> (b)) >= 1)
|
||||||
|
|
||||||
|
|
||||||
#if L_INTHASBITS(SIZE_Bx)
|
#if L_INTHASBITS(SIZE_Bx)
|
||||||
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
|
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
|
||||||
#else
|
#else
|
||||||
#define MAXARG_Bx MAX_INT
|
#define MAXARG_Bx INT_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OFFSET_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
|
#define OFFSET_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
|
||||||
@@ -80,13 +91,13 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
#if L_INTHASBITS(SIZE_Ax)
|
#if L_INTHASBITS(SIZE_Ax)
|
||||||
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
|
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
|
||||||
#else
|
#else
|
||||||
#define MAXARG_Ax MAX_INT
|
#define MAXARG_Ax INT_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if L_INTHASBITS(SIZE_sJ)
|
#if L_INTHASBITS(SIZE_sJ)
|
||||||
#define MAXARG_sJ ((1 << SIZE_sJ) - 1)
|
#define MAXARG_sJ ((1 << SIZE_sJ) - 1)
|
||||||
#else
|
#else
|
||||||
#define MAXARG_sJ MAX_INT
|
#define MAXARG_sJ INT_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OFFSET_sJ (MAXARG_sJ >> 1)
|
#define OFFSET_sJ (MAXARG_sJ >> 1)
|
||||||
@@ -94,7 +105,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
#define MAXARG_A ((1<<SIZE_A)-1)
|
#define MAXARG_A ((1<<SIZE_A)-1)
|
||||||
#define MAXARG_B ((1<<SIZE_B)-1)
|
#define MAXARG_B ((1<<SIZE_B)-1)
|
||||||
|
#define MAXARG_vB ((1<<SIZE_vB)-1)
|
||||||
#define MAXARG_C ((1<<SIZE_C)-1)
|
#define MAXARG_C ((1<<SIZE_C)-1)
|
||||||
|
#define MAXARG_vC ((1<<SIZE_vC)-1)
|
||||||
#define OFFSET_sC (MAXARG_C >> 1)
|
#define OFFSET_sC (MAXARG_C >> 1)
|
||||||
|
|
||||||
#define int2sC(i) ((i) + OFFSET_sC)
|
#define int2sC(i) ((i) + OFFSET_sC)
|
||||||
@@ -113,28 +126,36 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
|
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
|
||||||
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
|
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
|
||||||
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
|
((cast_Inst(o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
|
||||||
|
|
||||||
#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m)
|
#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m)
|
||||||
|
|
||||||
|
|
||||||
#define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
|
#define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
|
||||||
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
|
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
|
||||||
((cast(Instruction, v)<<pos)&MASK1(size,pos))))
|
((cast_Inst(v)<<pos)&MASK1(size,pos))))
|
||||||
|
|
||||||
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
|
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
|
||||||
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
|
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
|
||||||
|
|
||||||
#define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
|
#define GETARG_B(i) \
|
||||||
|
check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
|
||||||
|
#define GETARG_vB(i) \
|
||||||
|
check_exp(checkopm(i, ivABC), getarg(i, POS_vB, SIZE_vB))
|
||||||
#define GETARG_sB(i) sC2int(GETARG_B(i))
|
#define GETARG_sB(i) sC2int(GETARG_B(i))
|
||||||
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
|
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
|
||||||
|
#define SETARG_vB(i,v) setarg(i, v, POS_vB, SIZE_vB)
|
||||||
|
|
||||||
#define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
|
#define GETARG_C(i) \
|
||||||
|
check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
|
||||||
|
#define GETARG_vC(i) \
|
||||||
|
check_exp(checkopm(i, ivABC), getarg(i, POS_vC, SIZE_vC))
|
||||||
#define GETARG_sC(i) sC2int(GETARG_C(i))
|
#define GETARG_sC(i) sC2int(GETARG_C(i))
|
||||||
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
|
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
|
||||||
|
#define SETARG_vC(i,v) setarg(i, v, POS_vC, SIZE_vC)
|
||||||
|
|
||||||
#define TESTARG_k(i) check_exp(checkopm(i, iABC), (cast_int(((i) & (1u << POS_k)))))
|
#define TESTARG_k(i) (cast_int(((i) & (1u << POS_k))))
|
||||||
#define GETARG_k(i) check_exp(checkopm(i, iABC), getarg(i, POS_k, 1))
|
#define GETARG_k(i) getarg(i, POS_k, 1)
|
||||||
#define SETARG_k(i,v) setarg(i, v, POS_k, 1)
|
#define SETARG_k(i,v) setarg(i, v, POS_k, 1)
|
||||||
|
|
||||||
#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
|
#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
|
||||||
@@ -153,22 +174,28 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
setarg(i, cast_uint((j)+OFFSET_sJ), POS_sJ, SIZE_sJ)
|
setarg(i, cast_uint((j)+OFFSET_sJ), POS_sJ, SIZE_sJ)
|
||||||
|
|
||||||
|
|
||||||
#define CREATE_ABCk(o,a,b,c,k) ((cast(Instruction, o)<<POS_OP) \
|
#define CREATE_ABCk(o,a,b,c,k) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, a)<<POS_A) \
|
| (cast_Inst(a)<<POS_A) \
|
||||||
| (cast(Instruction, b)<<POS_B) \
|
| (cast_Inst(b)<<POS_B) \
|
||||||
| (cast(Instruction, c)<<POS_C) \
|
| (cast_Inst(c)<<POS_C) \
|
||||||
| (cast(Instruction, k)<<POS_k))
|
| (cast_Inst(k)<<POS_k))
|
||||||
|
|
||||||
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
|
#define CREATE_vABCk(o,a,b,c,k) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, a)<<POS_A) \
|
| (cast_Inst(a)<<POS_A) \
|
||||||
| (cast(Instruction, bc)<<POS_Bx))
|
| (cast_Inst(b)<<POS_vB) \
|
||||||
|
| (cast_Inst(c)<<POS_vC) \
|
||||||
|
| (cast_Inst(k)<<POS_k))
|
||||||
|
|
||||||
#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \
|
#define CREATE_ABx(o,a,bc) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, a)<<POS_Ax))
|
| (cast_Inst(a)<<POS_A) \
|
||||||
|
| (cast_Inst(bc)<<POS_Bx))
|
||||||
|
|
||||||
#define CREATE_sJ(o,j,k) ((cast(Instruction, o) << POS_OP) \
|
#define CREATE_Ax(o,a) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, j) << POS_sJ) \
|
| (cast_Inst(a)<<POS_Ax))
|
||||||
| (cast(Instruction, k) << POS_k))
|
|
||||||
|
#define CREATE_sJ(o,j,k) ((cast_Inst(o) << POS_OP) \
|
||||||
|
| (cast_Inst(j) << POS_sJ) \
|
||||||
|
| (cast_Inst(k) << POS_k))
|
||||||
|
|
||||||
|
|
||||||
#if !defined(MAXINDEXRK) /* (for debugging only) */
|
#if !defined(MAXINDEXRK) /* (for debugging only) */
|
||||||
@@ -177,9 +204,16 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** invalid register that fits in 8 bits
|
** Maximum size for the stack of a Lua function. It must fit in 8 bits.
|
||||||
|
** The highest valid register is one less than this value.
|
||||||
*/
|
*/
|
||||||
#define NO_REG MAXARG_A
|
#define MAX_FSTACK MAXARG_A
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Invalid register (one more than last valid register).
|
||||||
|
*/
|
||||||
|
#define NO_REG MAX_FSTACK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -190,8 +224,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
|
** Grep "ORDER OP" if you change this enum.
|
||||||
** has extra descriptions in the notes after the enumeration.
|
** See "Notes" below for more information about some instructions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -204,25 +238,25 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
|
|||||||
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
||||||
OP_LOADKX,/* A R[A] := K[extra arg] */
|
OP_LOADKX,/* A R[A] := K[extra arg] */
|
||||||
OP_LOADFALSE,/* A R[A] := false */
|
OP_LOADFALSE,/* A R[A] := false */
|
||||||
OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */
|
OP_LFALSESKIP,/*A R[A] := false; pc++ */
|
||||||
OP_LOADTRUE,/* A R[A] := true */
|
OP_LOADTRUE,/* A R[A] := true */
|
||||||
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
||||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
||||||
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
|
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
|
||||||
|
|
||||||
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */
|
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */
|
||||||
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
|
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
|
||||||
OP_GETI,/* A B C R[A] := R[B][C] */
|
OP_GETI,/* A B C R[A] := R[B][C] */
|
||||||
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */
|
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */
|
||||||
|
|
||||||
OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */
|
OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */
|
||||||
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
|
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
|
||||||
OP_SETI,/* A B C R[A][B] := RK(C) */
|
OP_SETI,/* A B C R[A][B] := RK(C) */
|
||||||
OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */
|
OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */
|
||||||
|
|
||||||
OP_NEWTABLE,/* A B C k R[A] := {} */
|
OP_NEWTABLE,/* A vB vC k R[A] := {} */
|
||||||
|
|
||||||
OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */
|
OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][K[C]:shortstring] */
|
||||||
|
|
||||||
OP_ADDI,/* A B sC R[A] := R[B] + sC */
|
OP_ADDI,/* A B sC R[A] := R[B] + sC */
|
||||||
|
|
||||||
@@ -238,8 +272,8 @@ OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */
|
|||||||
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */
|
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */
|
||||||
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
|
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
|
||||||
|
|
||||||
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
|
|
||||||
OP_SHLI,/* A B sC R[A] := sC << R[B] */
|
OP_SHLI,/* A B sC R[A] := sC << R[B] */
|
||||||
|
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
|
||||||
|
|
||||||
OP_ADD,/* A B C R[A] := R[B] + R[C] */
|
OP_ADD,/* A B C R[A] := R[B] + R[C] */
|
||||||
OP_SUB,/* A B C R[A] := R[B] - R[C] */
|
OP_SUB,/* A B C R[A] := R[B] - R[C] */
|
||||||
@@ -255,7 +289,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */
|
|||||||
OP_SHL,/* A B C R[A] := R[B] << R[C] */
|
OP_SHL,/* A B C R[A] := R[B] << R[C] */
|
||||||
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
|
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
|
||||||
|
|
||||||
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */
|
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */
|
||||||
OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
|
OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
|
||||||
OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
|
OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
|
||||||
|
|
||||||
@@ -281,12 +315,12 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
|
|||||||
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
||||||
|
|
||||||
OP_TEST,/* A k if (not R[A] == k) then pc++ */
|
OP_TEST,/* A k if (not R[A] == k) then pc++ */
|
||||||
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
|
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */
|
||||||
|
|
||||||
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
|
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
|
||||||
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
|
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
|
||||||
|
|
||||||
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */
|
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] */
|
||||||
OP_RETURN0,/* return */
|
OP_RETURN0,/* return */
|
||||||
OP_RETURN1,/* A return R[A] */
|
OP_RETURN1,/* A return R[A] */
|
||||||
|
|
||||||
@@ -298,13 +332,17 @@ OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */
|
|||||||
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
|
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
|
||||||
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
|
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
|
||||||
|
|
||||||
OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
|
OP_SETLIST,/* A vB vC k R[A][vC+i] := R[A+i], 1 <= i <= vB */
|
||||||
|
|
||||||
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
||||||
|
|
||||||
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
|
OP_VARARG,/* A B C k R[A], ..., R[A+C-2] = varargs */
|
||||||
|
|
||||||
OP_VARARGPREP,/*A (adjust vararg parameters) */
|
OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */
|
||||||
|
|
||||||
|
OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx - 1] is global name)*/
|
||||||
|
|
||||||
|
OP_VARARGPREP,/* (adjust varargs) */
|
||||||
|
|
||||||
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||||
} OpCode;
|
} OpCode;
|
||||||
@@ -333,7 +371,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
OP_RETURN*, OP_SETLIST) may use 'top'.
|
OP_RETURN*, OP_SETLIST) may use 'top'.
|
||||||
|
|
||||||
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
|
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
|
||||||
set top (like in OP_CALL with C == 0).
|
set top (like in OP_CALL with C == 0). 'k' means function has a
|
||||||
|
vararg table, which is in R[B].
|
||||||
|
|
||||||
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
||||||
|
|
||||||
@@ -344,22 +383,27 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
|
real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
|
||||||
bits of C).
|
bits of C).
|
||||||
|
|
||||||
(*) In OP_NEWTABLE, B is log2 of the hash size (which is always a
|
(*) In OP_NEWTABLE, vB is log2 of the hash size (which is always a
|
||||||
power of 2) plus 1, or zero for size zero. If not k, the array size
|
power of 2) plus 1, or zero for size zero. If not k, the array size
|
||||||
is C. Otherwise, the array size is EXTRAARG _ C.
|
is vC. Otherwise, the array size is EXTRAARG _ vC.
|
||||||
|
|
||||||
|
(*) In OP_ERRNNIL, (Bx == 0) means index of global name doesn't
|
||||||
|
fit in Bx. (So, that name is not available for the error message.)
|
||||||
|
|
||||||
(*) For comparisons, k specifies what condition the test should accept
|
(*) For comparisons, k specifies what condition the test should accept
|
||||||
(true or false).
|
(true or false).
|
||||||
|
|
||||||
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
||||||
(the constant is the first operand).
|
(the constant is the first operand).
|
||||||
|
|
||||||
(*) All 'skips' (pc++) assume that next instruction is a jump.
|
(*) All comparison and test instructions assume that the instruction
|
||||||
|
being skipped (pc++) is a jump.
|
||||||
|
|
||||||
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
||||||
function builds upvalues, which may need to be closed. C > 0 means
|
function builds upvalues, which may need to be closed. C > 0 means
|
||||||
the function is vararg, so that its 'func' must be corrected before
|
the function has hidden vararg arguments, so that its 'func' must be
|
||||||
returning; in this case, (C - 1) is its number of fixed parameters.
|
corrected before returning; in this case, (C - 1) is its number of
|
||||||
|
fixed parameters.
|
||||||
|
|
||||||
(*) In comparisons with an immediate operand, C signals whether the
|
(*) In comparisons with an immediate operand, C signals whether the
|
||||||
original operand was a float. (It must be corrected in case of
|
original operand was a float. (It must be corrected in case of
|
||||||
@@ -373,8 +417,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
** bits 0-2: op mode
|
** bits 0-2: op mode
|
||||||
** bit 3: instruction set register A
|
** bit 3: instruction set register A
|
||||||
** bit 4: operator is a test (next instruction must be a jump)
|
** bit 4: operator is a test (next instruction must be a jump)
|
||||||
** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0)
|
** bit 5: used by 'luaP_isIT'
|
||||||
** bit 6: instruction sets 'L->top' for next instruction (when C == 0)
|
** bit 6: used by 'luaP_isOT'
|
||||||
** bit 7: instruction is an MM instruction (call a metamethod)
|
** bit 7: instruction is an MM instruction (call a metamethod)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -383,23 +427,18 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
|
|||||||
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
|
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
|
||||||
#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
|
#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
|
||||||
#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
|
#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
|
||||||
#define testITMode(m) (luaP_opmodes[m] & (1 << 5))
|
|
||||||
#define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
|
|
||||||
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
|
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
|
||||||
|
|
||||||
/* "out top" (set top for next instruction) */
|
|
||||||
#define isOT(i) \
|
|
||||||
((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \
|
|
||||||
GET_OPCODE(i) == OP_TAILCALL)
|
|
||||||
|
|
||||||
/* "in top" (uses top from previous instruction) */
|
/* Check whether instruction sets top for next instruction, that is,
|
||||||
#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0)
|
** it results in multiple values. Used only for tests.
|
||||||
|
*/
|
||||||
#define opmode(mm,ot,it,t,a,m) \
|
#define luaP_isOT(i) \
|
||||||
(((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
|
(GET_OPCODE(i) == OP_TAILCALL || \
|
||||||
|
((luaP_opmodes[GET_OPCODE(i)] & (1 << 6)) && GETARG_C(i) == 0))
|
||||||
|
|
||||||
|
|
||||||
/* number of list items to accumulate before a SETLIST instruction */
|
LUAI_FUNC int luaP_isIT (Instruction i);
|
||||||
#define LFIELDS_PER_FLUSH 50
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+3
-1
@@ -45,8 +45,8 @@ static const char *const opnames[] = {
|
|||||||
"BANDK",
|
"BANDK",
|
||||||
"BORK",
|
"BORK",
|
||||||
"BXORK",
|
"BXORK",
|
||||||
"SHRI",
|
|
||||||
"SHLI",
|
"SHLI",
|
||||||
|
"SHRI",
|
||||||
"ADD",
|
"ADD",
|
||||||
"SUB",
|
"SUB",
|
||||||
"MUL",
|
"MUL",
|
||||||
@@ -94,6 +94,8 @@ static const char *const opnames[] = {
|
|||||||
"SETLIST",
|
"SETLIST",
|
||||||
"CLOSURE",
|
"CLOSURE",
|
||||||
"VARARG",
|
"VARARG",
|
||||||
|
"GETVARG",
|
||||||
|
"ERRNNIL",
|
||||||
"VARARGPREP",
|
"VARARGPREP",
|
||||||
"EXTRAARG",
|
"EXTRAARG",
|
||||||
NULL
|
NULL
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -30,23 +31,14 @@
|
|||||||
*/
|
*/
|
||||||
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
|
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
|
||||||
|
|
||||||
/* options for ANSI C 89 (only 1-char options) */
|
|
||||||
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
|
|
||||||
|
|
||||||
/* options for ISO C 99 and POSIX */
|
|
||||||
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
|
|
||||||
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
|
|
||||||
|
|
||||||
/* options for Windows */
|
|
||||||
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
|
|
||||||
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
|
|
||||||
|
|
||||||
#if defined(LUA_USE_WINDOWS)
|
#if defined(LUA_USE_WINDOWS)
|
||||||
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
|
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
|
||||||
#elif defined(LUA_USE_C89)
|
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
|
||||||
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
|
#elif defined(LUA_USE_C89) /* C89 (only 1-char options) */
|
||||||
|
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
|
||||||
#else /* C99 specification */
|
#else /* C99 specification */
|
||||||
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
|
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
|
||||||
|
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
@@ -138,12 +130,21 @@
|
|||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(l_system)
|
||||||
|
#if defined(LUA_USE_IOS)
|
||||||
|
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
|
||||||
|
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
|
||||||
|
#else
|
||||||
|
#define l_system(cmd) system(cmd) /* default definition */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int os_execute (lua_State *L) {
|
static int os_execute (lua_State *L) {
|
||||||
const char *cmd = luaL_optstring(L, 1, NULL);
|
const char *cmd = luaL_optstring(L, 1, NULL);
|
||||||
int stat;
|
int stat;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
stat = system(cmd);
|
stat = l_system(cmd);
|
||||||
if (cmd != NULL)
|
if (cmd != NULL)
|
||||||
return luaL_execresult(L, stat);
|
return luaL_execresult(L, stat);
|
||||||
else {
|
else {
|
||||||
@@ -155,6 +156,7 @@ static int os_execute (lua_State *L) {
|
|||||||
|
|
||||||
static int os_remove (lua_State *L) {
|
static int os_remove (lua_State *L) {
|
||||||
const char *filename = luaL_checkstring(L, 1);
|
const char *filename = luaL_checkstring(L, 1);
|
||||||
|
errno = 0;
|
||||||
return luaL_fileresult(L, remove(filename) == 0, filename);
|
return luaL_fileresult(L, remove(filename) == 0, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +164,7 @@ static int os_remove (lua_State *L) {
|
|||||||
static int os_rename (lua_State *L) {
|
static int os_rename (lua_State *L) {
|
||||||
const char *fromname = luaL_checkstring(L, 1);
|
const char *fromname = luaL_checkstring(L, 1);
|
||||||
const char *toname = luaL_checkstring(L, 2);
|
const char *toname = luaL_checkstring(L, 2);
|
||||||
|
errno = 0;
|
||||||
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
|
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,9 +263,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
|
|||||||
res = d;
|
res = d;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* unsigned avoids overflow when lua_Integer has 32 bits */
|
if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
|
||||||
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
|
|
||||||
: (lua_Integer)INT_MIN + delta <= res))
|
|
||||||
return luaL_error(L, "field '%s' is out-of-bound", key);
|
return luaL_error(L, "field '%s' is out-of-bound", key);
|
||||||
res -= delta;
|
res -= delta;
|
||||||
}
|
}
|
||||||
@@ -272,9 +273,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *checkoption (lua_State *L, const char *conv,
|
static const char *checkoption (lua_State *L, const char *conv,
|
||||||
ptrdiff_t convlen, char *buff) {
|
size_t convlen, char *buff) {
|
||||||
const char *option = LUA_STRFTIMEOPTIONS;
|
const char *option = LUA_STRFTIMEOPTIONS;
|
||||||
int oplen = 1; /* length of options being checked */
|
unsigned oplen = 1; /* length of options being checked */
|
||||||
for (; *option != '\0' && oplen <= convlen; option += oplen) {
|
for (; *option != '\0' && oplen <= convlen; option += oplen) {
|
||||||
if (*option == '|') /* next block? */
|
if (*option == '|') /* next block? */
|
||||||
oplen++; /* will check options with next length (+1) */
|
oplen++; /* will check options with next length (+1) */
|
||||||
@@ -332,7 +333,8 @@ static int os_date (lua_State *L) {
|
|||||||
size_t reslen;
|
size_t reslen;
|
||||||
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
|
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
|
||||||
s++; /* skip '%' */
|
s++; /* skip '%' */
|
||||||
s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
|
/* copy specifier to 'cc' */
|
||||||
|
s = checkoption(L, s, ct_diff2sz(se - s), cc + 1);
|
||||||
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
|
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
|
||||||
luaL_addsize(&b, reslen);
|
luaL_addsize(&b, reslen);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,26 +32,36 @@ typedef enum {
|
|||||||
VKFLT, /* floating constant; nval = numerical float value */
|
VKFLT, /* floating constant; nval = numerical float value */
|
||||||
VKINT, /* integer constant; ival = numerical integer value */
|
VKINT, /* integer constant; ival = numerical integer value */
|
||||||
VKSTR, /* string constant; strval = TString address;
|
VKSTR, /* string constant; strval = TString address;
|
||||||
(string is fixed by the lexer) */
|
(string is fixed by the scanner) */
|
||||||
VNONRELOC, /* expression has its value in a fixed register;
|
VNONRELOC, /* expression has its value in a fixed register;
|
||||||
info = result register */
|
info = result register */
|
||||||
VLOCAL, /* local variable; var.ridx = register index;
|
VLOCAL, /* local variable; var.ridx = register index;
|
||||||
var.vidx = relative index in 'actvar.arr' */
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
|
VVARGVAR, /* vararg parameter; var.ridx = register index;
|
||||||
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
|
VGLOBAL, /* global variable;
|
||||||
|
info = relative index in 'actvar.arr' (or -1 for
|
||||||
|
implicit declaration) */
|
||||||
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
|
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
|
||||||
VCONST, /* compile-time <const> variable;
|
VCONST, /* compile-time <const> variable;
|
||||||
info = absolute index in 'actvar.arr' */
|
info = absolute index in 'actvar.arr' */
|
||||||
VINDEXED, /* indexed variable;
|
VINDEXED, /* indexed variable;
|
||||||
ind.t = table register;
|
ind.t = table register;
|
||||||
ind.idx = key's R index */
|
ind.idx = key's R index;
|
||||||
|
ind.ro = true if it represents a read-only global;
|
||||||
|
ind.keystr = if key is a string, index in 'k' of that string;
|
||||||
|
-1 if key is not a string */
|
||||||
|
VVARGIND, /* indexed vararg parameter;
|
||||||
|
ind.* as in VINDEXED */
|
||||||
VINDEXUP, /* indexed upvalue;
|
VINDEXUP, /* indexed upvalue;
|
||||||
ind.t = table upvalue;
|
ind.idx = key's K index;
|
||||||
ind.idx = key's K index */
|
ind.* as in VINDEXED */
|
||||||
VINDEXI, /* indexed variable with constant integer;
|
VINDEXI, /* indexed variable with constant integer;
|
||||||
ind.t = table register;
|
ind.t = table register;
|
||||||
ind.idx = key's value */
|
ind.idx = key's value */
|
||||||
VINDEXSTR, /* indexed variable with literal string;
|
VINDEXSTR, /* indexed variable with literal string;
|
||||||
ind.t = table register;
|
ind.idx = key's K index;
|
||||||
ind.idx = key's K index */
|
ind.* as in VINDEXED */
|
||||||
VJMP, /* expression is a test/comparison;
|
VJMP, /* expression is a test/comparison;
|
||||||
info = pc of corresponding jump instruction */
|
info = pc of corresponding jump instruction */
|
||||||
VRELOC, /* expression can put result in any register;
|
VRELOC, /* expression can put result in any register;
|
||||||
@@ -75,10 +85,12 @@ typedef struct expdesc {
|
|||||||
struct { /* for indexed variables */
|
struct { /* for indexed variables */
|
||||||
short idx; /* index (R or "long" K) */
|
short idx; /* index (R or "long" K) */
|
||||||
lu_byte t; /* table (register or upvalue) */
|
lu_byte t; /* table (register or upvalue) */
|
||||||
|
lu_byte ro; /* true if variable is read-only */
|
||||||
|
int keystr; /* index in 'k' of string key, or -1 if not a string */
|
||||||
} ind;
|
} ind;
|
||||||
struct { /* for local variables */
|
struct { /* for local variables */
|
||||||
lu_byte ridx; /* register holding the variable */
|
lu_byte ridx; /* register holding the variable */
|
||||||
unsigned short vidx; /* compiler index (in 'actvar.arr') */
|
short vidx; /* index in 'actvar.arr' */
|
||||||
} var;
|
} var;
|
||||||
} u;
|
} u;
|
||||||
int t; /* patch list of 'exit when true' */
|
int t; /* patch list of 'exit when true' */
|
||||||
@@ -87,12 +99,22 @@ typedef struct expdesc {
|
|||||||
|
|
||||||
|
|
||||||
/* kinds of variables */
|
/* kinds of variables */
|
||||||
#define VDKREG 0 /* regular */
|
#define VDKREG 0 /* regular local */
|
||||||
#define RDKCONST 1 /* constant */
|
#define RDKCONST 1 /* local constant */
|
||||||
#define RDKTOCLOSE 2 /* to-be-closed */
|
#define RDKVAVAR 2 /* vararg parameter */
|
||||||
#define RDKCTC 3 /* compile-time constant */
|
#define RDKTOCLOSE 3 /* to-be-closed */
|
||||||
|
#define RDKCTC 4 /* local compile-time constant */
|
||||||
|
#define GDKREG 5 /* regular global */
|
||||||
|
#define GDKCONST 6 /* global constant */
|
||||||
|
|
||||||
/* description of an active local variable */
|
/* variables that live in registers */
|
||||||
|
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
||||||
|
|
||||||
|
/* test for global variables */
|
||||||
|
#define varglobal(v) ((v)->vd.kind >= GDKREG)
|
||||||
|
|
||||||
|
|
||||||
|
/* description of an active variable */
|
||||||
typedef union Vardesc {
|
typedef union Vardesc {
|
||||||
struct {
|
struct {
|
||||||
TValuefields; /* constant value (if it is a compile-time constant) */
|
TValuefields; /* constant value (if it is a compile-time constant) */
|
||||||
@@ -111,8 +133,8 @@ typedef struct Labeldesc {
|
|||||||
TString *name; /* label identifier */
|
TString *name; /* label identifier */
|
||||||
int pc; /* position in code */
|
int pc; /* position in code */
|
||||||
int line; /* line where it appeared */
|
int line; /* line where it appeared */
|
||||||
lu_byte nactvar; /* number of active variables in that position */
|
short nactvar; /* number of active variables in that position */
|
||||||
lu_byte close; /* goto that escapes upvalues */
|
lu_byte close; /* true for goto that escapes upvalues */
|
||||||
} Labeldesc;
|
} Labeldesc;
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +168,7 @@ typedef struct FuncState {
|
|||||||
struct FuncState *prev; /* enclosing function */
|
struct FuncState *prev; /* enclosing function */
|
||||||
struct LexState *ls; /* lexical state */
|
struct LexState *ls; /* lexical state */
|
||||||
struct BlockCnt *bl; /* chain of current blocks */
|
struct BlockCnt *bl; /* chain of current blocks */
|
||||||
|
Table *kcache; /* cache for reusing constants */
|
||||||
int pc; /* next position to code (equivalent to 'ncode') */
|
int pc; /* next position to code (equivalent to 'ncode') */
|
||||||
int lasttarget; /* 'label' of last 'jump label' */
|
int lasttarget; /* 'label' of last 'jump label' */
|
||||||
int previousline; /* last line that was saved in 'lineinfo' */
|
int previousline; /* last line that was saved in 'lineinfo' */
|
||||||
@@ -155,7 +178,7 @@ typedef struct FuncState {
|
|||||||
int firstlocal; /* index of first local var (in Dyndata array) */
|
int firstlocal; /* index of first local var (in Dyndata array) */
|
||||||
int firstlabel; /* index of first label (in 'dyd->label->arr') */
|
int firstlabel; /* index of first label (in 'dyd->label->arr') */
|
||||||
short ndebugvars; /* number of elements in 'f->locvars' */
|
short ndebugvars; /* number of elements in 'f->locvars' */
|
||||||
lu_byte nactvar; /* number of active local variables */
|
short nactvar; /* number of active variable declarations */
|
||||||
lu_byte nups; /* number of upvalues */
|
lu_byte nups; /* number of upvalues */
|
||||||
lu_byte freereg; /* first free register */
|
lu_byte freereg; /* first free register */
|
||||||
lu_byte iwthabs; /* instructions issued since last absolute line info */
|
lu_byte iwthabs; /* instructions issued since last absolute line info */
|
||||||
@@ -163,9 +186,12 @@ typedef struct FuncState {
|
|||||||
} FuncState;
|
} FuncState;
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC int luaY_nvarstack (FuncState *fs);
|
LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs);
|
||||||
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l,
|
||||||
Dyndata *dyd, const char *name, int firstchar);
|
const char *what);
|
||||||
|
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Table *anchor,
|
||||||
|
Mbuffer *buff, Dyndata *dyd,
|
||||||
|
const char *name, int firstchar);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,87 +29,58 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** thread state + extra space
|
|
||||||
*/
|
|
||||||
typedef struct LX {
|
|
||||||
lu_byte extra_[LUA_EXTRASPACE];
|
|
||||||
lua_State l;
|
|
||||||
} LX;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Main thread combines a thread state and the global state
|
|
||||||
*/
|
|
||||||
typedef struct LG {
|
|
||||||
LX l;
|
|
||||||
global_State g;
|
|
||||||
} LG;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
|
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A macro to create a "random" seed when a state is created;
|
** these macros allow user-specific actions when a thread is
|
||||||
** the seed is used to randomize string hashes.
|
** created/deleted
|
||||||
*/
|
*/
|
||||||
#if !defined(luai_makeseed)
|
#if !defined(luai_userstateopen)
|
||||||
|
#define luai_userstateopen(L) ((void)L)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#if !defined(luai_userstateclose)
|
||||||
|
#define luai_userstateclose(L) ((void)L)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
#if !defined(luai_userstatethread)
|
||||||
** Compute an initial seed with some level of randomness.
|
#define luai_userstatethread(L,L1) ((void)L)
|
||||||
** Rely on Address Space Layout Randomization (if present) and
|
#endif
|
||||||
** current time.
|
|
||||||
*/
|
|
||||||
#define addbuff(b,p,e) \
|
|
||||||
{ size_t t = cast_sizet(e); \
|
|
||||||
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
|
|
||||||
|
|
||||||
static unsigned int luai_makeseed (lua_State *L) {
|
|
||||||
char buff[3 * sizeof(size_t)];
|
|
||||||
unsigned int h = cast_uint(time(NULL));
|
|
||||||
int p = 0;
|
|
||||||
addbuff(buff, p, L); /* heap variable */
|
|
||||||
addbuff(buff, p, &h); /* local variable */
|
|
||||||
addbuff(buff, p, &lua_newstate); /* public function */
|
|
||||||
lua_assert(p == sizeof(buff));
|
|
||||||
return luaS_hash(buff, p, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if !defined(luai_userstatefree)
|
||||||
|
#define luai_userstatefree(L,L1) ((void)L)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
|
** set GCdebt to a new value keeping the real number of allocated
|
||||||
** invariant (and avoiding underflows in 'totalbytes')
|
** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in
|
||||||
|
** 'GCtotalobjs'.
|
||||||
*/
|
*/
|
||||||
void luaE_setdebt (global_State *g, l_mem debt) {
|
void luaE_setdebt (global_State *g, l_mem debt) {
|
||||||
l_mem tb = gettotalbytes(g);
|
l_mem tb = gettotalbytes(g);
|
||||||
lua_assert(tb > 0);
|
lua_assert(tb > 0);
|
||||||
if (debt < tb - MAX_LMEM)
|
if (debt > MAX_LMEM - tb)
|
||||||
debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
|
debt = MAX_LMEM - tb; /* will make GCtotalbytes == MAX_LMEM */
|
||||||
g->totalbytes = tb - debt;
|
g->GCtotalbytes = tb + debt;
|
||||||
g->GCdebt = debt;
|
g->GCdebt = debt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
|
CallInfo *luaE_extendCI (lua_State *L, int err) {
|
||||||
UNUSED(L); UNUSED(limit);
|
|
||||||
return LUAI_MAXCCALLS; /* warning?? */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CallInfo *luaE_extendCI (lua_State *L) {
|
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
lua_assert(L->ci->next == NULL);
|
ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo);
|
||||||
ci = luaM_new(L, CallInfo);
|
if (l_unlikely(ci == NULL)) { /* allocation failed? */
|
||||||
lua_assert(L->ci->next == NULL);
|
if (err)
|
||||||
L->ci->next = ci;
|
luaM_error(L); /* raise the error */
|
||||||
|
return NULL; /* else only report it */
|
||||||
|
}
|
||||||
|
ci->next = L->ci->next;
|
||||||
ci->previous = L->ci;
|
ci->previous = L->ci;
|
||||||
ci->next = NULL;
|
L->ci->next = ci;
|
||||||
|
if (ci->next)
|
||||||
|
ci->next->previous = ci;
|
||||||
ci->u.l.trap = 0;
|
ci->u.l.trap = 0;
|
||||||
L->nci++;
|
L->nci++;
|
||||||
return ci;
|
return ci;
|
||||||
@@ -119,7 +90,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** free all CallInfo structures not in use by a thread
|
** free all CallInfo structures not in use by a thread
|
||||||
*/
|
*/
|
||||||
void luaE_freeCI (lua_State *L) {
|
static void freeCI (lua_State *L) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
CallInfo *next = ci->next;
|
CallInfo *next = ci->next;
|
||||||
ci->next = NULL;
|
ci->next = NULL;
|
||||||
@@ -166,7 +137,7 @@ void luaE_checkcstack (lua_State *L) {
|
|||||||
if (getCcalls(L) == LUAI_MAXCCALLS)
|
if (getCcalls(L) == LUAI_MAXCCALLS)
|
||||||
luaG_runerror(L, "C stack overflow");
|
luaG_runerror(L, "C stack overflow");
|
||||||
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
||||||
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
|
luaD_errerr(L); /* error while handling stack error */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -177,36 +148,40 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void stack_init (lua_State *L1, lua_State *L) {
|
static void resetCI (lua_State *L) {
|
||||||
int i; CallInfo *ci;
|
CallInfo *ci = L->ci = &L->base_ci;
|
||||||
/* initialize stack array */
|
ci->func.p = L->stack.p;
|
||||||
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
setnilvalue2s(ci->func.p); /* 'function' entry for basic 'ci' */
|
||||||
L1->tbclist = L1->stack;
|
ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */
|
||||||
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
|
||||||
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
|
|
||||||
L1->top = L1->stack;
|
|
||||||
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
|
|
||||||
/* initialize first ci */
|
|
||||||
ci = &L1->base_ci;
|
|
||||||
ci->next = ci->previous = NULL;
|
|
||||||
ci->callstatus = CIST_C;
|
|
||||||
ci->func = L1->top;
|
|
||||||
ci->u.c.k = NULL;
|
ci->u.c.k = NULL;
|
||||||
ci->nresults = 0;
|
ci->callstatus = CIST_C;
|
||||||
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
|
L->status = LUA_OK;
|
||||||
L1->top++;
|
L->errfunc = 0; /* stack unwind can "throw away" the error function */
|
||||||
ci->top = L1->top + LUA_MINSTACK;
|
}
|
||||||
L1->ci = ci;
|
|
||||||
|
|
||||||
|
static void stack_init (lua_State *L1, lua_State *L) {
|
||||||
|
int i;
|
||||||
|
/* initialize stack array */
|
||||||
|
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
||||||
|
L1->tbclist.p = L1->stack.p;
|
||||||
|
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
||||||
|
setnilvalue2s(L1->stack.p + i); /* erase new stack */
|
||||||
|
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
|
||||||
|
/* initialize first ci */
|
||||||
|
resetCI(L1);
|
||||||
|
L1->top.p = L1->stack.p + 1; /* +1 for 'function' entry */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void freestack (lua_State *L) {
|
static void freestack (lua_State *L) {
|
||||||
if (L->stack == NULL)
|
if (L->stack.p == NULL)
|
||||||
return; /* stack not completely built yet */
|
return; /* stack not completely built yet */
|
||||||
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
||||||
luaE_freeCI(L);
|
freeCI(L);
|
||||||
lua_assert(L->nci == 0);
|
lua_assert(L->nci == 0);
|
||||||
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
|
/* free stack */
|
||||||
|
luaM_freearray(L, L->stack.p, cast_sizet(stacksize(L) + EXTRA_STACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -215,13 +190,19 @@ static void freestack (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
static void init_registry (lua_State *L, global_State *g) {
|
static void init_registry (lua_State *L, global_State *g) {
|
||||||
/* create registry */
|
/* create registry */
|
||||||
|
TValue aux;
|
||||||
Table *registry = luaH_new(L);
|
Table *registry = luaH_new(L);
|
||||||
sethvalue(L, &g->l_registry, registry);
|
sethvalue(L, &g->l_registry, registry);
|
||||||
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
|
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
|
||||||
|
/* registry[1] = false */
|
||||||
|
setbfvalue(&aux);
|
||||||
|
luaH_setint(L, registry, 1, &aux);
|
||||||
/* registry[LUA_RIDX_MAINTHREAD] = L */
|
/* registry[LUA_RIDX_MAINTHREAD] = L */
|
||||||
setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L);
|
setthvalue(L, &aux, L);
|
||||||
|
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux);
|
||||||
/* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
|
/* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
|
||||||
sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L));
|
sethvalue(L, &aux, luaH_new(L));
|
||||||
|
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &aux);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -248,7 +229,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
|||||||
*/
|
*/
|
||||||
static void preinit_thread (lua_State *L, global_State *g) {
|
static void preinit_thread (lua_State *L, global_State *g) {
|
||||||
G(L) = g;
|
G(L) = g;
|
||||||
L->stack = NULL;
|
L->stack.p = NULL;
|
||||||
L->ci = NULL;
|
L->ci = NULL;
|
||||||
L->nci = 0;
|
L->nci = 0;
|
||||||
L->twups = L; /* thread has no upvalues */
|
L->twups = L; /* thread has no upvalues */
|
||||||
@@ -263,6 +244,16 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
|||||||
L->status = LUA_OK;
|
L->status = LUA_OK;
|
||||||
L->errfunc = 0;
|
L->errfunc = 0;
|
||||||
L->oldpc = 0;
|
L->oldpc = 0;
|
||||||
|
L->base_ci.previous = L->base_ci.next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lu_mem luaE_threadsize (lua_State *L) {
|
||||||
|
lu_mem sz = cast(lu_mem, sizeof(LX))
|
||||||
|
+ cast_uint(L->nci) * sizeof(CallInfo);
|
||||||
|
if (L->stack.p != NULL)
|
||||||
|
sz += cast_uint(stacksize(L) + EXTRA_STACK) * sizeof(StackValue);
|
||||||
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -271,33 +262,30 @@ static void close_state (lua_State *L) {
|
|||||||
if (!completestate(g)) /* closing a partially built state? */
|
if (!completestate(g)) /* closing a partially built state? */
|
||||||
luaC_freeallobjects(L); /* just collect its objects */
|
luaC_freeallobjects(L); /* just collect its objects */
|
||||||
else { /* closing a fully built state */
|
else { /* closing a fully built state */
|
||||||
L->ci = &L->base_ci; /* unwind CallInfo list */
|
resetCI(L);
|
||||||
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
||||||
|
L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */
|
||||||
luaC_freeallobjects(L); /* collect all objects */
|
luaC_freeallobjects(L); /* collect all objects */
|
||||||
luai_userstateclose(L);
|
luai_userstateclose(L);
|
||||||
}
|
}
|
||||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
|
luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size));
|
||||||
freestack(L);
|
freestack(L);
|
||||||
lua_assert(gettotalbytes(g) == sizeof(LG));
|
lua_assert(gettotalbytes(g) == sizeof(global_State));
|
||||||
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
|
(*g->frealloc)(g->ud, g, sizeof(global_State), 0); /* free main block */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_State *lua_newthread (lua_State *L) {
|
LUA_API lua_State *lua_newthread (lua_State *L) {
|
||||||
global_State *g;
|
global_State *g = G(L);
|
||||||
|
GCObject *o;
|
||||||
lua_State *L1;
|
lua_State *L1;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
g = G(L);
|
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
/* create new thread */
|
/* create new thread */
|
||||||
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
|
o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
|
||||||
L1->marked = luaC_white(g);
|
L1 = gco2th(o);
|
||||||
L1->tt = LUA_VTHREAD;
|
|
||||||
/* link it on list 'allgc' */
|
|
||||||
L1->next = g->allgc;
|
|
||||||
g->allgc = obj2gco(L1);
|
|
||||||
/* anchor it on L stack */
|
/* anchor it on L stack */
|
||||||
setthvalue2s(L, L->top, L1);
|
setthvalue2s(L, L->top.p, L1);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
preinit_thread(L1, g);
|
preinit_thread(L1, g);
|
||||||
L1->hookmask = L->hookmask;
|
L1->hookmask = L->hookmask;
|
||||||
@@ -305,7 +293,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||||||
L1->hook = L->hook;
|
L1->hook = L->hook;
|
||||||
resethookcount(L1);
|
resethookcount(L1);
|
||||||
/* initialize L1 extra space */
|
/* initialize L1 extra space */
|
||||||
memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread),
|
memcpy(lua_getextraspace(L1), lua_getextraspace(mainthread(g)),
|
||||||
LUA_EXTRASPACE);
|
LUA_EXTRASPACE);
|
||||||
luai_userstatethread(L, L1);
|
luai_userstatethread(L, L1);
|
||||||
stack_init(L1, L); /* init stack */
|
stack_init(L1, L); /* init stack */
|
||||||
@@ -316,7 +304,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||||||
|
|
||||||
void luaE_freethread (lua_State *L, lua_State *L1) {
|
void luaE_freethread (lua_State *L, lua_State *L1) {
|
||||||
LX *l = fromstate(L1);
|
LX *l = fromstate(L1);
|
||||||
luaF_closeupval(L1, L1->stack); /* close all upvalues */
|
luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
|
||||||
lua_assert(L1->openupval == NULL);
|
lua_assert(L1->openupval == NULL);
|
||||||
luai_userstatefree(L, L1);
|
luai_userstatefree(L, L1);
|
||||||
freestack(L1);
|
freestack(L1);
|
||||||
@@ -324,42 +312,39 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaE_resetthread (lua_State *L, int status) {
|
TStatus luaE_resetthread (lua_State *L, TStatus status) {
|
||||||
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
|
resetCI(L);
|
||||||
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
|
|
||||||
ci->func = L->stack;
|
|
||||||
ci->callstatus = CIST_C;
|
|
||||||
if (status == LUA_YIELD)
|
if (status == LUA_YIELD)
|
||||||
status = LUA_OK;
|
status = LUA_OK;
|
||||||
L->status = LUA_OK; /* so it can run __close metamethods */
|
|
||||||
status = luaD_closeprotected(L, 1, status);
|
status = luaD_closeprotected(L, 1, status);
|
||||||
if (status != LUA_OK) /* errors? */
|
if (status != LUA_OK) /* errors? */
|
||||||
luaD_seterrorobj(L, status, L->stack + 1);
|
luaD_seterrorobj(L, status, L->stack.p + 1);
|
||||||
else
|
else
|
||||||
L->top = L->stack + 1;
|
L->top.p = L->stack.p + 1;
|
||||||
ci->top = L->top + LUA_MINSTACK;
|
luaD_reallocstack(L, cast_int(L->ci->top.p - L->stack.p), 0);
|
||||||
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_resetthread (lua_State *L) {
|
LUA_API int lua_closethread (lua_State *L, lua_State *from) {
|
||||||
int status;
|
TStatus status;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||||
status = luaE_resetthread(L, L->status);
|
status = luaE_resetthread(L, L->status);
|
||||||
|
if (L == from) /* closing itself? */
|
||||||
|
luaD_throwbaselevel(L, status);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return status;
|
return APIstatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned seed) {
|
||||||
int i;
|
int i;
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
global_State *g;
|
global_State *g = cast(global_State*,
|
||||||
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
|
(*f)(ud, NULL, LUA_TTHREAD, sizeof(global_State)));
|
||||||
if (l == NULL) return NULL;
|
if (g == NULL) return NULL;
|
||||||
L = &l->l.l;
|
L = &g->mainth.l;
|
||||||
g = &l->g;
|
|
||||||
L->tt = LUA_VTHREAD;
|
L->tt = LUA_VTHREAD;
|
||||||
g->currentwhite = bitmask(WHITE0BIT);
|
g->currentwhite = bitmask(WHITE0BIT);
|
||||||
L->marked = luaC_white(g);
|
L->marked = luaC_white(g);
|
||||||
@@ -371,8 +356,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
g->ud = ud;
|
g->ud = ud;
|
||||||
g->warnf = NULL;
|
g->warnf = NULL;
|
||||||
g->ud_warn = NULL;
|
g->ud_warn = NULL;
|
||||||
g->mainthread = L;
|
g->seed = seed;
|
||||||
g->seed = luai_makeseed(L);
|
|
||||||
g->gcstp = GCSTPGC; /* no GC while building state */
|
g->gcstp = GCSTPGC; /* no GC while building state */
|
||||||
g->strt.size = g->strt.nuse = 0;
|
g->strt.size = g->strt.nuse = 0;
|
||||||
g->strt.hash = NULL;
|
g->strt.hash = NULL;
|
||||||
@@ -389,16 +373,17 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
g->gray = g->grayagain = NULL;
|
g->gray = g->grayagain = NULL;
|
||||||
g->weak = g->ephemeron = g->allweak = NULL;
|
g->weak = g->ephemeron = g->allweak = NULL;
|
||||||
g->twups = NULL;
|
g->twups = NULL;
|
||||||
g->totalbytes = sizeof(LG);
|
g->GCtotalbytes = sizeof(global_State);
|
||||||
|
g->GCmarked = 0;
|
||||||
g->GCdebt = 0;
|
g->GCdebt = 0;
|
||||||
g->lastatomic = 0;
|
|
||||||
setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */
|
setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */
|
||||||
setgcparam(g->gcpause, LUAI_GCPAUSE);
|
setgcparam(g, PAUSE, LUAI_GCPAUSE);
|
||||||
setgcparam(g->gcstepmul, LUAI_GCMUL);
|
setgcparam(g, STEPMUL, LUAI_GCMUL);
|
||||||
g->gcstepsize = LUAI_GCSTEPSIZE;
|
setgcparam(g, STEPSIZE, LUAI_GCSTEPSIZE);
|
||||||
setgcparam(g->genmajormul, LUAI_GENMAJORMUL);
|
setgcparam(g, MINORMUL, LUAI_GENMINORMUL);
|
||||||
g->genminormul = LUAI_GENMINORMUL;
|
setgcparam(g, MINORMAJOR, LUAI_MINORMAJOR);
|
||||||
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
|
setgcparam(g, MAJORMINOR, LUAI_MAJORMINOR);
|
||||||
|
for (i=0; i < LUA_NUMTYPES; i++) g->mt[i] = NULL;
|
||||||
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
|
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
|
||||||
/* memory allocation error: free partial state */
|
/* memory allocation error: free partial state */
|
||||||
close_state(L);
|
close_state(L);
|
||||||
@@ -410,7 +395,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
|
|
||||||
LUA_API void lua_close (lua_State *L) {
|
LUA_API void lua_close (lua_State *L) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
L = G(L)->mainthread; /* only the main thread can be closed */
|
L = mainthread(G(L)); /* only the main thread can be closed */
|
||||||
close_state(L);
|
close_state(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,9 +411,9 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
|
|||||||
** Generate a warning from an error message
|
** Generate a warning from an error message
|
||||||
*/
|
*/
|
||||||
void luaE_warnerror (lua_State *L, const char *where) {
|
void luaE_warnerror (lua_State *L, const char *where) {
|
||||||
TValue *errobj = s2v(L->top - 1); /* error object */
|
TValue *errobj = s2v(L->top.p - 1); /* error object */
|
||||||
const char *msg = (ttisstring(errobj))
|
const char *msg = (ttisstring(errobj))
|
||||||
? svalue(errobj)
|
? getstr(tsvalue(errobj))
|
||||||
: "error object is not a string";
|
: "error object is not a string";
|
||||||
/* produce warning "error in %s (%s)" (where, msg) */
|
/* produce warning "error in %s (%s)" (where, msg) */
|
||||||
luaE_warning(L, "error in ", 1);
|
luaE_warning(L, "error in ", 1);
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Some header files included here need this definition */
|
||||||
|
typedef struct CallInfo CallInfo;
|
||||||
|
|
||||||
|
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
@@ -80,7 +85,7 @@
|
|||||||
** they must be visited again at the end of the cycle), but they are
|
** they must be visited again at the end of the cycle), but they are
|
||||||
** marked black because assignments to them must activate barriers (to
|
** marked black because assignments to them must activate barriers (to
|
||||||
** move them back to TOUCHED1).
|
** move them back to TOUCHED1).
|
||||||
** - Open upvales are kept gray to avoid barriers, but they stay out
|
** - Open upvalues are kept gray to avoid barriers, but they stay out
|
||||||
** of gray lists. (They don't even have a 'gclist' field.)
|
** of gray lists. (They don't even have a 'gclist' field.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -137,20 +142,32 @@ struct lua_longjmp; /* defined in ldo.c */
|
|||||||
#define EXTRA_STACK 5
|
#define EXTRA_STACK 5
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Size of cache for strings in the API. 'N' is the number of
|
||||||
|
** sets (better be a prime) and "M" is the size of each set.
|
||||||
|
** (M == 1 makes a direct cache.)
|
||||||
|
*/
|
||||||
|
#if !defined(STRCACHE_N)
|
||||||
|
#define STRCACHE_N 53
|
||||||
|
#define STRCACHE_M 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
||||||
|
|
||||||
#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
|
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
|
||||||
|
|
||||||
|
|
||||||
/* kinds of Garbage Collection */
|
/* kinds of Garbage Collection */
|
||||||
#define KGC_INC 0 /* incremental gc */
|
#define KGC_INC 0 /* incremental gc */
|
||||||
#define KGC_GEN 1 /* generational gc */
|
#define KGC_GENMINOR 1 /* generational gc in minor (regular) mode */
|
||||||
|
#define KGC_GENMAJOR 2 /* generational in major mode */
|
||||||
|
|
||||||
|
|
||||||
typedef struct stringtable {
|
typedef struct stringtable {
|
||||||
TString **hash;
|
TString **hash; /* array of buckets (linked lists of strings) */
|
||||||
int nuse; /* number of elements */
|
int nuse; /* number of elements */
|
||||||
int size;
|
int size; /* number of buckets */
|
||||||
} stringtable;
|
} stringtable;
|
||||||
|
|
||||||
|
|
||||||
@@ -166,17 +183,15 @@ typedef struct stringtable {
|
|||||||
** yield (from the yield until the next resume);
|
** yield (from the yield until the next resume);
|
||||||
** - field 'nres' is used only while closing tbc variables when
|
** - field 'nres' is used only while closing tbc variables when
|
||||||
** returning from a function;
|
** returning from a function;
|
||||||
** - field 'transferinfo' is used only during call/returnhooks,
|
|
||||||
** before the function starts or after it ends.
|
|
||||||
*/
|
*/
|
||||||
typedef struct CallInfo {
|
struct CallInfo {
|
||||||
StkId func; /* function index in the stack */
|
StkIdRel func; /* function index in the stack */
|
||||||
StkId top; /* top for this function */
|
StkIdRel top; /* top for this function */
|
||||||
struct CallInfo *previous, *next; /* dynamic call link */
|
struct CallInfo *previous, *next; /* dynamic call link */
|
||||||
union {
|
union {
|
||||||
struct { /* only for Lua functions */
|
struct { /* only for Lua functions */
|
||||||
const Instruction *savedpc;
|
const Instruction *savedpc;
|
||||||
volatile l_signalT trap;
|
volatile l_signalT trap; /* function is tracing lines/counts */
|
||||||
int nextraargs; /* # of extra arguments in vararg functions */
|
int nextraargs; /* # of extra arguments in vararg functions */
|
||||||
} l;
|
} l;
|
||||||
struct { /* only for C functions */
|
struct { /* only for C functions */
|
||||||
@@ -189,35 +204,54 @@ typedef struct CallInfo {
|
|||||||
int funcidx; /* called-function index */
|
int funcidx; /* called-function index */
|
||||||
int nyield; /* number of values yielded */
|
int nyield; /* number of values yielded */
|
||||||
int nres; /* number of values returned */
|
int nres; /* number of values returned */
|
||||||
struct { /* info about transferred values (for call/return hooks) */
|
|
||||||
unsigned short ftransfer; /* offset of first value transferred */
|
|
||||||
unsigned short ntransfer; /* number of values transferred */
|
|
||||||
} transferinfo;
|
|
||||||
} u2;
|
} u2;
|
||||||
short nresults; /* expected number of results from this function */
|
l_uint32 callstatus;
|
||||||
unsigned short callstatus;
|
};
|
||||||
} CallInfo;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Maximum expected number of results from a function
|
||||||
|
** (must fit in CIST_NRESULTS).
|
||||||
|
*/
|
||||||
|
#define MAXRESULTS 250
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Bits in CallInfo status
|
** Bits in CallInfo status
|
||||||
*/
|
*/
|
||||||
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
|
/* bits 0-7 are the expected number of results from this function + 1 */
|
||||||
#define CIST_C (1<<1) /* call is running a C function */
|
#define CIST_NRESULTS 0xffu
|
||||||
#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
|
|
||||||
#define CIST_HOOKED (1<<3) /* call is running a debug hook */
|
|
||||||
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
|
|
||||||
#define CIST_TAIL (1<<5) /* call was tail called */
|
|
||||||
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
|
||||||
#define CIST_FIN (1<<7) /* function "called" a finalizer */
|
|
||||||
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
|
|
||||||
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
|
|
||||||
/* Bits 10-12 are used for CIST_RECST (see below) */
|
|
||||||
#define CIST_RECST 10
|
|
||||||
#if defined(LUA_COMPAT_LT_LE)
|
|
||||||
#define CIST_LEQ (1<<13) /* using __lt for __le */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* bits 8-11 count call metamethods (and their extra arguments) */
|
||||||
|
#define CIST_CCMT 8 /* the offset, not the mask */
|
||||||
|
#define MAX_CCMT (0xfu << CIST_CCMT)
|
||||||
|
|
||||||
|
/* Bits 12-14 are used for CIST_RECST (see below) */
|
||||||
|
#define CIST_RECST 12 /* the offset, not the mask */
|
||||||
|
|
||||||
|
/* call is running a C function (still in first 16 bits) */
|
||||||
|
#define CIST_C (1u << (CIST_RECST + 3))
|
||||||
|
/* call is on a fresh "luaV_execute" frame */
|
||||||
|
#define CIST_FRESH (cast(l_uint32, CIST_C) << 1)
|
||||||
|
/* function is closing tbc variables */
|
||||||
|
#define CIST_CLSRET (CIST_FRESH << 1)
|
||||||
|
/* function has tbc variables to close */
|
||||||
|
#define CIST_TBC (CIST_CLSRET << 1)
|
||||||
|
/* original value of 'allowhook' */
|
||||||
|
#define CIST_OAH (CIST_TBC << 1)
|
||||||
|
/* call is running a debug hook */
|
||||||
|
#define CIST_HOOKED (CIST_OAH << 1)
|
||||||
|
/* doing a yieldable protected call */
|
||||||
|
#define CIST_YPCALL (CIST_HOOKED << 1)
|
||||||
|
/* call was tail called */
|
||||||
|
#define CIST_TAIL (CIST_YPCALL << 1)
|
||||||
|
/* last hook called yielded */
|
||||||
|
#define CIST_HOOKYIELD (CIST_TAIL << 1)
|
||||||
|
/* function "called" a finalizer */
|
||||||
|
#define CIST_FIN (CIST_HOOKYIELD << 1)
|
||||||
|
|
||||||
|
|
||||||
|
#define get_nresults(cs) (cast_int((cs) & CIST_NRESULTS) - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Field CIST_RECST stores the "recover status", used to keep the error
|
** Field CIST_RECST stores the "recover status", used to keep the error
|
||||||
@@ -228,8 +262,8 @@ typedef struct CallInfo {
|
|||||||
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
|
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
|
||||||
#define setcistrecst(ci,st) \
|
#define setcistrecst(ci,st) \
|
||||||
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
|
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
|
||||||
((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
|
((ci)->callstatus = ((ci)->callstatus & ~(7u << CIST_RECST)) \
|
||||||
| ((st) << CIST_RECST)))
|
| (cast(l_uint32, st) << CIST_RECST)))
|
||||||
|
|
||||||
|
|
||||||
/* active function is a Lua function */
|
/* active function is a Lua function */
|
||||||
@@ -238,9 +272,53 @@ typedef struct CallInfo {
|
|||||||
/* call is running Lua code (not a hook) */
|
/* call is running Lua code (not a hook) */
|
||||||
#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
|
#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
|
||||||
|
|
||||||
/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
|
|
||||||
#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
|
#define setoah(ci,v) \
|
||||||
#define getoah(st) ((st) & CIST_OAH)
|
((ci)->callstatus = ((v) ? (ci)->callstatus | CIST_OAH \
|
||||||
|
: (ci)->callstatus & ~CIST_OAH))
|
||||||
|
#define getoah(ci) (((ci)->callstatus & CIST_OAH) ? 1 : 0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 'per thread' state
|
||||||
|
*/
|
||||||
|
struct lua_State {
|
||||||
|
CommonHeader;
|
||||||
|
lu_byte allowhook;
|
||||||
|
TStatus status;
|
||||||
|
StkIdRel top; /* first free slot in the stack */
|
||||||
|
struct global_State *l_G;
|
||||||
|
CallInfo *ci; /* call info for current function */
|
||||||
|
StkIdRel stack_last; /* end of stack (last element + 1) */
|
||||||
|
StkIdRel stack; /* stack base */
|
||||||
|
UpVal *openupval; /* list of open upvalues in this stack */
|
||||||
|
StkIdRel tbclist; /* list of to-be-closed variables */
|
||||||
|
GCObject *gclist;
|
||||||
|
struct lua_State *twups; /* list of threads with open upvalues */
|
||||||
|
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||||
|
CallInfo base_ci; /* CallInfo for first level (C host) */
|
||||||
|
volatile lua_Hook hook;
|
||||||
|
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||||
|
l_uint32 nCcalls; /* number of nested non-yieldable or C calls */
|
||||||
|
int oldpc; /* last pc traced */
|
||||||
|
int nci; /* number of items in 'ci' list */
|
||||||
|
int basehookcount;
|
||||||
|
int hookcount;
|
||||||
|
volatile l_signalT hookmask;
|
||||||
|
struct { /* info about transferred values (for call/return hooks) */
|
||||||
|
int ftransfer; /* offset of first value transferred */
|
||||||
|
int ntransfer; /* number of values transferred */
|
||||||
|
} transferinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** thread state + extra space
|
||||||
|
*/
|
||||||
|
typedef struct LX {
|
||||||
|
lu_byte extra_[LUA_EXTRASPACE];
|
||||||
|
lua_State l;
|
||||||
|
} LX;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -249,25 +327,21 @@ typedef struct CallInfo {
|
|||||||
typedef struct global_State {
|
typedef struct global_State {
|
||||||
lua_Alloc frealloc; /* function to reallocate memory */
|
lua_Alloc frealloc; /* function to reallocate memory */
|
||||||
void *ud; /* auxiliary data to 'frealloc' */
|
void *ud; /* auxiliary data to 'frealloc' */
|
||||||
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
|
l_mem GCtotalbytes; /* number of bytes currently allocated + debt */
|
||||||
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
|
l_mem GCdebt; /* bytes counted but not yet allocated */
|
||||||
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
|
l_mem GCmarked; /* number of objects marked in a GC cycle */
|
||||||
lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */
|
l_mem GCmajorminor; /* auxiliary counter to control major-minor shifts */
|
||||||
stringtable strt; /* hash table for strings */
|
stringtable strt; /* hash table for strings */
|
||||||
TValue l_registry;
|
TValue l_registry;
|
||||||
TValue nilvalue; /* a nil value */
|
TValue nilvalue; /* a nil value */
|
||||||
unsigned int seed; /* randomized seed for hashes */
|
unsigned int seed; /* randomized seed for hashes */
|
||||||
|
lu_byte gcparams[LUA_GCPN];
|
||||||
lu_byte currentwhite;
|
lu_byte currentwhite;
|
||||||
lu_byte gcstate; /* state of garbage collector */
|
lu_byte gcstate; /* state of garbage collector */
|
||||||
lu_byte gckind; /* kind of GC running */
|
lu_byte gckind; /* kind of GC running */
|
||||||
lu_byte gcstopem; /* stops emergency collections */
|
lu_byte gcstopem; /* stops emergency collections */
|
||||||
lu_byte genminormul; /* control for minor generational collections */
|
|
||||||
lu_byte genmajormul; /* control for major generational collections */
|
|
||||||
lu_byte gcstp; /* control whether GC is running */
|
lu_byte gcstp; /* control whether GC is running */
|
||||||
lu_byte gcemergency; /* true if this is an emergency collection */
|
lu_byte gcemergency; /* true if this is an emergency collection */
|
||||||
lu_byte gcpause; /* size of pause between successive GCs */
|
|
||||||
lu_byte gcstepmul; /* GC "speed" */
|
|
||||||
lu_byte gcstepsize; /* (log2 of) GC granularity */
|
|
||||||
GCObject *allgc; /* list of all collectable objects */
|
GCObject *allgc; /* list of all collectable objects */
|
||||||
GCObject **sweepgc; /* current position of sweep in list */
|
GCObject **sweepgc; /* current position of sweep in list */
|
||||||
GCObject *finobj; /* list of collectable objects with finalizers */
|
GCObject *finobj; /* list of collectable objects with finalizers */
|
||||||
@@ -288,46 +362,18 @@ typedef struct global_State {
|
|||||||
GCObject *finobjrold; /* list of really old objects with finalizers */
|
GCObject *finobjrold; /* list of really old objects with finalizers */
|
||||||
struct lua_State *twups; /* list of threads with open upvalues */
|
struct lua_State *twups; /* list of threads with open upvalues */
|
||||||
lua_CFunction panic; /* to be called in unprotected errors */
|
lua_CFunction panic; /* to be called in unprotected errors */
|
||||||
struct lua_State *mainthread;
|
|
||||||
TString *memerrmsg; /* message for memory-allocation errors */
|
TString *memerrmsg; /* message for memory-allocation errors */
|
||||||
TString *tmname[TM_N]; /* array with tag-method names */
|
TString *tmname[TM_N]; /* array with tag-method names */
|
||||||
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
|
struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
|
||||||
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
||||||
lua_WarnFunction warnf; /* warning function */
|
lua_WarnFunction warnf; /* warning function */
|
||||||
void *ud_warn; /* auxiliary data to 'warnf' */
|
void *ud_warn; /* auxiliary data to 'warnf' */
|
||||||
|
LX mainth; /* main thread of this state */
|
||||||
} global_State;
|
} global_State;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** 'per thread' state
|
|
||||||
*/
|
|
||||||
struct lua_State {
|
|
||||||
CommonHeader;
|
|
||||||
lu_byte status;
|
|
||||||
lu_byte allowhook;
|
|
||||||
unsigned short nci; /* number of items in 'ci' list */
|
|
||||||
StkId top; /* first free slot in the stack */
|
|
||||||
global_State *l_G;
|
|
||||||
CallInfo *ci; /* call info for current function */
|
|
||||||
StkId stack_last; /* end of stack (last element + 1) */
|
|
||||||
StkId stack; /* stack base */
|
|
||||||
UpVal *openupval; /* list of open upvalues in this stack */
|
|
||||||
StkId tbclist; /* list of to-be-closed variables */
|
|
||||||
GCObject *gclist;
|
|
||||||
struct lua_State *twups; /* list of threads with open upvalues */
|
|
||||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
|
||||||
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
|
||||||
volatile lua_Hook hook;
|
|
||||||
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
|
||||||
l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
|
|
||||||
int oldpc; /* last pc traced */
|
|
||||||
int basehookcount;
|
|
||||||
int hookcount;
|
|
||||||
volatile l_signalT hookmask;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define G(L) (L->l_G)
|
#define G(L) (L->l_G)
|
||||||
|
#define mainthread(G) (&(G)->mainth.l)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** 'g->nilvalue' being a nil value flags that the state was completely
|
** 'g->nilvalue' being a nil value flags that the state was completely
|
||||||
@@ -380,24 +426,25 @@ union GCUnion {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** macro to convert a Lua object into a GCObject
|
** macro to convert a Lua object into a GCObject
|
||||||
** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.)
|
|
||||||
*/
|
*/
|
||||||
#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
|
#define obj2gco(v) \
|
||||||
|
check_exp(novariant((v)->tt) >= LUA_TSTRING, &(cast_u(v)->gc))
|
||||||
|
|
||||||
|
|
||||||
/* actual number of total bytes allocated */
|
/* actual number of total memory allocated */
|
||||||
#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
|
#define gettotalbytes(g) ((g)->GCtotalbytes - (g)->GCdebt)
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
||||||
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
||||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
LUAI_FUNC lu_mem luaE_threadsize (lua_State *L);
|
||||||
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L, int err);
|
||||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
||||||
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
||||||
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
||||||
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
||||||
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
|
LUAI_FUNC TStatus luaE_resetthread (lua_State *L, TStatus status);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,22 +25,32 @@
|
|||||||
/*
|
/*
|
||||||
** Maximum size for string table.
|
** Maximum size for string table.
|
||||||
*/
|
*/
|
||||||
#define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*))
|
#define MAXSTRTB cast_int(luaM_limitN(INT_MAX, TString*))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Initial size for the string table (must be power of 2).
|
||||||
|
** The Lua core alone registers ~50 strings (reserved words +
|
||||||
|
** metaevent keys + a few others). Libraries would typically add
|
||||||
|
** a few dozens more.
|
||||||
|
*/
|
||||||
|
#if !defined(MINSTRTABSIZE)
|
||||||
|
#define MINSTRTABSIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** equality for long strings
|
** generic equality for strings
|
||||||
*/
|
*/
|
||||||
int luaS_eqlngstr (TString *a, TString *b) {
|
int luaS_eqstr (TString *a, TString *b) {
|
||||||
size_t len = a->u.lnglen;
|
size_t len1, len2;
|
||||||
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
|
const char *s1 = getlstr(a, len1);
|
||||||
return (a == b) || /* same instance or... */
|
const char *s2 = getlstr(b, len2);
|
||||||
((len == b->u.lnglen) && /* equal length and ... */
|
return ((len1 == len2) && /* equal length and ... */
|
||||||
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
|
(memcmp(s1, s2, len1) == 0)); /* equal contents */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
static unsigned luaS_hash (const char *str, size_t l, unsigned seed) {
|
||||||
unsigned int h = seed ^ cast_uint(l);
|
unsigned int h = seed ^ cast_uint(l);
|
||||||
for (; l > 0; l--)
|
for (; l > 0; l--)
|
||||||
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
||||||
@@ -48,11 +58,11 @@ unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int luaS_hashlongstr (TString *ts) {
|
unsigned luaS_hashlongstr (TString *ts) {
|
||||||
lua_assert(ts->tt == LUA_VLNGSTR);
|
lua_assert(ts->tt == LUA_VLNGSTR);
|
||||||
if (ts->extra == 0) { /* no hash? */
|
if (ts->extra == 0) { /* no hash? */
|
||||||
size_t len = ts->u.lnglen;
|
size_t len = ts->u.lnglen;
|
||||||
ts->hash = luaS_hash(getstr(ts), len, ts->hash);
|
ts->hash = luaS_hash(getlngstr(ts), len, ts->hash);
|
||||||
ts->extra = 1; /* now it has its hash */
|
ts->extra = 1; /* now it has its hash */
|
||||||
}
|
}
|
||||||
return ts->hash;
|
return ts->hash;
|
||||||
@@ -136,27 +146,43 @@ void luaS_init (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t luaS_sizelngstr (size_t len, int kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case LSTRREG: /* regular long string */
|
||||||
|
/* don't need 'falloc'/'ud', but need space for content */
|
||||||
|
return offsetof(TString, falloc) + (len + 1) * sizeof(char);
|
||||||
|
case LSTRFIX: /* fixed external long string */
|
||||||
|
/* don't need 'falloc'/'ud' */
|
||||||
|
return offsetof(TString, falloc);
|
||||||
|
default: /* external long string with deallocation */
|
||||||
|
lua_assert(kind == LSTRMEM);
|
||||||
|
return sizeof(TString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** creates a new string object
|
** creates a new string object
|
||||||
*/
|
*/
|
||||||
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
|
static TString *createstrobj (lua_State *L, size_t totalsize, lu_byte tag,
|
||||||
|
unsigned h) {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
GCObject *o;
|
GCObject *o;
|
||||||
size_t totalsize; /* total size of TString object */
|
|
||||||
totalsize = sizelstring(l);
|
|
||||||
o = luaC_newobj(L, tag, totalsize);
|
o = luaC_newobj(L, tag, totalsize);
|
||||||
ts = gco2ts(o);
|
ts = gco2ts(o);
|
||||||
ts->hash = h;
|
ts->hash = h;
|
||||||
ts->extra = 0;
|
ts->extra = 0;
|
||||||
getstr(ts)[l] = '\0'; /* ending 0 */
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
|
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
|
||||||
TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed);
|
size_t totalsize = luaS_sizelngstr(l, LSTRREG);
|
||||||
|
TString *ts = createstrobj(L, totalsize, LUA_VLNGSTR, G(L)->seed);
|
||||||
ts->u.lnglen = l;
|
ts->u.lnglen = l;
|
||||||
|
ts->shrlen = LSTRREG; /* signals that it is a regular long string */
|
||||||
|
ts->contents = cast_charp(ts) + offsetof(TString, falloc);
|
||||||
|
ts->contents[l] = '\0'; /* ending 0 */
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +198,9 @@ void luaS_remove (lua_State *L, TString *ts) {
|
|||||||
|
|
||||||
|
|
||||||
static void growstrtab (lua_State *L, stringtable *tb) {
|
static void growstrtab (lua_State *L, stringtable *tb) {
|
||||||
if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */
|
if (l_unlikely(tb->nuse == INT_MAX)) { /* too many strings? */
|
||||||
luaC_fullgc(L, 1); /* try to free some... */
|
luaC_fullgc(L, 1); /* try to free some... */
|
||||||
if (tb->nuse == MAX_INT) /* still too many? */
|
if (tb->nuse == INT_MAX) /* still too many? */
|
||||||
luaM_error(L); /* cannot even create a message... */
|
luaM_error(L); /* cannot even create a message... */
|
||||||
}
|
}
|
||||||
if (tb->size <= MAXSTRTB / 2) /* can grow string table? */
|
if (tb->size <= MAXSTRTB / 2) /* can grow string table? */
|
||||||
@@ -193,7 +219,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
|||||||
TString **list = &tb->hash[lmod(h, tb->size)];
|
TString **list = &tb->hash[lmod(h, tb->size)];
|
||||||
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
||||||
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
||||||
if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
|
if (l == cast_uint(ts->shrlen) &&
|
||||||
|
(memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) {
|
||||||
/* found! */
|
/* found! */
|
||||||
if (isdead(g, ts)) /* dead (but not collected yet)? */
|
if (isdead(g, ts)) /* dead (but not collected yet)? */
|
||||||
changewhite(ts); /* resurrect it */
|
changewhite(ts); /* resurrect it */
|
||||||
@@ -205,9 +232,10 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
|||||||
growstrtab(L, tb);
|
growstrtab(L, tb);
|
||||||
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
|
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
|
||||||
}
|
}
|
||||||
ts = createstrobj(L, l, LUA_VSHRSTR, h);
|
ts = createstrobj(L, sizestrshr(l), LUA_VSHRSTR, h);
|
||||||
memcpy(getstr(ts), str, l * sizeof(char));
|
ts->shrlen = cast(ls_byte, l);
|
||||||
ts->shrlen = cast_byte(l);
|
getshrstr(ts)[l] = '\0'; /* ending 0 */
|
||||||
|
memcpy(getshrstr(ts), str, l * sizeof(char));
|
||||||
ts->u.hnext = *list;
|
ts->u.hnext = *list;
|
||||||
*list = ts;
|
*list = ts;
|
||||||
tb->nuse++;
|
tb->nuse++;
|
||||||
@@ -223,10 +251,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
|||||||
return internshrstr(L, str, l);
|
return internshrstr(L, str, l);
|
||||||
else {
|
else {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
|
if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString))))
|
||||||
luaM_toobig(L);
|
luaM_toobig(L);
|
||||||
ts = luaS_createlngstrobj(L, l);
|
ts = luaS_createlngstrobj(L, l);
|
||||||
memcpy(getstr(ts), str, l * sizeof(char));
|
memcpy(getlngstr(ts), str, l * sizeof(char));
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +283,7 @@ TString *luaS_new (lua_State *L, const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
|
Udata *luaS_newudata (lua_State *L, size_t s, unsigned short nuvalue) {
|
||||||
Udata *u;
|
Udata *u;
|
||||||
int i;
|
int i;
|
||||||
GCObject *o;
|
GCObject *o;
|
||||||
@@ -271,3 +299,55 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct NewExt {
|
||||||
|
ls_byte kind;
|
||||||
|
const char *s;
|
||||||
|
size_t len;
|
||||||
|
TString *ts; /* output */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void f_newext (lua_State *L, void *ud) {
|
||||||
|
struct NewExt *ne = cast(struct NewExt *, ud);
|
||||||
|
size_t size = luaS_sizelngstr(0, ne->kind);
|
||||||
|
ne->ts = createstrobj(L, size, LUA_VLNGSTR, G(L)->seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TString *luaS_newextlstr (lua_State *L,
|
||||||
|
const char *s, size_t len, lua_Alloc falloc, void *ud) {
|
||||||
|
struct NewExt ne;
|
||||||
|
if (!falloc) {
|
||||||
|
ne.kind = LSTRFIX;
|
||||||
|
f_newext(L, &ne); /* just create header */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ne.kind = LSTRMEM;
|
||||||
|
if (luaD_rawrunprotected(L, f_newext, &ne) != LUA_OK) { /* mem. error? */
|
||||||
|
(*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */
|
||||||
|
luaM_error(L); /* re-raise memory error */
|
||||||
|
}
|
||||||
|
ne.ts->falloc = falloc;
|
||||||
|
ne.ts->ud = ud;
|
||||||
|
}
|
||||||
|
ne.ts->shrlen = ne.kind;
|
||||||
|
ne.ts->u.lnglen = len;
|
||||||
|
ne.ts->contents = cast_charp(s);
|
||||||
|
return ne.ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Normalize an external string: If it is short, internalize it.
|
||||||
|
*/
|
||||||
|
TString *luaS_normstr (lua_State *L, TString *ts) {
|
||||||
|
size_t len = ts->u.lnglen;
|
||||||
|
if (len > LUAI_MAXSHORTLEN)
|
||||||
|
return ts; /* long string; keep the original */
|
||||||
|
else {
|
||||||
|
const char *str = getlngstr(ts);
|
||||||
|
return internshrstr(L, str, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,23 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Size of a TString: Size of the header plus space for the string
|
** Maximum length for short strings, that is, strings that are
|
||||||
|
** internalized. (Cannot be smaller than reserved words or tags for
|
||||||
|
** metamethods, as these strings must be internalized;
|
||||||
|
** #("function") = 8, #("__newindex") = 10.)
|
||||||
|
*/
|
||||||
|
#if !defined(LUAI_MAXSHORTLEN)
|
||||||
|
#define LUAI_MAXSHORTLEN 40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Size of a short TString: Size of the header plus space for the string
|
||||||
** itself (including final '\0').
|
** itself (including final '\0').
|
||||||
*/
|
*/
|
||||||
#define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char))
|
#define sizestrshr(l) \
|
||||||
|
(offsetof(TString, contents) + ((l) + 1) * sizeof(char))
|
||||||
|
|
||||||
|
|
||||||
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
|
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
|
||||||
(sizeof(s)/sizeof(char))-1))
|
(sizeof(s)/sizeof(char))-1))
|
||||||
@@ -32,7 +45,7 @@
|
|||||||
/*
|
/*
|
||||||
** test whether a string is a reserved word
|
** test whether a string is a reserved word
|
||||||
*/
|
*/
|
||||||
#define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0)
|
#define isreserved(s) (strisshr(s) && (s)->extra > 0)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -41,17 +54,20 @@
|
|||||||
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
|
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
|
LUAI_FUNC unsigned luaS_hashlongstr (TString *ts);
|
||||||
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
|
LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
|
||||||
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
|
|
||||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
||||||
LUAI_FUNC void luaS_clearcache (global_State *g);
|
LUAI_FUNC void luaS_clearcache (global_State *g);
|
||||||
LUAI_FUNC void luaS_init (lua_State *L);
|
LUAI_FUNC void luaS_init (lua_State *L);
|
||||||
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
|
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
|
||||||
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue);
|
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s,
|
||||||
|
unsigned short nuvalue);
|
||||||
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
||||||
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
|
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
|
||||||
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
||||||
|
LUAI_FUNC TString *luaS_newextlstr (lua_State *L,
|
||||||
|
const char *s, size_t len, lua_Alloc falloc, void *ud);
|
||||||
|
LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind);
|
||||||
|
LUAI_FUNC TString *luaS_normstr (lua_State *L, TString *ts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -36,22 +37,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* macro to 'unsign' a character */
|
|
||||||
#define uchar(c) ((unsigned char)(c))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Some sizes are better limited to fit in 'int', but must also fit in
|
|
||||||
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
|
|
||||||
*/
|
|
||||||
#define MAX_SIZET ((size_t)(~(size_t)0))
|
|
||||||
|
|
||||||
#define MAXSIZE \
|
|
||||||
(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int str_len (lua_State *L) {
|
static int str_len (lua_State *L) {
|
||||||
size_t l;
|
size_t l;
|
||||||
luaL_checklstring(L, 1, &l);
|
luaL_checklstring(L, 1, &l);
|
||||||
@@ -128,7 +113,7 @@ static int str_lower (lua_State *L) {
|
|||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
char *p = luaL_buffinitsize(L, &b, l);
|
char *p = luaL_buffinitsize(L, &b, l);
|
||||||
for (i=0; i<l; i++)
|
for (i=0; i<l; i++)
|
||||||
p[i] = tolower(uchar(s[i]));
|
p[i] = cast_char(tolower(cast_uchar(s[i])));
|
||||||
luaL_pushresultsize(&b, l);
|
luaL_pushresultsize(&b, l);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -141,33 +126,37 @@ static int str_upper (lua_State *L) {
|
|||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
char *p = luaL_buffinitsize(L, &b, l);
|
char *p = luaL_buffinitsize(L, &b, l);
|
||||||
for (i=0; i<l; i++)
|
for (i=0; i<l; i++)
|
||||||
p[i] = toupper(uchar(s[i]));
|
p[i] = cast_char(toupper(cast_uchar(s[i])));
|
||||||
luaL_pushresultsize(&b, l);
|
luaL_pushresultsize(&b, l);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MAX_SIZE is limited both by size_t and lua_Integer.
|
||||||
|
** When x <= MAX_SIZE, x can be safely cast to size_t or lua_Integer.
|
||||||
|
*/
|
||||||
static int str_rep (lua_State *L) {
|
static int str_rep (lua_State *L) {
|
||||||
size_t l, lsep;
|
size_t len, lsep;
|
||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Integer n = luaL_checkinteger(L, 2);
|
lua_Integer n = luaL_checkinteger(L, 2);
|
||||||
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
||||||
if (n <= 0)
|
if (n <= 0 || (len | lsep) == 0)
|
||||||
lua_pushliteral(L, "");
|
lua_pushliteral(L, ""); /* no repetitions or both strings empty */
|
||||||
else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n))
|
else if (l_unlikely(len > MAX_SIZE - lsep ||
|
||||||
|
cast_st2S(len + lsep) > cast_st2S(MAX_SIZE) / n))
|
||||||
return luaL_error(L, "resulting string too large");
|
return luaL_error(L, "resulting string too large");
|
||||||
else {
|
else {
|
||||||
size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
|
size_t totallen = (cast_sizet(n) * (len + lsep)) - lsep;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
char *p = luaL_buffinitsize(L, &b, totallen);
|
char *p = luaL_buffinitsize(L, &b, totallen);
|
||||||
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
||||||
memcpy(p, s, l * sizeof(char)); p += l;
|
memcpy(p, s, len * sizeof(char)); p += len;
|
||||||
if (lsep > 0) { /* empty 'memcpy' is not that cheap */
|
if (lsep > 0) { /* empty 'memcpy' is not that cheap */
|
||||||
memcpy(p, sep, lsep * sizeof(char));
|
memcpy(p, sep, lsep * sizeof(char)); p += lsep;
|
||||||
p += lsep;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
|
memcpy(p, s, len * sizeof(char)); /* last copy without separator */
|
||||||
luaL_pushresultsize(&b, totallen);
|
luaL_pushresultsize(&b, totallen);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -187,7 +176,7 @@ static int str_byte (lua_State *L) {
|
|||||||
n = (int)(pose - posi) + 1;
|
n = (int)(pose - posi) + 1;
|
||||||
luaL_checkstack(L, n, "string slice too long");
|
luaL_checkstack(L, n, "string slice too long");
|
||||||
for (i=0; i<n; i++)
|
for (i=0; i<n; i++)
|
||||||
lua_pushinteger(L, uchar(s[posi+i-1]));
|
lua_pushinteger(L, cast_uchar(s[posi + cast_uint(i) - 1]));
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,13 +185,13 @@ static int str_char (lua_State *L) {
|
|||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
int i;
|
int i;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
char *p = luaL_buffinitsize(L, &b, n);
|
char *p = luaL_buffinitsize(L, &b, cast_uint(n));
|
||||||
for (i=1; i<=n; i++) {
|
for (i=1; i<=n; i++) {
|
||||||
lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i);
|
lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i);
|
||||||
luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range");
|
luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range");
|
||||||
p[i - 1] = uchar(c);
|
p[i - 1] = cast_char(cast_uchar(c));
|
||||||
}
|
}
|
||||||
luaL_pushresultsize(&b, n);
|
luaL_pushresultsize(&b, cast_uint(n));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +214,12 @@ static int writer (lua_State *L, const void *b, size_t size, void *ud) {
|
|||||||
state->init = 1;
|
state->init = 1;
|
||||||
luaL_buffinit(L, &state->B);
|
luaL_buffinit(L, &state->B);
|
||||||
}
|
}
|
||||||
luaL_addlstring(&state->B, (const char *)b, size);
|
if (b == NULL) { /* finishing dump? */
|
||||||
|
luaL_pushresult(&state->B); /* push result */
|
||||||
|
lua_replace(L, 1); /* move it to reserved slot */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
luaL_addlstring(&state->B, (const char *)b, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,12 +227,13 @@ static int writer (lua_State *L, const void *b, size_t size, void *ud) {
|
|||||||
static int str_dump (lua_State *L) {
|
static int str_dump (lua_State *L) {
|
||||||
struct str_Writer state;
|
struct str_Writer state;
|
||||||
int strip = lua_toboolean(L, 2);
|
int strip = lua_toboolean(L, 2);
|
||||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
luaL_argcheck(L, lua_type(L, 1) == LUA_TFUNCTION && !lua_iscfunction(L, 1),
|
||||||
lua_settop(L, 1); /* ensure function is on the top of the stack */
|
1, "Lua function expected");
|
||||||
|
/* ensure function is on the top of the stack and vacate slot 1 */
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
state.init = 0;
|
state.init = 0;
|
||||||
if (l_unlikely(lua_dump(L, writer, &state, strip) != 0))
|
lua_dump(L, writer, &state, strip);
|
||||||
return luaL_error(L, "unable to dump given function");
|
lua_settop(L, 1); /* leave final result on top */
|
||||||
luaL_pushresult(&state.B);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,11 +269,18 @@ static int tonum (lua_State *L, int arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void trymt (lua_State *L, const char *mtname) {
|
/*
|
||||||
|
** To be here, either the first operand was a string or the first
|
||||||
|
** operand didn't have a corresponding metamethod. (Otherwise, that
|
||||||
|
** other metamethod would have been called.) So, if this metamethod
|
||||||
|
** doesn't work, the only other option would be for the second
|
||||||
|
** operand to have a different metamethod.
|
||||||
|
*/
|
||||||
|
static void trymt (lua_State *L, const char *mtkey, const char *opname) {
|
||||||
lua_settop(L, 2); /* back to the original arguments */
|
lua_settop(L, 2); /* back to the original arguments */
|
||||||
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
||||||
!luaL_getmetafield(L, 2, mtname)))
|
!luaL_getmetafield(L, 2, mtkey)))
|
||||||
luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
|
luaL_error(L, "attempt to %s a '%s' with a '%s'", opname,
|
||||||
luaL_typename(L, -2), luaL_typename(L, -1));
|
luaL_typename(L, -2), luaL_typename(L, -1));
|
||||||
lua_insert(L, -3); /* put metamethod before arguments */
|
lua_insert(L, -3); /* put metamethod before arguments */
|
||||||
lua_call(L, 2, 1); /* call metamethod */
|
lua_call(L, 2, 1); /* call metamethod */
|
||||||
@@ -289,7 +291,7 @@ static int arith (lua_State *L, int op, const char *mtname) {
|
|||||||
if (tonum(L, 1) && tonum(L, 2))
|
if (tonum(L, 1) && tonum(L, 2))
|
||||||
lua_arith(L, op); /* result will be on the top */
|
lua_arith(L, op); /* result will be on the top */
|
||||||
else
|
else
|
||||||
trymt(L, mtname);
|
trymt(L, mtname, mtname + 2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,10 +363,10 @@ typedef struct MatchState {
|
|||||||
const char *p_end; /* end ('\0') of pattern */
|
const char *p_end; /* end ('\0') of pattern */
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
||||||
unsigned char level; /* total number of captures (finished or unfinished) */
|
int level; /* total number of captures (finished or unfinished) */
|
||||||
struct {
|
struct {
|
||||||
const char *init;
|
const char *init;
|
||||||
ptrdiff_t len;
|
ptrdiff_t len; /* length or special value (CAP_*) */
|
||||||
} capture[LUA_MAXCAPTURES];
|
} capture[LUA_MAXCAPTURES];
|
||||||
} MatchState;
|
} MatchState;
|
||||||
|
|
||||||
@@ -453,15 +455,15 @@ static int matchbracketclass (int c, const char *p, const char *ec) {
|
|||||||
while (++p < ec) {
|
while (++p < ec) {
|
||||||
if (*p == L_ESC) {
|
if (*p == L_ESC) {
|
||||||
p++;
|
p++;
|
||||||
if (match_class(c, uchar(*p)))
|
if (match_class(c, cast_uchar(*p)))
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
||||||
p+=2;
|
p+=2;
|
||||||
if (uchar(*(p-2)) <= c && c <= uchar(*p))
|
if (cast_uchar(*(p-2)) <= c && c <= cast_uchar(*p))
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
else if (uchar(*p) == c) return sig;
|
else if (cast_uchar(*p) == c) return sig;
|
||||||
}
|
}
|
||||||
return !sig;
|
return !sig;
|
||||||
}
|
}
|
||||||
@@ -472,12 +474,12 @@ static int singlematch (MatchState *ms, const char *s, const char *p,
|
|||||||
if (s >= ms->src_end)
|
if (s >= ms->src_end)
|
||||||
return 0;
|
return 0;
|
||||||
else {
|
else {
|
||||||
int c = uchar(*s);
|
int c = cast_uchar(*s);
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case '.': return 1; /* matches any char */
|
case '.': return 1; /* matches any char */
|
||||||
case L_ESC: return match_class(c, uchar(*(p+1)));
|
case L_ESC: return match_class(c, cast_uchar(*(p+1)));
|
||||||
case '[': return matchbracketclass(c, p, ep-1);
|
case '[': return matchbracketclass(c, p, ep-1);
|
||||||
default: return (uchar(*p) == c);
|
default: return (cast_uchar(*p) == c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,7 +561,7 @@ static const char *end_capture (MatchState *ms, const char *s,
|
|||||||
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
||||||
size_t len;
|
size_t len;
|
||||||
l = check_capture(ms, l);
|
l = check_capture(ms, l);
|
||||||
len = ms->capture[l].len;
|
len = cast_sizet(ms->capture[l].len);
|
||||||
if ((size_t)(ms->src_end-s) >= len &&
|
if ((size_t)(ms->src_end-s) >= len &&
|
||||||
memcmp(ms->capture[l].init, s, len) == 0)
|
memcmp(ms->capture[l].init, s, len) == 0)
|
||||||
return s+len;
|
return s+len;
|
||||||
@@ -570,7 +572,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
|
|||||||
static const char *match (MatchState *ms, const char *s, const char *p) {
|
static const char *match (MatchState *ms, const char *s, const char *p) {
|
||||||
if (l_unlikely(ms->matchdepth-- == 0))
|
if (l_unlikely(ms->matchdepth-- == 0))
|
||||||
luaL_error(ms->L, "pattern too complex");
|
luaL_error(ms->L, "pattern too complex");
|
||||||
init: /* using goto's to optimize tail recursion */
|
init: /* using goto to optimize tail recursion */
|
||||||
if (p != ms->p_end) { /* end of pattern? */
|
if (p != ms->p_end) { /* end of pattern? */
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case '(': { /* start capture */
|
case '(': { /* start capture */
|
||||||
@@ -606,8 +608,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
|||||||
luaL_error(ms->L, "missing '[' after '%%f' in pattern");
|
luaL_error(ms->L, "missing '[' after '%%f' in pattern");
|
||||||
ep = classend(ms, p); /* points to what is next */
|
ep = classend(ms, p); /* points to what is next */
|
||||||
previous = (s == ms->src_init) ? '\0' : *(s - 1);
|
previous = (s == ms->src_init) ? '\0' : *(s - 1);
|
||||||
if (!matchbracketclass(uchar(previous), p, ep - 1) &&
|
if (!matchbracketclass(cast_uchar(previous), p, ep - 1) &&
|
||||||
matchbracketclass(uchar(*s), p, ep - 1)) {
|
matchbracketclass(cast_uchar(*s), p, ep - 1)) {
|
||||||
p = ep; goto init; /* return match(ms, s, ep); */
|
p = ep; goto init; /* return match(ms, s, ep); */
|
||||||
}
|
}
|
||||||
s = NULL; /* match failed */
|
s = NULL; /* match failed */
|
||||||
@@ -616,7 +618,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
|||||||
case '0': case '1': case '2': case '3':
|
case '0': case '1': case '2': case '3':
|
||||||
case '4': case '5': case '6': case '7':
|
case '4': case '5': case '6': case '7':
|
||||||
case '8': case '9': { /* capture results (%0-%9)? */
|
case '8': case '9': { /* capture results (%0-%9)? */
|
||||||
s = match_capture(ms, s, uchar(*(p + 1)));
|
s = match_capture(ms, s, cast_uchar(*(p + 1)));
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
p += 2; goto init; /* return match(ms, s, p + 2) */
|
p += 2; goto init; /* return match(ms, s, p + 2) */
|
||||||
}
|
}
|
||||||
@@ -683,7 +685,7 @@ static const char *lmemfind (const char *s1, size_t l1,
|
|||||||
if (memcmp(init, s2+1, l2) == 0)
|
if (memcmp(init, s2+1, l2) == 0)
|
||||||
return init-1;
|
return init-1;
|
||||||
else { /* correct 'l1' and 's1' to try again */
|
else { /* correct 'l1' and 's1' to try again */
|
||||||
l1 -= init-s1;
|
l1 -= ct_diff2sz(init - s1);
|
||||||
s1 = init;
|
s1 = init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -699,13 +701,13 @@ static const char *lmemfind (const char *s1, size_t l1,
|
|||||||
** its length and put its address in '*cap'. If it is an integer
|
** its length and put its address in '*cap'. If it is an integer
|
||||||
** (a position), push it on the stack and return CAP_POSITION.
|
** (a position), push it on the stack and return CAP_POSITION.
|
||||||
*/
|
*/
|
||||||
static size_t get_onecapture (MatchState *ms, int i, const char *s,
|
static ptrdiff_t get_onecapture (MatchState *ms, int i, const char *s,
|
||||||
const char *e, const char **cap) {
|
const char *e, const char **cap) {
|
||||||
if (i >= ms->level) {
|
if (i >= ms->level) {
|
||||||
if (l_unlikely(i != 0))
|
if (l_unlikely(i != 0))
|
||||||
luaL_error(ms->L, "invalid capture index %%%d", i + 1);
|
luaL_error(ms->L, "invalid capture index %%%d", i + 1);
|
||||||
*cap = s;
|
*cap = s;
|
||||||
return e - s;
|
return (e - s);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ptrdiff_t capl = ms->capture[i].len;
|
ptrdiff_t capl = ms->capture[i].len;
|
||||||
@@ -713,7 +715,8 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s,
|
|||||||
if (l_unlikely(capl == CAP_UNFINISHED))
|
if (l_unlikely(capl == CAP_UNFINISHED))
|
||||||
luaL_error(ms->L, "unfinished capture");
|
luaL_error(ms->L, "unfinished capture");
|
||||||
else if (capl == CAP_POSITION)
|
else if (capl == CAP_POSITION)
|
||||||
lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
|
lua_pushinteger(ms->L,
|
||||||
|
ct_diff2S(ms->capture[i].init - ms->src_init) + 1);
|
||||||
return capl;
|
return capl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,7 +730,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s,
|
|||||||
const char *cap;
|
const char *cap;
|
||||||
ptrdiff_t l = get_onecapture(ms, i, s, e, &cap);
|
ptrdiff_t l = get_onecapture(ms, i, s, e, &cap);
|
||||||
if (l != CAP_POSITION)
|
if (l != CAP_POSITION)
|
||||||
lua_pushlstring(ms->L, cap, l);
|
lua_pushlstring(ms->L, cap, cast_sizet(l));
|
||||||
/* else position was already pushed */
|
/* else position was already pushed */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,19 +757,25 @@ static int nospecials (const char *p, size_t l) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Prepare state for matches. These fields are not affected by each match.
|
||||||
|
*/
|
||||||
static void prepstate (MatchState *ms, lua_State *L,
|
static void prepstate (MatchState *ms, lua_State *L,
|
||||||
const char *s, size_t ls, const char *p, size_t lp) {
|
const char *s, size_t ls, const char *p, size_t lp) {
|
||||||
ms->L = L;
|
ms->L = L;
|
||||||
ms->matchdepth = MAXCCALLS;
|
|
||||||
ms->src_init = s;
|
ms->src_init = s;
|
||||||
ms->src_end = s + ls;
|
ms->src_end = s + ls;
|
||||||
ms->p_end = p + lp;
|
ms->p_end = p + lp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** (Re)prepare state for a match, setting fields that change during
|
||||||
|
** each match.
|
||||||
|
*/
|
||||||
static void reprepstate (MatchState *ms) {
|
static void reprepstate (MatchState *ms) {
|
||||||
|
ms->matchdepth = MAXCCALLS;
|
||||||
ms->level = 0;
|
ms->level = 0;
|
||||||
lua_assert(ms->matchdepth == MAXCCALLS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -784,8 +793,8 @@ static int str_find_aux (lua_State *L, int find) {
|
|||||||
/* do a plain search */
|
/* do a plain search */
|
||||||
const char *s2 = lmemfind(s + init, ls - init, p, lp);
|
const char *s2 = lmemfind(s + init, ls - init, p, lp);
|
||||||
if (s2) {
|
if (s2) {
|
||||||
lua_pushinteger(L, (s2 - s) + 1);
|
lua_pushinteger(L, ct_diff2S(s2 - s) + 1);
|
||||||
lua_pushinteger(L, (s2 - s) + lp);
|
lua_pushinteger(L, cast_st2S(ct_diff2sz(s2 - s) + lp));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -802,8 +811,8 @@ static int str_find_aux (lua_State *L, int find) {
|
|||||||
reprepstate(&ms);
|
reprepstate(&ms);
|
||||||
if ((res=match(&ms, s1, p)) != NULL) {
|
if ((res=match(&ms, s1, p)) != NULL) {
|
||||||
if (find) {
|
if (find) {
|
||||||
lua_pushinteger(L, (s1 - s) + 1); /* start */
|
lua_pushinteger(L, ct_diff2S(s1 - s) + 1); /* start */
|
||||||
lua_pushinteger(L, res - s); /* end */
|
lua_pushinteger(L, ct_diff2S(res - s)); /* end */
|
||||||
return push_captures(&ms, NULL, 0) + 2;
|
return push_captures(&ms, NULL, 0) + 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -875,23 +884,23 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
|
|||||||
const char *news = lua_tolstring(L, 3, &l);
|
const char *news = lua_tolstring(L, 3, &l);
|
||||||
const char *p;
|
const char *p;
|
||||||
while ((p = (char *)memchr(news, L_ESC, l)) != NULL) {
|
while ((p = (char *)memchr(news, L_ESC, l)) != NULL) {
|
||||||
luaL_addlstring(b, news, p - news);
|
luaL_addlstring(b, news, ct_diff2sz(p - news));
|
||||||
p++; /* skip ESC */
|
p++; /* skip ESC */
|
||||||
if (*p == L_ESC) /* '%%' */
|
if (*p == L_ESC) /* '%%' */
|
||||||
luaL_addchar(b, *p);
|
luaL_addchar(b, *p);
|
||||||
else if (*p == '0') /* '%0' */
|
else if (*p == '0') /* '%0' */
|
||||||
luaL_addlstring(b, s, e - s);
|
luaL_addlstring(b, s, ct_diff2sz(e - s));
|
||||||
else if (isdigit(uchar(*p))) { /* '%n' */
|
else if (isdigit(cast_uchar(*p))) { /* '%n' */
|
||||||
const char *cap;
|
const char *cap;
|
||||||
ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap);
|
ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap);
|
||||||
if (resl == CAP_POSITION)
|
if (resl == CAP_POSITION)
|
||||||
luaL_addvalue(b); /* add position to accumulated result */
|
luaL_addvalue(b); /* add position to accumulated result */
|
||||||
else
|
else
|
||||||
luaL_addlstring(b, cap, resl);
|
luaL_addlstring(b, cap, cast_sizet(resl));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
|
luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
|
||||||
l -= p + 1 - news;
|
l -= ct_diff2sz(p + 1 - news);
|
||||||
news = p + 1;
|
news = p + 1;
|
||||||
}
|
}
|
||||||
luaL_addlstring(b, news, l);
|
luaL_addlstring(b, news, l);
|
||||||
@@ -926,7 +935,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
|
|||||||
}
|
}
|
||||||
if (!lua_toboolean(L, -1)) { /* nil or false? */
|
if (!lua_toboolean(L, -1)) { /* nil or false? */
|
||||||
lua_pop(L, 1); /* remove value */
|
lua_pop(L, 1); /* remove value */
|
||||||
luaL_addlstring(b, s, e - s); /* keep original text */
|
luaL_addlstring(b, s, ct_diff2sz(e - s)); /* keep original text */
|
||||||
return 0; /* no changes */
|
return 0; /* no changes */
|
||||||
}
|
}
|
||||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||||
@@ -945,7 +954,8 @@ static int str_gsub (lua_State *L) {
|
|||||||
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
|
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
|
||||||
const char *lastmatch = NULL; /* end of last match */
|
const char *lastmatch = NULL; /* end of last match */
|
||||||
int tr = lua_type(L, 3); /* replacement type */
|
int tr = lua_type(L, 3); /* replacement type */
|
||||||
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
|
/* max replacements */
|
||||||
|
lua_Integer max_s = luaL_optinteger(L, 4, cast_st2S(srcl) + 1);
|
||||||
int anchor = (*p == '^');
|
int anchor = (*p == '^');
|
||||||
lua_Integer n = 0; /* replacement count */
|
lua_Integer n = 0; /* replacement count */
|
||||||
int changed = 0; /* change flag */
|
int changed = 0; /* change flag */
|
||||||
@@ -964,7 +974,7 @@ static int str_gsub (lua_State *L) {
|
|||||||
reprepstate(&ms); /* (re)prepare state for new match */
|
reprepstate(&ms); /* (re)prepare state for new match */
|
||||||
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
|
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
|
||||||
n++;
|
n++;
|
||||||
changed = add_value(&ms, &b, src, e, tr) | changed;
|
changed = add_value(&ms, &b, src, e, tr) || changed;
|
||||||
src = lastmatch = e;
|
src = lastmatch = e;
|
||||||
}
|
}
|
||||||
else if (src < ms.src_end) /* otherwise, skip one character */
|
else if (src < ms.src_end) /* otherwise, skip one character */
|
||||||
@@ -975,7 +985,7 @@ static int str_gsub (lua_State *L) {
|
|||||||
if (!changed) /* no changes? */
|
if (!changed) /* no changes? */
|
||||||
lua_pushvalue(L, 1); /* return original string */
|
lua_pushvalue(L, 1); /* return original string */
|
||||||
else { /* something changed */
|
else { /* something changed */
|
||||||
luaL_addlstring(&b, src, ms.src_end-src);
|
luaL_addlstring(&b, src, ct_diff2sz(ms.src_end - src));
|
||||||
luaL_pushresult(&b); /* create and return new string */
|
luaL_pushresult(&b); /* create and return new string */
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, n); /* number of substitutions */
|
lua_pushinteger(L, n); /* number of substitutions */
|
||||||
@@ -1013,15 +1023,15 @@ static int str_gsub (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** Add integer part of 'x' to buffer and return new 'x'
|
** Add integer part of 'x' to buffer and return new 'x'
|
||||||
*/
|
*/
|
||||||
static lua_Number adddigit (char *buff, int n, lua_Number x) {
|
static lua_Number adddigit (char *buff, unsigned n, lua_Number x) {
|
||||||
lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
|
lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
|
||||||
int d = (int)dd;
|
int d = (int)dd;
|
||||||
buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
|
buff[n] = cast_char(d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
|
||||||
return x - dd; /* return what is left */
|
return x - dd; /* return what is left */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int num2straux (char *buff, int sz, lua_Number x) {
|
static int num2straux (char *buff, unsigned sz, lua_Number x) {
|
||||||
/* if 'inf' or 'NaN', format it like '%g' */
|
/* if 'inf' or 'NaN', format it like '%g' */
|
||||||
if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
|
if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
|
||||||
return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
|
return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
|
||||||
@@ -1032,7 +1042,7 @@ static int num2straux (char *buff, int sz, lua_Number x) {
|
|||||||
else {
|
else {
|
||||||
int e;
|
int e;
|
||||||
lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
|
lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
|
||||||
int n = 0; /* character count */
|
unsigned n = 0; /* character count */
|
||||||
if (m < 0) { /* is number negative? */
|
if (m < 0) { /* is number negative? */
|
||||||
buff[n++] = '-'; /* add sign */
|
buff[n++] = '-'; /* add sign */
|
||||||
m = -m; /* make it positive */
|
m = -m; /* make it positive */
|
||||||
@@ -1046,20 +1056,20 @@ static int num2straux (char *buff, int sz, lua_Number x) {
|
|||||||
m = adddigit(buff, n++, m * 16);
|
m = adddigit(buff, n++, m * 16);
|
||||||
} while (m > 0);
|
} while (m > 0);
|
||||||
}
|
}
|
||||||
n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
|
n += cast_uint(l_sprintf(buff + n, sz - n, "p%+d", e)); /* add exponent */
|
||||||
lua_assert(n < sz);
|
lua_assert(n < sz);
|
||||||
return n;
|
return cast_int(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int lua_number2strx (lua_State *L, char *buff, int sz,
|
static int lua_number2strx (lua_State *L, char *buff, unsigned sz,
|
||||||
const char *fmt, lua_Number x) {
|
const char *fmt, lua_Number x) {
|
||||||
int n = num2straux(buff, sz, x);
|
int n = num2straux(buff, sz, x);
|
||||||
if (fmt[SIZELENMOD] == 'A') {
|
if (fmt[SIZELENMOD] == 'A') {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
buff[i] = toupper(uchar(buff[i]));
|
buff[i] = cast_char(toupper(cast_uchar(buff[i])));
|
||||||
}
|
}
|
||||||
else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
|
else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
|
||||||
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
||||||
@@ -1126,12 +1136,12 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
|
|||||||
luaL_addchar(b, '\\');
|
luaL_addchar(b, '\\');
|
||||||
luaL_addchar(b, *s);
|
luaL_addchar(b, *s);
|
||||||
}
|
}
|
||||||
else if (iscntrl(uchar(*s))) {
|
else if (iscntrl(cast_uchar(*s))) {
|
||||||
char buff[10];
|
char buff[10];
|
||||||
if (!isdigit(uchar(*(s+1))))
|
if (!isdigit(cast_uchar(*(s+1))))
|
||||||
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
|
l_sprintf(buff, sizeof(buff), "\\%d", (int)cast_uchar(*s));
|
||||||
else
|
else
|
||||||
l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
|
l_sprintf(buff, sizeof(buff), "\\%03d", (int)cast_uchar(*s));
|
||||||
luaL_addstring(b, buff);
|
luaL_addstring(b, buff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1160,9 +1170,9 @@ static int quotefloat (lua_State *L, char *buff, lua_Number n) {
|
|||||||
int nb = lua_number2strx(L, buff, MAX_ITEM,
|
int nb = lua_number2strx(L, buff, MAX_ITEM,
|
||||||
"%" LUA_NUMBER_FRMLEN "a", n);
|
"%" LUA_NUMBER_FRMLEN "a", n);
|
||||||
/* ensures that 'buff' string uses a dot as the radix character */
|
/* ensures that 'buff' string uses a dot as the radix character */
|
||||||
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
|
if (memchr(buff, '.', cast_uint(nb)) == NULL) { /* no dot? */
|
||||||
char point = lua_getlocaledecpoint(); /* try locale point */
|
char point = lua_getlocaledecpoint(); /* try locale point */
|
||||||
char *ppoint = (char *)memchr(buff, point, nb);
|
char *ppoint = (char *)memchr(buff, point, cast_uint(nb));
|
||||||
if (ppoint) *ppoint = '.'; /* change it to a dot */
|
if (ppoint) *ppoint = '.'; /* change it to a dot */
|
||||||
}
|
}
|
||||||
return nb;
|
return nb;
|
||||||
@@ -1192,7 +1202,7 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
|
|||||||
: LUA_INTEGER_FMT; /* else use default format */
|
: LUA_INTEGER_FMT; /* else use default format */
|
||||||
nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
|
nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
|
||||||
}
|
}
|
||||||
luaL_addsize(b, nb);
|
luaL_addsize(b, cast_uint(nb));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TNIL: case LUA_TBOOLEAN: {
|
case LUA_TNIL: case LUA_TBOOLEAN: {
|
||||||
@@ -1208,9 +1218,9 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *get2digits (const char *s) {
|
static const char *get2digits (const char *s) {
|
||||||
if (isdigit(uchar(*s))) {
|
if (isdigit(cast_uchar(*s))) {
|
||||||
s++;
|
s++;
|
||||||
if (isdigit(uchar(*s))) s++; /* (2 digits at most) */
|
if (isdigit(cast_uchar(*s))) s++; /* (2 digits at most) */
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1243,7 @@ static void checkformat (lua_State *L, const char *form, const char *flags,
|
|||||||
spec = get2digits(spec); /* skip precision */
|
spec = get2digits(spec); /* skip precision */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isalpha(uchar(*spec))) /* did not go to the end? */
|
if (!isalpha(cast_uchar(*spec))) /* did not go to the end? */
|
||||||
luaL_error(L, "invalid conversion specification: '%s'", form);
|
luaL_error(L, "invalid conversion specification: '%s'", form);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1286,7 +1296,7 @@ static int str_format (lua_State *L) {
|
|||||||
luaL_addchar(&b, *strfrmt++); /* %% */
|
luaL_addchar(&b, *strfrmt++); /* %% */
|
||||||
else { /* format item */
|
else { /* format item */
|
||||||
char form[MAX_FORMAT]; /* to store the format ('%...') */
|
char form[MAX_FORMAT]; /* to store the format ('%...') */
|
||||||
int maxitem = MAX_ITEM; /* maximum length for the result */
|
unsigned maxitem = MAX_ITEM; /* maximum length for the result */
|
||||||
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */
|
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */
|
||||||
int nb = 0; /* number of bytes in result */
|
int nb = 0; /* number of bytes in result */
|
||||||
if (++arg > top)
|
if (++arg > top)
|
||||||
@@ -1369,8 +1379,8 @@ static int str_format (lua_State *L) {
|
|||||||
return luaL_error(L, "invalid conversion '%s' to 'format'", form);
|
return luaL_error(L, "invalid conversion '%s' to 'format'", form);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_assert(nb < maxitem);
|
lua_assert(cast_uint(nb) < maxitem);
|
||||||
luaL_addsize(&b, nb);
|
luaL_addsize(&b, cast_uint(nb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
@@ -1418,7 +1428,7 @@ static const union {
|
|||||||
typedef struct Header {
|
typedef struct Header {
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
int islittle;
|
int islittle;
|
||||||
int maxalign;
|
unsigned maxalign;
|
||||||
} Header;
|
} Header;
|
||||||
|
|
||||||
|
|
||||||
@@ -1446,14 +1456,14 @@ typedef enum KOption {
|
|||||||
*/
|
*/
|
||||||
static int digit (int c) { return '0' <= c && c <= '9'; }
|
static int digit (int c) { return '0' <= c && c <= '9'; }
|
||||||
|
|
||||||
static int getnum (const char **fmt, int df) {
|
static size_t getnum (const char **fmt, size_t df) {
|
||||||
if (!digit(**fmt)) /* no number? */
|
if (!digit(**fmt)) /* no number? */
|
||||||
return df; /* return default value */
|
return df; /* return default value */
|
||||||
else {
|
else {
|
||||||
int a = 0;
|
size_t a = 0;
|
||||||
do {
|
do {
|
||||||
a = a*10 + (*((*fmt)++) - '0');
|
a = a*10 + cast_uint(*((*fmt)++) - '0');
|
||||||
} while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
|
} while (digit(**fmt) && a <= (MAX_SIZE - 9)/10);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1461,14 +1471,14 @@ static int getnum (const char **fmt, int df) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Read an integer numeral and raises an error if it is larger
|
** Read an integer numeral and raises an error if it is larger
|
||||||
** than the maximum size for integers.
|
** than the maximum size of integers.
|
||||||
*/
|
*/
|
||||||
static int getnumlimit (Header *h, const char **fmt, int df) {
|
static unsigned getnumlimit (Header *h, const char **fmt, size_t df) {
|
||||||
int sz = getnum(fmt, df);
|
size_t sz = getnum(fmt, df);
|
||||||
if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
|
if (l_unlikely((sz - 1u) >= MAXINTSIZE))
|
||||||
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
return cast_uint(luaL_error(h->L,
|
||||||
sz, MAXINTSIZE);
|
"integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE));
|
||||||
return sz;
|
return cast_uint(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1485,7 +1495,7 @@ static void initheader (lua_State *L, Header *h) {
|
|||||||
/*
|
/*
|
||||||
** Read and classify next option. 'size' is filled with option's size.
|
** Read and classify next option. 'size' is filled with option's size.
|
||||||
*/
|
*/
|
||||||
static KOption getoption (Header *h, const char **fmt, int *size) {
|
static KOption getoption (Header *h, const char **fmt, size_t *size) {
|
||||||
/* dummy structure to get native alignment requirements */
|
/* dummy structure to get native alignment requirements */
|
||||||
struct cD { char c; union { LUAI_MAXALIGN; } u; };
|
struct cD { char c; union { LUAI_MAXALIGN; } u; };
|
||||||
int opt = *((*fmt)++);
|
int opt = *((*fmt)++);
|
||||||
@@ -1507,8 +1517,8 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
||||||
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
||||||
case 'c':
|
case 'c':
|
||||||
*size = getnum(fmt, -1);
|
*size = getnum(fmt, cast_sizet(-1));
|
||||||
if (l_unlikely(*size == -1))
|
if (l_unlikely(*size == cast_sizet(-1)))
|
||||||
luaL_error(h->L, "missing size for format option 'c'");
|
luaL_error(h->L, "missing size for format option 'c'");
|
||||||
return Kchar;
|
return Kchar;
|
||||||
case 'z': return Kzstr;
|
case 'z': return Kzstr;
|
||||||
@@ -1519,7 +1529,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
case '>': h->islittle = 0; break;
|
case '>': h->islittle = 0; break;
|
||||||
case '=': h->islittle = nativeendian.little; break;
|
case '=': h->islittle = nativeendian.little; break;
|
||||||
case '!': {
|
case '!': {
|
||||||
const int maxalign = offsetof(struct cD, u);
|
const size_t maxalign = offsetof(struct cD, u);
|
||||||
h->maxalign = getnumlimit(h, fmt, maxalign);
|
h->maxalign = getnumlimit(h, fmt, maxalign);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1538,10 +1548,10 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
** the maximum alignment ('maxalign'). Kchar option needs no alignment
|
** the maximum alignment ('maxalign'). Kchar option needs no alignment
|
||||||
** despite its size.
|
** despite its size.
|
||||||
*/
|
*/
|
||||||
static KOption getdetails (Header *h, size_t totalsize,
|
static KOption getdetails (Header *h, size_t totalsize, const char **fmt,
|
||||||
const char **fmt, int *psize, int *ntoalign) {
|
size_t *psize, unsigned *ntoalign) {
|
||||||
KOption opt = getoption(h, fmt, psize);
|
KOption opt = getoption(h, fmt, psize);
|
||||||
int align = *psize; /* usually, alignment follows size */
|
size_t align = *psize; /* usually, alignment follows size */
|
||||||
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
||||||
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
||||||
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
||||||
@@ -1551,9 +1561,15 @@ static KOption getdetails (Header *h, size_t totalsize,
|
|||||||
else {
|
else {
|
||||||
if (align > h->maxalign) /* enforce maximum alignment */
|
if (align > h->maxalign) /* enforce maximum alignment */
|
||||||
align = h->maxalign;
|
align = h->maxalign;
|
||||||
if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */
|
if (l_unlikely(!ispow2(align))) { /* not a power of 2? */
|
||||||
|
*ntoalign = 0; /* to avoid warnings */
|
||||||
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
||||||
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
|
}
|
||||||
|
else {
|
||||||
|
/* 'szmoda' = totalsize % align */
|
||||||
|
unsigned szmoda = cast_uint(totalsize & (align - 1));
|
||||||
|
*ntoalign = cast_uint((align - szmoda) & (align - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
@@ -1566,9 +1582,9 @@ static KOption getdetails (Header *h, size_t totalsize,
|
|||||||
** bytes if necessary (by default they would be zeros).
|
** bytes if necessary (by default they would be zeros).
|
||||||
*/
|
*/
|
||||||
static void packint (luaL_Buffer *b, lua_Unsigned n,
|
static void packint (luaL_Buffer *b, lua_Unsigned n,
|
||||||
int islittle, int size, int neg) {
|
int islittle, unsigned size, int neg) {
|
||||||
char *buff = luaL_prepbuffsize(b, size);
|
char *buff = luaL_prepbuffsize(b, size);
|
||||||
int i;
|
unsigned i;
|
||||||
buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
|
buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
|
||||||
for (i = 1; i < size; i++) {
|
for (i = 1; i < size; i++) {
|
||||||
n >>= NB;
|
n >>= NB;
|
||||||
@@ -1587,7 +1603,7 @@ static void packint (luaL_Buffer *b, lua_Unsigned n,
|
|||||||
** given 'islittle' is different from native endianness.
|
** given 'islittle' is different from native endianness.
|
||||||
*/
|
*/
|
||||||
static void copywithendian (char *dest, const char *src,
|
static void copywithendian (char *dest, const char *src,
|
||||||
int size, int islittle) {
|
unsigned size, int islittle) {
|
||||||
if (islittle == nativeendian.little)
|
if (islittle == nativeendian.little)
|
||||||
memcpy(dest, src, size);
|
memcpy(dest, src, size);
|
||||||
else {
|
else {
|
||||||
@@ -1608,8 +1624,11 @@ static int str_pack (lua_State *L) {
|
|||||||
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
unsigned ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
|
luaL_argcheck(L, size + ntoalign <= MAX_SIZE - totalsize, arg,
|
||||||
|
"result too long");
|
||||||
totalsize += ntoalign + size;
|
totalsize += ntoalign + size;
|
||||||
while (ntoalign-- > 0)
|
while (ntoalign-- > 0)
|
||||||
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
||||||
@@ -1621,7 +1640,7 @@ static int str_pack (lua_State *L) {
|
|||||||
lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
|
lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
|
||||||
luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
|
luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
|
||||||
}
|
}
|
||||||
packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
|
packint(&b, (lua_Unsigned)n, h.islittle, cast_uint(size), (n < 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kuint: { /* unsigned integers */
|
case Kuint: { /* unsigned integers */
|
||||||
@@ -1629,7 +1648,7 @@ static int str_pack (lua_State *L) {
|
|||||||
if (size < SZINT) /* need overflow check? */
|
if (size < SZINT) /* need overflow check? */
|
||||||
luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
|
luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
|
||||||
arg, "unsigned overflow");
|
arg, "unsigned overflow");
|
||||||
packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
|
packint(&b, (lua_Unsigned)n, h.islittle, cast_uint(size), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kfloat: { /* C float */
|
case Kfloat: { /* C float */
|
||||||
@@ -1659,20 +1678,24 @@ static int str_pack (lua_State *L) {
|
|||||||
case Kchar: { /* fixed-size string */
|
case Kchar: { /* fixed-size string */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, len <= (size_t)size, arg,
|
luaL_argcheck(L, len <= size, arg, "string longer than given size");
|
||||||
"string longer than given size");
|
|
||||||
luaL_addlstring(&b, s, len); /* add string */
|
luaL_addlstring(&b, s, len); /* add string */
|
||||||
while (len++ < (size_t)size) /* pad extra space */
|
if (len < size) { /* does it need padding? */
|
||||||
luaL_addchar(&b, LUAL_PACKPADBYTE);
|
size_t psize = size - len; /* pad size */
|
||||||
|
char *buff = luaL_prepbuffsize(&b, psize);
|
||||||
|
memset(buff, LUAL_PACKPADBYTE, psize);
|
||||||
|
luaL_addsize(&b, psize);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: { /* strings with length count */
|
case Kstring: { /* strings with length count */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, size >= (int)sizeof(size_t) ||
|
luaL_argcheck(L, size >= sizeof(lua_Unsigned) ||
|
||||||
len < ((size_t)1 << (size * NB)),
|
len < ((lua_Unsigned)1 << (size * NB)),
|
||||||
arg, "string length does not fit in given size");
|
arg, "string length does not fit in given size");
|
||||||
packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
|
/* pack length */
|
||||||
|
packint(&b, (lua_Unsigned)len, h.islittle, cast_uint(size), 0);
|
||||||
luaL_addlstring(&b, s, len);
|
luaL_addlstring(&b, s, len);
|
||||||
totalsize += len;
|
totalsize += len;
|
||||||
break;
|
break;
|
||||||
@@ -1703,16 +1726,17 @@ static int str_packsize (lua_State *L) {
|
|||||||
size_t totalsize = 0; /* accumulate total size of result */
|
size_t totalsize = 0; /* accumulate total size of result */
|
||||||
initheader(L, &h);
|
initheader(L, &h);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
unsigned ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
||||||
"variable-length format");
|
"variable-length format");
|
||||||
size += ntoalign; /* total space used by option */
|
size += ntoalign; /* total space used by option */
|
||||||
luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
|
luaL_argcheck(L, totalsize <= MAX_SIZE - size,
|
||||||
"format result too large");
|
1, "format result too large");
|
||||||
totalsize += size;
|
totalsize += size;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, (lua_Integer)totalsize);
|
lua_pushinteger(L, cast_st2S(totalsize));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1761,9 +1785,10 @@ static int str_unpack (lua_State *L) {
|
|||||||
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
|
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
|
||||||
initheader(L, &h);
|
initheader(L, &h);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
unsigned ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
||||||
luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2,
|
luaL_argcheck(L, ntoalign + size <= ld - pos, 2,
|
||||||
"data string too short");
|
"data string too short");
|
||||||
pos += ntoalign; /* skip alignment */
|
pos += ntoalign; /* skip alignment */
|
||||||
/* stack space for item + next position */
|
/* stack space for item + next position */
|
||||||
@@ -1772,8 +1797,8 @@ static int str_unpack (lua_State *L) {
|
|||||||
switch (opt) {
|
switch (opt) {
|
||||||
case Kint:
|
case Kint:
|
||||||
case Kuint: {
|
case Kuint: {
|
||||||
lua_Integer res = unpackint(L, data + pos, h.islittle, size,
|
lua_Integer res = unpackint(L, data + pos, h.islittle,
|
||||||
(opt == Kint));
|
cast_int(size), (opt == Kint));
|
||||||
lua_pushinteger(L, res);
|
lua_pushinteger(L, res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1800,10 +1825,11 @@ static int str_unpack (lua_State *L) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: {
|
case Kstring: {
|
||||||
size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
|
lua_Unsigned len = (lua_Unsigned)unpackint(L, data + pos,
|
||||||
|
h.islittle, cast_int(size), 0);
|
||||||
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
||||||
lua_pushlstring(L, data + pos + size, len);
|
lua_pushlstring(L, data + pos + size, cast_sizet(len));
|
||||||
pos += len; /* skip string */
|
pos += cast_sizet(len); /* skip string */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kzstr: {
|
case Kzstr: {
|
||||||
@@ -1820,7 +1846,7 @@ static int str_unpack (lua_State *L) {
|
|||||||
}
|
}
|
||||||
pos += size;
|
pos += size;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, pos + 1); /* next position */
|
lua_pushinteger(L, cast_st2S(pos) + 1); /* next position */
|
||||||
return n + 1;
|
return n + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,21 @@
|
|||||||
** may have any of these metamethods. (First access that fails after the
|
** may have any of these metamethods. (First access that fails after the
|
||||||
** clearing will set the bit again.)
|
** clearing will set the bit again.)
|
||||||
*/
|
*/
|
||||||
#define invalidateTMcache(t) ((t)->flags &= ~maskflags)
|
#define invalidateTMcache(t) ((t)->flags &= cast_byte(~maskflags))
|
||||||
|
|
||||||
|
|
||||||
/* true when 't' is using 'dummynode' as its hash part */
|
/*
|
||||||
#define isdummy(t) ((t)->lastfree == NULL)
|
** Bit BITDUMMY set in 'flags' means the table is using the dummy node
|
||||||
|
** for its hash part.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BITDUMMY (1 << 6)
|
||||||
|
#define NOTBITDUMMY cast_byte(~BITDUMMY)
|
||||||
|
#define isdummy(t) ((t)->flags & BITDUMMY)
|
||||||
|
|
||||||
|
#define setnodummy(t) ((t)->flags &= NOTBITDUMMY)
|
||||||
|
#define setdummy(t) ((t)->flags |= BITDUMMY)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* allocated size for hash nodes */
|
/* allocated size for hash nodes */
|
||||||
@@ -35,31 +45,139 @@
|
|||||||
#define nodefromval(v) cast(Node *, (v))
|
#define nodefromval(v) cast(Node *, (v))
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
|
|
||||||
|
#define luaH_fastgeti(t,k,res,tag) \
|
||||||
|
{ Table *h = t; lua_Unsigned u = l_castS2U(k) - 1u; \
|
||||||
|
if ((u < h->asize)) { \
|
||||||
|
tag = *getArrTag(h, u); \
|
||||||
|
if (!tagisempty(tag)) { farr2val(h, u, tag, res); }} \
|
||||||
|
else { tag = luaH_getint(h, (k), res); }}
|
||||||
|
|
||||||
|
|
||||||
|
#define luaH_fastseti(t,k,val,hres) \
|
||||||
|
{ Table *h = t; lua_Unsigned u = l_castS2U(k) - 1u; \
|
||||||
|
if ((u < h->asize)) { \
|
||||||
|
lu_byte *tag = getArrTag(h, u); \
|
||||||
|
if (checknoTM(h->metatable, TM_NEWINDEX) || !tagisempty(*tag)) \
|
||||||
|
{ fval2arr(h, u, tag, val); hres = HOK; } \
|
||||||
|
else hres = ~cast_int(u); } \
|
||||||
|
else { hres = luaH_psetint(h, k, val); }}
|
||||||
|
|
||||||
|
|
||||||
|
/* results from pset */
|
||||||
|
#define HOK 0
|
||||||
|
#define HNOTFOUND 1
|
||||||
|
#define HNOTATABLE 2
|
||||||
|
#define HFIRSTNODE 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 'luaH_get*' operations set 'res', unless the value is absent, and
|
||||||
|
** return the tag of the result.
|
||||||
|
** The 'luaH_pset*' (pre-set) operations set the given value and return
|
||||||
|
** HOK, unless the original value is absent. In that case, if the key
|
||||||
|
** is really absent, they return HNOTFOUND. Otherwise, if there is a
|
||||||
|
** slot with that key but with no value, 'luaH_pset*' return an encoding
|
||||||
|
** of where the key is (usually called 'hres'). (pset cannot set that
|
||||||
|
** value because there might be a metamethod.) If the slot is in the
|
||||||
|
** hash part, the encoding is (HFIRSTNODE + hash index); if the slot is
|
||||||
|
** in the array part, the encoding is (~array index), a negative value.
|
||||||
|
** The value HNOTATABLE is used by the fast macros to signal that the
|
||||||
|
** value being indexed is not a table.
|
||||||
|
** (The size for the array part is limited by the maximum power of two
|
||||||
|
** that fits in an unsigned integer; that is INT_MAX+1. So, the C-index
|
||||||
|
** ranges from 0, which encodes to -1, to INT_MAX, which encodes to
|
||||||
|
** INT_MIN. The size of the hash part is limited by the maximum power of
|
||||||
|
** two that fits in a signed integer; that is (INT_MAX+1)/2. So, it is
|
||||||
|
** safe to add HFIRSTNODE to any index there.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The array part of a table is represented by an inverted array of
|
||||||
|
** values followed by an array of tags, to avoid wasting space with
|
||||||
|
** padding. In between them there is an unsigned int, explained later.
|
||||||
|
** The 'array' pointer points between the two arrays, so that values are
|
||||||
|
** indexed with negative indices and tags with non-negative indices.
|
||||||
|
|
||||||
|
Values Tags
|
||||||
|
--------------------------------------------------------
|
||||||
|
... | Value 1 | Value 0 |unsigned|0|1|...
|
||||||
|
--------------------------------------------------------
|
||||||
|
^ t->array
|
||||||
|
|
||||||
|
** All accesses to 't->array' should be through the macros 'getArrTag'
|
||||||
|
** and 'getArrVal'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Computes the address of the tag for the abstract C-index 'k' */
|
||||||
|
#define getArrTag(t,k) (cast(lu_byte*, (t)->array) + sizeof(unsigned) + (k))
|
||||||
|
|
||||||
|
/* Computes the address of the value for the abstract C-index 'k' */
|
||||||
|
#define getArrVal(t,k) ((t)->array - 1 - (k))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The unsigned between the two arrays is used as a hint for #t;
|
||||||
|
** see luaH_getn. It is stored there to avoid wasting space in
|
||||||
|
** the structure Table for tables with no array part.
|
||||||
|
*/
|
||||||
|
#define lenhint(t) cast(unsigned*, (t)->array)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Move TValues to/from arrays, using C indices
|
||||||
|
*/
|
||||||
|
#define arr2obj(h,k,val) \
|
||||||
|
((val)->tt_ = *getArrTag(h,(k)), (val)->value_ = *getArrVal(h,(k)))
|
||||||
|
|
||||||
|
#define obj2arr(h,k,val) \
|
||||||
|
(*getArrTag(h,(k)) = (val)->tt_, *getArrVal(h,(k)) = (val)->value_)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Often, we need to check the tag of a value before moving it. The
|
||||||
|
** following macros also move TValues to/from arrays, but receive the
|
||||||
|
** precomputed tag value or address as an extra argument.
|
||||||
|
*/
|
||||||
|
#define farr2val(h,k,tag,res) \
|
||||||
|
((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)))
|
||||||
|
|
||||||
|
#define fval2arr(h,k,tag,val) \
|
||||||
|
(*tag = (val)->tt_, *getArrVal(h,(k)) = (val)->value_)
|
||||||
|
|
||||||
|
|
||||||
|
LUAI_FUNC lu_byte luaH_get (Table *t, const TValue *key, TValue *res);
|
||||||
|
LUAI_FUNC lu_byte luaH_getshortstr (Table *t, TString *key, TValue *res);
|
||||||
|
LUAI_FUNC lu_byte luaH_getstr (Table *t, TString *key, TValue *res);
|
||||||
|
LUAI_FUNC lu_byte luaH_getint (Table *t, lua_Integer key, TValue *res);
|
||||||
|
|
||||||
|
/* Special get for metamethods */
|
||||||
|
LUAI_FUNC const TValue *luaH_Hgetshortstr (Table *t, TString *key);
|
||||||
|
|
||||||
|
LUAI_FUNC int luaH_psetint (Table *t, lua_Integer key, TValue *val);
|
||||||
|
LUAI_FUNC int luaH_psetshortstr (Table *t, TString *key, TValue *val);
|
||||||
|
LUAI_FUNC int luaH_psetstr (Table *t, TString *key, TValue *val);
|
||||||
|
LUAI_FUNC int luaH_pset (Table *t, const TValue *key, TValue *val);
|
||||||
|
|
||||||
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
||||||
TValue *value);
|
TValue *value);
|
||||||
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
|
|
||||||
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
|
|
||||||
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
|
|
||||||
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
|
||||||
TValue *value);
|
|
||||||
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
|
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
|
||||||
TValue *value);
|
TValue *value);
|
||||||
|
|
||||||
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
||||||
const TValue *slot, TValue *value);
|
TValue *value, int hres);
|
||||||
LUAI_FUNC Table *luaH_new (lua_State *L);
|
LUAI_FUNC Table *luaH_new (lua_State *L);
|
||||||
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
|
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned nasize,
|
||||||
unsigned int nhsize);
|
unsigned nhsize);
|
||||||
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
|
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned nasize);
|
||||||
|
LUAI_FUNC lu_mem luaH_size (Table *t);
|
||||||
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
|
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
|
||||||
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
|
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
|
||||||
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
|
LUAI_FUNC lua_Unsigned luaH_getn (lua_State *L, Table *t);
|
||||||
LUAI_FUNC unsigned int luaH_realasize (const Table *t);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_DEBUG)
|
#if defined(LUA_DEBUG)
|
||||||
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
|
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
|
||||||
LUAI_FUNC int luaH_isdummy (const Table *t);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -41,15 +42,17 @@ static int checkfield (lua_State *L, const char *key, int n) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Check that 'arg' either is a table or can behave like one (that is,
|
** Check that 'arg' either is a table or can behave like one (that is,
|
||||||
** has a metatable with the required metamethods)
|
** has a metatable with the required metamethods).
|
||||||
*/
|
*/
|
||||||
static void checktab (lua_State *L, int arg, int what) {
|
static void checktab (lua_State *L, int arg, int what) {
|
||||||
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
|
int tp = lua_type(L, arg);
|
||||||
|
if (tp != LUA_TTABLE) { /* is it not a table? */
|
||||||
int n = 1; /* number of elements to pop */
|
int n = 1; /* number of elements to pop */
|
||||||
if (lua_getmetatable(L, arg) && /* must have metatable */
|
if (lua_getmetatable(L, arg) && /* must have metatable */
|
||||||
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
|
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
|
||||||
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
|
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
|
||||||
(!(what & TAB_L) || checkfield(L, "__len", ++n))) {
|
(!(what & TAB_L) || /* strings don't need '__len' to have a length */
|
||||||
|
tp == LUA_TSTRING || checkfield(L, "__len", ++n))) {
|
||||||
lua_pop(L, n); /* pop metatable and tested metamethods */
|
lua_pop(L, n); /* pop metatable and tested metamethods */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -58,6 +61,16 @@ static void checktab (lua_State *L, int arg, int what) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int tcreate (lua_State *L) {
|
||||||
|
lua_Unsigned sizeseq = (lua_Unsigned)luaL_checkinteger(L, 1);
|
||||||
|
lua_Unsigned sizerest = (lua_Unsigned)luaL_optinteger(L, 2, 0);
|
||||||
|
luaL_argcheck(L, sizeseq <= cast_uint(INT_MAX), 1, "out of range");
|
||||||
|
luaL_argcheck(L, sizerest <= cast_uint(INT_MAX), 2, "out of range");
|
||||||
|
lua_createtable(L, cast_int(sizeseq), cast_int(sizerest));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int tinsert (lua_State *L) {
|
static int tinsert (lua_State *L) {
|
||||||
lua_Integer pos; /* where to insert new element */
|
lua_Integer pos; /* where to insert new element */
|
||||||
lua_Integer e = aux_getn(L, 1, TAB_RW);
|
lua_Integer e = aux_getn(L, 1, TAB_RW);
|
||||||
@@ -93,7 +106,7 @@ static int tremove (lua_State *L) {
|
|||||||
lua_Integer pos = luaL_optinteger(L, 2, size);
|
lua_Integer pos = luaL_optinteger(L, 2, size);
|
||||||
if (pos != size) /* validate 'pos' if given */
|
if (pos != size) /* validate 'pos' if given */
|
||||||
/* check whether 'pos' is in [1, size + 1] */
|
/* check whether 'pos' is in [1, size + 1] */
|
||||||
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
|
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
|
||||||
"position out of bounds");
|
"position out of bounds");
|
||||||
lua_geti(L, 1, pos); /* result = t[pos] */
|
lua_geti(L, 1, pos); /* result = t[pos] */
|
||||||
for ( ; pos < size; pos++) {
|
for ( ; pos < size; pos++) {
|
||||||
@@ -193,10 +206,11 @@ static int tpack (lua_State *L) {
|
|||||||
|
|
||||||
static int tunpack (lua_State *L) {
|
static int tunpack (lua_State *L) {
|
||||||
lua_Unsigned n;
|
lua_Unsigned n;
|
||||||
|
lua_Integer len = aux_getn(L, 1, TAB_R);
|
||||||
lua_Integer i = luaL_optinteger(L, 2, 1);
|
lua_Integer i = luaL_optinteger(L, 2, 1);
|
||||||
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, len);
|
||||||
if (i > e) return 0; /* empty range */
|
if (i > e) return 0; /* empty range */
|
||||||
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
|
n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */
|
||||||
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
||||||
!lua_checkstack(L, (int)(++n))))
|
!lua_checkstack(L, (int)(++n))))
|
||||||
return luaL_error(L, "too many results to unpack");
|
return luaL_error(L, "too many results to unpack");
|
||||||
@@ -220,41 +234,26 @@ static int tunpack (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* type for array indices */
|
/*
|
||||||
|
** Type for array indices. These indices are always limited by INT_MAX,
|
||||||
|
** so it is safe to cast them to lua_Integer even for Lua 32 bits.
|
||||||
|
*/
|
||||||
typedef unsigned int IdxT;
|
typedef unsigned int IdxT;
|
||||||
|
|
||||||
|
|
||||||
|
/* Versions of lua_seti/lua_geti specialized for IdxT */
|
||||||
|
#define geti(L,idt,idx) lua_geti(L, idt, l_castU2S(idx))
|
||||||
|
#define seti(L,idt,idx) lua_seti(L, idt, l_castU2S(idx))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Produce a "random" 'unsigned int' to randomize pivot choice. This
|
** Produce a "random" 'unsigned int' to randomize pivot choice. This
|
||||||
** macro is used only when 'sort' detects a big imbalance in the result
|
** macro is used only when 'sort' detects a big imbalance in the result
|
||||||
** of a partition. (If you don't want/need this "randomness", ~0 is a
|
** of a partition. (If you don't want/need this "randomness", ~0 is a
|
||||||
** good choice.)
|
** good choice.)
|
||||||
*/
|
*/
|
||||||
#if !defined(l_randomizePivot) /* { */
|
#if !defined(l_randomizePivot)
|
||||||
|
#define l_randomizePivot(L) luaL_makeseed(L)
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
/* size of 'e' measured in number of 'unsigned int's */
|
|
||||||
#define sof(e) (sizeof(e) / sizeof(unsigned int))
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Use 'time' and 'clock' as sources of "randomness". Because we don't
|
|
||||||
** know the types 'clock_t' and 'time_t', we cannot cast them to
|
|
||||||
** anything without risking overflows. A safe way to use their values
|
|
||||||
** is to copy them to an array of a known type and use the array values.
|
|
||||||
*/
|
|
||||||
static unsigned int l_randomizePivot (void) {
|
|
||||||
clock_t c = clock();
|
|
||||||
time_t t = time(NULL);
|
|
||||||
unsigned int buff[sof(c) + sof(t)];
|
|
||||||
unsigned int i, rnd = 0;
|
|
||||||
memcpy(buff, &c, sof(c) * sizeof(unsigned int));
|
|
||||||
memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
|
|
||||||
for (i = 0; i < sof(buff); i++)
|
|
||||||
rnd += buff[i];
|
|
||||||
return rnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
|
||||||
@@ -263,8 +262,8 @@ static unsigned int l_randomizePivot (void) {
|
|||||||
|
|
||||||
|
|
||||||
static void set2 (lua_State *L, IdxT i, IdxT j) {
|
static void set2 (lua_State *L, IdxT i, IdxT j) {
|
||||||
lua_seti(L, 1, i);
|
seti(L, 1, i);
|
||||||
lua_seti(L, 1, j);
|
seti(L, 1, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -301,15 +300,15 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
|
|||||||
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
|
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* next loop: repeat ++i while a[i] < P */
|
/* next loop: repeat ++i while a[i] < P */
|
||||||
while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
while ((void)geti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
||||||
if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */
|
if (l_unlikely(i == up - 1)) /* a[up - 1] < P == a[up - 1] */
|
||||||
luaL_error(L, "invalid order function for sorting");
|
luaL_error(L, "invalid order function for sorting");
|
||||||
lua_pop(L, 1); /* remove a[i] */
|
lua_pop(L, 1); /* remove a[i] */
|
||||||
}
|
}
|
||||||
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
|
/* after the loop, a[i] >= P and a[lo .. i - 1] < P (a) */
|
||||||
/* next loop: repeat --j while P < a[j] */
|
/* next loop: repeat --j while P < a[j] */
|
||||||
while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
|
while ((void)geti(L, 1, --j), sort_comp(L, -3, -1)) {
|
||||||
if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */
|
if (l_unlikely(j < i)) /* j <= i - 1 and a[j] > P, contradicts (a) */
|
||||||
luaL_error(L, "invalid order function for sorting");
|
luaL_error(L, "invalid order function for sorting");
|
||||||
lua_pop(L, 1); /* remove a[j] */
|
lua_pop(L, 1); /* remove a[j] */
|
||||||
}
|
}
|
||||||
@@ -333,7 +332,7 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
|
|||||||
*/
|
*/
|
||||||
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
|
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
|
||||||
IdxT r4 = (up - lo) / 4; /* range/4 */
|
IdxT r4 = (up - lo) / 4; /* range/4 */
|
||||||
IdxT p = rnd % (r4 * 2) + (lo + r4);
|
IdxT p = (rnd ^ lo ^ up) % (r4 * 2) + (lo + r4);
|
||||||
lua_assert(lo + r4 <= p && p <= up - r4);
|
lua_assert(lo + r4 <= p && p <= up - r4);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -342,14 +341,13 @@ static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
|
|||||||
/*
|
/*
|
||||||
** Quicksort algorithm (recursive function)
|
** Quicksort algorithm (recursive function)
|
||||||
*/
|
*/
|
||||||
static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
static void auxsort (lua_State *L, IdxT lo, IdxT up, unsigned rnd) {
|
||||||
unsigned int rnd) {
|
|
||||||
while (lo < up) { /* loop for tail recursion */
|
while (lo < up) { /* loop for tail recursion */
|
||||||
IdxT p; /* Pivot index */
|
IdxT p; /* Pivot index */
|
||||||
IdxT n; /* to be used later */
|
IdxT n; /* to be used later */
|
||||||
/* sort elements 'lo', 'p', and 'up' */
|
/* sort elements 'lo', 'p', and 'up' */
|
||||||
lua_geti(L, 1, lo);
|
geti(L, 1, lo);
|
||||||
lua_geti(L, 1, up);
|
geti(L, 1, up);
|
||||||
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
|
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
|
||||||
set2(L, lo, up); /* swap a[lo] - a[up] */
|
set2(L, lo, up); /* swap a[lo] - a[up] */
|
||||||
else
|
else
|
||||||
@@ -360,13 +358,13 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
|||||||
p = (lo + up)/2; /* middle element is a good pivot */
|
p = (lo + up)/2; /* middle element is a good pivot */
|
||||||
else /* for larger intervals, it is worth a random pivot */
|
else /* for larger intervals, it is worth a random pivot */
|
||||||
p = choosePivot(lo, up, rnd);
|
p = choosePivot(lo, up, rnd);
|
||||||
lua_geti(L, 1, p);
|
geti(L, 1, p);
|
||||||
lua_geti(L, 1, lo);
|
geti(L, 1, lo);
|
||||||
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
|
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
|
||||||
set2(L, p, lo); /* swap a[p] - a[lo] */
|
set2(L, p, lo); /* swap a[p] - a[lo] */
|
||||||
else {
|
else {
|
||||||
lua_pop(L, 1); /* remove a[lo] */
|
lua_pop(L, 1); /* remove a[lo] */
|
||||||
lua_geti(L, 1, up);
|
geti(L, 1, up);
|
||||||
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
|
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
|
||||||
set2(L, p, up); /* swap a[up] - a[p] */
|
set2(L, p, up); /* swap a[up] - a[p] */
|
||||||
else
|
else
|
||||||
@@ -374,9 +372,9 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
|||||||
}
|
}
|
||||||
if (up - lo == 2) /* only 3 elements? */
|
if (up - lo == 2) /* only 3 elements? */
|
||||||
return; /* already sorted */
|
return; /* already sorted */
|
||||||
lua_geti(L, 1, p); /* get middle element (Pivot) */
|
geti(L, 1, p); /* get middle element (Pivot) */
|
||||||
lua_pushvalue(L, -1); /* push Pivot */
|
lua_pushvalue(L, -1); /* push Pivot */
|
||||||
lua_geti(L, 1, up - 1); /* push a[up - 1] */
|
geti(L, 1, up - 1); /* push a[up - 1] */
|
||||||
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
|
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
|
||||||
p = partition(L, lo, up);
|
p = partition(L, lo, up);
|
||||||
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
|
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
|
||||||
@@ -391,7 +389,7 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
|||||||
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
|
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
|
||||||
}
|
}
|
||||||
if ((up - lo) / 128 > n) /* partition too imbalanced? */
|
if ((up - lo) / 128 > n) /* partition too imbalanced? */
|
||||||
rnd = l_randomizePivot(); /* try a new randomization */
|
rnd = l_randomizePivot(L); /* try a new randomization */
|
||||||
} /* tail call auxsort(L, lo, up, rnd) */
|
} /* tail call auxsort(L, lo, up, rnd) */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,6 +411,7 @@ static int sort (lua_State *L) {
|
|||||||
|
|
||||||
static const luaL_Reg tab_funcs[] = {
|
static const luaL_Reg tab_funcs[] = {
|
||||||
{"concat", tconcat},
|
{"concat", tconcat},
|
||||||
|
{"create", tcreate},
|
||||||
{"insert", tinsert},
|
{"insert", tinsert},
|
||||||
{"pack", tpack},
|
{"pack", tpack},
|
||||||
{"unpack", tunpack},
|
{"unpack", tunpack},
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
|
|
||||||
/* test Lua with compatibility code */
|
/* test Lua with compatibility code */
|
||||||
#define LUA_COMPAT_MATHLIB
|
#define LUA_COMPAT_MATHLIB
|
||||||
#define LUA_COMPAT_LT_LE
|
#undef LUA_COMPAT_GLOBAL
|
||||||
|
#define LUA_COMPAT_GLOBAL 0
|
||||||
|
|
||||||
|
|
||||||
#define LUA_DEBUG
|
#define LUA_DEBUG
|
||||||
@@ -44,6 +45,10 @@
|
|||||||
#define LUA_RAND32
|
#define LUA_RAND32
|
||||||
|
|
||||||
|
|
||||||
|
/* test stack reallocation without strict address use */
|
||||||
|
#define LUAI_STRICT_ADDRESS 0
|
||||||
|
|
||||||
|
|
||||||
/* memory-allocator control variables */
|
/* memory-allocator control variables */
|
||||||
typedef struct Memcontrol {
|
typedef struct Memcontrol {
|
||||||
int failnext;
|
int failnext;
|
||||||
@@ -58,23 +63,39 @@ typedef struct Memcontrol {
|
|||||||
LUA_API Memcontrol l_memcontrol;
|
LUA_API Memcontrol l_memcontrol;
|
||||||
|
|
||||||
|
|
||||||
|
#define luai_tracegc(L,f) luai_tracegctest(L, f)
|
||||||
|
extern void luai_tracegctest (lua_State *L, int first);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** generic variable for debug tricks
|
** generic variable for debug tricks
|
||||||
*/
|
*/
|
||||||
extern void *l_Trick;
|
extern void *l_Trick;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function to traverse and check all memory used by Lua
|
** Function to traverse and check all memory used by Lua
|
||||||
*/
|
*/
|
||||||
LUAI_FUNC int lua_checkmemory (lua_State *L);
|
extern int lua_checkmemory (lua_State *L);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function to print an object GC-friendly
|
** Function to print an object GC-friendly
|
||||||
*/
|
*/
|
||||||
struct GCObject;
|
struct GCObject;
|
||||||
LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o);
|
extern void lua_printobj (lua_State *L, struct GCObject *o);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Function to print a value
|
||||||
|
*/
|
||||||
|
struct TValue;
|
||||||
|
extern void lua_printvalue (struct TValue *v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Function to print the stack
|
||||||
|
*/
|
||||||
|
extern void lua_printstack (lua_State *L);
|
||||||
|
extern int lua_printallstack (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
/* test for lock/unlock */
|
/* test for lock/unlock */
|
||||||
@@ -101,13 +122,14 @@ LUA_API int luaB_opentests (lua_State *L);
|
|||||||
LUA_API void *debug_realloc (void *ud, void *block,
|
LUA_API void *debug_realloc (void *ud, void *block,
|
||||||
size_t osize, size_t nsize);
|
size_t osize, size_t nsize);
|
||||||
|
|
||||||
#if defined(lua_c)
|
|
||||||
#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
|
#define luaL_newstate() \
|
||||||
#define luaL_openlibs(L) \
|
lua_newstate(debug_realloc, &l_memcontrol, luaL_makeseed(NULL))
|
||||||
{ (luaL_openlibs)(L); \
|
#define luai_openlibs(L) \
|
||||||
|
{ luaL_openlibs(L); \
|
||||||
luaL_requiref(L, "T", luaB_opentests, 1); \
|
luaL_requiref(L, "T", luaB_opentests, 1); \
|
||||||
lua_pop(L, 1); }
|
lua_pop(L, 1); }
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -121,13 +143,14 @@ LUA_API void *debug_realloc (void *ud, void *block,
|
|||||||
#define STRCACHE_N 23
|
#define STRCACHE_N 23
|
||||||
#define STRCACHE_M 5
|
#define STRCACHE_M 5
|
||||||
|
|
||||||
#undef LUAI_USER_ALIGNMENT_T
|
#define MAXINDEXRK 1
|
||||||
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
|
|
||||||
|
|
||||||
|
|
||||||
/* make stack-overflow tests run faster */
|
/*
|
||||||
#undef LUAI_MAXSTACK
|
** Reduce maximum stack size to make stack-overflow tests run faster.
|
||||||
#define LUAI_MAXSTACK 50000
|
** (But value is still large enough to overflow smaller integers.)
|
||||||
|
*/
|
||||||
|
#define LUAI_MAXSTACK 68000
|
||||||
|
|
||||||
|
|
||||||
/* test mode uses more stack space */
|
/* test mode uses more stack space */
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ void luaT_init (lua_State *L) {
|
|||||||
** tag methods
|
** tag methods
|
||||||
*/
|
*/
|
||||||
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
|
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
|
||||||
const TValue *tm = luaH_getshortstr(events, ename);
|
const TValue *tm = luaH_Hgetshortstr(events, ename);
|
||||||
lua_assert(event <= TM_EQ);
|
lua_assert(event <= TM_EQ);
|
||||||
if (notm(tm)) { /* no tag method? */
|
if (notm(tm)) { /* no tag method? */
|
||||||
events->flags |= cast_byte(1u<<event); /* cache this fact */
|
events->flags |= cast_byte(1u<<event); /* cache this fact */
|
||||||
@@ -80,7 +80,7 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
|
|||||||
default:
|
default:
|
||||||
mt = G(L)->mt[ttype(o)];
|
mt = G(L)->mt[ttype(o)];
|
||||||
}
|
}
|
||||||
return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue);
|
return (mt ? luaH_Hgetshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
|
|||||||
Table *mt;
|
Table *mt;
|
||||||
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
|
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
|
||||||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
|
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
|
||||||
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
|
const TValue *name = luaH_Hgetshortstr(mt, luaS_new(L, "__name"));
|
||||||
if (ttisstring(name)) /* is '__name' a string? */
|
if (ttisstring(name)) /* is '__name' a string? */
|
||||||
return getstr(tsvalue(name)); /* use it as type name */
|
return getstr(tsvalue(name)); /* use it as type name */
|
||||||
}
|
}
|
||||||
@@ -102,12 +102,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
|
|||||||
|
|
||||||
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
const TValue *p2, const TValue *p3) {
|
const TValue *p2, const TValue *p3) {
|
||||||
StkId func = L->top;
|
StkId func = L->top.p;
|
||||||
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||||
setobj2s(L, func + 1, p1); /* 1st argument */
|
setobj2s(L, func + 1, p1); /* 1st argument */
|
||||||
setobj2s(L, func + 2, p2); /* 2nd argument */
|
setobj2s(L, func + 2, p2); /* 2nd argument */
|
||||||
setobj2s(L, func + 3, p3); /* 3rd argument */
|
setobj2s(L, func + 3, p3); /* 3rd argument */
|
||||||
L->top = func + 4;
|
L->top.p = func + 4;
|
||||||
/* metamethod may yield only when called from Lua code */
|
/* metamethod may yield only when called from Lua code */
|
||||||
if (isLuacode(L->ci))
|
if (isLuacode(L->ci))
|
||||||
luaD_call(L, func, 0);
|
luaD_call(L, func, 0);
|
||||||
@@ -116,21 +116,22 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
|
lu_byte luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
const TValue *p2, StkId res) {
|
const TValue *p2, StkId res) {
|
||||||
ptrdiff_t result = savestack(L, res);
|
ptrdiff_t result = savestack(L, res);
|
||||||
StkId func = L->top;
|
StkId func = L->top.p;
|
||||||
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||||
setobj2s(L, func + 1, p1); /* 1st argument */
|
setobj2s(L, func + 1, p1); /* 1st argument */
|
||||||
setobj2s(L, func + 2, p2); /* 2nd argument */
|
setobj2s(L, func + 2, p2); /* 2nd argument */
|
||||||
L->top += 3;
|
L->top.p += 3;
|
||||||
/* metamethod may yield only when called from Lua code */
|
/* metamethod may yield only when called from Lua code */
|
||||||
if (isLuacode(L->ci))
|
if (isLuacode(L->ci))
|
||||||
luaD_call(L, func, 1);
|
luaD_call(L, func, 1);
|
||||||
else
|
else
|
||||||
luaD_callnoyield(L, func, 1);
|
luaD_callnoyield(L, func, 1);
|
||||||
res = restorestack(L, result);
|
res = restorestack(L, result);
|
||||||
setobjs2s(L, res, --L->top); /* move result to its place */
|
setobjs2s(L, res, --L->top.p); /* move result to its place */
|
||||||
|
return ttypetag(s2v(res)); /* return tag of the result */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,15 +140,16 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|||||||
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
|
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
|
||||||
if (notm(tm))
|
if (notm(tm))
|
||||||
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
|
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
|
||||||
if (notm(tm)) return 0;
|
if (notm(tm))
|
||||||
luaT_callTMres(L, tm, p1, p2, res);
|
return -1; /* tag method not found */
|
||||||
return 1;
|
else /* call tag method and return the tag of the result */
|
||||||
|
return luaT_callTMres(L, tm, p1, p2, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
StkId res, TMS event) {
|
StkId res, TMS event) {
|
||||||
if (l_unlikely(!callbinTM(L, p1, p2, res, event))) {
|
if (l_unlikely(callbinTM(L, p1, p2, res, event) < 0)) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case TM_BAND: case TM_BOR: case TM_BXOR:
|
case TM_BAND: case TM_BOR: case TM_BXOR:
|
||||||
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
||||||
@@ -164,11 +166,14 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The use of 'p1' after 'callbinTM' is safe because, when a tag
|
||||||
|
** method is not found, 'callbinTM' cannot change the stack.
|
||||||
|
*/
|
||||||
void luaT_tryconcatTM (lua_State *L) {
|
void luaT_tryconcatTM (lua_State *L) {
|
||||||
StkId top = L->top;
|
StkId p1 = L->top.p - 2; /* first argument */
|
||||||
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
|
if (l_unlikely(callbinTM(L, s2v(p1), s2v(p1 + 1), p1, TM_CONCAT) < 0))
|
||||||
TM_CONCAT)))
|
luaG_concaterror(L, s2v(p1), s2v(p1 + 1));
|
||||||
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -191,28 +196,12 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Calls an order tag method.
|
** Calls an order tag method.
|
||||||
** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old
|
|
||||||
** behavior: if there is no '__le', try '__lt', based on l <= r iff
|
|
||||||
** !(r < l) (assuming a total order). If the metamethod yields during
|
|
||||||
** this substitution, the continuation has to know about it (to negate
|
|
||||||
** the result of r<l); bit CIST_LEQ in the call status keeps that
|
|
||||||
** information.
|
|
||||||
*/
|
*/
|
||||||
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
|
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
TMS event) {
|
TMS event) {
|
||||||
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
|
int tag = callbinTM(L, p1, p2, L->top.p, event); /* try original event */
|
||||||
return !l_isfalse(s2v(L->top));
|
if (tag >= 0) /* found tag method? */
|
||||||
#if defined(LUA_COMPAT_LT_LE)
|
return !tagisfalse(tag);
|
||||||
else if (event == TM_LE) {
|
|
||||||
/* try '!(p2 < p1)' for '(p1 <= p2)' */
|
|
||||||
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
|
|
||||||
if (callbinTM(L, p2, p1, L->top, TM_LT)) {
|
|
||||||
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
|
|
||||||
return l_isfalse(s2v(L->top));
|
|
||||||
}
|
|
||||||
/* else error will remove this 'ci'; no need to clear mark */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
luaG_ordererror(L, p1, p2); /* no metamethod found */
|
luaG_ordererror(L, p1, p2); /* no metamethod found */
|
||||||
return 0; /* to avoid warnings */
|
return 0; /* to avoid warnings */
|
||||||
}
|
}
|
||||||
@@ -235,37 +224,141 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
/*
|
||||||
const Proto *p) {
|
** Create a vararg table at the top of the stack, with 'n' elements
|
||||||
|
** starting at 'f'.
|
||||||
|
*/
|
||||||
|
static void createvarargtab (lua_State *L, StkId f, int n) {
|
||||||
|
int i;
|
||||||
|
TValue key, value;
|
||||||
|
Table *t = luaH_new(L);
|
||||||
|
sethvalue(L, s2v(L->top.p), t);
|
||||||
|
L->top.p++;
|
||||||
|
luaH_resize(L, t, cast_uint(n), 1);
|
||||||
|
setsvalue(L, &key, luaS_new(L, "n")); /* key is "n" */
|
||||||
|
setivalue(&value, n); /* value is n */
|
||||||
|
/* No need to anchor the key: Due to the resize, the next operation
|
||||||
|
cannot trigger a garbage collection */
|
||||||
|
luaH_set(L, t, &key, &value); /* t.n = n */
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
luaH_setint(L, t, i + 1, s2v(f + i));
|
||||||
|
luaC_checkGC(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** initial stack: func arg1 ... argn extra1 ...
|
||||||
|
** ^ ci->func ^ L->top
|
||||||
|
** final stack: func nil ... nil extra1 ... func arg1 ... argn
|
||||||
|
** ^ ci->func
|
||||||
|
*/
|
||||||
|
static void buildhiddenargs (lua_State *L, CallInfo *ci, const Proto *p,
|
||||||
|
int totalargs, int nfixparams, int nextra) {
|
||||||
int i;
|
int i;
|
||||||
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
|
|
||||||
int nextra = actual - nfixparams; /* number of extra arguments */
|
|
||||||
ci->u.l.nextraargs = nextra;
|
ci->u.l.nextraargs = nextra;
|
||||||
luaD_checkstack(L, p->maxstacksize + 1);
|
luaD_checkstack(L, p->maxstacksize + 1);
|
||||||
/* copy function to the top of the stack */
|
/* copy function to the top of the stack, after extra arguments */
|
||||||
setobjs2s(L, L->top++, ci->func);
|
setobjs2s(L, L->top.p++, ci->func.p);
|
||||||
/* move fixed parameters to the top of the stack */
|
/* move fixed parameters to after the copied function */
|
||||||
for (i = 1; i <= nfixparams; i++) {
|
for (i = 1; i <= nfixparams; i++) {
|
||||||
setobjs2s(L, L->top++, ci->func + i);
|
setobjs2s(L, L->top.p++, ci->func.p + i);
|
||||||
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
|
setnilvalue2s(ci->func.p + i); /* erase original parameter (for GC) */
|
||||||
}
|
}
|
||||||
ci->func += actual + 1;
|
ci->func.p += totalargs + 1; /* 'func' now lives after hidden arguments */
|
||||||
ci->top += actual + 1;
|
ci->top.p += totalargs + 1;
|
||||||
lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
|
void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
|
||||||
int i;
|
int totalargs = cast_int(L->top.p - ci->func.p) - 1;
|
||||||
|
int nfixparams = p->numparams;
|
||||||
|
int nextra = totalargs - nfixparams; /* number of extra arguments */
|
||||||
|
if (p->flag & PF_VATAB) { /* does it need a vararg table? */
|
||||||
|
lua_assert(!(p->flag & PF_VAHID));
|
||||||
|
createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
|
||||||
|
/* move table to proper place (last parameter) */
|
||||||
|
setobjs2s(L, ci->func.p + nfixparams + 1, L->top.p - 1);
|
||||||
|
}
|
||||||
|
else { /* no table */
|
||||||
|
lua_assert(p->flag & PF_VAHID);
|
||||||
|
buildhiddenargs(L, ci, p, totalargs, nfixparams, nextra);
|
||||||
|
/* set vararg parameter to nil */
|
||||||
|
setnilvalue2s(ci->func.p + nfixparams + 1);
|
||||||
|
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc) {
|
||||||
int nextra = ci->u.l.nextraargs;
|
int nextra = ci->u.l.nextraargs;
|
||||||
if (wanted < 0) {
|
lua_Integer n;
|
||||||
wanted = nextra; /* get all extra arguments available */
|
if (tointegerns(rc, &n)) { /* integral value? */
|
||||||
checkstackGCp(L, nextra, where); /* ensure stack space */
|
if (l_castS2U(n) - 1 < cast_uint(nextra)) {
|
||||||
L->top = where + nextra; /* next instruction will need top */
|
StkId slot = ci->func.p - nextra + cast_int(n) - 1;
|
||||||
|
setobjs2s(((lua_State*)NULL), ra, slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < wanted && i < nextra; i++)
|
else if (ttisstring(rc)) { /* string value? */
|
||||||
setobjs2s(L, where + i, ci->func - nextra + i);
|
size_t len;
|
||||||
for (; i < wanted; i++) /* complete required results with nil */
|
const char *s = getlstr(tsvalue(rc), len);
|
||||||
setnilvalue(s2v(where + i));
|
if (len == 1 && s[0] == 'n') { /* key is "n"? */
|
||||||
|
setivalue(s2v(ra), nextra);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setnilvalue2s(ra); /* else produce nil */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get the number of extra arguments in a vararg function. If vararg
|
||||||
|
** table has been optimized away, that number is in the call info.
|
||||||
|
** Otherwise, get the field 'n' from the vararg table and check that it
|
||||||
|
** has a proper value (non-negative integer not larger than the stack
|
||||||
|
** limit).
|
||||||
|
*/
|
||||||
|
static int getnumargs (lua_State *L, CallInfo *ci, Table *h) {
|
||||||
|
if (h == NULL) /* no vararg table? */
|
||||||
|
return ci->u.l.nextraargs;
|
||||||
|
else {
|
||||||
|
TValue res;
|
||||||
|
if (luaH_getshortstr(h, luaS_new(L, "n"), &res) != LUA_VNUMINT ||
|
||||||
|
l_castS2U(ivalue(&res)) > cast_uint(INT_MAX/2))
|
||||||
|
luaG_runerror(L, "vararg table has no proper 'n'");
|
||||||
|
return cast_int(ivalue(&res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get 'wanted' vararg arguments and put them in 'where'. 'vatab' is
|
||||||
|
** the register of the vararg table or -1 if there is no vararg table.
|
||||||
|
*/
|
||||||
|
void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted,
|
||||||
|
int vatab) {
|
||||||
|
Table *h = (vatab < 0) ? NULL : hvalue(s2v(ci->func.p + vatab + 1));
|
||||||
|
int nargs = getnumargs(L, ci, h); /* number of available vararg args. */
|
||||||
|
int i, touse; /* 'touse' is minimum between 'wanted' and 'nargs' */
|
||||||
|
if (wanted < 0) {
|
||||||
|
touse = wanted = nargs; /* get all extra arguments available */
|
||||||
|
checkstackp(L, nargs, where); /* ensure stack space */
|
||||||
|
L->top.p = where + nargs; /* next instruction will need top */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
touse = (nargs > wanted) ? wanted : nargs;
|
||||||
|
if (h == NULL) { /* no vararg table? */
|
||||||
|
for (i = 0; i < touse; i++) /* get vararg values from the stack */
|
||||||
|
setobjs2s(L, where + i, ci->func.p - nargs + i);
|
||||||
|
}
|
||||||
|
else { /* get vararg values from vararg table */
|
||||||
|
for (i = 0; i < touse; i++) {
|
||||||
|
lu_byte tag = luaH_getint(h, i + 1, s2v(where + i));
|
||||||
|
if (tagisempty(tag))
|
||||||
|
setnilvalue2s(where + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < wanted; i++) /* complete required results with nil */
|
||||||
|
setnilvalue2s(where + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ typedef enum {
|
|||||||
/*
|
/*
|
||||||
** Mask with 1 in all fast-access methods. A 1 in any of these bits
|
** Mask with 1 in all fast-access methods. A 1 in any of these bits
|
||||||
** in the flag of a (meta)table means the metatable does not have the
|
** in the flag of a (meta)table means the metatable does not have the
|
||||||
** corresponding metamethod field. (Bit 7 of the flag is used for
|
** corresponding metamethod field. (Bit 6 of the flag indicates that
|
||||||
** 'isrealasize'.)
|
** the table is using the dummy node.)
|
||||||
*/
|
*/
|
||||||
#define maskflags (~(~0u << (TM_EQ + 1)))
|
#define maskflags cast_byte(~(~0u << (TM_EQ + 1)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -60,11 +60,12 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
#define notm(tm) ttisnil(tm)
|
#define notm(tm) ttisnil(tm)
|
||||||
|
|
||||||
|
#define checknoTM(mt,e) ((mt) == NULL || (mt)->flags & (1u<<(e)))
|
||||||
|
|
||||||
#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
|
#define gfasttm(g,mt,e) \
|
||||||
((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
|
(checknoTM(mt, e) ? NULL : luaT_gettm(mt, e, (g)->tmname[e]))
|
||||||
|
|
||||||
#define fasttm(l,et,e) gfasttm(G(l), et, e)
|
#define fasttm(l,mt,e) gfasttm(G(l), mt, e)
|
||||||
|
|
||||||
#define ttypename(x) luaT_typenames_[(x) + 1]
|
#define ttypename(x) luaT_typenames_[(x) + 1]
|
||||||
|
|
||||||
@@ -80,8 +81,8 @@ LUAI_FUNC void luaT_init (lua_State *L);
|
|||||||
|
|
||||||
LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
const TValue *p2, const TValue *p3);
|
const TValue *p2, const TValue *p3);
|
||||||
LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f,
|
LUAI_FUNC lu_byte luaT_callTMres (lua_State *L, const TValue *f,
|
||||||
const TValue *p1, const TValue *p2, StkId p3);
|
const TValue *p1, const TValue *p2, StkId p3);
|
||||||
LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
StkId res, TMS event);
|
StkId res, TMS event);
|
||||||
LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
|
LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
|
||||||
@@ -94,10 +95,11 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
|
|||||||
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||||
int inv, int isfloat, TMS event);
|
int inv, int isfloat, TMS event);
|
||||||
|
|
||||||
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
|
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
|
||||||
struct CallInfo *ci, const Proto *p);
|
const Proto *p);
|
||||||
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
|
LUAI_FUNC void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc);
|
||||||
StkId where, int wanted);
|
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where,
|
||||||
|
int wanted, int vatab);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
#if !defined(LUA_PROGNAME)
|
#if !defined(LUA_PROGNAME)
|
||||||
@@ -29,6 +30,12 @@
|
|||||||
#define LUA_INIT_VAR "LUA_INIT"
|
#define LUA_INIT_VAR "LUA_INIT"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Name of the environment variable with the name of the readline library */
|
||||||
|
#if !defined(LUA_RLLIB_VAR)
|
||||||
|
#define LUA_RLLIB_VAR "LUA_READLINELIB"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
|
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
|
||||||
|
|
||||||
|
|
||||||
@@ -115,12 +122,13 @@ static void l_message (const char *pname, const char *msg) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether 'status' is not OK and, if so, prints the error
|
** Check whether 'status' is not OK and, if so, prints the error
|
||||||
** message on the top of the stack. It assumes that the error object
|
** message on the top of the stack.
|
||||||
** is a string, as it was either generated by Lua or by 'msghandler'.
|
|
||||||
*/
|
*/
|
||||||
static int report (lua_State *L, int status) {
|
static int report (lua_State *L, int status) {
|
||||||
if (status != LUA_OK) {
|
if (status != LUA_OK) {
|
||||||
const char *msg = lua_tostring(L, -1);
|
const char *msg = lua_tostring(L, -1);
|
||||||
|
if (msg == NULL)
|
||||||
|
msg = "(error message not a string)";
|
||||||
l_message(progname, msg);
|
l_message(progname, msg);
|
||||||
lua_pop(L, 1); /* remove message */
|
lua_pop(L, 1); /* remove message */
|
||||||
}
|
}
|
||||||
@@ -177,10 +185,11 @@ static void print_version (void) {
|
|||||||
** to the script (everything after 'script') go to positive indices;
|
** to the script (everything after 'script') go to positive indices;
|
||||||
** other arguments (before the script name) go to negative indices.
|
** other arguments (before the script name) go to negative indices.
|
||||||
** If there is no script name, assume interpreter's name as base.
|
** If there is no script name, assume interpreter's name as base.
|
||||||
|
** (If there is no interpreter's name either, 'script' is -1, so
|
||||||
|
** table sizes are zero.)
|
||||||
*/
|
*/
|
||||||
static void createargtable (lua_State *L, char **argv, int argc, int script) {
|
static void createargtable (lua_State *L, char **argv, int argc, int script) {
|
||||||
int i, narg;
|
int i, narg;
|
||||||
if (script == argc) script = 0; /* no script name? */
|
|
||||||
narg = argc - (script + 1); /* number of positive indices */
|
narg = argc - (script + 1); /* number of positive indices */
|
||||||
lua_createtable(L, narg, script + 1);
|
lua_createtable(L, narg, script + 1);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
@@ -198,23 +207,28 @@ static int dochunk (lua_State *L, int status) {
|
|||||||
|
|
||||||
|
|
||||||
static int dofile (lua_State *L, const char *name) {
|
static int dofile (lua_State *L, const char *name) {
|
||||||
return dochunk(L, luaL_loadfile(L, name));
|
return dochunk(L, luaL_loadfilex(L, name, "bt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dostring (lua_State *L, const char *s, const char *name) {
|
static int dostring (lua_State *L, const char *s, const char *name) {
|
||||||
return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name));
|
return dochunk(L, luaL_loadbufferx(L, s, strlen(s), name, "t"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
|
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
|
||||||
|
** If there is no explicit modname and globname contains a '-', cut
|
||||||
|
** the suffix after '-' (the "version") to make the global name.
|
||||||
*/
|
*/
|
||||||
static int dolibrary (lua_State *L, char *globname) {
|
static int dolibrary (lua_State *L, char *globname) {
|
||||||
int status;
|
int status;
|
||||||
|
char *suffix = NULL;
|
||||||
char *modname = strchr(globname, '=');
|
char *modname = strchr(globname, '=');
|
||||||
if (modname == NULL) /* no explicit name? */
|
if (modname == NULL) { /* no explicit name? */
|
||||||
modname = globname; /* module name is equal to global name */
|
modname = globname; /* module name is equal to global name */
|
||||||
|
suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
*modname = '\0'; /* global name ends here */
|
*modname = '\0'; /* global name ends here */
|
||||||
modname++; /* module name starts after the '=' */
|
modname++; /* module name starts after the '=' */
|
||||||
@@ -222,8 +236,11 @@ static int dolibrary (lua_State *L, char *globname) {
|
|||||||
lua_getglobal(L, "require");
|
lua_getglobal(L, "require");
|
||||||
lua_pushstring(L, modname);
|
lua_pushstring(L, modname);
|
||||||
status = docall(L, 1, 1); /* call 'require(modname)' */
|
status = docall(L, 1, 1); /* call 'require(modname)' */
|
||||||
if (status == LUA_OK)
|
if (status == LUA_OK) {
|
||||||
|
if (suffix != NULL) /* is there a suffix mark? */
|
||||||
|
*suffix = '\0'; /* remove suffix from global name */
|
||||||
lua_setglobal(L, globname); /* globname = require(modname) */
|
lua_setglobal(L, globname); /* globname = require(modname) */
|
||||||
|
}
|
||||||
return report(L, status);
|
return report(L, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +266,7 @@ static int handle_script (lua_State *L, char **argv) {
|
|||||||
const char *fname = argv[0];
|
const char *fname = argv[0];
|
||||||
if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
|
if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0)
|
||||||
fname = NULL; /* stdin */
|
fname = NULL; /* stdin */
|
||||||
status = luaL_loadfile(L, fname);
|
status = luaL_loadfilex(L, fname, "bt");
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
int n = pushargs(L); /* push arguments to script */
|
int n = pushargs(L); /* push arguments to script */
|
||||||
status = docall(L, n, LUA_MULTRET);
|
status = docall(L, n, LUA_MULTRET);
|
||||||
@@ -268,14 +285,23 @@ static int handle_script (lua_State *L, char **argv) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Traverses all arguments from 'argv', returning a mask with those
|
** Traverses all arguments from 'argv', returning a mask with those
|
||||||
** needed before running any Lua code (or an error code if it finds
|
** needed before running any Lua code or an error code if it finds any
|
||||||
** any invalid argument). 'first' returns the first not-handled argument
|
** invalid argument. In case of error, 'first' is the index of the bad
|
||||||
** (either the script name or a bad argument in case of error).
|
** argument. Otherwise, 'first' is -1 if there is no program name,
|
||||||
|
** 0 if there is no script name, or the index of the script name.
|
||||||
*/
|
*/
|
||||||
static int collectargs (char **argv, int *first) {
|
static int collectargs (char **argv, int *first) {
|
||||||
int args = 0;
|
int args = 0;
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; argv[i] != NULL; i++) {
|
if (argv[0] != NULL) { /* is there a program name? */
|
||||||
|
if (argv[0][0]) /* not empty? */
|
||||||
|
progname = argv[0]; /* save it */
|
||||||
|
}
|
||||||
|
else { /* no program name */
|
||||||
|
*first = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
|
||||||
*first = i;
|
*first = i;
|
||||||
if (argv[i][0] != '-') /* not an option? */
|
if (argv[i][0] != '-') /* not an option? */
|
||||||
return args; /* stop handling options */
|
return args; /* stop handling options */
|
||||||
@@ -283,7 +309,8 @@ static int collectargs (char **argv, int *first) {
|
|||||||
case '-': /* '--' */
|
case '-': /* '--' */
|
||||||
if (argv[i][2] != '\0') /* extra characters after '--'? */
|
if (argv[i][2] != '\0') /* extra characters after '--'? */
|
||||||
return has_error; /* invalid option */
|
return has_error; /* invalid option */
|
||||||
*first = i + 1;
|
/* if there is a script name, it comes after '--' */
|
||||||
|
*first = (argv[i + 1] != NULL) ? i + 1 : 0;
|
||||||
return args;
|
return args;
|
||||||
case '\0': /* '-' */
|
case '\0': /* '-' */
|
||||||
return args; /* script "name" is '-' */
|
return args; /* script "name" is '-' */
|
||||||
@@ -316,7 +343,7 @@ static int collectargs (char **argv, int *first) {
|
|||||||
return has_error;
|
return has_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*first = i; /* no script name */
|
*first = 0; /* no script name */
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,6 +355,7 @@ static int collectargs (char **argv, int *first) {
|
|||||||
*/
|
*/
|
||||||
static int runargs (lua_State *L, char **argv, int n) {
|
static int runargs (lua_State *L, char **argv, int n) {
|
||||||
int i;
|
int i;
|
||||||
|
lua_warning(L, "@off", 0); /* by default, Lua stand-alone has warnings off */
|
||||||
for (i = 1; i < n; i++) {
|
for (i = 1; i < n; i++) {
|
||||||
int option = argv[i][1];
|
int option = argv[i][1];
|
||||||
lua_assert(argv[i][0] == '-'); /* already checked */
|
lua_assert(argv[i][0] == '-'); /* already checked */
|
||||||
@@ -352,12 +380,21 @@ static int runargs (lua_State *L, char **argv, int n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *(*l_getenv)(const char *name);
|
||||||
|
|
||||||
|
/* Function to ignore environment variables, used by option -E */
|
||||||
|
static char *no_getenv (const char *name) {
|
||||||
|
UNUSED(name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int handle_luainit (lua_State *L) {
|
static int handle_luainit (lua_State *L) {
|
||||||
const char *name = "=" LUA_INITVARVERSION;
|
const char *name = "=" LUA_INITVARVERSION;
|
||||||
const char *init = getenv(name + 1);
|
const char *init = l_getenv(name + 1);
|
||||||
if (init == NULL) {
|
if (init == NULL) {
|
||||||
name = "=" LUA_INIT_VAR;
|
name = "=" LUA_INIT_VAR;
|
||||||
init = getenv(name + 1); /* try alternative name */
|
init = l_getenv(name + 1); /* try alternative name */
|
||||||
}
|
}
|
||||||
if (init == NULL) return LUA_OK;
|
if (init == NULL) return LUA_OK;
|
||||||
else if (init[0] == '@')
|
else if (init[0] == '@')
|
||||||
@@ -412,30 +449,97 @@ static int handle_luainit (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** lua_readline defines how to show a prompt and then read a line from
|
** * lua_initreadline initializes the readline system.
|
||||||
** the standard input.
|
** * lua_readline defines how to show a prompt and then read a line from
|
||||||
** lua_saveline defines how to "save" a read line in a "history".
|
** the standard input.
|
||||||
** lua_freeline defines how to free a line read by lua_readline.
|
** * lua_saveline defines how to "save" a read line in a "history".
|
||||||
|
** * lua_freeline defines how to free a line read by lua_readline.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(lua_readline) /* { */
|
#if !defined(lua_readline) /* { */
|
||||||
|
/* Otherwise, all previously listed functions should be defined. */
|
||||||
|
|
||||||
#if defined(LUA_USE_READLINE) /* { */
|
#if defined(LUA_USE_READLINE) /* { */
|
||||||
|
/* Lua will be linked with '-lreadline' */
|
||||||
|
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
#define lua_initreadline(L) ((void)L, rl_readline_name="lua")
|
#define lua_initreadline(L) ((void)L, rl_readline_name="lua")
|
||||||
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
|
#define lua_readline(buff,prompt) ((void)buff, readline(prompt))
|
||||||
#define lua_saveline(L,line) ((void)L, add_history(line))
|
#define lua_saveline(line) add_history(line)
|
||||||
#define lua_freeline(L,b) ((void)L, free(b))
|
#define lua_freeline(line) free(line)
|
||||||
|
|
||||||
#else /* }{ */
|
#else /* }{ */
|
||||||
|
/* use dynamically loaded readline (or nothing) */
|
||||||
|
|
||||||
#define lua_initreadline(L) ((void)L)
|
/* pointer to 'readline' function (if any) */
|
||||||
#define lua_readline(L,b,p) \
|
typedef char *(*l_readlineT) (const char *prompt);
|
||||||
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
|
static l_readlineT l_readline = NULL;
|
||||||
fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
|
|
||||||
#define lua_saveline(L,line) { (void)L; (void)line; }
|
/* pointer to 'add_history' function (if any) */
|
||||||
#define lua_freeline(L,b) { (void)L; (void)b; }
|
typedef void (*l_addhistT) (const char *string);
|
||||||
|
static l_addhistT l_addhist = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static char *lua_readline (char *buff, const char *prompt) {
|
||||||
|
if (l_readline != NULL) /* is there a 'readline'? */
|
||||||
|
return (*l_readline)(prompt); /* use it */
|
||||||
|
else { /* emulate 'readline' over 'buff' */
|
||||||
|
fputs(prompt, stdout);
|
||||||
|
fflush(stdout); /* show prompt */
|
||||||
|
return fgets(buff, LUA_MAXINPUT, stdin); /* read line */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void lua_saveline (const char *line) {
|
||||||
|
if (l_addhist != NULL) /* is there an 'add_history'? */
|
||||||
|
(*l_addhist)(line); /* use it */
|
||||||
|
/* else nothing to be done */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void lua_freeline (char *line) {
|
||||||
|
if (l_readline != NULL) /* is there a 'readline'? */
|
||||||
|
free(line); /* free line created by it */
|
||||||
|
/* else 'lua_readline' used an automatic buffer; nothing to free */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_USE_DLOPEN) && defined(LUA_READLINELIB) /* { */
|
||||||
|
/* try to load 'readline' dynamically */
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static void lua_initreadline (lua_State *L) {
|
||||||
|
const char *rllib = l_getenv(LUA_RLLIB_VAR); /* name of readline library */
|
||||||
|
void *lib; /* library handle */
|
||||||
|
if (rllib == NULL) /* no environment variable? */
|
||||||
|
rllib = LUA_READLINELIB; /* use default name */
|
||||||
|
lib = dlopen(rllib, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (lib != NULL) {
|
||||||
|
const char **name = cast(const char**, dlsym(lib, "rl_readline_name"));
|
||||||
|
if (name != NULL)
|
||||||
|
*name = "lua";
|
||||||
|
l_readline = cast(l_readlineT, cast_func(dlsym(lib, "readline")));
|
||||||
|
l_addhist = cast(l_addhistT, cast_func(dlsym(lib, "add_history")));
|
||||||
|
if (l_readline != NULL) /* could load readline function? */
|
||||||
|
return; /* everything ok */
|
||||||
|
/* else emit a warning */
|
||||||
|
}
|
||||||
|
lua_warning(L, "unable to load readline library '", 1);
|
||||||
|
lua_warning(L, rllib, 1);
|
||||||
|
lua_warning(L, "'", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* }{ */
|
||||||
|
/* no dlopen or LUA_READLINELIB undefined */
|
||||||
|
|
||||||
|
/* Leave pointers with NULL */
|
||||||
|
#define lua_initreadline(L) ((void)L)
|
||||||
|
|
||||||
|
#endif /* } */
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
@@ -471,10 +575,8 @@ static int incomplete (lua_State *L, int status) {
|
|||||||
if (status == LUA_ERRSYNTAX) {
|
if (status == LUA_ERRSYNTAX) {
|
||||||
size_t lmsg;
|
size_t lmsg;
|
||||||
const char *msg = lua_tolstring(L, -1, &lmsg);
|
const char *msg = lua_tolstring(L, -1, &lmsg);
|
||||||
if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) {
|
if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0)
|
||||||
lua_pop(L, 1);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0; /* else... */
|
return 0; /* else... */
|
||||||
}
|
}
|
||||||
@@ -485,21 +587,17 @@ static int incomplete (lua_State *L, int status) {
|
|||||||
*/
|
*/
|
||||||
static int pushline (lua_State *L, int firstline) {
|
static int pushline (lua_State *L, int firstline) {
|
||||||
char buffer[LUA_MAXINPUT];
|
char buffer[LUA_MAXINPUT];
|
||||||
char *b = buffer;
|
|
||||||
size_t l;
|
size_t l;
|
||||||
const char *prmt = get_prompt(L, firstline);
|
const char *prmt = get_prompt(L, firstline);
|
||||||
int readstatus = lua_readline(L, b, prmt);
|
char *b = lua_readline(buffer, prmt);
|
||||||
if (readstatus == 0)
|
|
||||||
return 0; /* no input (prompt will be popped by caller) */
|
|
||||||
lua_pop(L, 1); /* remove prompt */
|
lua_pop(L, 1); /* remove prompt */
|
||||||
|
if (b == NULL)
|
||||||
|
return 0; /* no input */
|
||||||
l = strlen(b);
|
l = strlen(b);
|
||||||
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
||||||
b[--l] = '\0'; /* remove it */
|
b[--l] = '\0'; /* remove it */
|
||||||
if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
|
lua_pushlstring(L, b, l);
|
||||||
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
|
lua_freeline(b);
|
||||||
else
|
|
||||||
lua_pushlstring(L, b, l);
|
|
||||||
lua_freeline(L, b);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,33 +609,45 @@ static int pushline (lua_State *L, int firstline) {
|
|||||||
static int addreturn (lua_State *L) {
|
static int addreturn (lua_State *L) {
|
||||||
const char *line = lua_tostring(L, -1); /* original line */
|
const char *line = lua_tostring(L, -1); /* original line */
|
||||||
const char *retline = lua_pushfstring(L, "return %s;", line);
|
const char *retline = lua_pushfstring(L, "return %s;", line);
|
||||||
int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
|
int status = luaL_loadbufferx(L, retline, strlen(retline), "=stdin", "t");
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK)
|
||||||
lua_remove(L, -2); /* remove modified line */
|
lua_remove(L, -2); /* remove modified line */
|
||||||
if (line[0] != '\0') /* non empty? */
|
|
||||||
lua_saveline(L, line); /* keep history */
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
|
lua_pop(L, 2); /* pop result from 'luaL_loadbufferx' and modified line */
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void checklocal (const char *line) {
|
||||||
|
static const size_t szloc = sizeof("local") - 1;
|
||||||
|
static const char space[] = " \t";
|
||||||
|
line += strspn(line, space); /* skip spaces */
|
||||||
|
if (strncmp(line, "local", szloc) == 0 && /* "local"? */
|
||||||
|
strchr(space, *(line + szloc)) != NULL) { /* followed by a space? */
|
||||||
|
lua_writestringerror("%s\n",
|
||||||
|
"warning: locals do not survive across lines in interactive mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Read multiple lines until a complete Lua statement
|
** Read multiple lines until a complete Lua statement or an error not
|
||||||
|
** for an incomplete statement. Start with first line already read in
|
||||||
|
** the stack.
|
||||||
*/
|
*/
|
||||||
static int multiline (lua_State *L) {
|
static int multiline (lua_State *L) {
|
||||||
|
size_t len;
|
||||||
|
const char *line = lua_tolstring(L, 1, &len); /* get first line */
|
||||||
|
checklocal(line);
|
||||||
for (;;) { /* repeat until gets a complete statement */
|
for (;;) { /* repeat until gets a complete statement */
|
||||||
size_t len;
|
int status = luaL_loadbufferx(L, line, len, "=stdin", "t"); /* try it */
|
||||||
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
|
if (!incomplete(L, status) || !pushline(L, 0))
|
||||||
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
|
return status; /* should not or cannot try to add continuation line */
|
||||||
if (!incomplete(L, status) || !pushline(L, 0)) {
|
lua_remove(L, -2); /* remove error message (from incomplete line) */
|
||||||
lua_saveline(L, line); /* keep history */
|
|
||||||
return status; /* cannot or should not try to add continuation line */
|
|
||||||
}
|
|
||||||
lua_pushliteral(L, "\n"); /* add newline... */
|
lua_pushliteral(L, "\n"); /* add newline... */
|
||||||
lua_insert(L, -2); /* ...between the two lines */
|
lua_insert(L, -2); /* ...between the two lines */
|
||||||
lua_concat(L, 3); /* join them */
|
lua_concat(L, 3); /* join them */
|
||||||
|
line = lua_tolstring(L, 1, &len); /* get what is has */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,12 +659,16 @@ static int multiline (lua_State *L) {
|
|||||||
** in the top of the stack.
|
** in the top of the stack.
|
||||||
*/
|
*/
|
||||||
static int loadline (lua_State *L) {
|
static int loadline (lua_State *L) {
|
||||||
|
const char *line;
|
||||||
int status;
|
int status;
|
||||||
lua_settop(L, 0);
|
lua_settop(L, 0);
|
||||||
if (!pushline(L, 1))
|
if (!pushline(L, 1))
|
||||||
return -1; /* no input */
|
return -1; /* no input */
|
||||||
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
|
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
|
||||||
status = multiline(L); /* try as command, maybe with continuation lines */
|
status = multiline(L); /* try as command, maybe with continuation lines */
|
||||||
|
line = lua_tostring(L, 1);
|
||||||
|
if (line[0] != '\0') /* non empty? */
|
||||||
|
lua_saveline(line); /* keep history */
|
||||||
lua_remove(L, 1); /* remove line from the stack */
|
lua_remove(L, 1); /* remove line from the stack */
|
||||||
lua_assert(lua_gettop(L) == 1);
|
lua_assert(lua_gettop(L) == 1);
|
||||||
return status;
|
return status;
|
||||||
@@ -599,6 +713,16 @@ static void doREPL (lua_State *L) {
|
|||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
#if !defined(luai_openlibs)
|
||||||
|
#if defined(LUA_NODEBUGLIB)
|
||||||
|
/* With this option, code must require the debug library before using it */
|
||||||
|
#define luai_openlibs(L) luaL_openselectedlibs(L, ~LUA_DBLIBK, LUA_DBLIBK)
|
||||||
|
#else
|
||||||
|
/* The default is to open all standard libraries */
|
||||||
|
#define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Main body of stand-alone interpreter (to be called in protected mode).
|
** Main body of stand-alone interpreter (to be called in protected mode).
|
||||||
@@ -609,8 +733,8 @@ static int pmain (lua_State *L) {
|
|||||||
char **argv = (char **)lua_touserdata(L, 2);
|
char **argv = (char **)lua_touserdata(L, 2);
|
||||||
int script;
|
int script;
|
||||||
int args = collectargs(argv, &script);
|
int args = collectargs(argv, &script);
|
||||||
|
int optlim = (script > 0) ? script : argc; /* first argv not an option */
|
||||||
luaL_checkversion(L); /* check that interpreter has correct version */
|
luaL_checkversion(L); /* check that interpreter has correct version */
|
||||||
if (argv[0] && argv[0][0]) progname = argv[0];
|
|
||||||
if (args == has_error) { /* bad arg? */
|
if (args == has_error) { /* bad arg? */
|
||||||
print_usage(argv[script]); /* 'script' has index of bad arg. */
|
print_usage(argv[script]); /* 'script' has index of bad arg. */
|
||||||
return 0;
|
return 0;
|
||||||
@@ -618,24 +742,27 @@ static int pmain (lua_State *L) {
|
|||||||
if (args & has_v) /* option '-v'? */
|
if (args & has_v) /* option '-v'? */
|
||||||
print_version();
|
print_version();
|
||||||
if (args & has_E) { /* option '-E'? */
|
if (args & has_E) { /* option '-E'? */
|
||||||
|
l_getenv = &no_getenv; /* program will ignore environment variables */
|
||||||
lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
|
lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
|
||||||
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
|
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
|
||||||
}
|
}
|
||||||
luaL_openlibs(L); /* open standard libraries */
|
else
|
||||||
|
l_getenv = &getenv;
|
||||||
|
luai_openlibs(L); /* open standard libraries */
|
||||||
createargtable(L, argv, argc, script); /* create table 'arg' */
|
createargtable(L, argv, argc, script); /* create table 'arg' */
|
||||||
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
|
lua_gc(L, LUA_GCRESTART); /* start GC... */
|
||||||
if (!(args & has_E)) { /* no option '-E'? */
|
lua_gc(L, LUA_GCGEN); /* ...in generational mode */
|
||||||
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
|
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
|
||||||
return 0; /* error running LUA_INIT */
|
return 0; /* error running LUA_INIT */
|
||||||
}
|
if (!runargs(L, argv, optlim)) /* execute arguments -e, -l, and -W */
|
||||||
if (!runargs(L, argv, script)) /* execute arguments -e and -l */
|
|
||||||
return 0; /* something failed */
|
return 0; /* something failed */
|
||||||
if (script < argc && /* execute main script (if there is one) */
|
if (script > 0) { /* execute main script (if there is one) */
|
||||||
handle_script(L, argv + script) != LUA_OK)
|
if (handle_script(L, argv + script) != LUA_OK)
|
||||||
return 0;
|
return 0; /* interrupt in case of error */
|
||||||
|
}
|
||||||
if (args & has_i) /* -i option? */
|
if (args & has_i) /* -i option? */
|
||||||
doREPL(L); /* do read-eval-print loop */
|
doREPL(L); /* do read-eval-print loop */
|
||||||
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
|
else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
|
||||||
if (lua_stdin_is_tty()) { /* running in interactive mode? */
|
if (lua_stdin_is_tty()) { /* running in interactive mode? */
|
||||||
print_version();
|
print_version();
|
||||||
doREPL(L); /* do read-eval-print loop */
|
doREPL(L); /* do read-eval-print loop */
|
||||||
@@ -654,6 +781,7 @@ int main (int argc, char **argv) {
|
|||||||
l_message(argv[0], "cannot create state: not enough memory");
|
l_message(argv[0], "cannot create state: not enough memory");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
|
||||||
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
|
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
|
||||||
lua_pushinteger(L, argc); /* 1st argument */
|
lua_pushinteger(L, argc); /* 1st argument */
|
||||||
lua_pushlightuserdata(L, argv); /* 2nd argument */
|
lua_pushlightuserdata(L, argv); /* 2nd argument */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lua.h $
|
** $Id: lua.h $
|
||||||
** Lua - A Scripting Language
|
** Lua - A Scripting Language
|
||||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
** Lua.org, PUC-Rio, Brazil (www.lua.org)
|
||||||
** See Copyright Notice at the end of this file
|
** See Copyright Notice at the end of this file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -13,22 +13,21 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
#include "luaconf.h"
|
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2026 Lua.org, PUC-Rio"
|
||||||
|
|
||||||
|
|
||||||
#define LUA_VERSION_MAJOR "5"
|
|
||||||
#define LUA_VERSION_MINOR "4"
|
|
||||||
#define LUA_VERSION_RELEASE "4"
|
|
||||||
|
|
||||||
#define LUA_VERSION_NUM 504
|
|
||||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
|
|
||||||
|
|
||||||
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
|
||||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
|
||||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
|
|
||||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||||
|
|
||||||
|
|
||||||
|
#define LUA_VERSION_MAJOR_N 5
|
||||||
|
#define LUA_VERSION_MINOR_N 5
|
||||||
|
#define LUA_VERSION_RELEASE_N 1
|
||||||
|
|
||||||
|
#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N)
|
||||||
|
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N)
|
||||||
|
|
||||||
|
|
||||||
|
#include "luaconf.h"
|
||||||
|
|
||||||
|
|
||||||
/* mark for precompiled code ('<esc>Lua') */
|
/* mark for precompiled code ('<esc>Lua') */
|
||||||
#define LUA_SIGNATURE "\x1bLua"
|
#define LUA_SIGNATURE "\x1bLua"
|
||||||
|
|
||||||
@@ -38,10 +37,10 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Pseudo-indices
|
** Pseudo-indices
|
||||||
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
** (The stack size is limited to INT_MAX/2; we keep some free empty
|
||||||
** space after that to help overflow detection)
|
** space after that to help overflow detection.)
|
||||||
*/
|
*/
|
||||||
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
|
#define LUA_REGISTRYINDEX (-(INT_MAX/2 + 1000))
|
||||||
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
||||||
|
|
||||||
|
|
||||||
@@ -81,9 +80,10 @@ typedef struct lua_State lua_State;
|
|||||||
|
|
||||||
|
|
||||||
/* predefined values in the registry */
|
/* predefined values in the registry */
|
||||||
#define LUA_RIDX_MAINTHREAD 1
|
/* index 1 is reserved for the reference mechanism */
|
||||||
#define LUA_RIDX_GLOBALS 2
|
#define LUA_RIDX_GLOBALS 2
|
||||||
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
|
#define LUA_RIDX_MAINTHREAD 3
|
||||||
|
#define LUA_RIDX_LAST 3
|
||||||
|
|
||||||
|
|
||||||
/* type of numbers in Lua */
|
/* type of numbers in Lua */
|
||||||
@@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
|||||||
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Type used by the debug API to collect debug information
|
||||||
|
*/
|
||||||
|
typedef struct lua_Debug lua_Debug;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions to be called by the debugger in specific events
|
||||||
|
*/
|
||||||
|
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -150,10 +160,10 @@ extern const char lua_ident[];
|
|||||||
/*
|
/*
|
||||||
** state manipulation
|
** state manipulation
|
||||||
*/
|
*/
|
||||||
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud, unsigned seed);
|
||||||
LUA_API void (lua_close) (lua_State *L);
|
LUA_API void (lua_close) (lua_State *L);
|
||||||
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
||||||
LUA_API int (lua_resetthread) (lua_State *L);
|
LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
|
||||||
|
|
||||||
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
||||||
|
|
||||||
@@ -234,6 +244,8 @@ LUA_API void (lua_pushnil) (lua_State *L);
|
|||||||
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
|
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
|
||||||
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
|
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
|
||||||
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
|
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
|
||||||
|
LUA_API const char *(lua_pushexternalstring) (lua_State *L,
|
||||||
|
const char *s, size_t len, lua_Alloc falloc, void *ud);
|
||||||
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
|
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
|
||||||
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
|
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
|
||||||
va_list argp);
|
va_list argp);
|
||||||
@@ -313,7 +325,7 @@ LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** garbage-collection function and options
|
** garbage-collection options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LUA_GCSTOP 0
|
#define LUA_GCSTOP 0
|
||||||
@@ -322,11 +334,28 @@ LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
|
|||||||
#define LUA_GCCOUNT 3
|
#define LUA_GCCOUNT 3
|
||||||
#define LUA_GCCOUNTB 4
|
#define LUA_GCCOUNTB 4
|
||||||
#define LUA_GCSTEP 5
|
#define LUA_GCSTEP 5
|
||||||
#define LUA_GCSETPAUSE 6
|
#define LUA_GCISRUNNING 6
|
||||||
#define LUA_GCSETSTEPMUL 7
|
#define LUA_GCGEN 7
|
||||||
#define LUA_GCISRUNNING 9
|
#define LUA_GCINC 8
|
||||||
#define LUA_GCGEN 10
|
#define LUA_GCPARAM 9
|
||||||
#define LUA_GCINC 11
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** garbage-collection parameters
|
||||||
|
*/
|
||||||
|
/* parameters for generational mode */
|
||||||
|
#define LUA_GCPMINORMUL 0 /* control minor collections */
|
||||||
|
#define LUA_GCPMAJORMINOR 1 /* control shift major->minor */
|
||||||
|
#define LUA_GCPMINORMAJOR 2 /* control shift minor->major */
|
||||||
|
|
||||||
|
/* parameters for incremental mode */
|
||||||
|
#define LUA_GCPPAUSE 3 /* size of pause between successive GCs */
|
||||||
|
#define LUA_GCPSTEPMUL 4 /* GC "speed" */
|
||||||
|
#define LUA_GCPSTEPSIZE 5 /* GC granularity */
|
||||||
|
|
||||||
|
/* number of parameters */
|
||||||
|
#define LUA_GCPN 6
|
||||||
|
|
||||||
|
|
||||||
LUA_API int (lua_gc) (lua_State *L, int what, ...);
|
LUA_API int (lua_gc) (lua_State *L, int what, ...);
|
||||||
|
|
||||||
@@ -342,7 +371,9 @@ LUA_API int (lua_next) (lua_State *L, int idx);
|
|||||||
LUA_API void (lua_concat) (lua_State *L, int n);
|
LUA_API void (lua_concat) (lua_State *L, int n);
|
||||||
LUA_API void (lua_len) (lua_State *L, int idx);
|
LUA_API void (lua_len) (lua_State *L, int idx);
|
||||||
|
|
||||||
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
|
#define LUA_N2SBUFFSZ 64
|
||||||
|
LUA_API unsigned (lua_numbertocstring) (lua_State *L, int idx, char *buff);
|
||||||
|
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
|
||||||
|
|
||||||
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
||||||
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
||||||
@@ -401,19 +432,12 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
|
|||||||
** compatibility macros
|
** compatibility macros
|
||||||
** ===============================================================
|
** ===============================================================
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_COMPAT_APIINTCASTS)
|
|
||||||
|
|
||||||
#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
|
|
||||||
#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
|
|
||||||
#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
|
#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
|
||||||
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
||||||
#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
||||||
|
|
||||||
#define LUA_NUMTAGS LUA_NUMTYPES
|
#define lua_resetthread(L) lua_closethread(L,NULL)
|
||||||
|
|
||||||
/* }============================================================== */
|
/* }============================================================== */
|
||||||
|
|
||||||
@@ -442,12 +466,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
|
|||||||
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||||
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||||
|
|
||||||
typedef struct lua_Debug lua_Debug; /* activation record */
|
|
||||||
|
|
||||||
|
|
||||||
/* Functions to be called by the debugger in specific events */
|
|
||||||
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
|
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
|
||||||
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
|
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
|
||||||
@@ -465,7 +483,6 @@ LUA_API lua_Hook (lua_gethook) (lua_State *L);
|
|||||||
LUA_API int (lua_gethookmask) (lua_State *L);
|
LUA_API int (lua_gethookmask) (lua_State *L);
|
||||||
LUA_API int (lua_gethookcount) (lua_State *L);
|
LUA_API int (lua_gethookcount) (lua_State *L);
|
||||||
|
|
||||||
LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit);
|
|
||||||
|
|
||||||
struct lua_Debug {
|
struct lua_Debug {
|
||||||
int event;
|
int event;
|
||||||
@@ -480,9 +497,10 @@ struct lua_Debug {
|
|||||||
unsigned char nups; /* (u) number of upvalues */
|
unsigned char nups; /* (u) number of upvalues */
|
||||||
unsigned char nparams;/* (u) number of parameters */
|
unsigned char nparams;/* (u) number of parameters */
|
||||||
char isvararg; /* (u) */
|
char isvararg; /* (u) */
|
||||||
|
unsigned char extraargs; /* (t) number of extra arguments */
|
||||||
char istailcall; /* (t) */
|
char istailcall; /* (t) */
|
||||||
unsigned short ftransfer; /* (r) index of first value transferred */
|
int ftransfer; /* (r) index of first value transferred */
|
||||||
unsigned short ntransfer; /* (r) number of transferred values */
|
int ntransfer; /* (r) number of transferred values */
|
||||||
char short_src[LUA_IDSIZE]; /* (S) */
|
char short_src[LUA_IDSIZE]; /* (S) */
|
||||||
/* private part */
|
/* private part */
|
||||||
struct CallInfo *i_ci; /* active function */
|
struct CallInfo *i_ci; /* active function */
|
||||||
@@ -491,8 +509,19 @@ struct lua_Debug {
|
|||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
#define LUAI_TOSTRAUX(x) #x
|
||||||
|
#define LUAI_TOSTR(x) LUAI_TOSTRAUX(x)
|
||||||
|
|
||||||
|
#define LUA_VERSION_MAJOR LUAI_TOSTR(LUA_VERSION_MAJOR_N)
|
||||||
|
#define LUA_VERSION_MINOR LUAI_TOSTR(LUA_VERSION_MINOR_N)
|
||||||
|
#define LUA_VERSION_RELEASE LUAI_TOSTR(LUA_VERSION_RELEASE_N)
|
||||||
|
|
||||||
|
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||||
|
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
|
* Copyright (C) 1994-2026 Lua.org, PUC-Rio.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -58,15 +58,41 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When POSIX DLL ('LUA_USE_DLOPEN') is enabled, the Lua stand-alone
|
||||||
|
** application will try to dynamically link a 'readline' facility
|
||||||
|
** for its REPL. In that case, LUA_READLINELIB is the name of the
|
||||||
|
** library it will look for those facilities. If lua.c cannot open
|
||||||
|
** the specified library, it will generate a warning and then run
|
||||||
|
** without 'readline'. If that macro is not defined, lua.c will not
|
||||||
|
** use 'readline'.
|
||||||
|
*/
|
||||||
#if defined(LUA_USE_LINUX)
|
#if defined(LUA_USE_LINUX)
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
||||||
|
#if !defined(LUA_READLINELIB)
|
||||||
|
#define LUA_READLINELIB "libreadline.so"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_USE_MACOSX)
|
#if defined(LUA_USE_MACOSX)
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
|
#define LUA_USE_DLOPEN /* macOS does not need -ldl */
|
||||||
|
#if !defined(LUA_READLINELIB)
|
||||||
|
#define LUA_READLINELIB "libedit.dylib"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_USE_IOS)
|
||||||
|
#define LUA_USE_POSIX
|
||||||
|
#define LUA_USE_DLOPEN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_USE_C89) && defined(LUA_USE_POSIX)
|
||||||
|
#error "POSIX is not compatible with C89"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -116,7 +142,7 @@
|
|||||||
/*
|
/*
|
||||||
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
||||||
*/
|
*/
|
||||||
#define LUA_32BITS 0
|
/* #define LUA_32BITS */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -131,7 +157,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if LUA_32BITS /* { */
|
#if defined(LUA_32BITS) /* { */
|
||||||
/*
|
/*
|
||||||
** 32-bit integers and 'float'
|
** 32-bit integers and 'float'
|
||||||
*/
|
*/
|
||||||
@@ -202,17 +228,17 @@
|
|||||||
|
|
||||||
#if !defined(LUA_PATH_DEFAULT)
|
#if !defined(LUA_PATH_DEFAULT)
|
||||||
#define LUA_PATH_DEFAULT \
|
#define LUA_PATH_DEFAULT \
|
||||||
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
|
LUA_LDIR "?.lua;" LUA_LDIR "?\\init.lua;" \
|
||||||
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
|
LUA_CDIR "?.lua;" LUA_CDIR "?\\init.lua;" \
|
||||||
LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
|
LUA_SHRDIR "?.lua;" LUA_SHRDIR "?\\init.lua;" \
|
||||||
".\\?.lua;" ".\\?\\init.lua"
|
".\\?.lua;" ".\\?\\init.lua"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(LUA_CPATH_DEFAULT)
|
#if !defined(LUA_CPATH_DEFAULT)
|
||||||
#define LUA_CPATH_DEFAULT \
|
#define LUA_CPATH_DEFAULT \
|
||||||
LUA_CDIR"?.dll;" \
|
LUA_CDIR "?.dll;" \
|
||||||
LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
|
LUA_CDIR "..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
|
||||||
LUA_CDIR"loadall.dll;" ".\\?.dll"
|
LUA_CDIR "loadall.dll;" ".\\?.dll"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* }{ */
|
#else /* }{ */
|
||||||
@@ -223,14 +249,14 @@
|
|||||||
|
|
||||||
#if !defined(LUA_PATH_DEFAULT)
|
#if !defined(LUA_PATH_DEFAULT)
|
||||||
#define LUA_PATH_DEFAULT \
|
#define LUA_PATH_DEFAULT \
|
||||||
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
|
LUA_LDIR "?.lua;" LUA_LDIR "?/init.lua;" \
|
||||||
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
|
LUA_CDIR "?.lua;" LUA_CDIR "?/init.lua;" \
|
||||||
"./?.lua;" "./?/init.lua"
|
"./?.lua;" "./?/init.lua"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(LUA_CPATH_DEFAULT)
|
#if !defined(LUA_CPATH_DEFAULT)
|
||||||
#define LUA_CPATH_DEFAULT \
|
#define LUA_CPATH_DEFAULT \
|
||||||
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
|
LUA_CDIR "?.so;" LUA_CDIR "loadall.so;" "./?.so"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
@@ -251,6 +277,15 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** LUA_IGMARK is a mark to ignore all after it when building the
|
||||||
|
** module name (e.g., used to build the luaopen_ function name).
|
||||||
|
** Typically, the suffix after the mark is the module version,
|
||||||
|
** as in "mod-v1.2.so".
|
||||||
|
*/
|
||||||
|
#define LUA_IGMARK "-"
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -288,32 +323,13 @@
|
|||||||
** More often than not the libs go together with the core.
|
** More often than not the libs go together with the core.
|
||||||
*/
|
*/
|
||||||
#define LUALIB_API LUA_API
|
#define LUALIB_API LUA_API
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
/* Lua uses the "C name" when calling open functions */
|
||||||
|
#define LUAMOD_API extern "C"
|
||||||
|
#else
|
||||||
#define LUAMOD_API LUA_API
|
#define LUAMOD_API LUA_API
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUAI_FUNC is a mark for all extern functions that are not to be
|
|
||||||
** exported to outside modules.
|
|
||||||
@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables,
|
|
||||||
** none of which to be exported to outside modules (LUAI_DDEF for
|
|
||||||
** definitions and LUAI_DDEC for declarations).
|
|
||||||
** CHANGE them if you need to mark them in some special way. Elf/gcc
|
|
||||||
** (versions 3.2 and later) mark them as "hidden" to optimize access
|
|
||||||
** when Lua is compiled as a shared library. Not all elf targets support
|
|
||||||
** this attribute. Unfortunately, gcc does not offer a way to check
|
|
||||||
** whether the target offers that support, and those without support
|
|
||||||
** give a warning about it. To avoid these warnings, change to the
|
|
||||||
** default definition.
|
|
||||||
*/
|
|
||||||
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
|
|
||||||
defined(__ELF__) /* { */
|
|
||||||
#define LUAI_FUNC __attribute__((visibility("internal"))) extern
|
|
||||||
#else /* }{ */
|
|
||||||
#define LUAI_FUNC extern
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
#define LUAI_DDEC(dec) LUAI_FUNC dec
|
|
||||||
#define LUAI_DDEF /* empty */
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -325,11 +341,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3.
|
@@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word
|
||||||
** You can define it to get all options, or change specific options
|
|
||||||
** to fit your specific needs.
|
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_COMPAT_5_3) /* { */
|
#if !defined(LUA_COMPAT_GLOBAL)
|
||||||
|
#define LUA_COMPAT_GLOBAL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ LUA_COMPAT_LOOPVAR makes for-loop control variables not read-only,
|
||||||
|
** as they were in previous versions.
|
||||||
|
*/
|
||||||
|
#if !defined(LUA_COMPAT_LOOPVAR)
|
||||||
|
#define LUA_COMPAT_LOOPVAR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
||||||
@@ -337,23 +363,7 @@
|
|||||||
** (These functions were already officially removed in 5.3;
|
** (These functions were already officially removed in 5.3;
|
||||||
** nevertheless they are still available here.)
|
** nevertheless they are still available here.)
|
||||||
*/
|
*/
|
||||||
#define LUA_COMPAT_MATHLIB
|
/* #define LUA_COMPAT_MATHLIB */
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
|
|
||||||
** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
|
|
||||||
** luaL_checkint, luaL_checklong, etc.)
|
|
||||||
** (These macros were also officially removed in 5.3, but they are still
|
|
||||||
** available here.)
|
|
||||||
*/
|
|
||||||
#define LUA_COMPAT_APIINTCASTS
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod
|
|
||||||
** using '__lt'.
|
|
||||||
*/
|
|
||||||
#define LUA_COMPAT_LT_LE
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -370,8 +380,6 @@
|
|||||||
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
|
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
|
||||||
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
|
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
|
||||||
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -390,35 +398,23 @@
|
|||||||
@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
|
@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
|
||||||
** by prefixing it with one of FLT/DBL/LDBL.
|
** by prefixing it with one of FLT/DBL/LDBL.
|
||||||
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
|
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
|
||||||
@@ LUA_NUMBER_FMT is the format for writing floats.
|
@@ LUA_NUMBER_FMT is the format for writing floats with the maximum
|
||||||
@@ lua_number2str converts a float to a string.
|
** number of digits that respects tostring(tonumber(numeral)) == numeral.
|
||||||
|
** (That would be floor(log10(2^n)), where n is the number of bits in
|
||||||
|
** the float mantissa.)
|
||||||
|
@@ LUA_NUMBER_FMT_N is the format for writing floats with the minimum
|
||||||
|
** number of digits that ensures tonumber(tostring(number)) == number.
|
||||||
|
** (That would be LUA_NUMBER_FMT+2.)
|
||||||
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
|
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
|
||||||
@@ l_floor takes the floor of a float.
|
@@ l_floor takes the floor of a float.
|
||||||
@@ lua_str2number converts a decimal numeral to a number.
|
@@ lua_str2number converts a decimal numeral to a number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* The following definitions are good for most cases here */
|
/* The following definition is good for most cases here */
|
||||||
|
|
||||||
#define l_floor(x) (l_mathop(floor)(x))
|
#define l_floor(x) (l_mathop(floor)(x))
|
||||||
|
|
||||||
#define lua_number2str(s,sz,n) \
|
|
||||||
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ lua_numbertointeger converts a float number with an integral value
|
|
||||||
** to an integer, or returns 0 if float is not within the range of
|
|
||||||
** a lua_Integer. (The range comparisons are tricky because of
|
|
||||||
** rounding. The tests here assume a two-complement representation,
|
|
||||||
** where MININTEGER always has an exact representation as a float;
|
|
||||||
** MAXINTEGER may not have one, and therefore its conversion to float
|
|
||||||
** may have an ill-defined value.)
|
|
||||||
*/
|
|
||||||
#define lua_numbertointeger(n,p) \
|
|
||||||
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
|
|
||||||
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
|
|
||||||
(*(p) = (LUA_INTEGER)(n), 1))
|
|
||||||
|
|
||||||
|
|
||||||
/* now the variable definitions */
|
/* now the variable definitions */
|
||||||
|
|
||||||
@@ -432,6 +428,7 @@
|
|||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN ""
|
#define LUA_NUMBER_FRMLEN ""
|
||||||
#define LUA_NUMBER_FMT "%.7g"
|
#define LUA_NUMBER_FMT "%.7g"
|
||||||
|
#define LUA_NUMBER_FMT_N "%.9g"
|
||||||
|
|
||||||
#define l_mathop(op) op##f
|
#define l_mathop(op) op##f
|
||||||
|
|
||||||
@@ -448,6 +445,7 @@
|
|||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN "L"
|
#define LUA_NUMBER_FRMLEN "L"
|
||||||
#define LUA_NUMBER_FMT "%.19Lg"
|
#define LUA_NUMBER_FMT "%.19Lg"
|
||||||
|
#define LUA_NUMBER_FMT_N "%.21Lg"
|
||||||
|
|
||||||
#define l_mathop(op) op##l
|
#define l_mathop(op) op##l
|
||||||
|
|
||||||
@@ -462,7 +460,8 @@
|
|||||||
#define LUAI_UACNUMBER double
|
#define LUAI_UACNUMBER double
|
||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN ""
|
#define LUA_NUMBER_FRMLEN ""
|
||||||
#define LUA_NUMBER_FMT "%.14g"
|
#define LUA_NUMBER_FMT "%.15g"
|
||||||
|
#define LUA_NUMBER_FMT_N "%.17g"
|
||||||
|
|
||||||
#define l_mathop(op) op
|
#define l_mathop(op) op
|
||||||
|
|
||||||
@@ -665,7 +664,7 @@
|
|||||||
*/
|
*/
|
||||||
#if !defined(luai_likely)
|
#if !defined(luai_likely)
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
|
#if !defined(LUA_NOBUILTIN) && defined(__GNUC__) && (__GNUC__ >= 3)
|
||||||
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
|
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
|
||||||
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
||||||
#else
|
#else
|
||||||
@@ -676,13 +675,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_CORE) || defined(LUA_LIB)
|
|
||||||
/* shorter names for Lua's own use */
|
|
||||||
#define l_likely(x) luai_likely(x)
|
|
||||||
#define l_unlikely(x) luai_unlikely(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -707,10 +699,7 @@
|
|||||||
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
|
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
|
||||||
** Define it as a help when debugging C code.
|
** Define it as a help when debugging C code.
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_USE_APICHECK)
|
/* #define LUA_USE_APICHECK */
|
||||||
#include <assert.h>
|
|
||||||
#define luai_apicheck(l,e) assert(e)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -723,20 +712,6 @@
|
|||||||
** =====================================================================
|
** =====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUAI_MAXSTACK limits the size of the Lua stack.
|
|
||||||
** CHANGE it if you need a different limit. This limit is arbitrary;
|
|
||||||
** its only purpose is to stop Lua from consuming unlimited stack
|
|
||||||
** space (and to reserve some numbers for pseudo-indices).
|
|
||||||
** (It must fit into max(size_t)/32.)
|
|
||||||
*/
|
|
||||||
#if LUAI_IS32INT
|
|
||||||
#define LUAI_MAXSTACK 1000000
|
|
||||||
#else
|
|
||||||
#define LUAI_MAXSTACK 15000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
||||||
** a Lua state with very fast access.
|
** a Lua state with very fast access.
|
||||||
@@ -747,23 +722,31 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
||||||
@@ of a function in debug information.
|
** of a function in debug information.
|
||||||
** CHANGE it if you want a different size.
|
** CHANGE it if you want a different size.
|
||||||
*/
|
*/
|
||||||
#define LUA_IDSIZE 60
|
#define LUA_IDSIZE 60
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
|
@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
|
||||||
|
** buffer system.
|
||||||
*/
|
*/
|
||||||
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
|
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure
|
@@ LUAI_MAXALIGN defines fields that ensure proper alignment for
|
||||||
** maximum alignment for the other items in that union.
|
** memory areas offered by Lua (e.g., userdata memory).
|
||||||
|
** Add fields to it if you need alignment for non-ISO objects.
|
||||||
*/
|
*/
|
||||||
|
#if defined(LLONG_MAX)
|
||||||
|
/* use ISO C99 stuff */
|
||||||
|
#define LUAI_MAXALIGN long double u; void *s; long long l
|
||||||
|
#else
|
||||||
|
/* use only C89 stuff */
|
||||||
#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l
|
#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l
|
||||||
|
#endif
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -780,7 +763,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -14,39 +14,52 @@
|
|||||||
/* version suffix for environment variable names */
|
/* version suffix for environment variable names */
|
||||||
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
|
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
|
||||||
|
|
||||||
|
#define LUA_GLIBK 1
|
||||||
LUAMOD_API int (luaopen_base) (lua_State *L);
|
LUAMOD_API int (luaopen_base) (lua_State *L);
|
||||||
|
|
||||||
#define LUA_COLIBNAME "coroutine"
|
|
||||||
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_TABLIBNAME "table"
|
|
||||||
LUAMOD_API int (luaopen_table) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_IOLIBNAME "io"
|
|
||||||
LUAMOD_API int (luaopen_io) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_OSLIBNAME "os"
|
|
||||||
LUAMOD_API int (luaopen_os) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_STRLIBNAME "string"
|
|
||||||
LUAMOD_API int (luaopen_string) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_UTF8LIBNAME "utf8"
|
|
||||||
LUAMOD_API int (luaopen_utf8) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_MATHLIBNAME "math"
|
|
||||||
LUAMOD_API int (luaopen_math) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_DBLIBNAME "debug"
|
|
||||||
LUAMOD_API int (luaopen_debug) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_LOADLIBNAME "package"
|
#define LUA_LOADLIBNAME "package"
|
||||||
|
#define LUA_LOADLIBK (LUA_GLIBK << 1)
|
||||||
LUAMOD_API int (luaopen_package) (lua_State *L);
|
LUAMOD_API int (luaopen_package) (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
/* open all previous libraries */
|
#define LUA_COLIBNAME "coroutine"
|
||||||
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
#define LUA_COLIBK (LUA_LOADLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_DBLIBNAME "debug"
|
||||||
|
#define LUA_DBLIBK (LUA_COLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_debug) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_IOLIBNAME "io"
|
||||||
|
#define LUA_IOLIBK (LUA_DBLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_io) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_MATHLIBNAME "math"
|
||||||
|
#define LUA_MATHLIBK (LUA_IOLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_math) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_OSLIBNAME "os"
|
||||||
|
#define LUA_OSLIBK (LUA_MATHLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_os) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_STRLIBNAME "string"
|
||||||
|
#define LUA_STRLIBK (LUA_OSLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_string) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_TABLIBNAME "table"
|
||||||
|
#define LUA_TABLIBK (LUA_STRLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_table) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_UTF8LIBNAME "utf8"
|
||||||
|
#define LUA_UTF8LIBK (LUA_TABLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_utf8) (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
|
/* open selected libraries */
|
||||||
|
LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int load, int preload);
|
||||||
|
|
||||||
|
/* open all libraries */
|
||||||
|
#define luaL_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstring.h"
|
#include "lstring.h"
|
||||||
|
#include "ltable.h"
|
||||||
#include "lundump.h"
|
#include "lundump.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
|
|
||||||
@@ -34,6 +35,10 @@ typedef struct {
|
|||||||
lua_State *L;
|
lua_State *L;
|
||||||
ZIO *Z;
|
ZIO *Z;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
Table *h; /* list for string reuse */
|
||||||
|
size_t offset; /* current position relative to beginning of dump */
|
||||||
|
lua_Unsigned nstr; /* number of strings in the list */
|
||||||
|
lu_byte fixed; /* dump is fixed in memory */
|
||||||
} LoadState;
|
} LoadState;
|
||||||
|
|
||||||
|
|
||||||
@@ -47,11 +52,33 @@ static l_noret error (LoadState *S, const char *why) {
|
|||||||
** All high-level loads go through loadVector; you can change it to
|
** All high-level loads go through loadVector; you can change it to
|
||||||
** adapt to the endianness of the input
|
** adapt to the endianness of the input
|
||||||
*/
|
*/
|
||||||
#define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0]))
|
#define loadVector(S,b,n) loadBlock(S,b,cast_sizet(n)*sizeof((b)[0]))
|
||||||
|
|
||||||
static void loadBlock (LoadState *S, void *b, size_t size) {
|
static void loadBlock (LoadState *S, void *b, size_t size) {
|
||||||
if (luaZ_read(S->Z, b, size) != 0)
|
if (luaZ_read(S->Z, b, size) != 0)
|
||||||
error(S, "truncated chunk");
|
error(S, "truncated chunk");
|
||||||
|
S->offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadAlign (LoadState *S, unsigned align) {
|
||||||
|
unsigned padding = align - cast_uint(S->offset % align);
|
||||||
|
if (padding < align) { /* (padding == align) means no padding */
|
||||||
|
lua_Integer paddingContent;
|
||||||
|
loadBlock(S, &paddingContent, padding);
|
||||||
|
lua_assert(S->offset % align == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define getaddr(S,n,t) cast(t *, getaddr_(S,cast_sizet(n) * sizeof(t)))
|
||||||
|
|
||||||
|
static const void *getaddr_ (LoadState *S, size_t size) {
|
||||||
|
const void *block = luaZ_getaddr(S->Z, size);
|
||||||
|
S->offset += size;
|
||||||
|
if (block == NULL)
|
||||||
|
error(S, "truncated fixed buffer");
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -62,34 +89,36 @@ static lu_byte loadByte (LoadState *S) {
|
|||||||
int b = zgetc(S->Z);
|
int b = zgetc(S->Z);
|
||||||
if (b == EOZ)
|
if (b == EOZ)
|
||||||
error(S, "truncated chunk");
|
error(S, "truncated chunk");
|
||||||
|
S->offset++;
|
||||||
return cast_byte(b);
|
return cast_byte(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t loadUnsigned (LoadState *S, size_t limit) {
|
static lua_Unsigned loadVarint (LoadState *S, lua_Unsigned limit) {
|
||||||
size_t x = 0;
|
lua_Unsigned x = 0;
|
||||||
int b;
|
int b;
|
||||||
limit >>= 7;
|
limit >>= 7;
|
||||||
do {
|
do {
|
||||||
b = loadByte(S);
|
b = loadByte(S);
|
||||||
if (x >= limit)
|
if (x > limit)
|
||||||
error(S, "integer overflow");
|
error(S, "integer overflow");
|
||||||
x = (x << 7) | (b & 0x7f);
|
x = (x << 7) | (b & 0x7f);
|
||||||
} while ((b & 0x80) == 0);
|
} while ((b & 0x80) != 0);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t loadSize (LoadState *S) {
|
static size_t loadSize (LoadState *S) {
|
||||||
return loadUnsigned(S, ~(size_t)0);
|
return cast_sizet(loadVarint(S, MAX_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int loadInt (LoadState *S) {
|
static int loadInt (LoadState *S) {
|
||||||
return cast_int(loadUnsigned(S, INT_MAX));
|
return cast_int(loadVarint(S, cast_sizet(INT_MAX)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static lua_Number loadNumber (LoadState *S) {
|
static lua_Number loadNumber (LoadState *S) {
|
||||||
lua_Number x;
|
lua_Number x;
|
||||||
loadVar(S, x);
|
loadVar(S, x);
|
||||||
@@ -98,58 +127,79 @@ static lua_Number loadNumber (LoadState *S) {
|
|||||||
|
|
||||||
|
|
||||||
static lua_Integer loadInteger (LoadState *S) {
|
static lua_Integer loadInteger (LoadState *S) {
|
||||||
lua_Integer x;
|
lua_Unsigned cx = loadVarint(S, LUA_MAXUNSIGNED);
|
||||||
loadVar(S, x);
|
/* decode unsigned to signed */
|
||||||
return x;
|
if ((cx & 1) != 0)
|
||||||
|
return l_castU2S(~(cx >> 1));
|
||||||
|
else
|
||||||
|
return l_castU2S(cx >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Load a nullable string into prototype 'p'.
|
** Load a nullable string into slot 'sl' from prototype 'p'. The
|
||||||
|
** assignment to the slot and the barrier must be performed before any
|
||||||
|
** possible GC activity, to anchor the string. (Both 'loadVector' and
|
||||||
|
** 'luaH_setint' can call the GC.)
|
||||||
*/
|
*/
|
||||||
static TString *loadStringN (LoadState *S, Proto *p) {
|
static void loadString (LoadState *S, Proto *p, TString **sl) {
|
||||||
lua_State *L = S->L;
|
lua_State *L = S->L;
|
||||||
TString *ts;
|
TString *ts;
|
||||||
|
TValue sv;
|
||||||
size_t size = loadSize(S);
|
size_t size = loadSize(S);
|
||||||
if (size == 0) /* no string? */
|
if (size == 0) { /* previously saved string? */
|
||||||
return NULL;
|
lua_Unsigned idx = loadVarint(S, LUA_MAXUNSIGNED); /* get its index */
|
||||||
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
|
TValue stv;
|
||||||
char buff[LUAI_MAXSHORTLEN];
|
if (idx == 0) { /* no string? */
|
||||||
loadVector(S, buff, size); /* load string into buffer */
|
lua_assert(*sl == NULL); /* must be prefilled */
|
||||||
ts = luaS_newlstr(L, buff, size); /* create string */
|
return;
|
||||||
|
}
|
||||||
|
if (novariant(luaH_getint(S->h, l_castU2S(idx), &stv)) != LUA_TSTRING)
|
||||||
|
error(S, "invalid string index");
|
||||||
|
*sl = ts = tsvalue(&stv); /* get its value */
|
||||||
|
luaC_objbarrier(L, p, ts);
|
||||||
|
return; /* do not save it again */
|
||||||
}
|
}
|
||||||
else { /* long string */
|
else if ((size -= 1) <= LUAI_MAXSHORTLEN) { /* short string? */
|
||||||
ts = luaS_createlngstrobj(L, size); /* create string */
|
char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
|
||||||
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
|
loadVector(S, buff, size + 1); /* load string into buffer */
|
||||||
luaD_inctop(L);
|
*sl = ts = luaS_newlstr(L, buff, size); /* create string */
|
||||||
loadVector(S, getstr(ts), size); /* load directly in final place */
|
luaC_objbarrier(L, p, ts);
|
||||||
L->top--; /* pop string */
|
|
||||||
}
|
}
|
||||||
luaC_objbarrier(L, p, ts);
|
else if (S->fixed) { /* for a fixed buffer, use a fixed string */
|
||||||
return ts;
|
const char *s = getaddr(S, size + 1, char); /* get content address */
|
||||||
}
|
*sl = ts = luaS_newextlstr(L, s, size, NULL, NULL);
|
||||||
|
luaC_objbarrier(L, p, ts);
|
||||||
|
}
|
||||||
/*
|
else { /* create internal copy */
|
||||||
** Load a non-nullable string into prototype 'p'.
|
*sl = ts = luaS_createlngstrobj(L, size); /* create string */
|
||||||
*/
|
luaC_objbarrier(L, p, ts);
|
||||||
static TString *loadString (LoadState *S, Proto *p) {
|
loadVector(S, getlngstr(ts), size + 1); /* load directly in final place */
|
||||||
TString *st = loadStringN(S, p);
|
}
|
||||||
if (st == NULL)
|
/* add string to list of saved strings */
|
||||||
error(S, "bad format for constant string");
|
S->nstr++;
|
||||||
return st;
|
setsvalue(L, &sv, ts);
|
||||||
|
luaH_setint(L, S->h, l_castU2S(S->nstr), &sv);
|
||||||
|
luaC_objbarrierback(L, obj2gco(S->h), ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void loadCode (LoadState *S, Proto *f) {
|
static void loadCode (LoadState *S, Proto *f) {
|
||||||
int n = loadInt(S);
|
int n = loadInt(S);
|
||||||
f->code = luaM_newvectorchecked(S->L, n, Instruction);
|
loadAlign(S, sizeof(f->code[0]));
|
||||||
f->sizecode = n;
|
if (S->fixed) {
|
||||||
loadVector(S, f->code, n);
|
f->code = getaddr(S, n, Instruction);
|
||||||
|
f->sizecode = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f->code = luaM_newvectorchecked(S->L, n, Instruction);
|
||||||
|
f->sizecode = n;
|
||||||
|
loadVector(S, f->code, n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void loadFunction(LoadState *S, Proto *f, TString *psource);
|
static void loadFunction(LoadState *S, Proto *f);
|
||||||
|
|
||||||
|
|
||||||
static void loadConstants (LoadState *S, Proto *f) {
|
static void loadConstants (LoadState *S, Proto *f) {
|
||||||
@@ -179,10 +229,16 @@ static void loadConstants (LoadState *S, Proto *f) {
|
|||||||
setivalue(o, loadInteger(S));
|
setivalue(o, loadInteger(S));
|
||||||
break;
|
break;
|
||||||
case LUA_VSHRSTR:
|
case LUA_VSHRSTR:
|
||||||
case LUA_VLNGSTR:
|
case LUA_VLNGSTR: {
|
||||||
setsvalue2n(S->L, o, loadString(S, f));
|
lua_assert(f->source == NULL);
|
||||||
|
loadString(S, f, &f->source); /* use 'source' to anchor string */
|
||||||
|
if (f->source == NULL)
|
||||||
|
error(S, "bad format for constant string");
|
||||||
|
setsvalue2n(S->L, o, f->source); /* save it in the right place */
|
||||||
|
f->source = NULL;
|
||||||
break;
|
break;
|
||||||
default: lua_assert(0);
|
}
|
||||||
|
default: error(S, "invalid constant");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +254,7 @@ static void loadProtos (LoadState *S, Proto *f) {
|
|||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
f->p[i] = luaF_newproto(S->L);
|
f->p[i] = luaF_newproto(S->L);
|
||||||
luaC_objbarrier(S->L, f, f->p[i]);
|
luaC_objbarrier(S->L, f, f->p[i]);
|
||||||
loadFunction(S, f->p[i], f->source);
|
loadFunction(S, f->p[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,8 +266,8 @@ static void loadProtos (LoadState *S, Proto *f) {
|
|||||||
** in that case all prototypes must be consistent for the GC.
|
** in that case all prototypes must be consistent for the GC.
|
||||||
*/
|
*/
|
||||||
static void loadUpvalues (LoadState *S, Proto *f) {
|
static void loadUpvalues (LoadState *S, Proto *f) {
|
||||||
int i, n;
|
int i;
|
||||||
n = loadInt(S);
|
int n = loadInt(S);
|
||||||
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
|
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
|
||||||
f->sizeupvalues = n;
|
f->sizeupvalues = n;
|
||||||
for (i = 0; i < n; i++) /* make array valid for GC */
|
for (i = 0; i < n; i++) /* make array valid for GC */
|
||||||
@@ -225,17 +281,29 @@ static void loadUpvalues (LoadState *S, Proto *f) {
|
|||||||
|
|
||||||
|
|
||||||
static void loadDebug (LoadState *S, Proto *f) {
|
static void loadDebug (LoadState *S, Proto *f) {
|
||||||
int i, n;
|
int i;
|
||||||
|
int n = loadInt(S);
|
||||||
|
if (S->fixed) {
|
||||||
|
f->lineinfo = getaddr(S, n, ls_byte);
|
||||||
|
f->sizelineinfo = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
|
||||||
|
f->sizelineinfo = n;
|
||||||
|
loadVector(S, f->lineinfo, n);
|
||||||
|
}
|
||||||
n = loadInt(S);
|
n = loadInt(S);
|
||||||
f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
|
if (n > 0) {
|
||||||
f->sizelineinfo = n;
|
loadAlign(S, sizeof(int));
|
||||||
loadVector(S, f->lineinfo, n);
|
if (S->fixed) {
|
||||||
n = loadInt(S);
|
f->abslineinfo = getaddr(S, n, AbsLineInfo);
|
||||||
f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
|
f->sizeabslineinfo = n;
|
||||||
f->sizeabslineinfo = n;
|
}
|
||||||
for (i = 0; i < n; i++) {
|
else {
|
||||||
f->abslineinfo[i].pc = loadInt(S);
|
f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
|
||||||
f->abslineinfo[i].line = loadInt(S);
|
f->sizeabslineinfo = n;
|
||||||
|
loadVector(S, f->abslineinfo, n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
n = loadInt(S);
|
n = loadInt(S);
|
||||||
f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
|
f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
|
||||||
@@ -243,29 +311,32 @@ static void loadDebug (LoadState *S, Proto *f) {
|
|||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
f->locvars[i].varname = NULL;
|
f->locvars[i].varname = NULL;
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
f->locvars[i].varname = loadStringN(S, f);
|
loadString(S, f, &f->locvars[i].varname);
|
||||||
f->locvars[i].startpc = loadInt(S);
|
f->locvars[i].startpc = loadInt(S);
|
||||||
f->locvars[i].endpc = loadInt(S);
|
f->locvars[i].endpc = loadInt(S);
|
||||||
}
|
}
|
||||||
n = loadInt(S);
|
n = loadInt(S);
|
||||||
|
if (n != 0) /* does it have debug information? */
|
||||||
|
n = f->sizeupvalues; /* must be this many */
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
f->upvalues[i].name = loadStringN(S, f);
|
loadString(S, f, &f->upvalues[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void loadFunction (LoadState *S, Proto *f, TString *psource) {
|
static void loadFunction (LoadState *S, Proto *f) {
|
||||||
f->source = loadStringN(S, f);
|
|
||||||
if (f->source == NULL) /* no source in dump? */
|
|
||||||
f->source = psource; /* reuse parent's source */
|
|
||||||
f->linedefined = loadInt(S);
|
f->linedefined = loadInt(S);
|
||||||
f->lastlinedefined = loadInt(S);
|
f->lastlinedefined = loadInt(S);
|
||||||
f->numparams = loadByte(S);
|
f->numparams = loadByte(S);
|
||||||
f->is_vararg = loadByte(S);
|
/* get only the meaningful flags */
|
||||||
|
f->flag = cast_byte(loadByte(S) & ~PF_FIXED);
|
||||||
|
if (S->fixed)
|
||||||
|
f->flag |= PF_FIXED; /* signal that code is fixed */
|
||||||
f->maxstacksize = loadByte(S);
|
f->maxstacksize = loadByte(S);
|
||||||
loadCode(S, f);
|
loadCode(S, f);
|
||||||
loadConstants(S, f);
|
loadConstants(S, f);
|
||||||
loadUpvalues(S, f);
|
loadUpvalues(S, f);
|
||||||
loadProtos(S, f);
|
loadProtos(S, f);
|
||||||
|
loadString(S, f, &f->source);
|
||||||
loadDebug(S, f);
|
loadDebug(S, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,13 +350,29 @@ static void checkliteral (LoadState *S, const char *s, const char *msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void fchecksize (LoadState *S, size_t size, const char *tname) {
|
static l_noret numerror (LoadState *S, const char *what, const char *tname) {
|
||||||
if (loadByte(S) != size)
|
const char *msg = luaO_pushfstring(S->L, "%s %s mismatch", tname, what);
|
||||||
error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
|
error(S, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
|
static void checknumsize (LoadState *S, int size, const char *tname) {
|
||||||
|
if (size != loadByte(S))
|
||||||
|
numerror(S, "size", tname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void checknumformat (LoadState *S, int eq, const char *tname) {
|
||||||
|
if (!eq)
|
||||||
|
numerror(S, "format", tname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define checknum(S,tvar,value,tname) \
|
||||||
|
{ tvar i; checknumsize(S, sizeof(i), tname); \
|
||||||
|
loadVar(S, i); \
|
||||||
|
checknumformat(S, i == value, tname); }
|
||||||
|
|
||||||
|
|
||||||
static void checkHeader (LoadState *S) {
|
static void checkHeader (LoadState *S) {
|
||||||
/* skip 1st char (already read and checked) */
|
/* skip 1st char (already read and checked) */
|
||||||
@@ -295,38 +382,39 @@ static void checkHeader (LoadState *S) {
|
|||||||
if (loadByte(S) != LUAC_FORMAT)
|
if (loadByte(S) != LUAC_FORMAT)
|
||||||
error(S, "format mismatch");
|
error(S, "format mismatch");
|
||||||
checkliteral(S, LUAC_DATA, "corrupted chunk");
|
checkliteral(S, LUAC_DATA, "corrupted chunk");
|
||||||
checksize(S, Instruction);
|
checknum(S, int, LUAC_INT, "int");
|
||||||
checksize(S, lua_Integer);
|
checknum(S, Instruction, LUAC_INST, "instruction");
|
||||||
checksize(S, lua_Number);
|
checknum(S, lua_Integer, LUAC_INT, "Lua integer");
|
||||||
if (loadInteger(S) != LUAC_INT)
|
checknum(S, lua_Number, LUAC_NUM, "Lua number");
|
||||||
error(S, "integer format mismatch");
|
|
||||||
if (loadNumber(S) != LUAC_NUM)
|
|
||||||
error(S, "float format mismatch");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Load precompiled chunk.
|
** Load precompiled chunk.
|
||||||
*/
|
*/
|
||||||
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
|
LClosure *luaU_undump (lua_State *L, ZIO *Z, Table *anchor, const char *name,
|
||||||
|
int fixed) {
|
||||||
LoadState S;
|
LoadState S;
|
||||||
LClosure *cl;
|
LClosure *cl;
|
||||||
if (*name == '@' || *name == '=')
|
if (*name == '@' || *name == '=')
|
||||||
S.name = name + 1;
|
name = name + 1;
|
||||||
else if (*name == LUA_SIGNATURE[0])
|
else if (*name == LUA_SIGNATURE[0])
|
||||||
S.name = "binary string";
|
name = "binary string";
|
||||||
else
|
S.name = name;
|
||||||
S.name = name;
|
|
||||||
S.L = L;
|
S.L = L;
|
||||||
S.Z = Z;
|
S.Z = Z;
|
||||||
|
S.fixed = cast_byte(fixed);
|
||||||
|
S.offset = 1; /* fist byte was already read */
|
||||||
checkHeader(&S);
|
checkHeader(&S);
|
||||||
|
S.h = anchor;
|
||||||
|
S.nstr = 0;
|
||||||
cl = luaF_newLclosure(L, loadByte(&S));
|
cl = luaF_newLclosure(L, loadByte(&S));
|
||||||
setclLvalue2s(L, L->top, cl);
|
luaD_anchorobj(L, anchor, obj2gco(cl));
|
||||||
luaD_inctop(L);
|
|
||||||
cl->p = luaF_newproto(L);
|
cl->p = luaF_newproto(L);
|
||||||
luaC_objbarrier(L, cl, cl->p);
|
luaC_objbarrier(L, cl, cl->p);
|
||||||
loadFunction(&S, cl->p, NULL);
|
loadFunction(&S, cl->p);
|
||||||
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
if (cl->nupvalues != cl->p->sizeupvalues)
|
||||||
|
error(&S, "corrupted chunk");
|
||||||
luai_verifycode(L, cl->p);
|
luai_verifycode(L, cl->p);
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#ifndef lundump_h
|
#ifndef lundump_h
|
||||||
#define lundump_h
|
#define lundump_h
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
@@ -15,19 +17,21 @@
|
|||||||
/* data to catch conversion errors */
|
/* data to catch conversion errors */
|
||||||
#define LUAC_DATA "\x19\x93\r\n\x1a\n"
|
#define LUAC_DATA "\x19\x93\r\n\x1a\n"
|
||||||
|
|
||||||
#define LUAC_INT 0x5678
|
#define LUAC_INT -0x5678
|
||||||
#define LUAC_NUM cast_num(370.5)
|
#define LUAC_INST 0x12345678
|
||||||
|
#define LUAC_NUM cast_num(-370.5)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Encode major-minor version in one byte, one nibble for each
|
** Encode major-minor version in one byte, one nibble for each
|
||||||
*/
|
*/
|
||||||
#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */
|
#define LUAC_VERSION (LUA_VERSION_MAJOR_N*16+LUA_VERSION_MINOR_N)
|
||||||
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
|
|
||||||
|
|
||||||
#define LUAC_FORMAT 0 /* this is the official format */
|
#define LUAC_FORMAT 0 /* this is the official format */
|
||||||
|
|
||||||
|
|
||||||
/* load one chunk; from lundump.c */
|
/* load one chunk; from lundump.c */
|
||||||
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
|
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Table *anchor,
|
||||||
|
const char* name, int fixed);
|
||||||
|
|
||||||
/* dump one chunk; from ldump.c */
|
/* dump one chunk; from ldump.c */
|
||||||
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
||||||
|
|||||||
+64
-56
@@ -10,7 +10,6 @@
|
|||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -19,23 +18,19 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAXUNICODE 0x10FFFFu
|
#define MAXUNICODE 0x10FFFFu
|
||||||
|
|
||||||
#define MAXUTF 0x7FFFFFFFu
|
#define MAXUTF 0x7FFFFFFFu
|
||||||
|
|
||||||
/*
|
|
||||||
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
|
#define MSGInvalid "invalid UTF-8 code"
|
||||||
*/
|
|
||||||
#if (UINT_MAX >> 30) >= 1
|
|
||||||
typedef unsigned int utfint;
|
|
||||||
#else
|
|
||||||
typedef unsigned long utfint;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define iscont(p) ((*(p) & 0xC0) == 0x80)
|
#define iscont(c) (((c) & 0xC0) == 0x80)
|
||||||
|
#define iscontp(p) iscont(*(p))
|
||||||
|
|
||||||
|
|
||||||
/* from strlib */
|
/* from strlib */
|
||||||
@@ -51,26 +46,29 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
|
|||||||
** Decode one UTF-8 sequence, returning NULL if byte sequence is
|
** Decode one UTF-8 sequence, returning NULL if byte sequence is
|
||||||
** invalid. The array 'limits' stores the minimum value for each
|
** invalid. The array 'limits' stores the minimum value for each
|
||||||
** sequence length, to check for overlong representations. Its first
|
** sequence length, to check for overlong representations. Its first
|
||||||
** entry forces an error for non-ascii bytes with no continuation
|
** entry forces an error for non-ASCII bytes with no continuation
|
||||||
** bytes (count == 0).
|
** bytes (count == 0).
|
||||||
*/
|
*/
|
||||||
static const char *utf8_decode (const char *s, utfint *val, int strict) {
|
static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
|
||||||
static const utfint limits[] =
|
static const l_uint32 limits[] =
|
||||||
{~(utfint)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
|
{~(l_uint32)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
|
||||||
unsigned int c = (unsigned char)s[0];
|
unsigned int c = (unsigned char)s[0];
|
||||||
utfint res = 0; /* final result */
|
l_uint32 res = 0; /* final result */
|
||||||
if (c < 0x80) /* ascii? */
|
if (c < 0x80) /* ASCII? */
|
||||||
res = c;
|
res = c;
|
||||||
|
else if (c >= 0xfe) /* c >= 1111 1110b ? */
|
||||||
|
return NULL; /* would need six or more continuation bytes */
|
||||||
else {
|
else {
|
||||||
int count = 0; /* to count number of continuation bytes */
|
int count = 0; /* to count number of continuation bytes */
|
||||||
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
||||||
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
|
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
|
||||||
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
|
if (!iscont(cc)) /* not a continuation byte? */
|
||||||
return NULL; /* invalid byte sequence */
|
return NULL; /* invalid byte sequence */
|
||||||
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
||||||
}
|
}
|
||||||
res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */
|
lua_assert(count <= 5);
|
||||||
if (count > 5 || res > MAXUTF || res < limits[count])
|
res |= ((l_uint32)(c & 0x7F) << (count * 5)); /* add first byte */
|
||||||
|
if (res > MAXUTF || res < limits[count])
|
||||||
return NULL; /* invalid byte sequence */
|
return NULL; /* invalid byte sequence */
|
||||||
s += count; /* skip continuation bytes read */
|
s += count; /* skip continuation bytes read */
|
||||||
}
|
}
|
||||||
@@ -107,7 +105,7 @@ static int utflen (lua_State *L) {
|
|||||||
lua_pushinteger(L, posi + 1); /* ... and current position */
|
lua_pushinteger(L, posi + 1); /* ... and current position */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
posi = s1 - s;
|
posi = ct_diff2S(s1 - s);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, n);
|
lua_pushinteger(L, n);
|
||||||
@@ -137,11 +135,11 @@ static int codepoint (lua_State *L) {
|
|||||||
n = 0; /* count the number of returns */
|
n = 0; /* count the number of returns */
|
||||||
se = s + pose; /* string end */
|
se = s + pose; /* string end */
|
||||||
for (s += posi - 1; s < se;) {
|
for (s += posi - 1; s < se;) {
|
||||||
utfint code;
|
l_uint32 code;
|
||||||
s = utf8_decode(s, &code, !lax);
|
s = utf8_decode(s, &code, !lax);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
return luaL_error(L, "invalid UTF-8 code");
|
return luaL_error(L, MSGInvalid);
|
||||||
lua_pushinteger(L, code);
|
lua_pushinteger(L, l_castU2S(code));
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@@ -151,7 +149,7 @@ static int codepoint (lua_State *L) {
|
|||||||
static void pushutfchar (lua_State *L, int arg) {
|
static void pushutfchar (lua_State *L, int arg) {
|
||||||
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg);
|
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg);
|
||||||
luaL_argcheck(L, code <= MAXUTF, arg, "value out of range");
|
luaL_argcheck(L, code <= MAXUTF, arg, "value out of range");
|
||||||
lua_pushfstring(L, "%U", (long)code);
|
lua_pushfstring(L, "%U", cast(unsigned long, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -177,47 +175,56 @@ static int utfchar (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** offset(s, n, [i]) -> index where n-th character counting from
|
** offset(s, n, [i]) -> indices where n-th character counting from
|
||||||
** position 'i' starts; 0 means character at 'i'.
|
** position 'i' starts and ends; 0 means character at 'i'.
|
||||||
*/
|
*/
|
||||||
static int byteoffset (lua_State *L) {
|
static int byteoffset (lua_State *L) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, 1, &len);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Integer n = luaL_checkinteger(L, 2);
|
lua_Integer n = luaL_checkinteger(L, 2);
|
||||||
lua_Integer posi = (n >= 0) ? 1 : len + 1;
|
lua_Integer posi = (n >= 0) ? 1 : cast_st2S(len) + 1;
|
||||||
posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
|
posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
|
||||||
luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
|
luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
|
||||||
"position out of bounds");
|
"position out of bounds");
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
/* find beginning of current byte sequence */
|
/* find beginning of current byte sequence */
|
||||||
while (posi > 0 && iscont(s + posi)) posi--;
|
while (posi > 0 && iscontp(s + posi)) posi--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (iscont(s + posi))
|
if (iscontp(s + posi))
|
||||||
return luaL_error(L, "initial position is a continuation byte");
|
return luaL_error(L, "initial position is a continuation byte");
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
while (n < 0 && posi > 0) { /* move back */
|
while (n < 0 && posi > 0) { /* move back */
|
||||||
do { /* find beginning of previous character */
|
do { /* find beginning of previous character */
|
||||||
posi--;
|
posi--;
|
||||||
} while (posi > 0 && iscont(s + posi));
|
} while (posi > 0 && iscontp(s + posi));
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
n--; /* do not move for 1st character */
|
n--; /* do not move for 1st character */
|
||||||
while (n > 0 && posi < (lua_Integer)len) {
|
while (n > 0 && posi < (lua_Integer)len) {
|
||||||
do { /* find beginning of next character */
|
do { /* find beginning of next character */
|
||||||
posi++;
|
posi++;
|
||||||
} while (iscont(s + posi)); /* (cannot pass final '\0') */
|
} while (iscontp(s + posi)); /* (cannot pass final '\0') */
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n == 0) /* did it find given character? */
|
if (n != 0) { /* did not find given character? */
|
||||||
lua_pushinteger(L, posi + 1);
|
|
||||||
else /* no such character */
|
|
||||||
luaL_pushfail(L);
|
luaL_pushfail(L);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pushinteger(L, posi + 1); /* initial position */
|
||||||
|
if ((s[posi] & 0x80) != 0) { /* multi-byte character? */
|
||||||
|
if (iscont(s[posi]))
|
||||||
|
return luaL_error(L, "initial position is a continuation byte");
|
||||||
|
while (iscontp(s + posi + 1))
|
||||||
|
posi++; /* skip to last continuation byte */
|
||||||
|
}
|
||||||
|
/* else one-byte character: final position is the initial one */
|
||||||
|
lua_pushinteger(L, posi + 1); /* 'posi' now is the final position */
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -226,17 +233,17 @@ static int iter_aux (lua_State *L, int strict) {
|
|||||||
const char *s = luaL_checklstring(L, 1, &len);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
|
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
|
||||||
if (n < len) {
|
if (n < len) {
|
||||||
while (iscont(s + n)) n++; /* skip continuation bytes */
|
while (iscontp(s + n)) n++; /* go to next character */
|
||||||
}
|
}
|
||||||
if (n >= len) /* (also handles original 'n' being negative) */
|
if (n >= len) /* (also handles original 'n' being negative) */
|
||||||
return 0; /* no more codepoints */
|
return 0; /* no more codepoints */
|
||||||
else {
|
else {
|
||||||
utfint code;
|
l_uint32 code;
|
||||||
const char *next = utf8_decode(s + n, &code, strict);
|
const char *next = utf8_decode(s + n, &code, strict);
|
||||||
if (next == NULL)
|
if (next == NULL || iscontp(next))
|
||||||
return luaL_error(L, "invalid UTF-8 code");
|
return luaL_error(L, MSGInvalid);
|
||||||
lua_pushinteger(L, n + 1);
|
lua_pushinteger(L, l_castU2S(n + 1));
|
||||||
lua_pushinteger(L, code);
|
lua_pushinteger(L, l_castU2S(code));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +260,8 @@ static int iter_auxlax (lua_State *L) {
|
|||||||
|
|
||||||
static int iter_codes (lua_State *L) {
|
static int iter_codes (lua_State *L) {
|
||||||
int lax = lua_toboolean(L, 2);
|
int lax = lua_toboolean(L, 2);
|
||||||
luaL_checkstring(L, 1);
|
const char *s = luaL_checkstring(L, 1);
|
||||||
|
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
|
||||||
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
|
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
|
||||||
lua_pushvalue(L, 1);
|
lua_pushvalue(L, 1);
|
||||||
lua_pushinteger(L, 0);
|
lua_pushinteger(L, 0);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
F2Ieq, /* no rounding; accepts only integral values */
|
F2Ieq, /* no rounding; accepts only integral values */
|
||||||
F2Ifloor, /* takes the floor of the number */
|
F2Ifloor, /* takes the floor of the number */
|
||||||
F2Iceil /* takes the ceil of the number */
|
F2Iceil /* takes the ceiling of the number */
|
||||||
} F2Imod;
|
} F2Imod;
|
||||||
|
|
||||||
|
|
||||||
@@ -76,40 +76,40 @@ typedef enum {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** fast track for 'gettable': if 't' is a table and 't[k]' is present,
|
** fast track for 'gettable'
|
||||||
** return 1 with 'slot' pointing to 't[k]' (position of final result).
|
|
||||||
** Otherwise, return 0 (meaning it will have to check metamethod)
|
|
||||||
** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL
|
|
||||||
** (otherwise). 'f' is the raw get function to use.
|
|
||||||
*/
|
*/
|
||||||
#define luaV_fastget(L,t,k,slot,f) \
|
#define luaV_fastget(t,k,res,f, tag) \
|
||||||
(!ttistable(t) \
|
(tag = (!ttistable(t) ? LUA_VNOTABLE : f(hvalue(t), k, res)))
|
||||||
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
|
|
||||||
: (slot = f(hvalue(t), k), /* else, do raw access */ \
|
|
||||||
!isempty(slot))) /* result not empty? */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special case of 'luaV_fastget' for integers, inlining the fast case
|
** Special case of 'luaV_fastget' for integers, inlining the fast case
|
||||||
** of 'luaH_getint'.
|
** of 'luaH_getint'.
|
||||||
*/
|
*/
|
||||||
#define luaV_fastgeti(L,t,k,slot) \
|
#define luaV_fastgeti(t,k,res,tag) \
|
||||||
(!ttistable(t) \
|
if (!ttistable(t)) tag = LUA_VNOTABLE; \
|
||||||
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
|
else { luaH_fastgeti(hvalue(t), k, res, tag); }
|
||||||
: (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \
|
|
||||||
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
|
|
||||||
!isempty(slot))) /* result not empty? */
|
#define luaV_fastset(t,k,val,hres,f) \
|
||||||
|
(hres = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, val)))
|
||||||
|
|
||||||
|
#define luaV_fastseti(t,k,val,hres) \
|
||||||
|
if (!ttistable(t)) hres = HNOTATABLE; \
|
||||||
|
else { luaH_fastseti(hvalue(t), k, val, hres); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Finish a fast set operation (when fast get succeeds). In that case,
|
** Finish a fast set operation (when fast set succeeds).
|
||||||
** 'slot' points to the place to put the value.
|
|
||||||
*/
|
*/
|
||||||
#define luaV_finishfastset(L,t,slot,v) \
|
#define luaV_finishfastset(L,t,v) luaC_barrierback(L, gcvalue(t), v)
|
||||||
{ setobj2t(L, cast(TValue *,slot), v); \
|
|
||||||
luaC_barrierback(L, gcvalue(t), v); }
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Shift right is the same as shift left with a negative 'y'
|
||||||
|
*/
|
||||||
|
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
|
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
|
||||||
@@ -120,10 +120,10 @@ LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode);
|
|||||||
LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
|
LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
|
||||||
F2Imod mode);
|
F2Imod mode);
|
||||||
LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
|
LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
|
||||||
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
|
LUAI_FUNC lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key,
|
||||||
StkId val, const TValue *slot);
|
StkId val, lu_byte tag);
|
||||||
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||||
TValue *val, const TValue *slot);
|
TValue *val, int aux);
|
||||||
LUAI_FUNC void luaV_finishOp (lua_State *L);
|
LUAI_FUNC void luaV_finishOp (lua_State *L);
|
||||||
LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci);
|
LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci);
|
||||||
LUAI_FUNC void luaV_concat (lua_State *L, int total);
|
LUAI_FUNC void luaV_concat (lua_State *L, int total);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lapi.h"
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
@@ -45,17 +46,25 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
|
|||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------- read --- */
|
/* --------------------------------------------------------------- read --- */
|
||||||
|
|
||||||
|
static int checkbuffer (ZIO *z) {
|
||||||
|
if (z->n == 0) { /* no bytes in buffer? */
|
||||||
|
if (luaZ_fill(z) == EOZ) /* try to read more */
|
||||||
|
return 0; /* no more input */
|
||||||
|
else {
|
||||||
|
z->n++; /* luaZ_fill consumed first byte; put it back */
|
||||||
|
z->p--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; /* now buffer has something */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
||||||
while (n) {
|
while (n) {
|
||||||
size_t m;
|
size_t m;
|
||||||
if (z->n == 0) { /* no bytes in buffer? */
|
if (!checkbuffer(z))
|
||||||
if (luaZ_fill(z) == EOZ) /* try to read more */
|
return n; /* no more input; return number of missing bytes */
|
||||||
return n; /* no more input; return number of missing bytes */
|
|
||||||
else {
|
|
||||||
z->n++; /* luaZ_fill consumed first byte; put it back */
|
|
||||||
z->p--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
|
m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
|
||||||
memcpy(b, z->p, m);
|
memcpy(b, z->p, m);
|
||||||
z->n -= m;
|
z->n -= m;
|
||||||
@@ -66,3 +75,15 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const void *luaZ_getaddr (ZIO* z, size_t n) {
|
||||||
|
const void *res;
|
||||||
|
if (!checkbuffer(z))
|
||||||
|
return NULL; /* no more input */
|
||||||
|
if (z->n < n) /* not enough bytes? */
|
||||||
|
return NULL; /* block not whole; cannot give an address */
|
||||||
|
res = z->p; /* get block address */
|
||||||
|
z->n -= n; /* consume these bytes */
|
||||||
|
z->p += n;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ typedef struct Mbuffer {
|
|||||||
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
||||||
#define luaZ_bufflen(buff) ((buff)->n)
|
#define luaZ_bufflen(buff) ((buff)->n)
|
||||||
|
|
||||||
#define luaZ_buffremove(buff,i) ((buff)->n -= (i))
|
#define luaZ_buffremove(buff,i) ((buff)->n -= cast_sizet(i))
|
||||||
#define luaZ_resetbuffer(buff) ((buff)->n = 0)
|
#define luaZ_resetbuffer(buff) ((buff)->n = 0)
|
||||||
|
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
|
|||||||
void *data);
|
void *data);
|
||||||
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
|
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
|
||||||
|
|
||||||
|
LUAI_FUNC const void *luaZ_getaddr (ZIO* z, size_t n);
|
||||||
|
|
||||||
|
|
||||||
/* --------- Private Part ------------------ */
|
/* --------- Private Part ------------------ */
|
||||||
|
|||||||
@@ -8,20 +8,18 @@ CWARNSCPP= \
|
|||||||
-Wfatal-errors \
|
-Wfatal-errors \
|
||||||
-Wextra \
|
-Wextra \
|
||||||
-Wshadow \
|
-Wshadow \
|
||||||
-Wsign-compare \
|
|
||||||
-Wundef \
|
-Wundef \
|
||||||
-Wwrite-strings \
|
-Wwrite-strings \
|
||||||
-Wredundant-decls \
|
-Wredundant-decls \
|
||||||
-Wdisabled-optimization \
|
-Wdisabled-optimization \
|
||||||
-Wdouble-promotion \
|
-Wdouble-promotion \
|
||||||
-Wmissing-declarations \
|
-Wmissing-declarations \
|
||||||
|
-Wconversion \
|
||||||
# the next warnings might be useful sometimes,
|
# the next warnings might be useful sometimes,
|
||||||
# but usually they generate too much noise
|
# but usually they generate too much noise
|
||||||
|
# -Wstrict-overflow=2 \
|
||||||
# -Werror \
|
# -Werror \
|
||||||
# -pedantic # warns if we use jump tables \
|
# -pedantic # warns if we use jump tables \
|
||||||
# -Wconversion \
|
|
||||||
# -Wsign-conversion \
|
|
||||||
# -Wstrict-overflow=2 \
|
|
||||||
# -Wformat=2 \
|
# -Wformat=2 \
|
||||||
# -Wcast-qual \
|
# -Wcast-qual \
|
||||||
|
|
||||||
@@ -57,22 +55,34 @@ CWARNS= $(CWARNSCPP) $(CWARNSC) $(CWARNGCC)
|
|||||||
|
|
||||||
# -pg -malign-double
|
# -pg -malign-double
|
||||||
# -DLUA_USE_CTYPE -DLUA_USE_APICHECK
|
# -DLUA_USE_CTYPE -DLUA_USE_APICHECK
|
||||||
# ('-ftrapv' for runtime checks of integer overflows)
|
|
||||||
# -fsanitize=undefined -ftrapv -fno-inline
|
|
||||||
# TESTS= -DLUA_USER_H='"ltests.h"' -O0 -g
|
|
||||||
|
|
||||||
|
# The following options help detect "undefined behavior"s that seldom
|
||||||
|
# create problems; some are only available in newer gcc versions. To
|
||||||
|
# use some of them, we also have to define an environment variable
|
||||||
|
# ASAN_OPTIONS="detect_invalid_pointer_pairs=2".
|
||||||
|
# -fsanitize=undefined (you may need to add "-lubsan" to libs)
|
||||||
|
# -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare
|
||||||
|
|
||||||
|
# Test mode: Add test library, turn on asserts, redefine several
|
||||||
|
# constants ("to give some bugs a chance"), track memory use, and add
|
||||||
|
# debug information.
|
||||||
|
# TESTS= -DLUA_USER_H='"ltests.h"' -Og -g
|
||||||
|
|
||||||
LOCAL = $(TESTS) $(CWARNS)
|
LOCAL = $(TESTS) $(CWARNS)
|
||||||
|
|
||||||
|
|
||||||
# enable Linux goodies
|
# To enable Linux goodies, -DLUA_USE_LINUX
|
||||||
MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE
|
# For C89, "-std=c89 -DLUA_USE_C89"
|
||||||
MYLDFLAGS= $(LOCAL) -Wl,-E
|
# Note that Linux/Posix options are not compatible with C89
|
||||||
MYLIBS= -ldl -lreadline
|
# (For 32-bit, add option "-m32" to MYCFLAGS and MYLDFLAGS.)
|
||||||
|
MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX
|
||||||
|
MYLDFLAGS= -Wl,-E
|
||||||
|
MYLIBS= -ldl
|
||||||
|
|
||||||
|
|
||||||
CC= gcc
|
CC= gcc
|
||||||
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common -march=native
|
# (Optionally we can use -march=native -mno-avx512f.)
|
||||||
|
CFLAGS= -Wall -O2 $(MYCFLAGS) -fno-stack-protector -fno-common
|
||||||
AR= ar rc
|
AR= ar rc
|
||||||
RANLIB= ranlib
|
RANLIB= ranlib
|
||||||
RM= rm -f
|
RM= rm -f
|
||||||
@@ -140,40 +150,45 @@ $(ALL_O): makefile ltests.h
|
|||||||
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
|
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
|
||||||
ltable.h lundump.h lvm.h
|
ltable.h lundump.h lvm.h
|
||||||
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
|
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h llimits.h
|
||||||
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
|
llimits.h
|
||||||
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
||||||
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
||||||
ldo.h lgc.h lstring.h ltable.h lvm.h
|
ldo.h lgc.h lstring.h ltable.h lvm.h lopnames.h
|
||||||
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
|
llimits.h
|
||||||
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
|
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
|
||||||
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h llimits.h
|
||||||
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
|
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
|
||||||
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
|
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
|
||||||
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
|
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
|
||||||
lparser.h lstring.h ltable.h lundump.h lvm.h
|
lparser.h lstring.h ltable.h lundump.h lvm.h
|
||||||
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
|
ldump.o: ldump.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
ltm.h lzio.h lmem.h lundump.h
|
lobject.h ltm.h lzio.h lmem.h lgc.h ltable.h lundump.h
|
||||||
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h
|
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h
|
||||||
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
|
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
|
||||||
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
|
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h llimits.h
|
||||||
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h llimits.h
|
||||||
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
|
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
|
||||||
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
|
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
|
||||||
lstring.h ltable.h
|
lstring.h ltable.h
|
||||||
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
|
llimits.h
|
||||||
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
|
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
|
||||||
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
|
llimits.h
|
||||||
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
|
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
|
||||||
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
|
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
|
||||||
lvm.h
|
lvm.h
|
||||||
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
|
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h \
|
||||||
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lobject.h
|
||||||
|
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h llimits.h
|
||||||
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
||||||
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
||||||
ldo.h lfunc.h lstring.h lgc.h ltable.h
|
ldo.h lfunc.h lstring.h lgc.h ltable.h
|
||||||
@@ -182,25 +197,28 @@ lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
|||||||
lstring.h ltable.h
|
lstring.h ltable.h
|
||||||
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
||||||
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
|
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
|
||||||
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
|
llimits.h
|
||||||
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||||
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
|
llimits.h
|
||||||
ltests.o: ltests.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
ltests.o: ltests.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
lobject.h ltm.h lzio.h lmem.h lauxlib.h lcode.h llex.h lopcodes.h \
|
lobject.h ltm.h lzio.h lmem.h lauxlib.h lcode.h llex.h lopcodes.h \
|
||||||
lparser.h lctype.h ldebug.h ldo.h lfunc.h lopnames.h lstring.h lgc.h \
|
lparser.h lctype.h ldebug.h ldo.h lfunc.h lopnames.h lstring.h lgc.h \
|
||||||
ltable.h lualib.h
|
ltable.h lualib.h
|
||||||
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||||
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h llimits.h
|
||||||
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
||||||
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
|
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
|
||||||
lundump.h
|
ltable.h lundump.h
|
||||||
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h \
|
||||||
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
llimits.h
|
||||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
|
lvm.o: lvm.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
ltable.h lvm.h ljumptab.h
|
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
|
||||||
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
|
lstring.h ltable.h lvm.h ljumptab.h
|
||||||
lobject.h ltm.h lzio.h
|
lzio.o: lzio.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||||
|
lobject.h ltm.h lzio.h lmem.h
|
||||||
|
|
||||||
# (end of Makefile)
|
# (end of Makefile)
|
||||||
|
|||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env lua5.3
|
#!/usr/bin/env lua
|
||||||
|
|
||||||
|
|
||||||
-- special marks:
|
-- special marks:
|
||||||
@@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
header = [[
|
header = [[
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Lua 5.4 Reference Manual</title>
|
<title>Lua 5.5 Reference Manual</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<link rel="stylesheet" href="lua.css">
|
<link rel="stylesheet" href="lua.css">
|
||||||
<link rel="stylesheet" href="manual.css">
|
<link rel="stylesheet" href="manual.css">
|
||||||
@@ -23,14 +23,14 @@ header = [[
|
|||||||
<hr>
|
<hr>
|
||||||
<h1>
|
<h1>
|
||||||
<a href="http://www.lua.org/home.html"><img src="logo.gif" alt="[Lua logo]" border="0"></a>
|
<a href="http://www.lua.org/home.html"><img src="logo.gif" alt="[Lua logo]" border="0"></a>
|
||||||
Lua 5.4 Reference Manual
|
Lua 5.5 Reference Manual
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
|
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
<a href="http://www.lua.org/copyright.html">Copyright</a>
|
<a href="http://www.lua.org/copyright.html">Copyright</a>
|
||||||
© 2022 Lua.org, PUC-Rio. All rights reserved.
|
© 2026 Lua.org, PUC-Rio. All rights reserved.
|
||||||
</small>
|
</small>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ item = function (s)
|
|||||||
local t, p = string.match(s, "^([^\n|]+)|()")
|
local t, p = string.match(s, "^([^\n|]+)|()")
|
||||||
if t then
|
if t then
|
||||||
s = string.sub(s, p)
|
s = string.sub(s, p)
|
||||||
s = Tag.b(t..": ") .. s
|
s = Tag.b(t) ..": " .. s
|
||||||
end
|
end
|
||||||
return Tag.li(fixpara(s))
|
return Tag.li(fixpara(s))
|
||||||
end,
|
end,
|
||||||
|
|||||||
+1108
-631
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* one.c -- Lua core, libraries, and interpreter in a single file
|
** Lua core, libraries, and interpreter in a single file.
|
||||||
|
** Compiling just this file generates a complete Lua stand-alone
|
||||||
|
** program:
|
||||||
|
**
|
||||||
|
** $ gcc -O2 -std=c99 -o lua onelua.c -lm
|
||||||
|
**
|
||||||
|
** or (for C89)
|
||||||
|
**
|
||||||
|
** $ gcc -O2 -std=c89 -DLUA_USE_C89 -o lua onelua.c -lm
|
||||||
|
**
|
||||||
|
** or (for Linux)
|
||||||
|
**
|
||||||
|
** gcc -O2 -o lua -DLUA_USE_LINUX -Wl,-E onelua.c -lm -ldl
|
||||||
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* default is to build the full interpreter */
|
/* default is to build the full interpreter */
|
||||||
@@ -11,15 +24,28 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* choose suitable platform-specific features */
|
|
||||||
/* some of these may need extra libraries such as -ldl -lreadline -lncurses */
|
/*
|
||||||
|
** Choose suitable platform-specific features. Default is no
|
||||||
|
** platform-specific features. Some of these options may need extra
|
||||||
|
** libraries such as -ldl -lreadline -lncurses
|
||||||
|
*/
|
||||||
#if 0
|
#if 0
|
||||||
#define LUA_USE_LINUX
|
#define LUA_USE_LINUX
|
||||||
#define LUA_USE_MACOSX
|
#define LUA_USE_MACOSX
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_ANSI
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Other specific features
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#define LUA_32BITS
|
||||||
|
#define LUA_USE_C89
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* no need to change anything below this line ----------------------------- */
|
/* no need to change anything below this line ----------------------------- */
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
@@ -40,12 +66,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
/* setup for luaconf.h */
|
/* setup for luaconf.h */
|
||||||
#define LUA_CORE
|
#define LUA_CORE
|
||||||
#define LUA_LIB
|
#define LUA_LIB
|
||||||
#define ltable_c
|
|
||||||
#define lvm_c
|
|
||||||
#include "luaconf.h"
|
#include "luaconf.h"
|
||||||
|
|
||||||
/* do not export internal symbols */
|
/* do not export internal symbols */
|
||||||
@@ -96,6 +120,11 @@
|
|||||||
#include "linit.c"
|
#include "linit.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* test library -- used only for internal development */
|
||||||
|
#if defined(LUA_DEBUG)
|
||||||
|
#include "ltests.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* lua */
|
/* lua */
|
||||||
#ifdef MAKE_LUA
|
#ifdef MAKE_LUA
|
||||||
#include "lua.c"
|
#include "lua.c"
|
||||||
|
|||||||
Regular → Executable
+13
-35
@@ -1,9 +1,13 @@
|
|||||||
#!../lua
|
#!../lua
|
||||||
-- $Id: testes/all.lua $
|
-- $Id: testes/all.lua $
|
||||||
-- See Copyright Notice at the end of this file
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
local version = "Lua 5.4"
|
global _soft, _port, _nomsg
|
||||||
|
global T
|
||||||
|
|
||||||
|
local version = "Lua 5.5"
|
||||||
if _VERSION ~= version then
|
if _VERSION ~= version then
|
||||||
io.stderr:write("This test suite is for ", version,
|
io.stderr:write("This test suite is for ", version,
|
||||||
", not for ", _VERSION, "\nExiting tests")
|
", not for ", _VERSION, "\nExiting tests")
|
||||||
@@ -28,14 +32,13 @@ _nomsg = rawget(_G, "_nomsg") or false
|
|||||||
local usertests = rawget(_G, "_U")
|
local usertests = rawget(_G, "_U")
|
||||||
|
|
||||||
if usertests then
|
if usertests then
|
||||||
-- tests for sissies ;) Avoid problems
|
_soft = true -- avoid tests that take too long
|
||||||
_soft = true
|
_port = true -- avoid non-portable tests
|
||||||
_port = true
|
_nomsg = true -- avoid messages about tests not performed
|
||||||
_nomsg = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- tests should require debug when needed
|
-- tests should require debug when needed
|
||||||
debug = nil
|
global debug; debug = nil
|
||||||
|
|
||||||
|
|
||||||
if usertests then
|
if usertests then
|
||||||
@@ -72,7 +75,7 @@ do -- (
|
|||||||
|
|
||||||
-- track messages for tests not performed
|
-- track messages for tests not performed
|
||||||
local msgs = {}
|
local msgs = {}
|
||||||
function Message (m)
|
global function Message (m)
|
||||||
if not _nomsg then
|
if not _nomsg then
|
||||||
print(m)
|
print(m)
|
||||||
msgs[#msgs+1] = string.sub(m, 3, -3)
|
msgs[#msgs+1] = string.sub(m, 3, -3)
|
||||||
@@ -163,6 +166,7 @@ f()
|
|||||||
|
|
||||||
dofile('db.lua')
|
dofile('db.lua')
|
||||||
assert(dofile('calls.lua') == deep and deep)
|
assert(dofile('calls.lua') == deep and deep)
|
||||||
|
_G.deep = nil
|
||||||
olddofile('strings.lua')
|
olddofile('strings.lua')
|
||||||
olddofile('literals.lua')
|
olddofile('literals.lua')
|
||||||
dofile('tpack.lua')
|
dofile('tpack.lua')
|
||||||
@@ -182,6 +186,7 @@ dofile('nextvar.lua')
|
|||||||
dofile('pm.lua')
|
dofile('pm.lua')
|
||||||
dofile('utf8.lua')
|
dofile('utf8.lua')
|
||||||
dofile('api.lua')
|
dofile('api.lua')
|
||||||
|
dofile('memerr.lua')
|
||||||
assert(dofile('events.lua') == 12)
|
assert(dofile('events.lua') == 12)
|
||||||
dofile('vararg.lua')
|
dofile('vararg.lua')
|
||||||
dofile('closure.lua')
|
dofile('closure.lua')
|
||||||
@@ -282,30 +287,3 @@ end
|
|||||||
|
|
||||||
print("final OK !!!")
|
print("final OK !!!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
*****************************************************************************
|
|
||||||
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*****************************************************************************
|
|
||||||
]]
|
|
||||||
|
|
||||||
|
|||||||
+185
-302
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/api.lua $
|
-- $Id: testes/api.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
if T==nil then
|
if T==nil then
|
||||||
(Message or print)('\n >>> testC not active: skipping API tests <<<\n')
|
(Message or print)('\n >>> testC not active: skipping API tests <<<\n')
|
||||||
@@ -11,10 +11,7 @@ local debug = require "debug"
|
|||||||
local pack = table.pack
|
local pack = table.pack
|
||||||
|
|
||||||
|
|
||||||
-- standard error message for memory errors
|
local function tcheck (t1, t2)
|
||||||
local MEMERRMSG = "not enough memory"
|
|
||||||
|
|
||||||
function tcheck (t1, t2)
|
|
||||||
assert(t1.n == (t2.n or #t2) + 1)
|
assert(t1.n == (t2.n or #t2) + 1)
|
||||||
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
|
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
|
||||||
end
|
end
|
||||||
@@ -28,7 +25,7 @@ end
|
|||||||
|
|
||||||
print('testing C API')
|
print('testing C API')
|
||||||
|
|
||||||
a = T.testC("pushvalue R; return 1")
|
local a = T.testC("pushvalue R; return 1")
|
||||||
assert(a == debug.getregistry())
|
assert(a == debug.getregistry())
|
||||||
|
|
||||||
|
|
||||||
@@ -43,10 +40,10 @@ a = T.d2s(12458954321123.0)
|
|||||||
assert(a == string.pack("d", 12458954321123.0))
|
assert(a == string.pack("d", 12458954321123.0))
|
||||||
assert(T.s2d(a) == 12458954321123.0)
|
assert(T.s2d(a) == 12458954321123.0)
|
||||||
|
|
||||||
a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
|
local a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
|
||||||
assert(a == 2 and b == 3 and not c)
|
assert(a == 2 and b == 3 and not c)
|
||||||
|
|
||||||
f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
|
local f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
|
||||||
a,b,c = f()
|
a,b,c = f()
|
||||||
assert(a == 2 and b == 3 and not c)
|
assert(a == 2 and b == 3 and not c)
|
||||||
|
|
||||||
@@ -61,7 +58,7 @@ assert(a==false and b==true and c==false)
|
|||||||
a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
|
a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
|
||||||
assert(a == 40 and b == 5 and not c)
|
assert(a == 40 and b == 5 and not c)
|
||||||
|
|
||||||
t = pack(T.testC("settop 5; return *", 2, 3))
|
local t = pack(T.testC("settop 5; return *", 2, 3))
|
||||||
tcheck(t, {n=4,2,3})
|
tcheck(t, {n=4,2,3})
|
||||||
|
|
||||||
t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
|
t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
|
||||||
@@ -117,7 +114,7 @@ end
|
|||||||
|
|
||||||
-- testing warnings
|
-- testing warnings
|
||||||
T.testC([[
|
T.testC([[
|
||||||
warningC "#This shold be a"
|
warningC "#This should be a"
|
||||||
warningC " single "
|
warningC " single "
|
||||||
warning "warning"
|
warning "warning"
|
||||||
warningC "#This should be "
|
warningC "#This should be "
|
||||||
@@ -165,17 +162,35 @@ do -- test returning more results than fit in the caller stack
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- testing multiple returns
|
||||||
|
local function foo (n)
|
||||||
|
if n > 0 then return n, foo(n - 1) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = {T.testC("call 1 10; return 10", foo, 20)}
|
||||||
|
assert(t[1] == 20 and t[10] == 11 and t[11] == nil)
|
||||||
|
|
||||||
|
local t = table.pack(T.testC("call 1 10; return 10", foo, 2))
|
||||||
|
assert(t[1] == 2 and t[2] == 1 and t[3] == nil and t.n == 10)
|
||||||
|
|
||||||
|
local t = {T.testC([[
|
||||||
|
checkstack 300 "error"; call 1 250; return 250]], foo, 250)}
|
||||||
|
assert(t[1] == 250 and t[250] == 1 and t[251] == nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- testing globals
|
-- testing globals
|
||||||
_G.a = 14; _G.b = "a31"
|
_G.AA = 14; _G.BB = "a31"
|
||||||
local a = {T.testC[[
|
local a = {T.testC[[
|
||||||
getglobal a;
|
getglobal AA;
|
||||||
getglobal b;
|
getglobal BB;
|
||||||
getglobal b;
|
getglobal BB;
|
||||||
setglobal a;
|
setglobal AA;
|
||||||
return *
|
return *
|
||||||
]]}
|
]]}
|
||||||
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31")
|
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.AA == "a31")
|
||||||
|
|
||||||
|
_G.AA, _G.BB = nil
|
||||||
|
|
||||||
-- testing arith
|
-- testing arith
|
||||||
assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5)
|
assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5)
|
||||||
@@ -199,13 +214,14 @@ a,b,c = T.testC([[pushnum 1;
|
|||||||
pushstring 10; arith _;
|
pushstring 10; arith _;
|
||||||
pushstring 5; return 3]])
|
pushstring 5; return 3]])
|
||||||
assert(a == 1 and b == -10 and c == "5")
|
assert(a == 1 and b == -10 and c == "5")
|
||||||
mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
|
local mt = {
|
||||||
|
__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
|
||||||
__mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end,
|
__mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end,
|
||||||
__unm = function (a) return setmetatable({a[1]* 2}, mt) end}
|
__unm = function (a) return setmetatable({a[1]* 2}, mt) end}
|
||||||
a,b,c = setmetatable({4}, mt),
|
a,b,c = setmetatable({4}, mt),
|
||||||
setmetatable({8}, mt),
|
setmetatable({8}, mt),
|
||||||
setmetatable({-3}, mt)
|
setmetatable({-3}, mt)
|
||||||
x,y,z = T.testC("arith +; return 2", 10, a, b)
|
local x,y,z = T.testC("arith +; return 2", 10, a, b)
|
||||||
assert(x == 10 and y[1] == 12 and z == nil)
|
assert(x == 10 and y[1] == 12 and z == nil)
|
||||||
assert(T.testC("arith %; return 1", a, c)[1] == 4%-3)
|
assert(T.testC("arith %; return 1", a, c)[1] == 4%-3)
|
||||||
assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] ==
|
assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] ==
|
||||||
@@ -230,7 +246,8 @@ assert(not T.testC("compare LT 1 4, return 1"))
|
|||||||
assert(not T.testC("compare LE 9 1, return 1"))
|
assert(not T.testC("compare LE 9 1, return 1"))
|
||||||
assert(not T.testC("compare EQ 9 9, return 1"))
|
assert(not T.testC("compare EQ 9 9, return 1"))
|
||||||
|
|
||||||
local b = {__lt = function (a,b) return a[1] < b[1] end}
|
local b = {__lt = function (a,b) return a[1] < b[1] end,
|
||||||
|
__le = function (a,b) return a[1] <= b[1] end}
|
||||||
local a1,a3,a4 = setmetatable({1}, b),
|
local a1,a3,a4 = setmetatable({1}, b),
|
||||||
setmetatable({3}, b),
|
setmetatable({3}, b),
|
||||||
setmetatable({4}, b)
|
setmetatable({4}, b)
|
||||||
@@ -312,9 +329,9 @@ assert(T.testC("concat 1; return 1", "xuxu") == "xuxu")
|
|||||||
|
|
||||||
-- testing lua_is
|
-- testing lua_is
|
||||||
|
|
||||||
function B(x) return x and 1 or 0 end
|
local function B (x) return x and 1 or 0 end
|
||||||
|
|
||||||
function count (x, n)
|
local function count (x, n)
|
||||||
n = n or 2
|
n = n or 2
|
||||||
local prog = [[
|
local prog = [[
|
||||||
isnumber %d;
|
isnumber %d;
|
||||||
@@ -345,7 +362,7 @@ assert(count(nil, 15) == 100)
|
|||||||
|
|
||||||
-- testing lua_to...
|
-- testing lua_to...
|
||||||
|
|
||||||
function to (s, x, n)
|
local function to (s, x, n)
|
||||||
n = n or 2
|
n = n or 2
|
||||||
return T.testC(string.format("%s %d; return 1", s, n), x)
|
return T.testC(string.format("%s %d; return 1", s, n), x)
|
||||||
end
|
end
|
||||||
@@ -397,6 +414,10 @@ do
|
|||||||
-- trivial error
|
-- trivial error
|
||||||
assert(T.checkpanic("pushstring hi; error") == "hi")
|
assert(T.checkpanic("pushstring hi; error") == "hi")
|
||||||
|
|
||||||
|
-- thread status inside panic (bug in 5.4.4)
|
||||||
|
assert(T.checkpanic("pushstring hi; error", "threadstatus; return 2") ==
|
||||||
|
"ERRRUN")
|
||||||
|
|
||||||
-- using the stack inside panic
|
-- using the stack inside panic
|
||||||
assert(T.checkpanic("pushstring hi; error;",
|
assert(T.checkpanic("pushstring hi; error;",
|
||||||
[[checkstack 5 XX
|
[[checkstack 5 XX
|
||||||
@@ -405,20 +426,30 @@ do
|
|||||||
concat 3]]) == "hi alo mundo")
|
concat 3]]) == "hi alo mundo")
|
||||||
|
|
||||||
-- "argerror" without frames
|
-- "argerror" without frames
|
||||||
assert(T.checkpanic("loadstring 4") ==
|
assert(T.checkpanic("loadstring 4 name bt") ==
|
||||||
"bad argument #4 (string expected, got no value)")
|
"bad argument #4 (string expected, got no value)")
|
||||||
|
|
||||||
|
|
||||||
-- memory error
|
-- memory error + thread status
|
||||||
T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
|
local x = T.checkpanic(
|
||||||
assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
|
[[ alloccount 0 # force a memory error in next line
|
||||||
T.totalmem(0) -- restore high limit
|
newtable
|
||||||
|
]],
|
||||||
|
[[
|
||||||
|
alloccount -1 # allow free allocations again
|
||||||
|
pushstring XX
|
||||||
|
threadstatus
|
||||||
|
concat 2 # to make sure message came from here
|
||||||
|
return 1
|
||||||
|
]])
|
||||||
|
T.alloccount()
|
||||||
|
assert(x == "XX" .. "not enough memory")
|
||||||
|
|
||||||
-- stack error
|
-- stack error
|
||||||
if not _soft then
|
if not _soft then
|
||||||
local msg = T.checkpanic[[
|
local msg = T.checkpanic[[
|
||||||
pushstring "function f() f() end"
|
pushstring "function f() f() end"
|
||||||
loadstring -1; call 0 0
|
loadstring -1 name t; call 0 0
|
||||||
getglobal f; call 0 0
|
getglobal f; call 0 0
|
||||||
]]
|
]]
|
||||||
assert(string.find(msg, "stack overflow"))
|
assert(string.find(msg, "stack overflow"))
|
||||||
@@ -428,7 +459,7 @@ do
|
|||||||
assert(T.checkpanic([[
|
assert(T.checkpanic([[
|
||||||
pushstring "return {__close = function () Y = 'ho'; end}"
|
pushstring "return {__close = function () Y = 'ho'; end}"
|
||||||
newtable
|
newtable
|
||||||
loadstring -2
|
loadstring -2 name t
|
||||||
call 0 1
|
call 0 1
|
||||||
setmetatable -2
|
setmetatable -2
|
||||||
toclose -1
|
toclose -1
|
||||||
@@ -456,6 +487,8 @@ if not _soft then
|
|||||||
print'+'
|
print'+'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local lim = _soft and 500 or 12000
|
local lim = _soft and 500 or 12000
|
||||||
local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"}
|
local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"}
|
||||||
for i = 1,lim do
|
for i = 1,lim do
|
||||||
@@ -463,7 +496,7 @@ for i = 1,lim do
|
|||||||
prog[#prog + 1] = "pushnum " .. i * 10
|
prog[#prog + 1] = "pushnum " .. i * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
prog[#prog + 1] = "rawgeti R 2" -- get global table in registry
|
prog[#prog + 1] = "rawgeti R !G" -- get global table in registry
|
||||||
prog[#prog + 1] = "insert " .. -(2*lim + 2)
|
prog[#prog + 1] = "insert " .. -(2*lim + 2)
|
||||||
|
|
||||||
for i = 1,lim do
|
for i = 1,lim do
|
||||||
@@ -479,39 +512,98 @@ for i = 1,lim do assert(t[i] == i*10); t[i] = undef end
|
|||||||
assert(next(t) == nil)
|
assert(next(t) == nil)
|
||||||
prog, g, t = nil
|
prog, g, t = nil
|
||||||
|
|
||||||
|
do -- shrink stack
|
||||||
|
local m1, m2 = 0, collectgarbage"count" * 1024
|
||||||
|
while m1 ~= m2 do -- repeat until stable
|
||||||
|
collectgarbage()
|
||||||
|
m1 = m2
|
||||||
|
m2 = collectgarbage"count" * 1024
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- testing errors
|
-- testing errors
|
||||||
|
|
||||||
a = T.testC([[
|
a = T.testC([[
|
||||||
loadstring 2; pcall 0 1 0;
|
loadstring 2 name t; pcall 0 1 0;
|
||||||
pushvalue 3; insert -2; pcall 1 1 0;
|
pushvalue 3; insert -2; pcall 1 1 0;
|
||||||
pcall 0 0 0;
|
pcall 0 0 0;
|
||||||
return 1
|
return 1
|
||||||
]], "x=150", function (a) assert(a==nil); return 3 end)
|
]], "XX=150", function (a) assert(a==nil); return 3 end)
|
||||||
|
|
||||||
assert(type(a) == 'string' and x == 150)
|
assert(type(a) == 'string' and XX == 150)
|
||||||
|
_G.XX = nil
|
||||||
|
|
||||||
function check3(p, ...)
|
local function check3(p, ...)
|
||||||
local arg = {...}
|
local arg = {...}
|
||||||
assert(#arg == 3)
|
assert(#arg == 3)
|
||||||
assert(string.find(arg[3], p))
|
assert(string.find(arg[3], p))
|
||||||
end
|
end
|
||||||
check3(":1:", T.testC("loadstring 2; return *", "x="))
|
check3(":1:", T.testC("loadstring 2 name t; return *", "x="))
|
||||||
check3("%.", T.testC("loadfile 2; return *", "."))
|
check3("%.", T.testC("loadfile 2; return *", "."))
|
||||||
check3("xxxx", T.testC("loadfile 2; return *", "xxxx"))
|
check3("xxxx", T.testC("loadfile 2; return *", "xxxx"))
|
||||||
|
|
||||||
-- test errors in non protected threads
|
-- test errors in non protected threads
|
||||||
function checkerrnopro (code, msg)
|
local function checkerrnopro (code, msg)
|
||||||
local th = coroutine.create(function () end) -- create new thread
|
local th = coroutine.create(function () end) -- create new thread
|
||||||
local stt, err = pcall(T.testC, th, code) -- run code there
|
local stt, err = pcall(T.testC, th, code) -- run code there
|
||||||
assert(not stt and string.find(err, msg))
|
assert(not stt and string.find(err, msg))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
print("testing load of binaries in fixed buffers")
|
||||||
|
local source = {}
|
||||||
|
local N = 1000
|
||||||
|
-- create a somewhat "large" source
|
||||||
|
for i = 1, N do source[i] = "X = X + 1; " end
|
||||||
|
-- add a long string to the source
|
||||||
|
source[#source + 1] = string.format("Y = '%s'", string.rep("a", N));
|
||||||
|
source = table.concat(source)
|
||||||
|
-- give chunk an explicit name to avoid using source as name
|
||||||
|
source = load(source, "name1")
|
||||||
|
-- dump without debug information
|
||||||
|
source = string.dump(source, true)
|
||||||
|
-- each "X=X+1" generates 4 opcodes with 4 bytes each, plus the string
|
||||||
|
assert(#source > N * 4 * 4 + N)
|
||||||
|
collectgarbage(); collectgarbage()
|
||||||
|
local m1 = collectgarbage"count" * 1024
|
||||||
|
-- load dump using fixed buffer
|
||||||
|
local code = T.testC([[
|
||||||
|
loadstring 2 name B;
|
||||||
|
return 1
|
||||||
|
]], source)
|
||||||
|
collectgarbage()
|
||||||
|
local m2 = collectgarbage"count" * 1024
|
||||||
|
-- load used fewer than 400 bytes. Code alone has more than 3*N bytes,
|
||||||
|
-- and string literal has N bytes. Both were not loaded.
|
||||||
|
assert(m2 > m1 and m2 - m1 < 400)
|
||||||
|
X = 0; code(); assert(X == N and Y == string.rep("a", N))
|
||||||
|
X = nil; Y = nil
|
||||||
|
|
||||||
|
-- testing debug info in fixed buffers
|
||||||
|
source = {"X = 0"}
|
||||||
|
for i = 2, 300 do source[i] = "X = X + 1" end
|
||||||
|
source[#source + 1] = "X = X + {}" -- error in last line
|
||||||
|
source = table.concat(source, "\n")
|
||||||
|
source = load(source, "name1")
|
||||||
|
source = string.dump(source)
|
||||||
|
-- load dump using fixed buffer
|
||||||
|
local code = T.testC([[
|
||||||
|
loadstring 2 name B;
|
||||||
|
return 1
|
||||||
|
]], source)
|
||||||
|
checkerr(":301:", code) -- correct line information
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
if not _soft then
|
if not _soft then
|
||||||
collectgarbage("stop") -- avoid __gc with full stack
|
collectgarbage("stop") -- avoid __gc with full stack
|
||||||
checkerrnopro("pushnum 3; call 0 0", "attempt to call")
|
checkerrnopro("pushnum 3; call 0 0", "attempt to call")
|
||||||
print"testing stack overflow in unprotected thread"
|
print"testing stack overflow in unprotected thread"
|
||||||
function f () f() end
|
function F () F() end
|
||||||
checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow")
|
checkerrnopro("getglobal 'F'; call 0 0;", "stack overflow")
|
||||||
|
F = nil
|
||||||
collectgarbage("restart")
|
collectgarbage("restart")
|
||||||
end
|
end
|
||||||
print"+"
|
print"+"
|
||||||
@@ -588,7 +680,7 @@ assert(a[a] == "x")
|
|||||||
|
|
||||||
b = setmetatable({p = a}, {})
|
b = setmetatable({p = a}, {})
|
||||||
getmetatable(b).__index = function (t, i) return t.p[i] end
|
getmetatable(b).__index = function (t, i) return t.p[i] end
|
||||||
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
|
local k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
|
||||||
assert(x == 15 and k == 35)
|
assert(x == 15 and k == 35)
|
||||||
k = T.testC("getfield 2 y, return 1", b)
|
k = T.testC("getfield 2 y, return 1", b)
|
||||||
assert(k == 12)
|
assert(k == 12)
|
||||||
@@ -719,7 +811,7 @@ assert(debug.getuservalue(b) == 134)
|
|||||||
-- test barrier for uservalues
|
-- test barrier for uservalues
|
||||||
do
|
do
|
||||||
local oldmode = collectgarbage("incremental")
|
local oldmode = collectgarbage("incremental")
|
||||||
T.gcstate("atomic")
|
T.gcstate("enteratomic")
|
||||||
assert(T.gccolor(b) == "black")
|
assert(T.gccolor(b) == "black")
|
||||||
debug.setuservalue(b, {x = 100})
|
debug.setuservalue(b, {x = 100})
|
||||||
T.gcstate("pause") -- complete collection
|
T.gcstate("pause") -- complete collection
|
||||||
@@ -748,8 +840,8 @@ local i = T.ref{}
|
|||||||
T.unref(i)
|
T.unref(i)
|
||||||
assert(T.ref{} == i)
|
assert(T.ref{} == i)
|
||||||
|
|
||||||
Arr = {}
|
local Arr = {}
|
||||||
Lim = 100
|
local Lim = 100
|
||||||
for i=1,Lim do -- lock many objects
|
for i=1,Lim do -- lock many objects
|
||||||
Arr[i] = T.ref({})
|
Arr[i] = T.ref({})
|
||||||
end
|
end
|
||||||
@@ -761,7 +853,7 @@ for i=1,Lim do -- unlock all them
|
|||||||
T.unref(Arr[i])
|
T.unref(Arr[i])
|
||||||
end
|
end
|
||||||
|
|
||||||
function printlocks ()
|
local function printlocks ()
|
||||||
local f = T.makeCfunc("gettable R; return 1")
|
local f = T.makeCfunc("gettable R; return 1")
|
||||||
local n = f("n")
|
local n = f("n")
|
||||||
print("n", n)
|
print("n", n)
|
||||||
@@ -793,8 +885,8 @@ assert(type(T.getref(a)) == 'table')
|
|||||||
|
|
||||||
|
|
||||||
-- colect in cl the `val' of all collected userdata
|
-- colect in cl the `val' of all collected userdata
|
||||||
tt = {}
|
local tt = {}
|
||||||
cl = {n=0}
|
local cl = {n=0}
|
||||||
A = nil; B = nil
|
A = nil; B = nil
|
||||||
local F
|
local F
|
||||||
F = function (x)
|
F = function (x)
|
||||||
@@ -811,12 +903,13 @@ F = function (x)
|
|||||||
assert(T.udataval(A) == B)
|
assert(T.udataval(A) == B)
|
||||||
debug.getmetatable(A) -- just access it
|
debug.getmetatable(A) -- just access it
|
||||||
end
|
end
|
||||||
A = x -- ressurect userdata
|
A = x -- resurrect userdata
|
||||||
B = udval
|
B = udval
|
||||||
return 1,2,3
|
return 1,2,3
|
||||||
end
|
end
|
||||||
tt.__gc = F
|
tt.__gc = F
|
||||||
|
|
||||||
|
|
||||||
-- test whether udate collection frees memory in the right time
|
-- test whether udate collection frees memory in the right time
|
||||||
do
|
do
|
||||||
collectgarbage();
|
collectgarbage();
|
||||||
@@ -853,9 +946,9 @@ end
|
|||||||
collectgarbage("stop")
|
collectgarbage("stop")
|
||||||
|
|
||||||
-- create 3 userdatas with tag `tt'
|
-- create 3 userdatas with tag `tt'
|
||||||
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a)
|
a = T.newuserdata(0); debug.setmetatable(a, tt); local na = T.udataval(a)
|
||||||
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b)
|
b = T.newuserdata(0); debug.setmetatable(b, tt); local nb = T.udataval(b)
|
||||||
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c)
|
c = T.newuserdata(0); debug.setmetatable(c, tt); local nc = T.udataval(c)
|
||||||
|
|
||||||
-- create userdata without meta table
|
-- create userdata without meta table
|
||||||
x = T.newuserdata(4)
|
x = T.newuserdata(4)
|
||||||
@@ -866,29 +959,31 @@ checkerr("FILE%* expected, got userdata", io.input, x)
|
|||||||
|
|
||||||
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
|
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
|
||||||
|
|
||||||
d=T.ref(a);
|
-- Test references in an arbitrary table
|
||||||
e=T.ref(b);
|
local reftable = {}
|
||||||
f=T.ref(c);
|
local d = T.ref(a, reftable);
|
||||||
t = {T.getref(d), T.getref(e), T.getref(f)}
|
local e = T.ref(b, reftable);
|
||||||
|
local f = T.ref(c, reftable);
|
||||||
|
t = {T.getref(d, reftable), T.getref(e, reftable), T.getref(f, reftable)}
|
||||||
assert(t[1] == a and t[2] == b and t[3] == c)
|
assert(t[1] == a and t[2] == b and t[3] == c)
|
||||||
|
|
||||||
t=nil; a=nil; c=nil;
|
t=nil; a=nil; c=nil;
|
||||||
T.unref(e); T.unref(f)
|
T.unref(e, reftable); T.unref(f, reftable)
|
||||||
|
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
|
|
||||||
-- check that unref objects have been collected
|
-- check that unref objects have been collected
|
||||||
assert(#cl == 1 and cl[1] == nc)
|
assert(#cl == 1 and cl[1] == nc)
|
||||||
|
|
||||||
x = T.getref(d)
|
x = T.getref(d, reftable)
|
||||||
assert(type(x) == 'userdata' and debug.getmetatable(x) == tt)
|
assert(type(x) == 'userdata' and debug.getmetatable(x) == tt)
|
||||||
x =nil
|
x =nil
|
||||||
tt.b = b -- create cycle
|
tt.b = b -- create cycle
|
||||||
tt=nil -- frees tt for GC
|
tt=nil -- frees tt for GC
|
||||||
A = nil
|
A = nil
|
||||||
b = nil
|
b = nil
|
||||||
T.unref(d);
|
T.unref(d, reftable);
|
||||||
n5 = T.newuserdata(0)
|
local n5 = T.newuserdata(0)
|
||||||
debug.setmetatable(n5, {__gc=F})
|
debug.setmetatable(n5, {__gc=F})
|
||||||
n5 = T.udataval(n5)
|
n5 = T.udataval(n5)
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
@@ -896,6 +991,21 @@ assert(#cl == 4)
|
|||||||
-- check order of collection
|
-- check order of collection
|
||||||
assert(cl[2] == n5 and cl[3] == nb and cl[4] == na)
|
assert(cl[2] == n5 and cl[3] == nb and cl[4] == na)
|
||||||
|
|
||||||
|
-- reuse a reference in 'reftable'
|
||||||
|
T.unref(T.ref(23, reftable), reftable)
|
||||||
|
|
||||||
|
do -- check reftable
|
||||||
|
local count = 0
|
||||||
|
local i = 1
|
||||||
|
while reftable[i] ~= 0 do
|
||||||
|
i = reftable[i] -- traverse linked list of free references
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
-- maximum number of simultaneously locked objects was 3
|
||||||
|
assert(count == 3 and #reftable == 3 + 1) -- +1 for reserved [1]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
collectgarbage"restart"
|
collectgarbage"restart"
|
||||||
|
|
||||||
|
|
||||||
@@ -959,11 +1069,11 @@ print'+'
|
|||||||
|
|
||||||
|
|
||||||
-- testing changing hooks during hooks
|
-- testing changing hooks during hooks
|
||||||
_G.t = {}
|
_G.TT = {}
|
||||||
T.sethook([[
|
T.sethook([[
|
||||||
# set a line hook after 3 count hooks
|
# set a line hook after 3 count hooks
|
||||||
sethook 4 0 '
|
sethook 4 0 '
|
||||||
getglobal t;
|
getglobal TT;
|
||||||
pushvalue -3; append -2
|
pushvalue -3; append -2
|
||||||
pushvalue -2; append -2
|
pushvalue -2; append -2
|
||||||
']], "c", 3)
|
']], "c", 3)
|
||||||
@@ -973,12 +1083,13 @@ a = 1 -- count hook (set line hook)
|
|||||||
a = 1 -- line hook
|
a = 1 -- line hook
|
||||||
a = 1 -- line hook
|
a = 1 -- line hook
|
||||||
debug.sethook()
|
debug.sethook()
|
||||||
t = _G.t
|
local t = _G.TT
|
||||||
assert(t[1] == "line")
|
assert(t[1] == "line")
|
||||||
line = t[2]
|
local line = t[2]
|
||||||
assert(t[3] == "line" and t[4] == line + 1)
|
assert(t[3] == "line" and t[4] == line + 1)
|
||||||
assert(t[5] == "line" and t[6] == line + 2)
|
assert(t[5] == "line" and t[6] == line + 2)
|
||||||
assert(t[7] == nil)
|
assert(t[7] == nil)
|
||||||
|
_G.TT = nil
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
@@ -1003,6 +1114,7 @@ do -- testing errors during GC
|
|||||||
collectgarbage("restart")
|
collectgarbage("restart")
|
||||||
warn("@on")
|
warn("@on")
|
||||||
end
|
end
|
||||||
|
_G.A = nil
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- test for userdata vals
|
-- test for userdata vals
|
||||||
do
|
do
|
||||||
@@ -1032,17 +1144,19 @@ assert(a == 'alo' and b == '3')
|
|||||||
|
|
||||||
T.doremote(L1, "_ERRORMESSAGE = nil")
|
T.doremote(L1, "_ERRORMESSAGE = nil")
|
||||||
-- error: `sin' is not defined
|
-- error: `sin' is not defined
|
||||||
a, _, b = T.doremote(L1, "return sin(1)")
|
a, b, c = T.doremote(L1, "return sin(1)")
|
||||||
assert(a == nil and b == 2) -- 2 == run-time error
|
assert(a == nil and c == 2) -- 2 == run-time error
|
||||||
|
|
||||||
-- error: syntax error
|
-- error: syntax error
|
||||||
a, b, c = T.doremote(L1, "return a+")
|
a, b, c = T.doremote(L1, "return a+")
|
||||||
assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error
|
assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error
|
||||||
|
|
||||||
T.loadlib(L1)
|
T.loadlib(L1, 2, ~2) -- load only 'package', preload all others
|
||||||
a, b, c = T.doremote(L1, [[
|
a, b, c = T.doremote(L1, [[
|
||||||
string = require'string'
|
string = require'string'
|
||||||
a = require'_G'; assert(a == _G and require("_G") == a)
|
local initialG = _G -- not loaded yet
|
||||||
|
local a = require'_G'; assert(a == _G and require("_G") == a)
|
||||||
|
assert(initialG == nil and io == nil) -- now we have 'assert'
|
||||||
io = require'io'; assert(type(io.read) == "function")
|
io = require'io'; assert(type(io.read) == "function")
|
||||||
assert(require("io") == io)
|
assert(require("io") == io)
|
||||||
a = require'table'; assert(type(a.insert) == "function")
|
a = require'table'; assert(type(a.insert) == "function")
|
||||||
@@ -1056,7 +1170,7 @@ T.closestate(L1);
|
|||||||
|
|
||||||
|
|
||||||
L1 = T.newstate()
|
L1 = T.newstate()
|
||||||
T.loadlib(L1)
|
T.loadlib(L1, 0, 0)
|
||||||
T.doremote(L1, "a = {}")
|
T.doremote(L1, "a = {}")
|
||||||
T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1;
|
T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1;
|
||||||
settable -3]])
|
settable -3]])
|
||||||
@@ -1108,7 +1222,8 @@ do
|
|||||||
local a, b = pcall(T.makeCfunc[[
|
local a, b = pcall(T.makeCfunc[[
|
||||||
call 0 1 # create resource
|
call 0 1 # create resource
|
||||||
toclose -1 # mark it to be closed
|
toclose -1 # mark it to be closed
|
||||||
error # resource is the error object
|
pushvalue -1 # replicate it as error object
|
||||||
|
error # resource right after error object
|
||||||
]], newresource)
|
]], newresource)
|
||||||
assert(a == false and b[1] == 11)
|
assert(a == false and b[1] == 11)
|
||||||
assert(#openresource == 0) -- was closed
|
assert(#openresource == 0) -- was closed
|
||||||
@@ -1184,238 +1299,6 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
** {==================================================================
|
|
||||||
** Testing memory limits
|
|
||||||
** ===================================================================
|
|
||||||
--]]
|
|
||||||
|
|
||||||
print("memory-allocation errors")
|
|
||||||
|
|
||||||
checkerr("block too big", T.newuserdata, math.maxinteger)
|
|
||||||
collectgarbage()
|
|
||||||
local f = load"local a={}; for i=1,100000 do a[i]=i end"
|
|
||||||
T.alloccount(10)
|
|
||||||
checkerr(MEMERRMSG, f)
|
|
||||||
T.alloccount() -- remove limit
|
|
||||||
|
|
||||||
|
|
||||||
-- test memory errors; increase limit for maximum memory by steps,
|
|
||||||
-- o that we get memory errors in all allocations of a given
|
|
||||||
-- task, until there is enough memory to complete the task without
|
|
||||||
-- errors.
|
|
||||||
function testbytes (s, f)
|
|
||||||
collectgarbage()
|
|
||||||
local M = T.totalmem()
|
|
||||||
local oldM = M
|
|
||||||
local a,b = nil
|
|
||||||
while true do
|
|
||||||
collectgarbage(); collectgarbage()
|
|
||||||
T.totalmem(M)
|
|
||||||
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
|
||||||
T.totalmem(0) -- remove limit
|
|
||||||
if a and b == "OK" then break end -- stop when no more errors
|
|
||||||
if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
|
|
||||||
error(a, 0) -- propagate it
|
|
||||||
end
|
|
||||||
M = M + 7 -- increase memory limit
|
|
||||||
end
|
|
||||||
print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
|
|
||||||
return a
|
|
||||||
end
|
|
||||||
|
|
||||||
-- test memory errors; increase limit for number of allocations one
|
|
||||||
-- by one, so that we get memory errors in all allocations of a given
|
|
||||||
-- task, until there is enough allocations to complete the task without
|
|
||||||
-- errors.
|
|
||||||
|
|
||||||
function testalloc (s, f)
|
|
||||||
collectgarbage()
|
|
||||||
local M = 0
|
|
||||||
local a,b = nil
|
|
||||||
while true do
|
|
||||||
collectgarbage(); collectgarbage()
|
|
||||||
T.alloccount(M)
|
|
||||||
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
|
||||||
T.alloccount() -- remove limit
|
|
||||||
if a and b == "OK" then break end -- stop when no more errors
|
|
||||||
if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
|
|
||||||
error(a, 0) -- propagate it
|
|
||||||
end
|
|
||||||
M = M + 1 -- increase allocation limit
|
|
||||||
end
|
|
||||||
print(string.format("minimum allocations for %s: %d allocations", s, M))
|
|
||||||
return a
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function testamem (s, f)
|
|
||||||
testalloc(s, f)
|
|
||||||
return testbytes(s, f)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- doing nothing
|
|
||||||
b = testamem("doing nothing", function () return 10 end)
|
|
||||||
assert(b == 10)
|
|
||||||
|
|
||||||
-- testing memory errors when creating a new state
|
|
||||||
|
|
||||||
testamem("state creation", function ()
|
|
||||||
local st = T.newstate()
|
|
||||||
if st then T.closestate(st) end -- close new state
|
|
||||||
return st
|
|
||||||
end)
|
|
||||||
|
|
||||||
testamem("empty-table creation", function ()
|
|
||||||
return {}
|
|
||||||
end)
|
|
||||||
|
|
||||||
testamem("string creation", function ()
|
|
||||||
return "XXX" .. "YYY"
|
|
||||||
end)
|
|
||||||
|
|
||||||
testamem("coroutine creation", function()
|
|
||||||
return coroutine.create(print)
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- testing to-be-closed variables
|
|
||||||
testamem("to-be-closed variables", function()
|
|
||||||
local flag
|
|
||||||
do
|
|
||||||
local x <close> =
|
|
||||||
setmetatable({}, {__close = function () flag = true end})
|
|
||||||
flag = false
|
|
||||||
local x = {}
|
|
||||||
end
|
|
||||||
return flag
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- testing threads
|
|
||||||
|
|
||||||
-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1)
|
|
||||||
mt = T.testC("rawgeti R 1; return 1")
|
|
||||||
assert(type(mt) == "thread" and coroutine.running() == mt)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function expand (n,s)
|
|
||||||
if n==0 then return "" end
|
|
||||||
local e = string.rep("=", n)
|
|
||||||
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
|
|
||||||
e, s, expand(n-1,s), e)
|
|
||||||
end
|
|
||||||
|
|
||||||
G=0; collectgarbage(); a =collectgarbage("count")
|
|
||||||
load(expand(20,"G=G+1"))()
|
|
||||||
assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
|
|
||||||
|
|
||||||
testamem("running code on new thread", function ()
|
|
||||||
return T.doonnewstack("x=1") == 0 -- try to create thread
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
-- testing memory x compiler
|
|
||||||
|
|
||||||
testamem("loadstring", function ()
|
|
||||||
return load("x=1") -- try to do load a string
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
local testprog = [[
|
|
||||||
local function foo () return end
|
|
||||||
local t = {"x"}
|
|
||||||
a = "aaa"
|
|
||||||
for i = 1, #t do a=a..t[i] end
|
|
||||||
return true
|
|
||||||
]]
|
|
||||||
|
|
||||||
-- testing memory x dofile
|
|
||||||
_G.a = nil
|
|
||||||
local t =os.tmpname()
|
|
||||||
local f = assert(io.open(t, "w"))
|
|
||||||
f:write(testprog)
|
|
||||||
f:close()
|
|
||||||
testamem("dofile", function ()
|
|
||||||
local a = loadfile(t)
|
|
||||||
return a and a()
|
|
||||||
end)
|
|
||||||
assert(os.remove(t))
|
|
||||||
assert(_G.a == "aaax")
|
|
||||||
|
|
||||||
|
|
||||||
-- other generic tests
|
|
||||||
|
|
||||||
testamem("gsub", function ()
|
|
||||||
local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
|
|
||||||
return (a == 'ablo ablo')
|
|
||||||
end)
|
|
||||||
|
|
||||||
testamem("dump/undump", function ()
|
|
||||||
local a = load(testprog)
|
|
||||||
local b = a and string.dump(a)
|
|
||||||
a = b and load(b)
|
|
||||||
return a and a()
|
|
||||||
end)
|
|
||||||
|
|
||||||
local t = os.tmpname()
|
|
||||||
testamem("file creation", function ()
|
|
||||||
local f = assert(io.open(t, 'w'))
|
|
||||||
assert (not io.open"nomenaoexistente")
|
|
||||||
io.close(f);
|
|
||||||
return not loadfile'nomenaoexistente'
|
|
||||||
end)
|
|
||||||
assert(os.remove(t))
|
|
||||||
|
|
||||||
testamem("table creation", function ()
|
|
||||||
local a, lim = {}, 10
|
|
||||||
for i=1,lim do a[i] = i; a[i..'a'] = {} end
|
|
||||||
return (type(a[lim..'a']) == 'table' and a[lim] == lim)
|
|
||||||
end)
|
|
||||||
|
|
||||||
testamem("constructors", function ()
|
|
||||||
local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
|
|
||||||
return (type(a) == 'table' and a.e == 5)
|
|
||||||
end)
|
|
||||||
|
|
||||||
local a = 1
|
|
||||||
close = nil
|
|
||||||
testamem("closure creation", function ()
|
|
||||||
function close (b)
|
|
||||||
return function (x) return b + x end
|
|
||||||
end
|
|
||||||
return (close(2)(4) == 6)
|
|
||||||
end)
|
|
||||||
|
|
||||||
testamem("using coroutines", function ()
|
|
||||||
local a = coroutine.wrap(function ()
|
|
||||||
coroutine.yield(string.rep("a", 10))
|
|
||||||
return {}
|
|
||||||
end)
|
|
||||||
assert(string.len(a()) == 10)
|
|
||||||
return a()
|
|
||||||
end)
|
|
||||||
|
|
||||||
do -- auxiliary buffer
|
|
||||||
local lim = 100
|
|
||||||
local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
|
|
||||||
testamem("auxiliary buffer", function ()
|
|
||||||
return (#table.concat(a, ",") == 20*lim + lim - 1)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
testamem("growing stack", function ()
|
|
||||||
local function foo (n)
|
|
||||||
if n == 0 then return 1 else return 1 + foo(n - 1) end
|
|
||||||
end
|
|
||||||
return foo(100)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- }==================================================================
|
|
||||||
|
|
||||||
|
|
||||||
do -- testing failing in 'lua_checkstack'
|
do -- testing failing in 'lua_checkstack'
|
||||||
local res = T.testC([[rawcheckstack 500000; return 1]])
|
local res = T.testC([[rawcheckstack 500000; return 1]])
|
||||||
assert(res == false)
|
assert(res == false)
|
||||||
@@ -1436,10 +1319,10 @@ end
|
|||||||
|
|
||||||
do -- garbage collection with no extra memory
|
do -- garbage collection with no extra memory
|
||||||
local L = T.newstate()
|
local L = T.newstate()
|
||||||
T.loadlib(L)
|
T.loadlib(L, 1 | 2, 0) -- load _G and 'package'
|
||||||
local res = (T.doremote(L, [[
|
local res = (T.doremote(L, [[
|
||||||
_ENV = require"_G"
|
_ENV = _G
|
||||||
local T = require"T"
|
assert(string == nil)
|
||||||
local a = {}
|
local a = {}
|
||||||
for i = 1, 1000 do a[i] = 'i' .. i end -- grow string table
|
for i = 1, 1000 do a[i] = 'i' .. i end -- grow string table
|
||||||
local stsize, stuse = T.querystr()
|
local stsize, stuse = T.querystr()
|
||||||
|
|||||||
+46
-14
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/attrib.lua $
|
-- $Id: testes/attrib.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print "testing require"
|
print "testing require"
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ local DIR = "libs" .. dirsep
|
|||||||
|
|
||||||
-- prepend DIR to a name and correct directory separators
|
-- prepend DIR to a name and correct directory separators
|
||||||
local function D (x)
|
local function D (x)
|
||||||
x = string.gsub(x, "/", dirsep)
|
local x = string.gsub(x, "/", dirsep)
|
||||||
return DIR .. x
|
return DIR .. x
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ local function createfiles (files, preextras, posextras)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function removefiles (files)
|
local function removefiles (files)
|
||||||
for n in pairs(files) do
|
for n in pairs(files) do
|
||||||
os.remove(D(n))
|
os.remove(D(n))
|
||||||
end
|
end
|
||||||
@@ -154,10 +154,9 @@ local try = function (p, n, r, ext)
|
|||||||
assert(ext == x)
|
assert(ext == x)
|
||||||
end
|
end
|
||||||
|
|
||||||
a = require"names"
|
local a = require"names"
|
||||||
assert(a[1] == "names" and a[2] == D"names.lua")
|
assert(a[1] == "names" and a[2] == D"names.lua")
|
||||||
|
|
||||||
_G.a = nil
|
|
||||||
local st, msg = pcall(require, "err")
|
local st, msg = pcall(require, "err")
|
||||||
assert(not st and string.find(msg, "arithmetic") and B == 15)
|
assert(not st and string.find(msg, "arithmetic") and B == 15)
|
||||||
st, msg = pcall(require, "synerr")
|
st, msg = pcall(require, "synerr")
|
||||||
@@ -191,6 +190,7 @@ try("X", "XXxX", AA, "libs/XXxX")
|
|||||||
|
|
||||||
|
|
||||||
removefiles(files)
|
removefiles(files)
|
||||||
|
NAME, REQUIRED, AA, B = nil
|
||||||
|
|
||||||
|
|
||||||
-- testing require of sub-packages
|
-- testing require of sub-packages
|
||||||
@@ -223,7 +223,7 @@ assert(require"P1" == m and m.AA == 10)
|
|||||||
|
|
||||||
|
|
||||||
removefiles(files)
|
removefiles(files)
|
||||||
|
AA = nil
|
||||||
|
|
||||||
package.path = ""
|
package.path = ""
|
||||||
assert(not pcall(require, "file_does_not_exist"))
|
assert(not pcall(require, "file_does_not_exist"))
|
||||||
@@ -236,7 +236,7 @@ package.path = oldpath
|
|||||||
local fname = "file_does_not_exist2"
|
local fname = "file_does_not_exist2"
|
||||||
local m, err = pcall(require, fname)
|
local m, err = pcall(require, fname)
|
||||||
for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do
|
for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do
|
||||||
t = string.gsub(t, "?", fname)
|
local t = string.gsub(t, "?", fname)
|
||||||
assert(string.find(err, t, 1, true))
|
assert(string.find(err, t, 1, true))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -305,13 +305,14 @@ else
|
|||||||
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
|
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
|
||||||
assert(string.find(ext, "libs/lib1", 1, true))
|
assert(string.find(ext, "libs/lib1", 1, true))
|
||||||
assert(fs.id(45) == 45)
|
assert(fs.id(45) == 45)
|
||||||
|
_ENV.x, _ENV.y = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
_ENV = _G
|
_ENV = _G
|
||||||
|
|
||||||
|
|
||||||
-- testing preload
|
-- testing preload
|
||||||
|
|
||||||
do
|
do
|
||||||
local p = package
|
local p = package
|
||||||
package = {}
|
package = {}
|
||||||
@@ -330,6 +331,26 @@ do
|
|||||||
assert(type(package.path) == "string")
|
assert(type(package.path) == "string")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do print("testing external strings")
|
||||||
|
package.cpath = DC"?"
|
||||||
|
local lib2 = require"lib2-v2"
|
||||||
|
local t = {}
|
||||||
|
for _, len in ipairs{0, 10, 39, 40, 41, 1000} do
|
||||||
|
local str = string.rep("a", len)
|
||||||
|
local str1 = lib2.newstr(str)
|
||||||
|
assert(str == str1)
|
||||||
|
assert(not T or T.hash(str) == T.hash(str1))
|
||||||
|
t[str1] = 20; assert(t[str] == 20 and t[str1] == 20)
|
||||||
|
t[str] = 10; assert(t[str1] == 10)
|
||||||
|
local tt = {[str1] = str1}
|
||||||
|
assert(next(tt) == str1 and next(tt, str1) == nil)
|
||||||
|
assert(tt[str] == str)
|
||||||
|
local str2 = lib2.newstr(str1)
|
||||||
|
assert(str == str2 and t[str2] == 10 and tt[str2] == str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
end --]
|
end --]
|
||||||
@@ -338,10 +359,10 @@ print("testing assignments, logical operators, and constructors")
|
|||||||
|
|
||||||
local res, res2 = 27
|
local res, res2 = 27
|
||||||
|
|
||||||
a, b = 1, 2+3
|
local a, b = 1, 2+3
|
||||||
assert(a==1 and b==5)
|
assert(a==1 and b==5)
|
||||||
a={}
|
a={}
|
||||||
function f() return 10, 11, 12 end
|
local function f() return 10, 11, 12 end
|
||||||
a.x, b, a[1] = 1, 2, f()
|
a.x, b, a[1] = 1, 2, f()
|
||||||
assert(a.x==1 and b==2 and a[1]==10)
|
assert(a.x==1 and b==2 and a[1]==10)
|
||||||
a[f()], b, a[f()+3] = f(), a, 'x'
|
a[f()], b, a[f()+3] = f(), a, 'x'
|
||||||
@@ -353,15 +374,15 @@ do
|
|||||||
local a,b,c
|
local a,b,c
|
||||||
a,b = 0, f(1)
|
a,b = 0, f(1)
|
||||||
assert(a == 0 and b == 1)
|
assert(a == 0 and b == 1)
|
||||||
A,b = 0, f(1)
|
a,b = 0, f(1)
|
||||||
assert(A == 0 and b == 1)
|
assert(a == 0 and b == 1)
|
||||||
a,b,c = 0,5,f(4)
|
a,b,c = 0,5,f(4)
|
||||||
assert(a==0 and b==5 and c==1)
|
assert(a==0 and b==5 and c==1)
|
||||||
a,b,c = 0,5,f(0)
|
a,b,c = 0,5,f(0)
|
||||||
assert(a==0 and b==5 and c==nil)
|
assert(a==0 and b==5 and c==nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
|
local a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
|
||||||
assert(not a and b and c and d==6)
|
assert(not a and b and c and d==6)
|
||||||
|
|
||||||
d = 20
|
d = 20
|
||||||
@@ -419,6 +440,7 @@ assert(not pcall(function () local a = {[nil] = 10} end))
|
|||||||
assert(a[nil] == undef)
|
assert(a[nil] == undef)
|
||||||
a = nil
|
a = nil
|
||||||
|
|
||||||
|
local a, b, c
|
||||||
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
|
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
|
||||||
a, a.x, a.y = a, a[-3]
|
a, a.x, a.y = a, a[-3]
|
||||||
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
|
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
|
||||||
@@ -434,6 +456,16 @@ a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 ==
|
|||||||
10)
|
10)
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- _ENV constant
|
||||||
|
local function foo ()
|
||||||
|
local _ENV <const> = 11
|
||||||
|
X = "hi"
|
||||||
|
end
|
||||||
|
local st, msg = pcall(foo)
|
||||||
|
assert(not st and string.find(msg, "number"))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test of large float/integer indices
|
-- test of large float/integer indices
|
||||||
|
|
||||||
@@ -445,7 +477,7 @@ while maxint ~= (maxint + 0.0) or (maxint - 1) ~= (maxint - 1.0) do
|
|||||||
maxint = maxint // 2
|
maxint = maxint // 2
|
||||||
end
|
end
|
||||||
|
|
||||||
maxintF = maxint + 0.0 -- float version
|
local maxintF = maxint + 0.0 -- float version
|
||||||
|
|
||||||
assert(maxintF == maxint and math.type(maxintF) == "float" and
|
assert(maxintF == maxint and math.type(maxintF) == "float" and
|
||||||
maxintF >= 2.0^14)
|
maxintF >= 2.0^14)
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/big.lua $
|
-- $Id: testes/big.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
if _soft then
|
if _soft then
|
||||||
return 'a'
|
return 'a'
|
||||||
@@ -32,7 +32,7 @@ setmetatable(env, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
X = nil
|
X = nil
|
||||||
co = coroutine.wrap(f)
|
local co = coroutine.wrap(f)
|
||||||
assert(co() == 's')
|
assert(co() == 's')
|
||||||
assert(co() == 'g')
|
assert(co() == 'g')
|
||||||
assert(co() == 'g')
|
assert(co() == 'g')
|
||||||
|
|||||||
+13
-1
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/bitwise.lua $
|
-- $Id: testes/bitwise.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print("testing bitwise operations")
|
print("testing bitwise operations")
|
||||||
|
|
||||||
@@ -38,6 +38,18 @@ d = d << 32
|
|||||||
assert(a | b ~ c & d == 0xF4000000 << 32)
|
assert(a | b ~ c & d == 0xF4000000 << 32)
|
||||||
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
|
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
|
||||||
|
|
||||||
|
|
||||||
|
do -- constant folding
|
||||||
|
local code = string.format("return -1 >> %d", math.maxinteger)
|
||||||
|
assert(load(code)() == 0)
|
||||||
|
local code = string.format("return -1 >> %d", math.mininteger)
|
||||||
|
assert(load(code)() == 0)
|
||||||
|
local code = string.format("return -1 << %d", math.maxinteger)
|
||||||
|
assert(load(code)() == 0)
|
||||||
|
local code = string.format("return -1 << %d", math.mininteger)
|
||||||
|
assert(load(code)() == 0)
|
||||||
|
end
|
||||||
|
|
||||||
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
|
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
|
||||||
assert(-1 >> (numbits - 1) == 1)
|
assert(-1 >> (numbits - 1) == 1)
|
||||||
assert(-1 >> numbits == 0 and
|
assert(-1 >> numbits == 0 and
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ local strsub = string.sub
|
|||||||
|
|
||||||
local print = print
|
local print = print
|
||||||
|
|
||||||
_ENV = nil
|
global none
|
||||||
|
|
||||||
-- Try to convert a value to an integer, without assuming any coercion.
|
-- Try to convert a value to an integer, without assuming any coercion.
|
||||||
local function toint (x)
|
local function toint (x)
|
||||||
|
|||||||
+168
-46
@@ -1,5 +1,7 @@
|
|||||||
-- $Id: testes/calls.lua $
|
-- $Id: testes/calls.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
print("testing functions and calls")
|
print("testing functions and calls")
|
||||||
|
|
||||||
@@ -16,13 +18,13 @@ assert(type(nil) == 'nil'
|
|||||||
and type(type) == 'function')
|
and type(type) == 'function')
|
||||||
|
|
||||||
assert(type(assert) == type(print))
|
assert(type(assert) == type(print))
|
||||||
function f (x) return a:x (x) end
|
local function f (x) return a:x (x) end
|
||||||
assert(type(f) == 'function')
|
assert(type(f) == 'function')
|
||||||
assert(not pcall(type))
|
assert(not pcall(type))
|
||||||
|
|
||||||
|
|
||||||
-- testing local-function recursion
|
-- testing local-function recursion
|
||||||
fact = false
|
global fact = false
|
||||||
do
|
do
|
||||||
local res = 1
|
local res = 1
|
||||||
local function fact (n)
|
local function fact (n)
|
||||||
@@ -33,10 +35,11 @@ do
|
|||||||
assert(fact(5) == 120)
|
assert(fact(5) == 120)
|
||||||
end
|
end
|
||||||
assert(fact == false)
|
assert(fact == false)
|
||||||
|
fact = nil
|
||||||
|
|
||||||
-- testing declarations
|
-- testing declarations
|
||||||
a = {i = 10}
|
local a = {i = 10}
|
||||||
self = 20
|
local self = 20
|
||||||
function a:x (x) return x+self.i end
|
function a:x (x) return x+self.i end
|
||||||
function a.y (x) return x+self end
|
function a.y (x) return x+self end
|
||||||
|
|
||||||
@@ -62,7 +65,7 @@ a.b.c:f2('k', 12); assert(a.b.c.k == 12)
|
|||||||
|
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
t = nil -- 'declare' t
|
global t = nil -- 'declare' t
|
||||||
function f(a,b,c) local d = 'a'; t={a,b,c,d} end
|
function f(a,b,c) local d = 'a'; t={a,b,c,d} end
|
||||||
|
|
||||||
f( -- this line change must be valid
|
f( -- this line change must be valid
|
||||||
@@ -72,7 +75,9 @@ f(1,2, -- this one too
|
|||||||
3,4)
|
3,4)
|
||||||
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
|
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
|
||||||
|
|
||||||
function fat(x)
|
t = nil -- delete 't'
|
||||||
|
|
||||||
|
global function fat(x)
|
||||||
if x <= 1 then return 1
|
if x <= 1 then return 1
|
||||||
else return x*load("return fat(" .. x-1 .. ")", "")()
|
else return x*load("return fat(" .. x-1 .. ")", "")()
|
||||||
end
|
end
|
||||||
@@ -80,28 +85,31 @@ end
|
|||||||
|
|
||||||
assert(load "load 'assert(fat(6)==720)' () ")()
|
assert(load "load 'assert(fat(6)==720)' () ")()
|
||||||
a = load('return fat(5), 3')
|
a = load('return fat(5), 3')
|
||||||
a,b = a()
|
local a,b = a()
|
||||||
assert(a == 120 and b == 3)
|
assert(a == 120 and b == 3)
|
||||||
|
fat = nil
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
function err_on_n (n)
|
local function err_on_n (n)
|
||||||
if n==0 then error(); exit(1);
|
if n==0 then error(); exit(1);
|
||||||
else err_on_n (n-1); exit(1);
|
else err_on_n (n-1); exit(1);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
function dummy (n)
|
local function dummy (n)
|
||||||
if n > 0 then
|
if n > 0 then
|
||||||
assert(not pcall(err_on_n, n))
|
assert(not pcall(err_on_n, n))
|
||||||
dummy(n-1)
|
dummy(n-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
dummy(10)
|
||||||
end
|
end
|
||||||
|
|
||||||
dummy(10)
|
_G.deep = nil -- "declaration" (used by 'all.lua')
|
||||||
|
|
||||||
function deep (n)
|
global function deep (n)
|
||||||
if n>0 then deep(n-1) end
|
if n>0 then deep(n-1) end
|
||||||
end
|
end
|
||||||
deep(10)
|
deep(10)
|
||||||
@@ -151,6 +159,16 @@ do -- tail calls x varargs
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- C-stack overflow while handling C-stack overflow
|
||||||
|
local function loop ()
|
||||||
|
assert(pcall(loop))
|
||||||
|
end
|
||||||
|
|
||||||
|
local err, msg = xpcall(loop, loop)
|
||||||
|
assert(not err and string.find(msg, "error"))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
do -- tail calls x chain of __call
|
do -- tail calls x chain of __call
|
||||||
local n = 10000 -- depth
|
local n = 10000 -- depth
|
||||||
@@ -162,7 +180,7 @@ do -- tail calls x chain of __call
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- build a chain of __call metamethods ending in function 'foo'
|
-- build a chain of __call metamethods ending in function 'foo'
|
||||||
for i = 1, 100 do
|
for i = 1, 15 do
|
||||||
foo = setmetatable({}, {__call = foo})
|
foo = setmetatable({}, {__call = foo})
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -174,8 +192,8 @@ end
|
|||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
|
|
||||||
do -- testing chains of '__call'
|
do print"testing chains of '__call'"
|
||||||
local N = 20
|
local N = 15
|
||||||
local u = table.pack
|
local u = table.pack
|
||||||
for i = 1, N do
|
for i = 1, N do
|
||||||
u = setmetatable({i}, {__call = u})
|
u = setmetatable({i}, {__call = u})
|
||||||
@@ -188,9 +206,37 @@ do -- testing chains of '__call'
|
|||||||
assert(Res[i][1] == i)
|
assert(Res[i][1] == i)
|
||||||
end
|
end
|
||||||
assert(Res[N + 1] == "a" and Res[N + 2] == "b" and Res[N + 3] == "c")
|
assert(Res[N + 1] == "a" and Res[N + 2] == "b" and Res[N + 3] == "c")
|
||||||
|
|
||||||
|
local function u (...)
|
||||||
|
local n = debug.getinfo(1, 't').extraargs
|
||||||
|
assert(select("#", ...) == n)
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 0, N do
|
||||||
|
assert(u() == i)
|
||||||
|
u = setmetatable({}, {__call = u})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- testing chains too long
|
||||||
|
local a = {}
|
||||||
|
for i = 1, 16 do -- one too many
|
||||||
|
a = setmetatable({}, {__call = a})
|
||||||
|
end
|
||||||
|
local status, msg = pcall(a)
|
||||||
|
assert(not status and string.find(msg, "too long"))
|
||||||
|
|
||||||
|
setmetatable(a, {__call = a}) -- infinite chain
|
||||||
|
local status, msg = pcall(a)
|
||||||
|
assert(not status and string.find(msg, "too long"))
|
||||||
|
|
||||||
|
-- again, with a tail call
|
||||||
|
local status, msg = pcall(function () return a() end)
|
||||||
|
assert(not status and string.find(msg, "too long"))
|
||||||
|
end
|
||||||
|
|
||||||
a = nil
|
a = nil
|
||||||
(function (x) a=x end)(23)
|
(function (x) a=x end)(23)
|
||||||
assert(a == 23 and (function (x) return x*2 end)(20) == 40)
|
assert(a == 23 and (function (x) return x*2 end)(20) == 40)
|
||||||
@@ -199,7 +245,7 @@ assert(a == 23 and (function (x) return x*2 end)(20) == 40)
|
|||||||
-- testing closures
|
-- testing closures
|
||||||
|
|
||||||
-- fixed-point operator
|
-- fixed-point operator
|
||||||
Z = function (le)
|
local Z = function (le)
|
||||||
local function a (f)
|
local function a (f)
|
||||||
return le(function (x) return f(f)(x) end)
|
return le(function (x) return f(f)(x) end)
|
||||||
end
|
end
|
||||||
@@ -209,14 +255,14 @@ Z = function (le)
|
|||||||
|
|
||||||
-- non-recursive factorial
|
-- non-recursive factorial
|
||||||
|
|
||||||
F = function (f)
|
local F = function (f)
|
||||||
return function (n)
|
return function (n)
|
||||||
if n == 0 then return 1
|
if n == 0 then return 1
|
||||||
else return n*f(n-1) end
|
else return n*f(n-1) end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
fat = Z(F)
|
local fat = Z(F)
|
||||||
|
|
||||||
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
|
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
|
||||||
|
|
||||||
@@ -227,22 +273,21 @@ local function g (z)
|
|||||||
return f(z,z+1,z+2,z+3)
|
return f(z,z+1,z+2,z+3)
|
||||||
end
|
end
|
||||||
|
|
||||||
f = g(10)
|
local f = g(10)
|
||||||
assert(f(9, 16) == 10+11+12+13+10+9+16+10)
|
assert(f(9, 16) == 10+11+12+13+10+9+16+10)
|
||||||
|
|
||||||
Z, F, f = nil
|
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
-- testing multiple returns
|
-- testing multiple returns
|
||||||
|
|
||||||
function unlpack (t, i)
|
local function unlpack (t, i)
|
||||||
i = i or 1
|
i = i or 1
|
||||||
if (i <= #t) then
|
if (i <= #t) then
|
||||||
return t[i], unlpack(t, i+1)
|
return t[i], unlpack(t, i+1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function equaltab (t1, t2)
|
local function equaltab (t1, t2)
|
||||||
assert(#t1 == #t2)
|
assert(#t1 == #t2)
|
||||||
for i = 1, #t1 do
|
for i = 1, #t1 do
|
||||||
assert(t1[i] == t2[i])
|
assert(t1[i] == t2[i])
|
||||||
@@ -251,8 +296,8 @@ end
|
|||||||
|
|
||||||
local pack = function (...) return (table.pack(...)) end
|
local pack = function (...) return (table.pack(...)) end
|
||||||
|
|
||||||
function f() return 1,2,30,4 end
|
local function f() return 1,2,30,4 end
|
||||||
function ret2 (a,b) return a,b end
|
local function ret2 (a,b) return a,b end
|
||||||
|
|
||||||
local a,b,c,d = unlpack{1,2,3}
|
local a,b,c,d = unlpack{1,2,3}
|
||||||
assert(a==1 and b==2 and c==3 and d==nil)
|
assert(a==1 and b==2 and c==3 and d==nil)
|
||||||
@@ -281,7 +326,7 @@ table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
|
|||||||
local x = "-- a comment\0\0\0\n x = 10 + \n23; \
|
local x = "-- a comment\0\0\0\n x = 10 + \n23; \
|
||||||
local a = function () x = 'hi' end; \
|
local a = function () x = 'hi' end; \
|
||||||
return '\0'"
|
return '\0'"
|
||||||
function read1 (x)
|
local function read1 (x)
|
||||||
local i = 0
|
local i = 0
|
||||||
return function ()
|
return function ()
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
@@ -290,7 +335,7 @@ function read1 (x)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function cannotload (msg, a,b)
|
local function cannotload (msg, a,b)
|
||||||
assert(not a and string.find(b, msg))
|
assert(not a and string.find(b, msg))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -309,7 +354,7 @@ assert(not load(function () return true end))
|
|||||||
|
|
||||||
-- small bug
|
-- small bug
|
||||||
local t = {nil, "return ", "3"}
|
local t = {nil, "return ", "3"}
|
||||||
f, msg = load(function () return table.remove(t, 1) end)
|
local f, msg = load(function () return table.remove(t, 1) end)
|
||||||
assert(f() == nil) -- should read the empty chunk
|
assert(f() == nil) -- should read the empty chunk
|
||||||
|
|
||||||
-- another small bug (in 5.2.1)
|
-- another small bug (in 5.2.1)
|
||||||
@@ -327,11 +372,38 @@ do -- another bug (in 5.4.0)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if T then
|
||||||
|
-- check stack level when calling reader function
|
||||||
|
local function get (str)
|
||||||
|
local pos = 0
|
||||||
|
local level = nil
|
||||||
|
return function ()
|
||||||
|
pos = pos + 1
|
||||||
|
local c = string.sub(str, pos, pos)
|
||||||
|
local newlevel = T.stacklevel()
|
||||||
|
if not level then
|
||||||
|
level = newlevel
|
||||||
|
else
|
||||||
|
assert(level == newlevel)
|
||||||
|
end
|
||||||
|
return #c > 0 and c or nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local str = "local function foo () end; return 121"
|
||||||
|
assert(assert(load(get(str)))() == 121)
|
||||||
|
|
||||||
|
str = string.dump(load(str))
|
||||||
|
assert(assert(load(get(str)))() == 121)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
x = string.dump(load("x = 1; return x"))
|
x = string.dump(load("x = 1; return x"))
|
||||||
a = assert(load(read1(x), nil, "b"))
|
a = assert(load(read1(x), nil, "b"))
|
||||||
assert(a() == 1 and _G.x == 1)
|
assert(a() == 1 and _G.x == 1)
|
||||||
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
|
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
|
||||||
cannotload("attempt to load a binary chunk", load(x, nil, "t"))
|
cannotload("attempt to load a binary chunk", load(x, nil, "t"))
|
||||||
|
_G.x = nil
|
||||||
|
|
||||||
assert(not pcall(string.dump, print)) -- no dump of C functions
|
assert(not pcall(string.dump, print)) -- no dump of C functions
|
||||||
|
|
||||||
@@ -344,7 +416,8 @@ assert(load("return _ENV", nil, nil, 123)() == 123)
|
|||||||
|
|
||||||
|
|
||||||
-- load when _ENV is not first upvalue
|
-- load when _ENV is not first upvalue
|
||||||
local x; XX = 123
|
global XX; local x
|
||||||
|
XX = 123
|
||||||
local function h ()
|
local function h ()
|
||||||
local y=x -- use 'x', so that it becomes 1st upvalue
|
local y=x -- use 'x', so that it becomes 1st upvalue
|
||||||
return XX -- global name
|
return XX -- global name
|
||||||
@@ -356,7 +429,7 @@ debug.setupvalue(x, 2, _G)
|
|||||||
assert(x() == 123)
|
assert(x() == 123)
|
||||||
|
|
||||||
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
|
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
|
||||||
|
XX = nil
|
||||||
|
|
||||||
-- test generic load with nested functions
|
-- test generic load with nested functions
|
||||||
x = [[
|
x = [[
|
||||||
@@ -436,15 +509,22 @@ assert((function (a) return a end)() == nil)
|
|||||||
|
|
||||||
print("testing binary chunks")
|
print("testing binary chunks")
|
||||||
do
|
do
|
||||||
local header = string.pack("c4BBc6BBB",
|
local headformat = "c4BBc6BiBI4BjBn"
|
||||||
"\27Lua", -- signature
|
local header = { -- header components
|
||||||
0x54, -- version 5.4 (0x54)
|
"\27Lua", -- signature
|
||||||
0, -- format
|
0x55, -- version 5.5 (0x55)
|
||||||
"\x19\x93\r\n\x1a\n", -- data
|
0, -- format
|
||||||
4, -- size of instruction
|
"\x19\x93\r\n\x1a\n", -- a binary string
|
||||||
string.packsize("j"), -- sizeof(lua integer)
|
string.packsize("i"), -- size of an int
|
||||||
string.packsize("n") -- sizeof(lua number)
|
-0x5678, -- an int
|
||||||
)
|
4, -- size of an instruction
|
||||||
|
0x12345678, -- an instruction (4 bytes)
|
||||||
|
string.packsize("j"), -- size of a Lua integer
|
||||||
|
-0x5678, -- a Lua integer
|
||||||
|
string.packsize("n"), -- size of a Lua float
|
||||||
|
-370.5, -- a Lua float
|
||||||
|
}
|
||||||
|
|
||||||
local c = string.dump(function ()
|
local c = string.dump(function ()
|
||||||
local a = 1; local b = 3;
|
local a = 1; local b = 3;
|
||||||
local f = function () return a + b + _ENV.c; end -- upvalues
|
local f = function () return a + b + _ENV.c; end -- upvalues
|
||||||
@@ -456,17 +536,23 @@ do
|
|||||||
assert(assert(load(c))() == 10)
|
assert(assert(load(c))() == 10)
|
||||||
|
|
||||||
-- check header
|
-- check header
|
||||||
assert(string.sub(c, 1, #header) == header)
|
local t = {string.unpack(headformat, c)}
|
||||||
-- check LUAC_INT and LUAC_NUM
|
|
||||||
local ci, cn = string.unpack("jn", c, #header + 1)
|
|
||||||
assert(ci == 0x5678 and cn == 370.5)
|
|
||||||
|
|
||||||
-- corrupted header
|
|
||||||
for i = 1, #header do
|
for i = 1, #header do
|
||||||
|
assert(t[i] == header[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Testing corrupted header.
|
||||||
|
-- A single wrong byte in the head invalidates the chunk,
|
||||||
|
-- except for the Lua float check. (If numbers are long double,
|
||||||
|
-- the representation may need padding, and changing that padding
|
||||||
|
-- will not invalidate the chunk.)
|
||||||
|
local headlen = string.packsize(headformat)
|
||||||
|
headlen = headlen - string.packsize("n") -- remove float check
|
||||||
|
for i = 1, headlen do
|
||||||
local s = string.sub(c, 1, i - 1) ..
|
local s = string.sub(c, 1, i - 1) ..
|
||||||
string.char(string.byte(string.sub(c, i, i)) + 1) ..
|
string.char((string.byte(string.sub(c, i, i)) + 1) & 0xFF) ..
|
||||||
string.sub(c, i + 1, -1)
|
string.sub(c, i + 1, -1)
|
||||||
assert(#s == #c)
|
assert(#s == #c and s ~= c)
|
||||||
assert(not load(s))
|
assert(not load(s))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -477,5 +563,41 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- check reuse of strings in dumps
|
||||||
|
local str = "|" .. string.rep("X", 50) .. "|"
|
||||||
|
local foo = load(string.format([[
|
||||||
|
local str <const> = "%s"
|
||||||
|
return {
|
||||||
|
function () return str end,
|
||||||
|
function () return str end,
|
||||||
|
function () return str end
|
||||||
|
}
|
||||||
|
]], str))
|
||||||
|
-- count occurrences of 'str' inside the dump
|
||||||
|
local dump = string.dump(foo)
|
||||||
|
local _, count = string.gsub(dump, str, {})
|
||||||
|
-- there should be only two occurrences:
|
||||||
|
-- one inside the source, other the string itself.
|
||||||
|
assert(count == 2)
|
||||||
|
|
||||||
|
if T then -- check reuse of strings in undump
|
||||||
|
local funcs = load(dump)()
|
||||||
|
assert(string.format("%p", T.listk(funcs[1])[1]) ==
|
||||||
|
string.format("%p", T.listk(funcs[3])[1]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- test limit of multiple returns (254 values)
|
||||||
|
local code = "return 10" .. string.rep(",10", 253)
|
||||||
|
local res = {assert(load(code))()}
|
||||||
|
assert(#res == 254 and res[254] == 10)
|
||||||
|
|
||||||
|
code = code .. ",10"
|
||||||
|
local status, msg = load(code)
|
||||||
|
assert(not status and string.find(msg, "too many returns"))
|
||||||
|
end
|
||||||
|
|
||||||
print('OK')
|
print('OK')
|
||||||
return deep
|
return deep
|
||||||
|
|||||||
+23
-14
@@ -1,10 +1,20 @@
|
|||||||
-- $Id: testes/closure.lua $
|
-- $Id: testes/closure.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
print "testing closures"
|
print "testing closures"
|
||||||
|
|
||||||
|
do -- bug in 5.4.7
|
||||||
|
_ENV[true] = 10
|
||||||
|
local function aux () return _ENV[1 < 2] end
|
||||||
|
assert(aux() == 10)
|
||||||
|
_ENV[true] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local A,B = 0,{g=10}
|
local A,B = 0,{g=10}
|
||||||
function f(x)
|
local function f(x)
|
||||||
local a = {}
|
local a = {}
|
||||||
for i=1,1000 do
|
for i=1,1000 do
|
||||||
local y = 0
|
local y = 0
|
||||||
@@ -60,35 +70,33 @@ end
|
|||||||
-- testing closures with 'for' control variable
|
-- testing closures with 'for' control variable
|
||||||
a = {}
|
a = {}
|
||||||
for i=1,10 do
|
for i=1,10 do
|
||||||
a[i] = {set = function(x) i=x end, get = function () return i end}
|
a[i] = function () return i end
|
||||||
if i == 3 then break end
|
if i == 3 then break end
|
||||||
end
|
end
|
||||||
assert(a[4] == undef)
|
assert(a[4] == undef)
|
||||||
a[1].set(10)
|
assert(a[2]() == 2)
|
||||||
assert(a[2].get() == 2)
|
assert(a[3]() == 3)
|
||||||
a[2].set('a')
|
|
||||||
assert(a[3].get() == 3)
|
|
||||||
assert(a[2].get() == 'a')
|
|
||||||
|
|
||||||
a = {}
|
a = {}
|
||||||
local t = {"a", "b"}
|
local t = {"a", "b"}
|
||||||
for i = 1, #t do
|
for i = 1, #t do
|
||||||
local k = t[i]
|
local k = t[i]
|
||||||
a[i] = {set = function(x, y) i=x; k=y end,
|
a[i] = {set = function(x) k=x end,
|
||||||
get = function () return i, k end}
|
get = function () return i, k end}
|
||||||
if i == 2 then break end
|
if i == 2 then break end
|
||||||
end
|
end
|
||||||
a[1].set(10, 20)
|
a[1].set(10)
|
||||||
local r,s = a[2].get()
|
local r,s = a[2].get()
|
||||||
assert(r == 2 and s == 'b')
|
assert(r == 2 and s == 'b')
|
||||||
r,s = a[1].get()
|
r,s = a[1].get()
|
||||||
assert(r == 10 and s == 20)
|
assert(r == 1 and s == 10)
|
||||||
a[2].set('a', 'b')
|
a[2].set('a')
|
||||||
r,s = a[2].get()
|
r,s = a[2].get()
|
||||||
assert(r == "a" and s == "b")
|
assert(r == 2 and s == "a")
|
||||||
|
|
||||||
|
|
||||||
-- testing closures with 'for' control variable x break
|
-- testing closures with 'for' control variable x break
|
||||||
|
local f
|
||||||
for i=1,3 do
|
for i=1,3 do
|
||||||
f = function () return i end
|
f = function () return i end
|
||||||
break
|
break
|
||||||
@@ -139,7 +147,7 @@ assert(b('get') == 'xuxu')
|
|||||||
b('set', 10); assert(b('get') == 14)
|
b('set', 10); assert(b('get') == 14)
|
||||||
|
|
||||||
|
|
||||||
local w
|
local y, w
|
||||||
-- testing multi-level closure
|
-- testing multi-level closure
|
||||||
function f(x)
|
function f(x)
|
||||||
return function (y)
|
return function (y)
|
||||||
@@ -230,6 +238,7 @@ t()
|
|||||||
-- test for debug manipulation of upvalues
|
-- test for debug manipulation of upvalues
|
||||||
local debug = require'debug'
|
local debug = require'debug'
|
||||||
|
|
||||||
|
local foo1, foo2, foo3
|
||||||
do
|
do
|
||||||
local a , b, c = 3, 5, 7
|
local a , b, c = 3, 5, 7
|
||||||
foo1 = function () return a+b end;
|
foo1 = function () return a+b end;
|
||||||
|
|||||||
+63
-8
@@ -1,5 +1,7 @@
|
|||||||
-- $Id: testes/code.lua $
|
-- $Id: testes/code.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
if T==nil then
|
if T==nil then
|
||||||
(Message or print)('\n >>> testC not active: skipping opcode tests <<<\n')
|
(Message or print)('\n >>> testC not active: skipping opcode tests <<<\n')
|
||||||
@@ -86,7 +88,7 @@ checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
|
|||||||
-- testing opcodes
|
-- testing opcodes
|
||||||
|
|
||||||
-- check that 'f' opcodes match '...'
|
-- check that 'f' opcodes match '...'
|
||||||
function check (f, ...)
|
local function check (f, ...)
|
||||||
local arg = {...}
|
local arg = {...}
|
||||||
local c = T.listcode(f)
|
local c = T.listcode(f)
|
||||||
for i=1, #arg do
|
for i=1, #arg do
|
||||||
@@ -99,7 +101,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- check that 'f' opcodes match '...' and that 'f(p) == r'.
|
-- check that 'f' opcodes match '...' and that 'f(p) == r'.
|
||||||
function checkR (f, p, r, ...)
|
local function checkR (f, p, r, ...)
|
||||||
local r1 = f(p)
|
local r1 = f(p)
|
||||||
assert(r == r1 and math.type(r) == math.type(r1))
|
assert(r == r1 and math.type(r) == math.type(r1))
|
||||||
check(f, ...)
|
check(f, ...)
|
||||||
@@ -107,7 +109,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- check that 'a' and 'b' has the same opcodes
|
-- check that 'a' and 'b' has the same opcodes
|
||||||
function checkequal (a, b)
|
local function checkequal (a, b)
|
||||||
a = T.listcode(a)
|
a = T.listcode(a)
|
||||||
b = T.listcode(b)
|
b = T.listcode(b)
|
||||||
assert(#a == #b)
|
assert(#a == #b)
|
||||||
@@ -405,20 +407,29 @@ do -- tests for table access in upvalues
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- de morgan
|
-- de morgan
|
||||||
checkequal(function () local a; if not (a or b) then b=a end end,
|
checkequal(function () local a, b; if not (a or b) then b=a end end,
|
||||||
function () local a; if (not a and not b) then b=a end end)
|
function () local a, b; if (not a and not b) then b=a end end)
|
||||||
|
|
||||||
checkequal(function (l) local a; return 0 <= a and a <= l end,
|
checkequal(function (l) local a; return 0 <= a and a <= l end,
|
||||||
function (l) local a; return not (not(a >= 0) or not(a <= l)) end)
|
function (l) local a; return not (not(a >= 0) or not(a <= l)) end)
|
||||||
|
|
||||||
|
|
||||||
-- if-break optimizations
|
|
||||||
check(function (a, b)
|
check(function (a, b)
|
||||||
while a do
|
while a do
|
||||||
if b then break else a = a + 1 end
|
if b then break else a = a + 1 end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0')
|
'TEST', 'JMP', 'TEST', 'JMP', 'JMP', 'CLOSE', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0')
|
||||||
|
|
||||||
|
check(function ()
|
||||||
|
do
|
||||||
|
goto exit -- don't need to close
|
||||||
|
local x <close> = nil
|
||||||
|
goto exit -- must close
|
||||||
|
end
|
||||||
|
::exit::
|
||||||
|
end, 'JMP', 'CLOSE', 'LOADNIL', 'TBC',
|
||||||
|
'CLOSE', 'JMP', 'CLOSE', 'RETURN')
|
||||||
|
|
||||||
checkequal(function () return 6 or true or nil end,
|
checkequal(function () return 6 or true or nil end,
|
||||||
function () return k6 or kTrue or kNil end)
|
function () return k6 or kTrue or kNil end)
|
||||||
@@ -445,5 +456,49 @@ do -- string constants
|
|||||||
assert(T.listk(f2)[1] == nil)
|
assert(T.listk(f2)[1] == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- check number of available registers
|
||||||
|
-- 1 register for local + 1 for function + 252 arguments
|
||||||
|
local source = "local a; return a(" .. string.rep("a, ", 252) .. "a)"
|
||||||
|
local prog = T.listcode(assert(load(source)))
|
||||||
|
-- maximum valid register is 254
|
||||||
|
for i = 1, 254 do
|
||||||
|
assert(string.find(prog[2 + i], "MOVE%s*" .. i))
|
||||||
|
end
|
||||||
|
-- one more argument would need register #255 (but that is reserved)
|
||||||
|
source = "local a; return a(" .. string.rep("a, ", 253) .. "a)"
|
||||||
|
local _, msg = load(source)
|
||||||
|
assert(string.find(msg, "too many registers"))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- basic check for SETLIST
|
||||||
|
-- create a list constructor with 50 elements
|
||||||
|
local source = "local a; return {" .. string.rep("a, ", 50) .. "}"
|
||||||
|
local func = assert(load(source))
|
||||||
|
local code = table.concat(T.listcode(func), "\n")
|
||||||
|
local _, count = string.gsub(code, "SETLIST", "")
|
||||||
|
-- code uses only 1 SETLIST for the constructor
|
||||||
|
assert(count == 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do print("testing code for integer limits")
|
||||||
|
local function checkints (n)
|
||||||
|
local source = string.format(
|
||||||
|
"local a = {[true] = 0X%x}; return a[true]", n)
|
||||||
|
local f = assert(load(source))
|
||||||
|
checkKlist(f, {n})
|
||||||
|
assert(f() == n)
|
||||||
|
f = load(string.dump(f))
|
||||||
|
assert(f() == n)
|
||||||
|
end
|
||||||
|
|
||||||
|
checkints(math.maxinteger)
|
||||||
|
checkints(math.mininteger)
|
||||||
|
checkints(-1)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
print 'OK'
|
print 'OK'
|
||||||
|
|
||||||
|
|||||||
+47
-18
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/constructs.lua $
|
-- $Id: testes/constructs.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
;;print "testing syntax";;
|
;;print "testing syntax";;
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ local function checkload (s, msg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- testing semicollons
|
-- testing semicollons
|
||||||
|
local a
|
||||||
do ;;; end
|
do ;;; end
|
||||||
; do ; a = 3; assert(a == 3) end;
|
; do ; a = 3; assert(a == 3) end;
|
||||||
;
|
;
|
||||||
@@ -49,17 +50,17 @@ assert((((nil and true) or false) and true) == false)
|
|||||||
|
|
||||||
local a,b = 1,nil;
|
local a,b = 1,nil;
|
||||||
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
|
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
|
||||||
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
|
local x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
|
||||||
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
|
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
|
||||||
|
|
||||||
x,y=1,2;
|
local x, y = 1, 2;
|
||||||
assert((x>y) and x or y == 2);
|
assert((x>y) and x or y == 2);
|
||||||
x,y=2,1;
|
x,y=2,1;
|
||||||
assert((x>y) and x or y == 2);
|
assert((x>y) and x or y == 2);
|
||||||
|
|
||||||
assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)
|
assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)
|
||||||
|
|
||||||
do -- testing operators with diffent kinds of constants
|
do -- testing operators with different kinds of constants
|
||||||
-- operands to consider:
|
-- operands to consider:
|
||||||
-- * fit in register
|
-- * fit in register
|
||||||
-- * constant doesn't fit in register
|
-- * constant doesn't fit in register
|
||||||
@@ -77,13 +78,13 @@ do -- testing operators with diffent kinds of constants
|
|||||||
local gab = f(o1, o2)
|
local gab = f(o1, o2)
|
||||||
|
|
||||||
_ENV.XX = o1
|
_ENV.XX = o1
|
||||||
code = string.format("return XX %s %s", op, o2)
|
local code = string.format("return XX %s %s", op, o2)
|
||||||
res = assert(load(code))()
|
local res = assert(load(code))()
|
||||||
assert(res == gab)
|
assert(res == gab)
|
||||||
|
|
||||||
_ENV.XX = o2
|
_ENV.XX = o2
|
||||||
local code = string.format("return (%s) %s XX", o1, op)
|
code = string.format("return (%s) %s XX", o1, op)
|
||||||
local res = assert(load(code))()
|
res = assert(load(code))()
|
||||||
assert(res == gab)
|
assert(res == gab)
|
||||||
|
|
||||||
code = string.format("return (%s) %s %s", o1, op, o2)
|
code = string.format("return (%s) %s %s", o1, op, o2)
|
||||||
@@ -92,6 +93,7 @@ do -- testing operators with diffent kinds of constants
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
_ENV.XX = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -100,10 +102,35 @@ repeat until 1; repeat until true;
|
|||||||
while false do end; while nil do end;
|
while false do end; while nil do end;
|
||||||
|
|
||||||
do -- test old bug (first name could not be an `upvalue')
|
do -- test old bug (first name could not be an `upvalue')
|
||||||
local a; function f(x) x={a=1}; x={x=1}; x={G=1} end
|
local a; local function f(x) x={a=1}; x={x=1}; x={G=1} end
|
||||||
end
|
end
|
||||||
|
|
||||||
function f (i)
|
|
||||||
|
do -- bug since 5.4.0
|
||||||
|
-- create code with a table using more than 256 constants
|
||||||
|
local code = {"local x = {"}
|
||||||
|
for i = 1, 257 do
|
||||||
|
code[#code + 1] = i .. ".1,"
|
||||||
|
end
|
||||||
|
code[#code + 1] = "};"
|
||||||
|
code = table.concat(code)
|
||||||
|
|
||||||
|
-- add "ret" to the end of that code and checks that
|
||||||
|
-- it produces the expected value "val"
|
||||||
|
local function check (ret, val)
|
||||||
|
local code = code .. ret
|
||||||
|
code = load(code)
|
||||||
|
assert(code() == val)
|
||||||
|
end
|
||||||
|
|
||||||
|
check("return (1 ~ (2 or 3))", 1 ~ 2)
|
||||||
|
check("return (1 | (2 or 3))", 1 | 2)
|
||||||
|
check("return (1 + (2 or 3))", 1 + 2)
|
||||||
|
check("return (1 << (2 or 3))", 1 << 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function f (i)
|
||||||
if type(i) ~= 'number' then return i,'jojo'; end;
|
if type(i) ~= 'number' then return i,'jojo'; end;
|
||||||
if i > 0 then return i, f(i-1); end;
|
if i > 0 then return i, f(i-1); end;
|
||||||
end
|
end
|
||||||
@@ -129,10 +156,10 @@ end
|
|||||||
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
|
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
|
||||||
|
|
||||||
for i=1,1000 do break; end;
|
for i=1,1000 do break; end;
|
||||||
n=100;
|
local n=100;
|
||||||
i=3;
|
local i=3;
|
||||||
t = {};
|
local t = {};
|
||||||
a=nil
|
local a=nil
|
||||||
while not a do
|
while not a do
|
||||||
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
|
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
|
||||||
end
|
end
|
||||||
@@ -175,14 +202,14 @@ a={y=1}
|
|||||||
x = {a.y}
|
x = {a.y}
|
||||||
assert(x[1] == 1)
|
assert(x[1] == 1)
|
||||||
|
|
||||||
function f(i)
|
local function f (i)
|
||||||
while 1 do
|
while 1 do
|
||||||
if i>0 then i=i-1;
|
if i>0 then i=i-1;
|
||||||
else return; end;
|
else return; end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function g(i)
|
local function g(i)
|
||||||
while 1 do
|
while 1 do
|
||||||
if i>0 then i=i-1
|
if i>0 then i=i-1
|
||||||
else return end
|
else return end
|
||||||
@@ -247,7 +274,7 @@ function g (a,b,c,d,e)
|
|||||||
if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
|
if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
|
||||||
end
|
end
|
||||||
|
|
||||||
function h (a,b,c,d,e)
|
local function h (a,b,c,d,e)
|
||||||
while (a>=b or c or (d and e) or nil) do return 1; end;
|
while (a>=b or c or (d and e) or nil) do return 1; end;
|
||||||
return 0;
|
return 0;
|
||||||
end;
|
end;
|
||||||
@@ -275,7 +302,7 @@ do
|
|||||||
assert(a==2)
|
assert(a==2)
|
||||||
end
|
end
|
||||||
|
|
||||||
function F(a)
|
local function F (a)
|
||||||
assert(debug.getinfo(1, "n").name == 'F')
|
assert(debug.getinfo(1, "n").name == 'F')
|
||||||
return a,2,3
|
return a,2,3
|
||||||
end
|
end
|
||||||
@@ -368,6 +395,8 @@ for n = 1, level do
|
|||||||
if i % 60000 == 0 then print('+') end
|
if i % 60000 == 0 then print('+') end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
IX = nil
|
||||||
|
_G.GLOB1 = nil
|
||||||
------------------------------------------------------------------
|
------------------------------------------------------------------
|
||||||
|
|
||||||
-- testing some syntax errors (chosen through 'gcov')
|
-- testing some syntax errors (chosen through 'gcov')
|
||||||
|
|||||||
+168
-48
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/coroutine.lua $
|
-- $Id: testes/coroutine.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print "testing coroutines"
|
print "testing coroutines"
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ local function eqtab (t1, t2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
_G.x = nil -- declare x
|
_G.x = nil -- declare x
|
||||||
function foo (a, ...)
|
_G.f = nil -- declare f
|
||||||
|
local function foo (a, ...)
|
||||||
local x, y = coroutine.running()
|
local x, y = coroutine.running()
|
||||||
assert(x == f and y == false)
|
assert(x == f and y == false)
|
||||||
-- next call should not corrupt coroutine (but must fail,
|
-- next call should not corrupt coroutine (but must fail,
|
||||||
@@ -67,10 +68,11 @@ assert(coroutine.status(f) == "dead")
|
|||||||
s, a = coroutine.resume(f, "xuxu")
|
s, a = coroutine.resume(f, "xuxu")
|
||||||
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
|
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
|
||||||
|
|
||||||
|
_G.f = nil
|
||||||
|
|
||||||
-- yields in tail calls
|
-- yields in tail calls
|
||||||
local function foo (i) return coroutine.yield(i) end
|
local function foo (i) return coroutine.yield(i) end
|
||||||
f = coroutine.wrap(function ()
|
local f = coroutine.wrap(function ()
|
||||||
for i=1,10 do
|
for i=1,10 do
|
||||||
assert(foo(i) == _G.x)
|
assert(foo(i) == _G.x)
|
||||||
end
|
end
|
||||||
@@ -79,8 +81,10 @@ end)
|
|||||||
for i=1,10 do _G.x = i; assert(f(i) == i) end
|
for i=1,10 do _G.x = i; assert(f(i) == i) end
|
||||||
_G.x = 'xuxu'; assert(f('xuxu') == 'a')
|
_G.x = 'xuxu'; assert(f('xuxu') == 'a')
|
||||||
|
|
||||||
|
_G.x = nil
|
||||||
|
|
||||||
-- recursive
|
-- recursive
|
||||||
function pf (n, i)
|
local function pf (n, i)
|
||||||
coroutine.yield(n)
|
coroutine.yield(n)
|
||||||
pf(n*i, i+1)
|
pf(n*i, i+1)
|
||||||
end
|
end
|
||||||
@@ -93,14 +97,14 @@ for i=1,10 do
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- sieve
|
-- sieve
|
||||||
function gen (n)
|
local function gen (n)
|
||||||
return coroutine.wrap(function ()
|
return coroutine.wrap(function ()
|
||||||
for i=2,n do coroutine.yield(i) end
|
for i=2,n do coroutine.yield(i) end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function filter (p, g)
|
local function filter (p, g)
|
||||||
return coroutine.wrap(function ()
|
return coroutine.wrap(function ()
|
||||||
while 1 do
|
while 1 do
|
||||||
local n = g()
|
local n = g()
|
||||||
@@ -123,6 +127,18 @@ assert(#a == 22 and a[#a] == 79)
|
|||||||
x, a = nil
|
x, a = nil
|
||||||
|
|
||||||
|
|
||||||
|
do -- "bug" in 5.4.2
|
||||||
|
local function foo () foo () end -- just create a stack overflow
|
||||||
|
local co = coroutine.create(foo)
|
||||||
|
-- running this coroutine would overflow the unsigned short 'nci', the
|
||||||
|
-- counter of CallInfo structures available to the thread.
|
||||||
|
-- (The issue only manifests in an 'assert'.)
|
||||||
|
local st, msg = coroutine.resume(co)
|
||||||
|
assert(string.find(msg, "stack overflow"))
|
||||||
|
assert(coroutine.status(co) == "dead")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
print("to-be-closed variables in coroutines")
|
print("to-be-closed variables in coroutines")
|
||||||
|
|
||||||
local function func2close (f)
|
local function func2close (f)
|
||||||
@@ -140,33 +156,32 @@ do
|
|||||||
st, msg = coroutine.close(co)
|
st, msg = coroutine.close(co)
|
||||||
assert(st and msg == nil)
|
assert(st and msg == nil)
|
||||||
|
|
||||||
|
|
||||||
-- cannot close the running coroutine
|
|
||||||
local st, msg = pcall(coroutine.close, coroutine.running())
|
|
||||||
assert(not st and string.find(msg, "running"))
|
|
||||||
|
|
||||||
local main = coroutine.running()
|
local main = coroutine.running()
|
||||||
|
|
||||||
|
-- cannot close 'main'
|
||||||
|
local st, msg = pcall(coroutine.close, main);
|
||||||
|
assert(not st and string.find(msg, "main"))
|
||||||
|
|
||||||
|
|
||||||
-- cannot close a "normal" coroutine
|
-- cannot close a "normal" coroutine
|
||||||
;(coroutine.wrap(function ()
|
;(coroutine.wrap(function ()
|
||||||
local st, msg = pcall(coroutine.close, main)
|
local st, msg = pcall(coroutine.close, main)
|
||||||
assert(not st and string.find(msg, "normal"))
|
assert(not st and string.find(msg, "normal"))
|
||||||
end))()
|
end))()
|
||||||
|
|
||||||
-- cannot close a coroutine while closing it
|
do -- close a coroutine while closing it
|
||||||
do
|
|
||||||
local co
|
local co
|
||||||
co = coroutine.create(
|
co = coroutine.create(
|
||||||
function()
|
function()
|
||||||
local x <close> = func2close(function()
|
local x <close> = func2close(function()
|
||||||
coroutine.close(co) -- try to close it again
|
coroutine.close(co) -- close it again
|
||||||
end)
|
end)
|
||||||
coroutine.yield(20)
|
coroutine.yield(20)
|
||||||
end)
|
end)
|
||||||
local st, msg = coroutine.resume(co)
|
local st, msg = coroutine.resume(co)
|
||||||
assert(st and msg == 20)
|
assert(st and msg == 20)
|
||||||
st, msg = coroutine.close(co)
|
st, msg = coroutine.close(co)
|
||||||
assert(not st and string.find(msg, "running coroutine"))
|
assert(st and msg == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- to-be-closed variables in coroutines
|
-- to-be-closed variables in coroutines
|
||||||
@@ -221,14 +236,14 @@ do
|
|||||||
-- <close> versus pcall in coroutines
|
-- <close> versus pcall in coroutines
|
||||||
local X = false
|
local X = false
|
||||||
local Y = false
|
local Y = false
|
||||||
function foo ()
|
local function foo ()
|
||||||
local x <close> = func2close(function (self, err)
|
local x <close> = func2close(function (self, err)
|
||||||
Y = debug.getinfo(2)
|
Y = debug.getinfo(2)
|
||||||
X = err
|
X = err
|
||||||
end)
|
end)
|
||||||
error(43)
|
error(43)
|
||||||
end
|
end
|
||||||
co = coroutine.create(function () return pcall(foo) end)
|
local co = coroutine.create(function () return pcall(foo) end)
|
||||||
local st1, st2, err = coroutine.resume(co)
|
local st1, st2, err = coroutine.resume(co)
|
||||||
assert(st1 and not st2 and err == 43)
|
assert(st1 and not st2 and err == 43)
|
||||||
assert(X == 43 and Y.what == "C")
|
assert(X == 43 and Y.what == "C")
|
||||||
@@ -273,9 +288,59 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do print("coroutines closing itself")
|
||||||
|
global <const> coroutine, string, os
|
||||||
|
global <const> assert, error, pcall
|
||||||
|
|
||||||
|
local X = nil
|
||||||
|
|
||||||
|
local function new ()
|
||||||
|
return coroutine.create(function (what)
|
||||||
|
|
||||||
|
local <close>var = func2close(function (t, err)
|
||||||
|
if what == "yield" then
|
||||||
|
coroutine.yield()
|
||||||
|
elseif what == "error" then
|
||||||
|
error(200)
|
||||||
|
else
|
||||||
|
X = "Ok"
|
||||||
|
return X
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- do an unprotected call so that coroutine becomes non-yieldable
|
||||||
|
string.gsub("a", "a", function ()
|
||||||
|
assert(not coroutine.isyieldable())
|
||||||
|
-- do protected calls while non-yieldable, to add recovery
|
||||||
|
-- entries (setjmp) to the stack
|
||||||
|
assert(pcall(pcall, function ()
|
||||||
|
-- 'close' works even while non-yieldable
|
||||||
|
coroutine.close() -- close itself
|
||||||
|
os.exit(false) -- not reacheable
|
||||||
|
end))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local co = new()
|
||||||
|
local st, msg = coroutine.resume(co, "ret")
|
||||||
|
assert(st and msg == nil)
|
||||||
|
assert(X == "Ok")
|
||||||
|
|
||||||
|
local co = new()
|
||||||
|
local st, msg = coroutine.resume(co, "error")
|
||||||
|
assert(not st and msg == 200)
|
||||||
|
|
||||||
|
local co = new()
|
||||||
|
local st, msg = coroutine.resume(co, "yield")
|
||||||
|
assert(not st and string.find(msg, "attempt to yield"))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- yielding across C boundaries
|
-- yielding across C boundaries
|
||||||
|
|
||||||
co = coroutine.wrap(function()
|
local co = coroutine.wrap(function()
|
||||||
assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
|
assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
|
||||||
assert(coroutine.isyieldable())
|
assert(coroutine.isyieldable())
|
||||||
coroutine.yield(20)
|
coroutine.yield(20)
|
||||||
@@ -303,15 +368,15 @@ local r1, r2, v = f1(nil)
|
|||||||
assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
|
assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
|
||||||
|
|
||||||
|
|
||||||
function f (a, b) a = coroutine.yield(a); error{a + b} end
|
local function f (a, b) a = coroutine.yield(a); error{a + b} end
|
||||||
function g(x) return x[1]*2 end
|
local function g(x) return x[1]*2 end
|
||||||
|
|
||||||
co = coroutine.wrap(function ()
|
co = coroutine.wrap(function ()
|
||||||
coroutine.yield(xpcall(f, g, 10, 20))
|
coroutine.yield(xpcall(f, g, 10, 20))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert(co() == 10)
|
assert(co() == 10)
|
||||||
r, msg = co(100)
|
local r, msg = co(100)
|
||||||
assert(not r and msg == 240)
|
assert(not r and msg == 240)
|
||||||
|
|
||||||
|
|
||||||
@@ -373,9 +438,10 @@ assert(not a and b == foo and coroutine.status(x) == "dead")
|
|||||||
a,b = coroutine.resume(x)
|
a,b = coroutine.resume(x)
|
||||||
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
|
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
|
||||||
|
|
||||||
|
goo = nil
|
||||||
|
|
||||||
-- co-routines x for loop
|
-- co-routines x for loop
|
||||||
function all (a, n, k)
|
local function all (a, n, k)
|
||||||
if k == 0 then coroutine.yield(a)
|
if k == 0 then coroutine.yield(a)
|
||||||
else
|
else
|
||||||
for i=1,n do
|
for i=1,n do
|
||||||
@@ -415,7 +481,7 @@ assert(f() == 43 and f() == 53)
|
|||||||
|
|
||||||
-- old bug: attempt to resume itself
|
-- old bug: attempt to resume itself
|
||||||
|
|
||||||
function co_func (current_co)
|
local function co_func (current_co)
|
||||||
assert(coroutine.running() == current_co)
|
assert(coroutine.running() == current_co)
|
||||||
assert(coroutine.resume(current_co) == false)
|
assert(coroutine.resume(current_co) == false)
|
||||||
coroutine.yield(10, 20)
|
coroutine.yield(10, 20)
|
||||||
@@ -488,18 +554,38 @@ assert(not pcall(a, a))
|
|||||||
a = nil
|
a = nil
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- bug in 5.4: thread can use message handler higher in the stack
|
||||||
|
-- than the variable being closed
|
||||||
|
local c = coroutine.create(function()
|
||||||
|
local clo <close> = setmetatable({}, {__close=function()
|
||||||
|
local x = 134 -- will overwrite message handler
|
||||||
|
error(x)
|
||||||
|
end})
|
||||||
|
-- yields coroutine but leaves a new message handler for it,
|
||||||
|
-- that would be used when closing the coroutine (except that it
|
||||||
|
-- will be overwritten)
|
||||||
|
xpcall(coroutine.yield, function() return "XXX" end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert(coroutine.resume(c)) -- start coroutine
|
||||||
|
local st, msg = coroutine.close(c)
|
||||||
|
assert(not st and msg == 134)
|
||||||
|
end
|
||||||
|
|
||||||
-- access to locals of erroneous coroutines
|
-- access to locals of erroneous coroutines
|
||||||
local x = coroutine.create (function ()
|
local x = coroutine.create (function ()
|
||||||
local a = 10
|
local a = 10
|
||||||
_G.f = function () a=a+1; return a end
|
_G.F = function () a=a+1; return a end
|
||||||
error('x')
|
error('x')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert(not coroutine.resume(x))
|
assert(not coroutine.resume(x))
|
||||||
-- overwrite previous position of local `a'
|
-- overwrite previous position of local `a'
|
||||||
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
|
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
|
||||||
assert(_G.f() == 11)
|
assert(_G.F() == 11)
|
||||||
assert(_G.f() == 12)
|
assert(_G.F() == 12)
|
||||||
|
_G.F = nil
|
||||||
|
|
||||||
|
|
||||||
if not T then
|
if not T then
|
||||||
@@ -510,7 +596,7 @@ else
|
|||||||
|
|
||||||
local turn
|
local turn
|
||||||
|
|
||||||
function fact (t, x)
|
local function fact (t, x)
|
||||||
assert(turn == t)
|
assert(turn == t)
|
||||||
if x == 0 then return 1
|
if x == 0 then return 1
|
||||||
else return x*fact(t, x-1)
|
else return x*fact(t, x-1)
|
||||||
@@ -579,6 +665,7 @@ else
|
|||||||
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
|
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
|
||||||
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
|
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
|
||||||
assert(co() == 10)
|
assert(co() == 10)
|
||||||
|
_G.X = nil
|
||||||
|
|
||||||
-- testing yields in count hook
|
-- testing yields in count hook
|
||||||
co = coroutine.wrap(function ()
|
co = coroutine.wrap(function ()
|
||||||
@@ -603,18 +690,22 @@ else
|
|||||||
-- (bug in 5.2/5.3)
|
-- (bug in 5.2/5.3)
|
||||||
c = coroutine.create(function (a, ...)
|
c = coroutine.create(function (a, ...)
|
||||||
T.sethook("yield 0", "l") -- will yield on next two lines
|
T.sethook("yield 0", "l") -- will yield on next two lines
|
||||||
assert(a == 10)
|
local b = a
|
||||||
return ...
|
return ...
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine
|
assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine
|
||||||
local n,v = debug.getlocal(c, 0, 1) -- check its local
|
local n,v = debug.getlocal(c, 0, 1) -- check its local
|
||||||
assert(n == "a" and v == 1)
|
assert(n == "a" and v == 1 and debug.getlocal(c, 0, 2) ~= "b")
|
||||||
assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal'
|
assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal'
|
||||||
local t = debug.getinfo(c, 0) -- test 'getinfo'
|
local t = debug.getinfo(c, 0) -- test 'getinfo'
|
||||||
assert(t.currentline == t.linedefined + 1)
|
assert(t.currentline == t.linedefined + 2)
|
||||||
assert(not debug.getinfo(c, 1)) -- no other level
|
assert(not debug.getinfo(c, 1)) -- no other level
|
||||||
assert(coroutine.resume(c)) -- run next line
|
assert(coroutine.resume(c)) -- run next line
|
||||||
|
local n,v = debug.getlocal(c, 0, 2) -- check vararg table
|
||||||
|
assert(n == "(vararg table)" and v == nil)
|
||||||
|
local n,v = debug.getlocal(c, 0, 3) -- check next local
|
||||||
|
assert(n == "b" and v == 10)
|
||||||
v = {coroutine.resume(c)} -- finish coroutine
|
v = {coroutine.resume(c)} -- finish coroutine
|
||||||
assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef)
|
assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef)
|
||||||
assert(not coroutine.resume(c))
|
assert(not coroutine.resume(c))
|
||||||
@@ -656,6 +747,8 @@ else
|
|||||||
|
|
||||||
assert(X == 'a a a' and Y == 'OK')
|
assert(X == 'a a a' and Y == 'OK')
|
||||||
|
|
||||||
|
X, Y = nil
|
||||||
|
|
||||||
|
|
||||||
-- resuming running coroutine
|
-- resuming running coroutine
|
||||||
C = coroutine.create(function ()
|
C = coroutine.create(function ()
|
||||||
@@ -672,7 +765,7 @@ else
|
|||||||
c == "ERRRUN" and d == 4)
|
c == "ERRRUN" and d == 4)
|
||||||
|
|
||||||
a, b, c, d = T.testC([[
|
a, b, c, d = T.testC([[
|
||||||
rawgeti R 1 # get main thread
|
rawgeti R !M # get main thread
|
||||||
pushnum 10;
|
pushnum 10;
|
||||||
pushnum 20;
|
pushnum 20;
|
||||||
resume -3 2;
|
resume -3 2;
|
||||||
@@ -690,19 +783,19 @@ else
|
|||||||
assert(T.testC(state, "newthread; isyieldable -1; remove 1; return 1"))
|
assert(T.testC(state, "newthread; isyieldable -1; remove 1; return 1"))
|
||||||
|
|
||||||
-- main thread is not yieldable
|
-- main thread is not yieldable
|
||||||
assert(not T.testC(state, "rawgeti R 1; isyieldable -1; remove 1; return 1"))
|
assert(not T.testC(state, "rawgeti R !M; isyieldable -1; remove 1; return 1"))
|
||||||
|
|
||||||
T.testC(state, "settop 0")
|
T.testC(state, "settop 0")
|
||||||
|
|
||||||
T.loadlib(state)
|
T.loadlib(state, 1 | 2, 4) -- load _G and 'package', preload 'coroutine'
|
||||||
|
|
||||||
assert(T.doremote(state, [[
|
assert(T.doremote(state, [[
|
||||||
coroutine = require'coroutine';
|
coroutine = require'coroutine';
|
||||||
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
|
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
|
||||||
return 'ok']]))
|
return 'ok']]))
|
||||||
|
|
||||||
t = table.pack(T.testC(state, [[
|
local t = table.pack(T.testC(state, [[
|
||||||
rawgeti R 1 # get main thread
|
rawgeti R !M # get main thread
|
||||||
pushstring 'XX'
|
pushstring 'XX'
|
||||||
getglobal X # get function for body
|
getglobal X # get function for body
|
||||||
pushstring AA # arg
|
pushstring AA # arg
|
||||||
@@ -711,7 +804,7 @@ else
|
|||||||
setglobal T # top
|
setglobal T # top
|
||||||
setglobal B # second yielded value
|
setglobal B # second yielded value
|
||||||
setglobal A # fist yielded value
|
setglobal A # fist yielded value
|
||||||
rawgeti R 1 # get main thread
|
rawgeti R !M # get main thread
|
||||||
pushnum 5 # arg (noise)
|
pushnum 5 # arg (noise)
|
||||||
resume 1 1 # after coroutine ends, previous stack is back
|
resume 1 1 # after coroutine ends, previous stack is back
|
||||||
pushstatus
|
pushstatus
|
||||||
@@ -730,31 +823,28 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- leaving a pending coroutine open
|
-- leaving a pending coroutine open
|
||||||
_X = coroutine.wrap(function ()
|
_G.TO_SURVIVE = coroutine.wrap(function ()
|
||||||
local a = 10
|
local a = 10
|
||||||
local x = function () a = a+1 end
|
local x = function () a = a+1 end
|
||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
_X()
|
_G.TO_SURVIVE()
|
||||||
|
|
||||||
|
|
||||||
if not _soft then
|
if not _soft then
|
||||||
-- bug (stack overflow)
|
-- bug (stack overflow)
|
||||||
local j = 2^9
|
local lim = 1000000 -- stack limit; assume 32-bit machine
|
||||||
local lim = 1000000 -- (C stack limit; assume 32-bit machine)
|
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1, lim + 5}
|
||||||
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
|
|
||||||
for i = 1, #t do
|
for i = 1, #t do
|
||||||
local j = t[i]
|
local j = t[i]
|
||||||
co = coroutine.create(function()
|
local co = coroutine.create(function()
|
||||||
local t = {}
|
return table.unpack({}, 1, j)
|
||||||
for i = 1, j do t[i] = i end
|
|
||||||
return table.unpack(t)
|
|
||||||
end)
|
end)
|
||||||
local r, msg = coroutine.resume(co)
|
local r, msg = coroutine.resume(co)
|
||||||
assert(not r)
|
-- must fail for unpacking larger than stack limit
|
||||||
|
assert(j < lim or not r)
|
||||||
end
|
end
|
||||||
co = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -938,7 +1028,7 @@ assert(run(function ()
|
|||||||
do local _ENV = _ENV
|
do local _ENV = _ENV
|
||||||
f = function () AAA = BBB + 1; return AAA end
|
f = function () AAA = BBB + 1; return AAA end
|
||||||
end
|
end
|
||||||
g = new(10); g.k.BBB = 10;
|
local g = new(10); g.k.BBB = 10;
|
||||||
debug.setupvalue(f, 1, g)
|
debug.setupvalue(f, 1, g)
|
||||||
assert(run(f, {"idx", "nidx", "idx"}) == 11)
|
assert(run(f, {"idx", "nidx", "idx"}) == 11)
|
||||||
assert(g.k.AAA == 11)
|
assert(g.k.AAA == 11)
|
||||||
@@ -1029,6 +1119,31 @@ f = T.makeCfunc([[
|
|||||||
return *
|
return *
|
||||||
]], 23, "huu")
|
]], 23, "huu")
|
||||||
|
|
||||||
|
|
||||||
|
do -- testing bug introduced in commit f407b3c4a
|
||||||
|
local X = false -- flag "to be closed"
|
||||||
|
local coro = coroutine.wrap(T.testC)
|
||||||
|
-- runs it until 'pcallk' (that yields)
|
||||||
|
-- 4th argument (at index 4): object to be closed
|
||||||
|
local res1, res2 = coro(
|
||||||
|
[[
|
||||||
|
toclose 3 # this could break the next 'pcallk'
|
||||||
|
pushvalue 2 # push function 'yield' to call it
|
||||||
|
pushint 22; pushint 33 # arguments to yield
|
||||||
|
# calls 'yield' (2 args; 2 results; continuation function at index 4)
|
||||||
|
pcallk 2 2 4
|
||||||
|
invalid command (should not arrive here)
|
||||||
|
]], -- 1st argument (at index 1): code;
|
||||||
|
coroutine.yield, -- (at index 2): function to be called
|
||||||
|
func2close(function () X = true end), -- (index 3): TBC slot
|
||||||
|
"pushint 43; return 3" -- (index 4): code for continuation function
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(res1 == 22 and res2 == 33 and not X)
|
||||||
|
local res1, res2, res3 = coro(34, "hi") -- runs continuation function
|
||||||
|
assert(res1 == 34 and res2 == "hi" and res3 == 43 and X)
|
||||||
|
end
|
||||||
|
|
||||||
x = coroutine.wrap(f)
|
x = coroutine.wrap(f)
|
||||||
assert(x() == 102)
|
assert(x() == 102)
|
||||||
eqtab({x()}, {23, "huu"})
|
eqtab({x()}, {23, "huu"})
|
||||||
@@ -1078,6 +1193,8 @@ assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
|
|||||||
|
|
||||||
-- testing yields with continuations
|
-- testing yields with continuations
|
||||||
|
|
||||||
|
local y
|
||||||
|
|
||||||
co = coroutine.wrap(function (...) return
|
co = coroutine.wrap(function (...) return
|
||||||
T.testC([[ # initial function
|
T.testC([[ # initial function
|
||||||
yieldk 1 2
|
yieldk 1 2
|
||||||
@@ -1130,6 +1247,9 @@ assert(x == "YIELD" and y == 4)
|
|||||||
|
|
||||||
assert(not pcall(co)) -- coroutine should be dead
|
assert(not pcall(co)) -- coroutine should be dead
|
||||||
|
|
||||||
|
_G.ctx = nil
|
||||||
|
_G.status = nil
|
||||||
|
|
||||||
|
|
||||||
-- bug in nCcalls
|
-- bug in nCcalls
|
||||||
local co = coroutine.wrap(function ()
|
local co = coroutine.wrap(function ()
|
||||||
|
|||||||
+27
-1
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/cstack.lua $
|
-- $Id: testes/cstack.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
|
||||||
local tracegc = require"tracegc"
|
local tracegc = require"tracegc"
|
||||||
@@ -84,6 +84,32 @@ do -- bug in 5.4.0
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- bug since 5.4.0
|
||||||
|
local count = 0
|
||||||
|
print("chain of 'coroutine.close'")
|
||||||
|
-- create N coroutines forming a list so that each one, when closed,
|
||||||
|
-- closes the previous one. (With a large enough N, previous Lua
|
||||||
|
-- versions crash in this test.)
|
||||||
|
local coro = false
|
||||||
|
for i = 1, 1000 do
|
||||||
|
local previous = coro
|
||||||
|
coro = coroutine.create(function()
|
||||||
|
local cc <close> = setmetatable({}, {__close=function()
|
||||||
|
count = count + 1
|
||||||
|
if previous then
|
||||||
|
assert(coroutine.close(previous))
|
||||||
|
end
|
||||||
|
end})
|
||||||
|
coroutine.yield() -- leaves 'cc' pending to be closed
|
||||||
|
end)
|
||||||
|
assert(coroutine.resume(coro)) -- start it and run until it yields
|
||||||
|
end
|
||||||
|
local st, msg = coroutine.close(coro)
|
||||||
|
assert(not st and string.find(msg, "C stack overflow"))
|
||||||
|
print("final count: ", count)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
print("nesting of resuming yielded coroutines")
|
print("nesting of resuming yielded coroutines")
|
||||||
local count = 0
|
local count = 0
|
||||||
|
|||||||
+56
-26
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/db.lua $
|
-- $Id: testes/db.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
-- testing debug library
|
-- testing debug library
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ end
|
|||||||
assert(not debug.gethook())
|
assert(not debug.gethook())
|
||||||
|
|
||||||
local testline = 19 -- line where 'test' is defined
|
local testline = 19 -- line where 'test' is defined
|
||||||
function test (s, l, p) -- this must be line 19
|
local function test (s, l, p) -- this must be line 19
|
||||||
collectgarbage() -- avoid gc during trace
|
collectgarbage() -- avoid gc during trace
|
||||||
local function f (event, line)
|
local function f (event, line)
|
||||||
assert(event == 'line')
|
assert(event == 'line')
|
||||||
@@ -49,8 +49,17 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- bug in 5.4.4-5.4.6: activelines in vararg functions
|
||||||
|
-- without debug information
|
||||||
|
do
|
||||||
|
local func = load(string.dump(load("print(10)"), true))
|
||||||
|
local actl = debug.getinfo(func, "L").activelines
|
||||||
|
assert(#actl == 0) -- no line info
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test file and string names truncation
|
-- test file and string names truncation
|
||||||
a = "function f () end"
|
local a = "function f () end"
|
||||||
local function dostring (s, x) return load(s, x)() end
|
local function dostring (s, x) return load(s, x)() end
|
||||||
dostring(a)
|
dostring(a)
|
||||||
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
|
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
|
||||||
@@ -72,7 +81,8 @@ dostring(a, string.format("=%s", string.rep('x', 500)))
|
|||||||
assert(string.find(debug.getinfo(f).short_src, "^x*$"))
|
assert(string.find(debug.getinfo(f).short_src, "^x*$"))
|
||||||
dostring(a, "=")
|
dostring(a, "=")
|
||||||
assert(debug.getinfo(f).short_src == "")
|
assert(debug.getinfo(f).short_src == "")
|
||||||
a = nil; f = nil;
|
_G.a = nil; _G.f = nil;
|
||||||
|
_G[string.rep("p", 400)] = nil
|
||||||
|
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
@@ -118,7 +128,8 @@ then
|
|||||||
else
|
else
|
||||||
a=2
|
a=2
|
||||||
end
|
end
|
||||||
]], {2,3,4,7})
|
]], {2,4,7})
|
||||||
|
|
||||||
|
|
||||||
test([[
|
test([[
|
||||||
local function foo()
|
local function foo()
|
||||||
@@ -128,6 +139,7 @@ A = 1
|
|||||||
A = 2
|
A = 2
|
||||||
A = 3
|
A = 3
|
||||||
]], {2, 3, 2, 4, 5, 6})
|
]], {2, 3, 2, 4, 5, 6})
|
||||||
|
_G.A = nil
|
||||||
|
|
||||||
|
|
||||||
test([[--
|
test([[--
|
||||||
@@ -175,6 +187,8 @@ end
|
|||||||
|
|
||||||
test([[for i=1,4 do a=1 end]], {1,1,1,1})
|
test([[for i=1,4 do a=1 end]], {1,1,1,1})
|
||||||
|
|
||||||
|
_G.a = nil
|
||||||
|
|
||||||
|
|
||||||
do -- testing line info/trace with large gaps in source
|
do -- testing line info/trace with large gaps in source
|
||||||
|
|
||||||
@@ -194,6 +208,7 @@ do -- testing line info/trace with large gaps in source
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
_G.a = nil
|
||||||
|
|
||||||
|
|
||||||
do -- testing active lines
|
do -- testing active lines
|
||||||
@@ -287,7 +302,6 @@ foo(200, 3, 4)
|
|||||||
local a = {}
|
local a = {}
|
||||||
for i = 1, (_soft and 100 or 1000) do a[i] = i end
|
for i = 1, (_soft and 100 or 1000) do a[i] = i end
|
||||||
foo(table.unpack(a))
|
foo(table.unpack(a))
|
||||||
a = nil
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -307,13 +321,14 @@ do -- test hook presence in debug info
|
|||||||
debug.sethook()
|
debug.sethook()
|
||||||
assert(count == 4)
|
assert(count == 4)
|
||||||
end
|
end
|
||||||
|
_ENV.a = nil
|
||||||
|
|
||||||
|
|
||||||
-- hook table has weak keys
|
-- hook table has weak keys
|
||||||
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
|
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
|
||||||
|
|
||||||
|
|
||||||
a = {}; L = nil
|
a = {}; local L = nil
|
||||||
local glob = 1
|
local glob = 1
|
||||||
local oldglob = glob
|
local oldglob = glob
|
||||||
debug.sethook(function (e,l)
|
debug.sethook(function (e,l)
|
||||||
@@ -334,12 +349,15 @@ end, "crl")
|
|||||||
|
|
||||||
|
|
||||||
function f(a,b)
|
function f(a,b)
|
||||||
|
-- declare some globals to check that they don't interfere with 'getlocal'
|
||||||
|
global collectgarbage
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
local _, x = debug.getlocal(1, 1)
|
local _, x = debug.getlocal(1, 1)
|
||||||
|
global assert, g, string
|
||||||
local _, y = debug.getlocal(1, 2)
|
local _, y = debug.getlocal(1, 2)
|
||||||
assert(x == a and y == b)
|
assert(x == a and y == b)
|
||||||
assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
|
assert(debug.setlocal(2, 4, "pera") == "AA".."AA")
|
||||||
assert(debug.setlocal(2, 4, "maçã") == "B")
|
assert(debug.setlocal(2, 5, "manga") == "B")
|
||||||
x = debug.getinfo(2)
|
x = debug.getinfo(2)
|
||||||
assert(x.func == g and x.what == "Lua" and x.name == 'g' and
|
assert(x.func == g and x.what == "Lua" and x.name == 'g' and
|
||||||
x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
|
x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
|
||||||
@@ -354,7 +372,7 @@ function foo()
|
|||||||
end; foo() -- set L
|
end; foo() -- set L
|
||||||
-- check line counting inside strings and empty lines
|
-- check line counting inside strings and empty lines
|
||||||
|
|
||||||
_ = 'alo\
|
local _ = 'alo\
|
||||||
alo' .. [[
|
alo' .. [[
|
||||||
|
|
||||||
]]
|
]]
|
||||||
@@ -367,12 +385,14 @@ function g (...)
|
|||||||
local arg = {...}
|
local arg = {...}
|
||||||
do local a,b,c; a=math.sin(40); end
|
do local a,b,c; a=math.sin(40); end
|
||||||
local feijao
|
local feijao
|
||||||
local AAAA,B = "xuxu", "mamão"
|
local AAAA,B = "xuxu", "abacate"
|
||||||
f(AAAA,B)
|
f(AAAA,B)
|
||||||
assert(AAAA == "pera" and B == "maçã")
|
assert(AAAA == "pera" and B == "manga")
|
||||||
do
|
do
|
||||||
|
global *
|
||||||
local B = 13
|
local B = 13
|
||||||
local x,y = debug.getlocal(1,5)
|
global<const> assert
|
||||||
|
local x,y = debug.getlocal(1,6)
|
||||||
assert(x == 'B' and y == 13)
|
assert(x == 'B' and y == 13)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -403,6 +423,7 @@ function g(a,b) return (a+1) + f() end
|
|||||||
|
|
||||||
assert(g(0,0) == 30)
|
assert(g(0,0) == 30)
|
||||||
|
|
||||||
|
_G.f, _G.g = nil
|
||||||
|
|
||||||
debug.sethook(nil);
|
debug.sethook(nil);
|
||||||
assert(not debug.gethook())
|
assert(not debug.gethook())
|
||||||
@@ -415,7 +436,7 @@ do
|
|||||||
assert(a == nil and not b)
|
assert(a == nil and not b)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- testing iteraction between multiple values x hooks
|
-- testing interaction between multiple values x hooks
|
||||||
do
|
do
|
||||||
local function f(...) return 3, ... end
|
local function f(...) return 3, ... end
|
||||||
local count = 0
|
local count = 0
|
||||||
@@ -437,7 +458,8 @@ local function collectlocals (level)
|
|||||||
local tab = {}
|
local tab = {}
|
||||||
for i = 1, math.huge do
|
for i = 1, math.huge do
|
||||||
local n, v = debug.getlocal(level + 1, i)
|
local n, v = debug.getlocal(level + 1, i)
|
||||||
if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then
|
if not (n and string.find(n, "^[a-zA-Z0-9_]+$") or
|
||||||
|
n == "(vararg table)") then
|
||||||
break -- consider only real variables
|
break -- consider only real variables
|
||||||
end
|
end
|
||||||
tab[n] = v
|
tab[n] = v
|
||||||
@@ -446,7 +468,7 @@ local function collectlocals (level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
X = nil
|
local X = nil
|
||||||
a = {}
|
a = {}
|
||||||
function a:f (a, b, ...) local arg = {...}; local c = 13 end
|
function a:f (a, b, ...) local arg = {...}; local c = 13 end
|
||||||
debug.sethook(function (e)
|
debug.sethook(function (e)
|
||||||
@@ -469,6 +491,7 @@ a:f(1,2,3,4,5)
|
|||||||
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
|
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
|
||||||
assert(XX == 12)
|
assert(XX == 12)
|
||||||
assert(not debug.gethook())
|
assert(not debug.gethook())
|
||||||
|
_G.XX = nil
|
||||||
|
|
||||||
|
|
||||||
-- testing access to local variables in return hook (bug in 5.2)
|
-- testing access to local variables in return hook (bug in 5.2)
|
||||||
@@ -570,7 +593,7 @@ t = getupvalues(foo2)
|
|||||||
assert(t.a == 1 and t.b == 2 and t.c == 3)
|
assert(t.a == 1 and t.b == 2 and t.c == 3)
|
||||||
assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
|
assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
|
||||||
assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
|
assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
|
||||||
-- upvalues of C functions are allways "called" "" (the empty string)
|
-- upvalues of C functions are always named "" (the empty string)
|
||||||
assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "")
|
assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "")
|
||||||
|
|
||||||
|
|
||||||
@@ -593,6 +616,7 @@ end
|
|||||||
|
|
||||||
debug.sethook()
|
debug.sethook()
|
||||||
|
|
||||||
|
local g, g1
|
||||||
|
|
||||||
-- tests for tail calls
|
-- tests for tail calls
|
||||||
local function f (x)
|
local function f (x)
|
||||||
@@ -606,6 +630,9 @@ local function f (x)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
assert(debug.getinfo(print, 't').istailcall == false)
|
||||||
|
assert(debug.getinfo(print, 't').extraargs == 0)
|
||||||
|
|
||||||
function g(x) return f(x) end
|
function g(x) return f(x) end
|
||||||
|
|
||||||
function g1(x) g(x) end
|
function g1(x) g(x) end
|
||||||
@@ -638,7 +665,7 @@ h(false)
|
|||||||
debug.sethook()
|
debug.sethook()
|
||||||
assert(b == 2) -- two tail calls
|
assert(b == 2) -- two tail calls
|
||||||
|
|
||||||
lim = _soft and 3000 or 30000
|
local lim = _soft and 3000 or 30000
|
||||||
local function foo (x)
|
local function foo (x)
|
||||||
if x==0 then
|
if x==0 then
|
||||||
assert(debug.getinfo(2).what == "main")
|
assert(debug.getinfo(2).what == "main")
|
||||||
@@ -680,7 +707,7 @@ assert(debug.traceback(print, 4) == print)
|
|||||||
assert(string.find(debug.traceback("hi", 4), "^hi\n"))
|
assert(string.find(debug.traceback("hi", 4), "^hi\n"))
|
||||||
assert(string.find(debug.traceback("hi"), "^hi\n"))
|
assert(string.find(debug.traceback("hi"), "^hi\n"))
|
||||||
assert(not string.find(debug.traceback("hi"), "'debug.traceback'"))
|
assert(not string.find(debug.traceback("hi"), "'debug.traceback'"))
|
||||||
assert(string.find(debug.traceback("hi", 0), "'debug.traceback'"))
|
assert(string.find(debug.traceback("hi", 0), "'traceback'"))
|
||||||
assert(string.find(debug.traceback(), "^stack traceback:\n"))
|
assert(string.find(debug.traceback(), "^stack traceback:\n"))
|
||||||
|
|
||||||
do -- C-function names in traceback
|
do -- C-function names in traceback
|
||||||
@@ -699,6 +726,9 @@ assert(t.isvararg == false and t.nparams == 3 and t.nups == 0)
|
|||||||
t = debug.getinfo(function (a,b,...) return t[a] end, "u")
|
t = debug.getinfo(function (a,b,...) return t[a] end, "u")
|
||||||
assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
|
assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
|
||||||
|
|
||||||
|
t = debug.getinfo(function (a,b,...t) t.n = 2; return t[a] end, "u")
|
||||||
|
assert(t.isvararg == true and t.nparams == 2 and t.nups == 0)
|
||||||
|
|
||||||
t = debug.getinfo(1) -- main
|
t = debug.getinfo(1) -- main
|
||||||
assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
|
assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
|
||||||
debug.getupvalue(t.func, 1) == "_ENV")
|
debug.getupvalue(t.func, 1) == "_ENV")
|
||||||
@@ -808,7 +838,7 @@ end
|
|||||||
|
|
||||||
co = coroutine.create(function (x) f(x) end)
|
co = coroutine.create(function (x) f(x) end)
|
||||||
a, b = coroutine.resume(co, 3)
|
a, b = coroutine.resume(co, 3)
|
||||||
t = {"'coroutine.yield'", "'f'", "in function <"}
|
t = {"'yield'", "'f'", "in function <"}
|
||||||
while coroutine.status(co) == "suspended" do
|
while coroutine.status(co) == "suspended" do
|
||||||
checktraceback(co, t)
|
checktraceback(co, t)
|
||||||
a, b = coroutine.resume(co)
|
a, b = coroutine.resume(co)
|
||||||
@@ -818,7 +848,7 @@ t[1] = "'error'"
|
|||||||
checktraceback(co, t)
|
checktraceback(co, t)
|
||||||
|
|
||||||
|
|
||||||
-- test acessing line numbers of a coroutine from a resume inside
|
-- test accessing line numbers of a coroutine from a resume inside
|
||||||
-- a C function (this is a known bug in Lua 5.0)
|
-- a C function (this is a known bug in Lua 5.0)
|
||||||
|
|
||||||
local function g(x)
|
local function g(x)
|
||||||
@@ -919,7 +949,7 @@ do
|
|||||||
local cl = countlines(rest)
|
local cl = countlines(rest)
|
||||||
-- at most 10 lines in first part, 11 in second, plus '...'
|
-- at most 10 lines in first part, 11 in second, plus '...'
|
||||||
assert(cl <= 10 + 11 + 1)
|
assert(cl <= 10 + 11 + 1)
|
||||||
local brk = string.find(rest, "%.%.%.")
|
local brk = string.find(rest, "%.%.%.\t%(skip")
|
||||||
if brk then -- does message have '...'?
|
if brk then -- does message have '...'?
|
||||||
local rest1 = string.sub(rest, 1, brk)
|
local rest1 = string.sub(rest, 1, brk)
|
||||||
local rest2 = string.sub(rest, brk, #rest)
|
local rest2 = string.sub(rest, brk, #rest)
|
||||||
@@ -940,14 +970,14 @@ end
|
|||||||
|
|
||||||
|
|
||||||
print("testing debug functions on chunk without debug info")
|
print("testing debug functions on chunk without debug info")
|
||||||
prog = [[-- program to be loaded without debug information (strip)
|
local prog = [[-- program to be loaded without debug information (strip)
|
||||||
local debug = require'debug'
|
local debug = require'debug'
|
||||||
local a = 12 -- a local variable
|
local a = 12 -- a local variable
|
||||||
|
|
||||||
local n, v = debug.getlocal(1, 1)
|
local n, v = debug.getlocal(1, 1)
|
||||||
assert(n == "(temporary)" and v == debug) -- unkown name but known value
|
assert(n == "(temporary)" and v == debug) -- unknown name but known value
|
||||||
n, v = debug.getlocal(1, 2)
|
n, v = debug.getlocal(1, 2)
|
||||||
assert(n == "(temporary)" and v == 12) -- unkown name but known value
|
assert(n == "(temporary)" and v == 12) -- unknown name but known value
|
||||||
|
|
||||||
-- a function with an upvalue
|
-- a function with an upvalue
|
||||||
local f = function () local x; return a end
|
local f = function () local x; return a end
|
||||||
@@ -997,7 +1027,7 @@ do -- bug in 5.4.0: line hooks in stripped code
|
|||||||
line = l
|
line = l
|
||||||
end, "l")
|
end, "l")
|
||||||
assert(s() == 2); debug.sethook(nil)
|
assert(s() == 2); debug.sethook(nil)
|
||||||
assert(line == nil) -- hook called withoug debug info for 1st instruction
|
assert(line == nil) -- hook called without debug info for 1st instruction
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- tests for 'source' in binary dumps
|
do -- tests for 'source' in binary dumps
|
||||||
|
|||||||
+194
-73
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/errors.lua $
|
-- $Id: testes/errors.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print("testing errors")
|
print("testing errors")
|
||||||
|
|
||||||
@@ -45,8 +45,8 @@ end
|
|||||||
-- test error message with no extra info
|
-- test error message with no extra info
|
||||||
assert(doit("error('hi', 0)") == 'hi')
|
assert(doit("error('hi', 0)") == 'hi')
|
||||||
|
|
||||||
-- test error message with no info
|
-- test nil error message
|
||||||
assert(doit("error()") == nil)
|
assert(doit("error()") == "<no error object>")
|
||||||
|
|
||||||
|
|
||||||
-- test common errors/errors that crashed in the past
|
-- test common errors/errors that crashed in the past
|
||||||
@@ -91,7 +91,7 @@ end
|
|||||||
|
|
||||||
if not T then
|
if not T then
|
||||||
(Message or print)
|
(Message or print)
|
||||||
('\n >>> testC not active: skipping memory message test <<<\n')
|
('\n >>> testC not active: skipping tests for messages in C <<<\n')
|
||||||
else
|
else
|
||||||
print "testing memory error message"
|
print "testing memory error message"
|
||||||
local a = {}
|
local a = {}
|
||||||
@@ -104,6 +104,44 @@ else
|
|||||||
end)
|
end)
|
||||||
T.totalmem(0)
|
T.totalmem(0)
|
||||||
assert(not st and msg == "not enough" .. " memory")
|
assert(not st and msg == "not enough" .. " memory")
|
||||||
|
|
||||||
|
-- stack space for luaL_traceback (bug in 5.4.6)
|
||||||
|
local res = T.testC[[
|
||||||
|
# push 16 elements on the stack
|
||||||
|
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
|
||||||
|
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
|
||||||
|
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
|
||||||
|
pushnum 1;
|
||||||
|
# traceback should work with 4 remaining slots
|
||||||
|
traceback xuxu 1;
|
||||||
|
return 1
|
||||||
|
]]
|
||||||
|
assert(string.find(res, "xuxu.-main chunk"))
|
||||||
|
|
||||||
|
do -- tests for error messages about extra arguments from __call
|
||||||
|
local function createobj (n)
|
||||||
|
-- function that raises an error on its n-th argument
|
||||||
|
local code = string.format("argerror %d 'msg'", n)
|
||||||
|
local func = T.makeCfunc(code)
|
||||||
|
-- create a chain of 2 __call objects
|
||||||
|
local M = setmetatable({}, {__call = func})
|
||||||
|
M = setmetatable({}, {__call = M})
|
||||||
|
-- put it as a method for a new object
|
||||||
|
return {foo = M}
|
||||||
|
end
|
||||||
|
|
||||||
|
_G.a = createobj(1) -- error in first (extra) argument
|
||||||
|
checkmessage("a:foo()", "bad extra argument #1")
|
||||||
|
|
||||||
|
_G.a = createobj(2) -- error in second (extra) argument
|
||||||
|
checkmessage("a:foo()", "bad extra argument #2")
|
||||||
|
|
||||||
|
_G.a = createobj(3) -- error in self (after two extra arguments)
|
||||||
|
checkmessage("a:foo()", "bad self")
|
||||||
|
|
||||||
|
_G.a = createobj(4) -- error in first regular argument (after self)
|
||||||
|
checkmessage("a:foo()", "bad argument #1")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -114,12 +152,23 @@ checkmessage("a = {} | 1", "bitwise operation")
|
|||||||
checkmessage("a = {} < 1", "attempt to compare")
|
checkmessage("a = {} < 1", "attempt to compare")
|
||||||
checkmessage("a = {} <= 1", "attempt to compare")
|
checkmessage("a = {} <= 1", "attempt to compare")
|
||||||
|
|
||||||
checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
|
checkmessage("aaa=1; bbbb=2; aaa=math.sin(3)+bbbb(3)", "global 'bbbb'")
|
||||||
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
|
checkmessage("aaa={}; do local aaa=1 end aaa:bbbb(3)", "method 'bbbb'")
|
||||||
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
|
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
|
||||||
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
|
assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
|
||||||
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")
|
checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
|
||||||
checkmessage("a=(1)..{}", "a table value")
|
checkmessage("aaa=(1)..{}", "a table value")
|
||||||
|
|
||||||
|
checkmessage("local function foo (...t) return t.xx + 1 end; foo()",
|
||||||
|
"field 'xx'")
|
||||||
|
|
||||||
|
-- bug in 5.4.6
|
||||||
|
checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'")
|
||||||
|
|
||||||
|
-- a similar bug, since 5.4.0
|
||||||
|
checkmessage("print(('_ENV').x + 1)", "field 'x'")
|
||||||
|
|
||||||
|
_G.aaa, _G.bbbb = nil
|
||||||
|
|
||||||
-- calls
|
-- calls
|
||||||
checkmessage("local a; a(13)", "local 'a'")
|
checkmessage("local a; a(13)", "local 'a'")
|
||||||
@@ -134,12 +183,13 @@ checkmessage([[
|
|||||||
|
|
||||||
-- tail calls
|
-- tail calls
|
||||||
checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
|
checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
|
||||||
checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'")
|
checkmessage("aaa={}; do local aaa=1 end; return aaa:bbbb(3)", "method 'bbbb'")
|
||||||
|
|
||||||
checkmessage("a = #print", "length of a function value")
|
checkmessage("aaa = #print", "length of a function value")
|
||||||
checkmessage("a = #3", "length of a number value")
|
checkmessage("aaa = #3", "length of a number value")
|
||||||
|
|
||||||
|
_G.aaa = nil
|
||||||
|
|
||||||
aaa = nil
|
|
||||||
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
|
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
|
||||||
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
|
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
|
||||||
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
|
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
|
||||||
@@ -152,15 +202,16 @@ checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
|
|||||||
|
|
||||||
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
|
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
|
||||||
|
|
||||||
checkmessage("b=1; local aaa={}; x=aaa+b", "local 'aaa'")
|
checkmessage("BB=1; local aaa={}; x=aaa+BB", "local 'aaa'")
|
||||||
checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
|
checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
|
||||||
checkmessage("aaa=2; b=nil;x=aaa*b", "global 'b'")
|
checkmessage("aaa=2; BB=nil;x=aaa*BB", "global 'BB'")
|
||||||
checkmessage("aaa={}; x=-aaa", "global 'aaa'")
|
checkmessage("aaa={}; x=-aaa", "global 'aaa'")
|
||||||
|
|
||||||
-- short circuit
|
-- short circuit
|
||||||
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
|
checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = math.sin(1) and bbbb(3)",
|
||||||
"local 'bbbb'")
|
"local 'bbbb'")
|
||||||
checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'")
|
checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = bbbb(1) or aaa(3)",
|
||||||
|
"local 'bbbb'")
|
||||||
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
|
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
|
||||||
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
|
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
|
||||||
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
|
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
|
||||||
@@ -187,8 +238,8 @@ checkmessage("return ~-3e40", "has no integer representation")
|
|||||||
checkmessage("return ~-3.009", "has no integer representation")
|
checkmessage("return ~-3.009", "has no integer representation")
|
||||||
checkmessage("return 3.009 & 1", "has no integer representation")
|
checkmessage("return 3.009 & 1", "has no integer representation")
|
||||||
checkmessage("return 34 >> {}", "table value")
|
checkmessage("return 34 >> {}", "table value")
|
||||||
checkmessage("a = 24 // 0", "divide by zero")
|
checkmessage("aaa = 24 // 0", "divide by zero")
|
||||||
checkmessage("a = 1 % 0", "'n%0'")
|
checkmessage("aaa = 1 % 0", "'n%0'")
|
||||||
|
|
||||||
|
|
||||||
-- type error for an object which is neither in an upvalue nor a register.
|
-- type error for an object which is neither in an upvalue nor a register.
|
||||||
@@ -255,28 +306,29 @@ do
|
|||||||
local f = function (a) return a + 1 end
|
local f = function (a) return a + 1 end
|
||||||
f = assert(load(string.dump(f, true)))
|
f = assert(load(string.dump(f, true)))
|
||||||
assert(f(3) == 4)
|
assert(f(3) == 4)
|
||||||
checkerr("^%?:%-1:", f, {})
|
checkerr("^%?:%?:", f, {})
|
||||||
|
|
||||||
-- code with a move to a local var ('OP_MOV A B' with A<B)
|
-- code with a move to a local var ('OP_MOV A B' with A<B)
|
||||||
f = function () local a; a = {}; return a + 2 end
|
f = function () local a; a = {}; return a + 2 end
|
||||||
-- no debug info (so that 'a' is unknown)
|
-- no debug info (so that 'a' is unknown)
|
||||||
f = assert(load(string.dump(f, true)))
|
f = assert(load(string.dump(f, true)))
|
||||||
-- symbolic execution should not get lost
|
-- symbolic execution should not get lost
|
||||||
checkerr("^%?:%-1:.*table value", f)
|
checkerr("^%?:%?:.*table value", f)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- tests for field accesses after RK limit
|
-- tests for field accesses after RK limit
|
||||||
local t = {}
|
local t = {}
|
||||||
for i = 1, 1000 do
|
for i = 1, 1000 do
|
||||||
t[i] = "a = x" .. i
|
t[i] = "aaa = x" .. i
|
||||||
end
|
end
|
||||||
local s = table.concat(t, "; ")
|
local s = table.concat(t, "; ")
|
||||||
t = nil
|
t = nil
|
||||||
checkmessage(s.."; a = bbb + 1", "global 'bbb'")
|
checkmessage(s.."; aaa = bbb + 1", "global 'bbb'")
|
||||||
checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'")
|
checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'")
|
||||||
checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'")
|
checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'")
|
||||||
checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
|
-- cannot use 'self' opcode
|
||||||
|
checkmessage(s.."; local t = {}; t:bbb()", "field 'bbb'")
|
||||||
|
|
||||||
checkmessage([[aaa=9
|
checkmessage([[aaa=9
|
||||||
repeat until 3==3
|
repeat until 3==3
|
||||||
@@ -324,14 +376,17 @@ main()
|
|||||||
]], "global 'NoSuchName'")
|
]], "global 'NoSuchName'")
|
||||||
print'+'
|
print'+'
|
||||||
|
|
||||||
a = {}; setmetatable(a, {__index = string})
|
aaa = {}; setmetatable(aaa, {__index = string})
|
||||||
checkmessage("a:sub()", "bad self")
|
checkmessage("aaa:sub()", "bad self")
|
||||||
checkmessage("string.sub('a', {})", "#2")
|
checkmessage("string.sub('a', {})", "#2")
|
||||||
checkmessage("('a'):sub{}", "#1")
|
checkmessage("('a'):sub{}", "#1")
|
||||||
|
|
||||||
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
|
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
|
||||||
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
|
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
|
||||||
|
|
||||||
|
_G.aaa = nil
|
||||||
|
|
||||||
|
|
||||||
-- tests for errors in coroutines
|
-- tests for errors in coroutines
|
||||||
|
|
||||||
local function f (n)
|
local function f (n)
|
||||||
@@ -349,7 +404,7 @@ checkerr("yield across", f)
|
|||||||
|
|
||||||
-- testing size of 'source' info; size of buffer for that info is
|
-- testing size of 'source' info; size of buffer for that info is
|
||||||
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
|
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
|
||||||
idsize = 60 - 1
|
local idsize = 60 - 1
|
||||||
local function checksize (source)
|
local function checksize (source)
|
||||||
-- syntax error
|
-- syntax error
|
||||||
local _, msg = load("x", source)
|
local _, msg = load("x", source)
|
||||||
@@ -366,38 +421,38 @@ end
|
|||||||
|
|
||||||
-- testing line error
|
-- testing line error
|
||||||
|
|
||||||
local function lineerror (s, l)
|
local function lineerror (s, l, w)
|
||||||
local err,msg = pcall(load(s))
|
local err,msg = pcall(load(s))
|
||||||
local line = tonumber(string.match(msg, ":(%d+):"))
|
local line = tonumber(string.match(msg, ":(%d+):"))
|
||||||
assert(line == l or (not line and not l))
|
assert((line == l or (not line and not l)) and string.find(msg, w))
|
||||||
end
|
end
|
||||||
|
|
||||||
lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2)
|
lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2, "limit")
|
||||||
lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3)
|
lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3, "to call")
|
||||||
lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4)
|
lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4, "to call")
|
||||||
lineerror("function a.x.y ()\na=a+1\nend", 1)
|
lineerror("function a.x.y ()\na=a+1\nend", 1, "index")
|
||||||
|
|
||||||
lineerror("a = \na\n+\n{}", 3)
|
lineerror("a = \na\n+\n{}", 3, "arithmetic")
|
||||||
lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6)
|
lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6, "arithmetic")
|
||||||
lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3)
|
lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3, "arithmetic")
|
||||||
|
|
||||||
lineerror("a\n=\n-\n\nprint\n;", 3)
|
lineerror("a\n=\n-\n\nprint\n;", 3, "arithmetic")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
a
|
a
|
||||||
(
|
( -- <<
|
||||||
23)
|
23)
|
||||||
]], 1)
|
]], 2, "call")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local a = {x = 13}
|
local a = {x = 13}
|
||||||
a
|
a
|
||||||
.
|
.
|
||||||
x
|
x
|
||||||
(
|
( -- <<
|
||||||
23
|
23
|
||||||
)
|
)
|
||||||
]], 2)
|
]], 5, "call")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local a = {x = 13}
|
local a = {x = 13}
|
||||||
@@ -407,24 +462,25 @@ x
|
|||||||
(
|
(
|
||||||
23 + a
|
23 + a
|
||||||
)
|
)
|
||||||
]], 6)
|
]], 6, "arithmetic")
|
||||||
|
|
||||||
local p = [[
|
local p = [[
|
||||||
function g() f() end
|
function g() f() end
|
||||||
function f(x) error('a', X) end
|
function f(x) error('a', XX) end
|
||||||
g()
|
g()
|
||||||
]]
|
]]
|
||||||
X=3;lineerror((p), 3)
|
XX=3;lineerror((p), 3, "a")
|
||||||
X=0;lineerror((p), false)
|
XX=0;lineerror((p), false, "a")
|
||||||
X=1;lineerror((p), 2)
|
XX=1;lineerror((p), 2, "a")
|
||||||
X=2;lineerror((p), 1)
|
XX=2;lineerror((p), 1, "a")
|
||||||
|
_G.XX, _G.g, _G.f = nil
|
||||||
|
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local b = false
|
local b = false
|
||||||
if not b then
|
if not b then
|
||||||
error 'test'
|
error 'test'
|
||||||
end]], 3)
|
end]], 3, "test")
|
||||||
|
|
||||||
lineerror([[
|
lineerror([[
|
||||||
local b = false
|
local b = false
|
||||||
@@ -434,26 +490,62 @@ if not b then
|
|||||||
error 'test'
|
error 'test'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end]], 5)
|
end]], 5, "test")
|
||||||
|
|
||||||
|
lineerror([[
|
||||||
|
_ENV = 1
|
||||||
|
global function foo ()
|
||||||
|
local a = 10
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
]], 2, "index")
|
||||||
|
|
||||||
|
|
||||||
|
-- bug in 5.4.0
|
||||||
|
lineerror([[
|
||||||
|
local a = 0
|
||||||
|
local b = 1
|
||||||
|
local c = b % a
|
||||||
|
]], 3, "perform")
|
||||||
|
|
||||||
do
|
do
|
||||||
-- Force a negative estimate for base line. Error in instruction 2
|
-- Force a negative estimate for base line. Error in instruction 2
|
||||||
-- (after VARARGPREP, GETGLOBAL), with first absolute line information
|
-- (after VARARGPREP, GETGLOBAL), with first absolute line information
|
||||||
-- (forced by too many lines) in instruction 0.
|
-- (forced by too many lines) in instruction 0.
|
||||||
local s = string.format("%s return __A.x", string.rep("\n", 300))
|
local s = string.format("%s return __A.x", string.rep("\n", 300))
|
||||||
lineerror(s, 301)
|
lineerror(s, 301, "index")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function stxlineerror (s, l, w)
|
||||||
|
local err,msg = load(s)
|
||||||
|
local line = tonumber(string.match(msg, ":(%d+):"))
|
||||||
|
assert((line == l or (not line and not l)) and string.find(msg, w, 1, true))
|
||||||
|
end
|
||||||
|
|
||||||
|
stxlineerror([[
|
||||||
|
::L1::
|
||||||
|
::L1::
|
||||||
|
]], 2, "already defined")
|
||||||
|
|
||||||
|
stxlineerror([[
|
||||||
|
global none
|
||||||
|
local x = b
|
||||||
|
]], 2, "not declared")
|
||||||
|
|
||||||
|
stxlineerror([[
|
||||||
|
local <close> a, b
|
||||||
|
]], 1, "multiple")
|
||||||
|
|
||||||
if not _soft then
|
if not _soft then
|
||||||
-- several tests that exaust the Lua stack
|
-- several tests that exhaust the Lua stack
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
print"testing stack overflow"
|
print"testing stack overflow"
|
||||||
C = 0
|
local C = 0
|
||||||
-- get line where stack overflow will happen
|
-- get line where stack overflow will happen
|
||||||
local l = debug.getinfo(1, "l").currentline + 1
|
local l = debug.getinfo(1, "l").currentline + 1
|
||||||
local function auxy () C=C+1; auxy() end -- produce a stack overflow
|
local function auxy () C=C+1; auxy() end -- produce a stack overflow
|
||||||
function y ()
|
function YY ()
|
||||||
collectgarbage("stop") -- avoid running finalizers without stack space
|
collectgarbage("stop") -- avoid running finalizers without stack space
|
||||||
auxy()
|
auxy()
|
||||||
collectgarbage("restart")
|
collectgarbage("restart")
|
||||||
@@ -465,9 +557,11 @@ if not _soft then
|
|||||||
return (string.find(m, "stack overflow"))
|
return (string.find(m, "stack overflow"))
|
||||||
end
|
end
|
||||||
-- repeated stack overflows (to check stack recovery)
|
-- repeated stack overflows (to check stack recovery)
|
||||||
assert(checkstackmessage(doit('y()')))
|
assert(checkstackmessage(doit('YY()')))
|
||||||
assert(checkstackmessage(doit('y()')))
|
assert(checkstackmessage(doit('YY()')))
|
||||||
assert(checkstackmessage(doit('y()')))
|
assert(checkstackmessage(doit('YY()')))
|
||||||
|
|
||||||
|
_G.YY = nil
|
||||||
|
|
||||||
|
|
||||||
-- error lines in stack overflow
|
-- error lines in stack overflow
|
||||||
@@ -495,7 +589,7 @@ if not _soft then
|
|||||||
|
|
||||||
-- error in error handling
|
-- error in error handling
|
||||||
local res, msg = xpcall(error, error)
|
local res, msg = xpcall(error, error)
|
||||||
assert(not res and type(msg) == 'string')
|
assert(not res and msg == 'error in error handling')
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
local function f (x)
|
local function f (x)
|
||||||
@@ -526,6 +620,27 @@ if not _soft then
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- errors in error handle that not necessarily go forever
|
||||||
|
local function err (n) -- function to be used as message handler
|
||||||
|
-- generate an error unless n is zero, so that there is a limited
|
||||||
|
-- loop of errors
|
||||||
|
if type(n) ~= "number" then -- some other error?
|
||||||
|
return n -- report it
|
||||||
|
elseif n == 0 then
|
||||||
|
return "END" -- that will be the final message
|
||||||
|
else error(n - 1) -- does the loop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local res, msg = xpcall(error, err, 170)
|
||||||
|
assert(not res and msg == "END")
|
||||||
|
|
||||||
|
-- too many levels
|
||||||
|
local res, msg = xpcall(error, err, 300)
|
||||||
|
assert(not res and msg == "C stack overflow")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
-- non string messages
|
-- non string messages
|
||||||
local t = {}
|
local t = {}
|
||||||
@@ -533,7 +648,7 @@ do
|
|||||||
assert(not res and msg == t)
|
assert(not res and msg == t)
|
||||||
|
|
||||||
res, msg = pcall(function () error(nil) end)
|
res, msg = pcall(function () error(nil) end)
|
||||||
assert(not res and msg == nil)
|
assert(not res and msg == "<no error object>")
|
||||||
|
|
||||||
local function f() error{msg='x'} end
|
local function f() error{msg='x'} end
|
||||||
res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
|
res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
|
||||||
@@ -553,7 +668,7 @@ do
|
|||||||
assert(not res and msg == t)
|
assert(not res and msg == t)
|
||||||
|
|
||||||
res, msg = pcall(assert, nil, nil)
|
res, msg = pcall(assert, nil, nil)
|
||||||
assert(not res and msg == nil)
|
assert(not res and type(msg) == "string")
|
||||||
|
|
||||||
-- 'assert' without arguments
|
-- 'assert' without arguments
|
||||||
res, msg = pcall(assert)
|
res, msg = pcall(assert)
|
||||||
@@ -561,7 +676,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- xpcall with arguments
|
-- xpcall with arguments
|
||||||
a, b, c = xpcall(string.find, error, "alo", "al")
|
local a, b, c = xpcall(string.find, error, "alo", "al")
|
||||||
assert(a and b == 1 and c == 2)
|
assert(a and b == 1 and c == 2)
|
||||||
a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
|
a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
|
||||||
assert(not a and type(b) == "table" and c == nil)
|
assert(not a and type(b) == "table" and c == nil)
|
||||||
@@ -581,11 +696,12 @@ checksyntax("a\1a = 1", "", "<\\1>", 1)
|
|||||||
-- test 255 as first char in a chunk
|
-- test 255 as first char in a chunk
|
||||||
checksyntax("\255a = 1", "", "<\\255>", 1)
|
checksyntax("\255a = 1", "", "<\\255>", 1)
|
||||||
|
|
||||||
doit('I = load("a=9+"); a=3')
|
doit('I = load("a=9+"); aaa=3')
|
||||||
assert(a==3 and not I)
|
assert(_G.aaa==3 and not _G.I)
|
||||||
|
_G.I,_G.aaa = nil
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
lim = 1000
|
local lim = 1000
|
||||||
if _soft then lim = 100 end
|
if _soft then lim = 100 end
|
||||||
for i=1,lim do
|
for i=1,lim do
|
||||||
doit('a = ')
|
doit('a = ')
|
||||||
@@ -596,21 +712,26 @@ end
|
|||||||
-- testing syntax limits
|
-- testing syntax limits
|
||||||
|
|
||||||
local function testrep (init, rep, close, repc, finalresult)
|
local function testrep (init, rep, close, repc, finalresult)
|
||||||
local s = init .. string.rep(rep, 100) .. close .. string.rep(repc, 100)
|
local function gencode (n)
|
||||||
local res, msg = load(s)
|
return init .. string.rep(rep, n) .. close .. string.rep(repc, n)
|
||||||
assert(res) -- 100 levels is OK
|
end
|
||||||
|
local res, msg = load(gencode(100)) -- 100 levels is OK
|
||||||
|
assert(res)
|
||||||
if (finalresult) then
|
if (finalresult) then
|
||||||
assert(res() == finalresult)
|
assert(res() == finalresult)
|
||||||
end
|
end
|
||||||
s = init .. string.rep(rep, 500)
|
local res, msg = load(gencode(500)) -- 500 levels not ok
|
||||||
local res, msg = load(s) -- 500 levels not ok
|
|
||||||
assert(not res and (string.find(msg, "too many") or
|
assert(not res and (string.find(msg, "too many") or
|
||||||
string.find(msg, "overflow")))
|
string.find(msg, "overflow")))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
testrep("local a", ",a", ";", "") -- local variables
|
||||||
|
testrep("local a", ",a", "= 1", ",1") -- local variables initialized
|
||||||
|
testrep("local a", ",a", "= f()", "") -- local variables initialized
|
||||||
testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment
|
testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment
|
||||||
testrep("local a; a=", "{", "0", "}")
|
testrep("local a; a=", "{", "0", "}") -- constructors
|
||||||
testrep("return ", "(", "2", ")", 2)
|
testrep("return ", "(", "2", ")", 2) -- parentheses
|
||||||
|
-- nested calls (a(a(a(a(...)))))
|
||||||
testrep("local function a (x) return x end; return ", "a(", "2.2", ")", 2.2)
|
testrep("local function a (x) return x end; return ", "a(", "2.2", ")", 2.2)
|
||||||
testrep("", "do ", "", " end")
|
testrep("", "do ", "", " end")
|
||||||
testrep("", "while a do ", "", " end")
|
testrep("", "while a do ", "", " end")
|
||||||
@@ -649,7 +770,7 @@ assert(c > 255 and string.find(b, "too many upvalues") and
|
|||||||
|
|
||||||
-- local variables
|
-- local variables
|
||||||
s = "\nfunction foo ()\n local "
|
s = "\nfunction foo ()\n local "
|
||||||
for j = 1,300 do
|
for j = 1,200 do
|
||||||
s = s.."a"..j..", "
|
s = s.."a"..j..", "
|
||||||
end
|
end
|
||||||
s = s.."b\n"
|
s = s.."b\n"
|
||||||
|
|||||||
+25
-2
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/events.lua $
|
-- $Id: testes/events.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print('testing metatables')
|
print('testing metatables')
|
||||||
|
|
||||||
@@ -248,6 +248,15 @@ end
|
|||||||
test(Op(1), Op(2), Op(3))
|
test(Op(1), Op(2), Op(3))
|
||||||
|
|
||||||
|
|
||||||
|
do -- test nil as false
|
||||||
|
local x = setmetatable({12}, {__eq= function (a,b)
|
||||||
|
return a[1] == b[1] or nil
|
||||||
|
end})
|
||||||
|
assert(not (x == {20}))
|
||||||
|
assert(x == {12})
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test `partial order'
|
-- test `partial order'
|
||||||
|
|
||||||
local function rawSet(x)
|
local function rawSet(x)
|
||||||
@@ -370,6 +379,17 @@ x = 0 .."a".."b"..c..d.."e".."f".."g"
|
|||||||
assert(x.val == "0abcdefg")
|
assert(x.val == "0abcdefg")
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- bug since 5.4.1 (test needs T)
|
||||||
|
local mt = setmetatable({__newindex={}}, {__mode='v'})
|
||||||
|
local t = setmetatable({}, mt)
|
||||||
|
|
||||||
|
if T then T.allocfailnext() end
|
||||||
|
|
||||||
|
-- seg. fault
|
||||||
|
for i=1, 10 do t[i] = 1 end
|
||||||
|
end
|
||||||
|
|
||||||
-- concat metamethod x numbers (bug in 5.1.1)
|
-- concat metamethod x numbers (bug in 5.1.1)
|
||||||
c = {}
|
c = {}
|
||||||
local x
|
local x
|
||||||
@@ -420,6 +440,9 @@ assert(i == 3 and x[1] == 3 and x[3] == 5)
|
|||||||
|
|
||||||
assert(_G.X == 20)
|
assert(_G.X == 20)
|
||||||
|
|
||||||
|
_G.X, _G.B = nil
|
||||||
|
|
||||||
|
|
||||||
print'+'
|
print'+'
|
||||||
|
|
||||||
local _g = _G
|
local _g = _G
|
||||||
@@ -469,7 +492,7 @@ assert(not pcall(function (a,b) return a[b] end, a, 10))
|
|||||||
assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true))
|
assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true))
|
||||||
|
|
||||||
-- bug in 5.1
|
-- bug in 5.1
|
||||||
T, K, V = nil
|
local T, K, V = nil
|
||||||
grandparent = {}
|
grandparent = {}
|
||||||
grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
|
grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
|
||||||
|
|
||||||
|
|||||||
+77
-13
@@ -1,5 +1,7 @@
|
|||||||
-- $Id: testes/files.lua $
|
-- $Id: testes/files.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
local debug = require "debug"
|
local debug = require "debug"
|
||||||
|
|
||||||
@@ -74,6 +76,8 @@ io.input(io.stdin); io.output(io.stdout);
|
|||||||
|
|
||||||
os.remove(file)
|
os.remove(file)
|
||||||
assert(not loadfile(file))
|
assert(not loadfile(file))
|
||||||
|
-- Lua code cannot use chunks with fixed buffers
|
||||||
|
checkerr("invalid mode", load, "", "", "B")
|
||||||
checkerr("", dofile, file)
|
checkerr("", dofile, file)
|
||||||
assert(not io.open(file))
|
assert(not io.open(file))
|
||||||
io.output(file)
|
io.output(file)
|
||||||
@@ -92,8 +96,8 @@ assert(io.output():seek("end") == string.len("alo joao"))
|
|||||||
|
|
||||||
assert(io.output():seek("set") == 0)
|
assert(io.output():seek("set") == 0)
|
||||||
|
|
||||||
assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n"))
|
assert(io.write('"alo"', "{a}\n", "second line\n", "third line \n"))
|
||||||
assert(io.write('çfourth_line'))
|
assert(io.write('Xfourth_line'))
|
||||||
io.output(io.stdout)
|
io.output(io.stdout)
|
||||||
collectgarbage() -- file should be closed by GC
|
collectgarbage() -- file should be closed by GC
|
||||||
assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
|
assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
|
||||||
@@ -300,14 +304,14 @@ do -- test error returns
|
|||||||
end
|
end
|
||||||
checkerr("invalid format", io.read, "x")
|
checkerr("invalid format", io.read, "x")
|
||||||
assert(io.read(0) == "") -- not eof
|
assert(io.read(0) == "") -- not eof
|
||||||
assert(io.read(5, 'l') == '"álo"')
|
assert(io.read(5, 'l') == '"alo"')
|
||||||
assert(io.read(0) == "")
|
assert(io.read(0) == "")
|
||||||
assert(io.read() == "second line")
|
assert(io.read() == "second line")
|
||||||
local x = io.input():seek()
|
local x = io.input():seek()
|
||||||
assert(io.read() == "third line ")
|
assert(io.read() == "third line ")
|
||||||
assert(io.input():seek("set", x))
|
assert(io.input():seek("set", x))
|
||||||
assert(io.read('L') == "third line \n")
|
assert(io.read('L') == "third line \n")
|
||||||
assert(io.read(1) == "ç")
|
assert(io.read(1) == "X")
|
||||||
assert(io.read(string.len"fourth_line") == "fourth_line")
|
assert(io.read(string.len"fourth_line") == "fourth_line")
|
||||||
assert(io.input():seek("cur", -string.len"fourth_line"))
|
assert(io.input():seek("cur", -string.len"fourth_line"))
|
||||||
assert(io.read() == "fourth_line")
|
assert(io.read() == "fourth_line")
|
||||||
@@ -345,7 +349,7 @@ collectgarbage()
|
|||||||
|
|
||||||
assert(io.write(' ' .. t .. ' '))
|
assert(io.write(' ' .. t .. ' '))
|
||||||
assert(io.write(';', 'end of file\n'))
|
assert(io.write(';', 'end of file\n'))
|
||||||
f:flush(); io.flush()
|
assert(f:flush()); assert(io.flush())
|
||||||
f:close()
|
f:close()
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
@@ -427,12 +431,12 @@ do -- testing closing file in line iteration
|
|||||||
-- get the to-be-closed variable from a loop
|
-- get the to-be-closed variable from a loop
|
||||||
local function gettoclose (lv)
|
local function gettoclose (lv)
|
||||||
lv = lv + 1
|
lv = lv + 1
|
||||||
local stvar = 0 -- to-be-closed is 4th state variable in the loop
|
local stvar = 0 -- to-be-closed is 3th state variable in the loop
|
||||||
for i = 1, 1000 do
|
for i = 1, 1000 do
|
||||||
local n, v = debug.getlocal(lv, i)
|
local n, v = debug.getlocal(lv, i)
|
||||||
if n == "(for state)" then
|
if n == "(for state)" then
|
||||||
stvar = stvar + 1
|
stvar = stvar + 1
|
||||||
if stvar == 4 then return v end
|
if stvar == 3 then return v end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -459,7 +463,24 @@ do -- testing closing file in line iteration
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test for multipe arguments in 'lines'
|
do print("testing flush")
|
||||||
|
local f = io.output("/dev/null")
|
||||||
|
assert(f:write("abcd")) -- write to buffer
|
||||||
|
assert(f:flush()) -- write to device
|
||||||
|
assert(f:write("abcd")) -- write to buffer
|
||||||
|
assert(io.flush()) -- write to device
|
||||||
|
assert(f:close())
|
||||||
|
|
||||||
|
local f = io.output("/dev/full")
|
||||||
|
assert(f:write("abcd")) -- write to buffer
|
||||||
|
assert(not f:flush()) -- cannot write to device
|
||||||
|
assert(f:write("abcd")) -- write to buffer
|
||||||
|
assert(not io.flush()) -- cannot write to device
|
||||||
|
assert(f:close())
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- test for multiple arguments in 'lines'
|
||||||
io.output(file); io.write"0123456789\n":close()
|
io.output(file); io.write"0123456789\n":close()
|
||||||
for a,b in io.lines(file, 1, 1) do
|
for a,b in io.lines(file, 1, 1) do
|
||||||
if a == "\n" then assert(not b)
|
if a == "\n" then assert(not b)
|
||||||
@@ -507,15 +528,17 @@ load((io.lines(file, 1)))()
|
|||||||
assert(_G.X == 4)
|
assert(_G.X == 4)
|
||||||
load((io.lines(file, 3)))()
|
load((io.lines(file, 3)))()
|
||||||
assert(_G.X == 8)
|
assert(_G.X == 8)
|
||||||
|
_G.X = nil
|
||||||
|
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
|
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
|
||||||
io.output(file)
|
io.output(file)
|
||||||
assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1)))
|
assert(io.write(string.format("X2 = %q\n-- comment without ending EOS", x1)))
|
||||||
io.close()
|
io.close()
|
||||||
assert(loadfile(file))()
|
assert(loadfile(file))()
|
||||||
assert(x1 == x2)
|
assert(x1 == _G.X2)
|
||||||
|
_G.X2 = nil
|
||||||
print('+')
|
print('+')
|
||||||
assert(os.remove(file))
|
assert(os.remove(file))
|
||||||
assert(not os.remove(file))
|
assert(not os.remove(file))
|
||||||
@@ -692,6 +715,37 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if T and T.nonblock and not _port then
|
||||||
|
print("testing failed write")
|
||||||
|
|
||||||
|
-- unable to write anything to /dev/full
|
||||||
|
local f = io.open("/dev/full", "w")
|
||||||
|
assert(f:setvbuf("no"))
|
||||||
|
local _, _, err, count = f:write("abcd")
|
||||||
|
assert(err > 0 and count == 0)
|
||||||
|
assert(f:close())
|
||||||
|
|
||||||
|
-- receiver will read a "few" bytes (enough to empty a large buffer)
|
||||||
|
local receiver = [[
|
||||||
|
lua -e 'assert(io.stdin:setvbuf("no")); assert(#io.read(1e4) == 1e4)' ]]
|
||||||
|
|
||||||
|
local f = io.popen(receiver, "w")
|
||||||
|
assert(f:setvbuf("no"))
|
||||||
|
T.nonblock(f)
|
||||||
|
|
||||||
|
-- able to write a few bytes
|
||||||
|
assert(f:write(string.rep("a", 1e2)))
|
||||||
|
|
||||||
|
-- Unable to write more bytes than the pipe buffer supports.
|
||||||
|
-- (In Linux, the pipe buffer size is 64K (2^16). Posix requires at
|
||||||
|
-- least 512 bytes.)
|
||||||
|
local _, _, err, count = f:write("abcd", string.rep("a", 2^17))
|
||||||
|
assert(err > 0 and count >= 512 and count < 2^17)
|
||||||
|
|
||||||
|
assert(f:close())
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
if not _soft then
|
if not _soft then
|
||||||
print("testing large files (> BUFSIZ)")
|
print("testing large files (> BUFSIZ)")
|
||||||
io.output(file)
|
io.output(file)
|
||||||
@@ -762,6 +816,7 @@ if not _port then
|
|||||||
assert((v[3] == nil and z > 0) or v[3] == z)
|
assert((v[3] == nil and z > 0) or v[3] == z)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
print("(done)")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -785,13 +840,13 @@ assert(os.date("!\0\0") == "\0\0")
|
|||||||
local x = string.rep("a", 10000)
|
local x = string.rep("a", 10000)
|
||||||
assert(os.date(x) == x)
|
assert(os.date(x) == x)
|
||||||
local t = os.time()
|
local t = os.time()
|
||||||
D = os.date("*t", t)
|
global D = os.date("*t", t)
|
||||||
assert(os.date(string.rep("%d", 1000), t) ==
|
assert(os.date(string.rep("%d", 1000), t) ==
|
||||||
string.rep(os.date("%d", t), 1000))
|
string.rep(os.date("%d", t), 1000))
|
||||||
assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
|
assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
|
||||||
|
|
||||||
local function checkDateTable (t)
|
local function checkDateTable (t)
|
||||||
_G.D = os.date("*t", t)
|
D = os.date("*t", t)
|
||||||
assert(os.time(D) == t)
|
assert(os.time(D) == t)
|
||||||
load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and
|
load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and
|
||||||
D.hour==%H and D.min==%M and D.sec==%S and
|
D.hour==%H and D.min==%M and D.sec==%S and
|
||||||
@@ -825,8 +880,17 @@ checkerr("missing", os.time, {hour = 12}) -- missing date
|
|||||||
if string.packsize("i") == 4 then -- 4-byte ints
|
if string.packsize("i") == 4 then -- 4-byte ints
|
||||||
checkerr("field 'year' is out-of-bound", os.time,
|
checkerr("field 'year' is out-of-bound", os.time,
|
||||||
{year = -(1 << 31) + 1899, month = 1, day = 1})
|
{year = -(1 << 31) + 1899, month = 1, day = 1})
|
||||||
|
|
||||||
|
checkerr("field 'year' is out-of-bound", os.time,
|
||||||
|
{year = -(1 << 31), month = 1, day = 1})
|
||||||
|
|
||||||
|
if math.maxinteger > 2^31 then -- larger lua_integer?
|
||||||
|
checkerr("field 'year' is out-of-bound", os.time,
|
||||||
|
{year = (1 << 31) + 1900, month = 1, day = 1})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if not _port then
|
if not _port then
|
||||||
-- test Posix-specific modifiers
|
-- test Posix-specific modifiers
|
||||||
assert(type(os.date("%Ex")) == 'string')
|
assert(type(os.date("%Ex")) == 'string')
|
||||||
|
|||||||
+140
-79
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/gc.lua $
|
-- $Id: testes/gc.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print('testing incremental garbage collection')
|
print('testing incremental garbage collection')
|
||||||
|
|
||||||
@@ -27,27 +27,54 @@ end
|
|||||||
|
|
||||||
-- test weird parameters to 'collectgarbage'
|
-- test weird parameters to 'collectgarbage'
|
||||||
do
|
do
|
||||||
-- save original parameters
|
collectgarbage("incremental")
|
||||||
local a = collectgarbage("setpause", 200)
|
local opause = collectgarbage("param", "pause", 100)
|
||||||
local b = collectgarbage("setstepmul", 200)
|
local ostepmul = collectgarbage("param", "stepmul", 100)
|
||||||
|
assert(collectgarbage("param", "pause") == 100)
|
||||||
|
assert(collectgarbage("param", "stepmul") == 100)
|
||||||
local t = {0, 2, 10, 90, 500, 5000, 30000, 0x7ffffffe}
|
local t = {0, 2, 10, 90, 500, 5000, 30000, 0x7ffffffe}
|
||||||
for i = 1, #t do
|
for i = 1, #t do
|
||||||
local p = t[i]
|
collectgarbage("param", "pause", t[i])
|
||||||
for j = 1, #t do
|
for j = 1, #t do
|
||||||
local m = t[j]
|
collectgarbage("param", "stepmul", t[j])
|
||||||
collectgarbage("setpause", p)
|
collectgarbage("step", t[j])
|
||||||
collectgarbage("setstepmul", m)
|
|
||||||
collectgarbage("step", 0)
|
|
||||||
collectgarbage("step", 10000)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- restore original parameters
|
-- restore original parameters
|
||||||
collectgarbage("setpause", a)
|
collectgarbage("param", "pause", opause)
|
||||||
collectgarbage("setstepmul", b)
|
collectgarbage("param", "stepmul", ostepmul)
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- test the "size" of basic GC steps (whatever they mean...)
|
||||||
|
--
|
||||||
|
do print("steps")
|
||||||
|
|
||||||
|
local function dosteps (siz)
|
||||||
|
collectgarbage()
|
||||||
|
local a = {}
|
||||||
|
for i=1,100 do a[i] = {{}}; local b = {} end
|
||||||
|
local x = gcinfo()
|
||||||
|
local i = 0
|
||||||
|
repeat -- do steps until it completes a collection cycle
|
||||||
|
i = i+1
|
||||||
|
until collectgarbage("step", siz)
|
||||||
|
assert(gcinfo() < x)
|
||||||
|
return i -- number of steps
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if not _port then
|
||||||
|
collectgarbage"stop"
|
||||||
|
assert(dosteps(10) < dosteps(2))
|
||||||
|
collectgarbage"restart"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
_G["while"] = 234
|
_G["while"] = 234
|
||||||
|
|
||||||
|
|
||||||
@@ -125,7 +152,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
a:test()
|
a:test()
|
||||||
|
_G.temp = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -134,7 +161,7 @@ do local f = function () end end
|
|||||||
|
|
||||||
|
|
||||||
print("functions with errors")
|
print("functions with errors")
|
||||||
prog = [[
|
local prog = [[
|
||||||
do
|
do
|
||||||
a = 10;
|
a = 10;
|
||||||
function foo(x,y)
|
function foo(x,y)
|
||||||
@@ -153,60 +180,24 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
rawset(_G, "a", nil)
|
||||||
|
_G.x = nil
|
||||||
|
|
||||||
foo = nil
|
|
||||||
print('long strings')
|
|
||||||
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
|
||||||
assert(string.len(x)==80)
|
|
||||||
s = ''
|
|
||||||
k = math.min(300, (math.maxinteger // 80) // 2)
|
|
||||||
for n = 1, k do s = s..x; j=tostring(n) end
|
|
||||||
assert(string.len(s) == k*80)
|
|
||||||
s = string.sub(s, 1, 10000)
|
|
||||||
s, i = string.gsub(s, '(%d%d%d%d)', '')
|
|
||||||
assert(i==10000 // 4)
|
|
||||||
s = nil
|
|
||||||
x = nil
|
|
||||||
|
|
||||||
assert(_G["while"] == 234)
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- test the "size" of basic GC steps (whatever they mean...)
|
|
||||||
--
|
|
||||||
do
|
do
|
||||||
print("steps")
|
foo = nil
|
||||||
|
print('long strings')
|
||||||
print("steps (2)")
|
local x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||||
|
assert(string.len(x)==80)
|
||||||
local function dosteps (siz)
|
local s = ''
|
||||||
collectgarbage()
|
local k = math.min(300, (math.maxinteger // 80) // 2)
|
||||||
local a = {}
|
for n = 1, k do s = s..x; local j=tostring(n) end
|
||||||
for i=1,100 do a[i] = {{}}; local b = {} end
|
assert(string.len(s) == k*80)
|
||||||
local x = gcinfo()
|
s = string.sub(s, 1, 10000)
|
||||||
local i = 0
|
local s, i = string.gsub(s, '(%d%d%d%d)', '')
|
||||||
repeat -- do steps until it completes a collection cycle
|
assert(i==10000 // 4)
|
||||||
i = i+1
|
|
||||||
until collectgarbage("step", siz)
|
|
||||||
assert(gcinfo() < x)
|
|
||||||
return i -- number of steps
|
|
||||||
end
|
|
||||||
|
|
||||||
collectgarbage"stop"
|
|
||||||
|
|
||||||
if not _port then
|
|
||||||
assert(dosteps(10) < dosteps(2))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- collector should do a full collection with so many steps
|
|
||||||
assert(dosteps(20000) == 1)
|
|
||||||
assert(collectgarbage("step", 20000) == true)
|
|
||||||
assert(collectgarbage("step", 20000) == true)
|
|
||||||
|
|
||||||
assert(not collectgarbage("isrunning"))
|
|
||||||
collectgarbage"restart"
|
|
||||||
assert(collectgarbage("isrunning"))
|
|
||||||
|
|
||||||
|
assert(_G["while"] == 234)
|
||||||
|
_G["while"] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -227,8 +218,8 @@ end
|
|||||||
|
|
||||||
|
|
||||||
print("clearing tables")
|
print("clearing tables")
|
||||||
lim = 15
|
local lim = 15
|
||||||
a = {}
|
local a = {}
|
||||||
-- fill a with `collectable' indices
|
-- fill a with `collectable' indices
|
||||||
for i=1,lim do a[{}] = i end
|
for i=1,lim do a[{}] = i end
|
||||||
b = {}
|
b = {}
|
||||||
@@ -297,6 +288,21 @@ x,y,z=nil
|
|||||||
collectgarbage()
|
collectgarbage()
|
||||||
assert(next(a) == string.rep('$', 11))
|
assert(next(a) == string.rep('$', 11))
|
||||||
|
|
||||||
|
do -- invalid mode
|
||||||
|
local a = setmetatable({}, {__mode = 34})
|
||||||
|
collectgarbage()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if T then -- bug since 5.3: all-weak tables are not being revisited
|
||||||
|
T.gcstate("propagate")
|
||||||
|
local t = setmetatable({}, {__mode = "kv"})
|
||||||
|
T.gcstate("enteratomic") -- 't' was visited
|
||||||
|
setmetatable(t, {__mode = "kv"})
|
||||||
|
T.gcstate("pause") -- its new metatable is not being visited
|
||||||
|
assert(getmetatable(t).__mode == "kv")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- 'bug' in 5.1
|
-- 'bug' in 5.1
|
||||||
a = {}
|
a = {}
|
||||||
@@ -455,12 +461,9 @@ do -- tests for string keys in weak tables
|
|||||||
local m = collectgarbage("count") -- current memory
|
local m = collectgarbage("count") -- current memory
|
||||||
local a = setmetatable({}, {__mode = "kv"})
|
local a = setmetatable({}, {__mode = "kv"})
|
||||||
a[string.rep("a", 2^22)] = 25 -- long string key -> number value
|
a[string.rep("a", 2^22)] = 25 -- long string key -> number value
|
||||||
a[string.rep("b", 2^22)] = {} -- long string key -> colectable value
|
a[string.rep("b", 2^22)] = {} -- long string key -> collectable value
|
||||||
a[{}] = 14 -- colectable key
|
a[{}] = 14 -- collectable key
|
||||||
assert(collectgarbage("count") > m + 2^13) -- 2^13 == 2 * 2^22 in KB
|
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
assert(collectgarbage("count") >= m + 2^12 and
|
|
||||||
collectgarbage("count") < m + 2^13) -- one key was collected
|
|
||||||
local k, v = next(a) -- string key with number value preserved
|
local k, v = next(a) -- string key with number value preserved
|
||||||
assert(k == string.rep("a", 2^22) and v == 25)
|
assert(k == string.rep("a", 2^22) and v == 25)
|
||||||
assert(next(a, k) == nil) -- everything else cleared
|
assert(next(a, k) == nil) -- everything else cleared
|
||||||
@@ -471,7 +474,7 @@ do -- tests for string keys in weak tables
|
|||||||
assert(next(a) == nil)
|
assert(next(a) == nil)
|
||||||
-- make sure will not try to compare with dead key
|
-- make sure will not try to compare with dead key
|
||||||
assert(a[string.rep("b", 100)] == undef)
|
assert(a[string.rep("b", 100)] == undef)
|
||||||
assert(collectgarbage("count") <= m + 1) -- eveything collected
|
assert(collectgarbage("count") <= m + 1) -- everything collected
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -536,7 +539,7 @@ do
|
|||||||
local co = coroutine.create(f)
|
local co = coroutine.create(f)
|
||||||
assert(coroutine.resume(co, co))
|
assert(coroutine.resume(co, co))
|
||||||
end
|
end
|
||||||
-- Now, thread and closure are not reacheable any more.
|
-- Now, thread and closure are not reachable any more.
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
assert(collected)
|
assert(collected)
|
||||||
collectgarbage("restart")
|
collectgarbage("restart")
|
||||||
@@ -546,12 +549,13 @@ end
|
|||||||
do
|
do
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
collectgarbage"stop"
|
collectgarbage"stop"
|
||||||
collectgarbage("step", 0) -- steps should not unblock the collector
|
collectgarbage("step") -- steps should not unblock the collector
|
||||||
local x = gcinfo()
|
local x = gcinfo()
|
||||||
repeat
|
repeat
|
||||||
for i=1,1000 do _ENV.a = {} end -- no collection during the loop
|
for i=1,1000 do _ENV.a = {} end -- no collection during the loop
|
||||||
until gcinfo() > 2 * x
|
until gcinfo() > 2 * x
|
||||||
collectgarbage"restart"
|
collectgarbage"restart"
|
||||||
|
_ENV.a = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -571,8 +575,8 @@ if T then -- tests for weird cases collecting upvalues
|
|||||||
-- create coroutine in a weak table, so it will never be marked
|
-- create coroutine in a weak table, so it will never be marked
|
||||||
t.co = coroutine.wrap(foo)
|
t.co = coroutine.wrap(foo)
|
||||||
local f = t.co() -- create function to access local 'a'
|
local f = t.co() -- create function to access local 'a'
|
||||||
T.gcstate("atomic") -- ensure all objects are traversed
|
T.gcstate("enteratomic") -- ensure all objects are traversed
|
||||||
assert(T.gcstate() == "atomic")
|
assert(T.gcstate() == "enteratomic")
|
||||||
assert(t.co() == 100) -- resume coroutine, creating new table for 'a'
|
assert(t.co() == 100) -- resume coroutine, creating new table for 'a'
|
||||||
assert(T.gccolor(t.co) == "white") -- thread was not traversed
|
assert(T.gccolor(t.co) == "white") -- thread was not traversed
|
||||||
T.gcstate("pause") -- collect thread, but should mark 'a' before that
|
T.gcstate("pause") -- collect thread, but should mark 'a' before that
|
||||||
@@ -585,7 +589,7 @@ if T then -- tests for weird cases collecting upvalues
|
|||||||
collectgarbage()
|
collectgarbage()
|
||||||
collectgarbage"stop"
|
collectgarbage"stop"
|
||||||
local a = {} -- avoid 'u' as first element in 'allgc'
|
local a = {} -- avoid 'u' as first element in 'allgc'
|
||||||
T.gcstate"atomic"
|
T.gcstate"enteratomic"
|
||||||
T.gcstate"sweepallgc"
|
T.gcstate"sweepallgc"
|
||||||
local x = {}
|
local x = {}
|
||||||
assert(T.gccolor(u) == "black") -- userdata is "old" (black)
|
assert(T.gccolor(u) == "black") -- userdata is "old" (black)
|
||||||
@@ -611,6 +615,21 @@ if T then
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if T then
|
||||||
|
collectgarbage("stop")
|
||||||
|
T.gcstate("pause")
|
||||||
|
local sup = {x = 0}
|
||||||
|
local a = setmetatable({}, {__newindex = sup})
|
||||||
|
T.gcstate("enteratomic")
|
||||||
|
assert(T.gccolor(sup) == "black")
|
||||||
|
a.x = {} -- should not break the invariant
|
||||||
|
assert(not (T.gccolor(sup) == "black" and T.gccolor(sup.x) == "white"))
|
||||||
|
T.gcstate("pause") -- complete the GC cycle
|
||||||
|
sup.x.y = 10
|
||||||
|
collectgarbage("restart")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
if T then
|
if T then
|
||||||
print("emergency collections")
|
print("emergency collections")
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
@@ -640,7 +659,7 @@ do
|
|||||||
assert(getmetatable(o) == tt)
|
assert(getmetatable(o) == tt)
|
||||||
-- create new objects during GC
|
-- create new objects during GC
|
||||||
local a = 'xuxu'..(10+3)..'joao', {}
|
local a = 'xuxu'..(10+3)..'joao', {}
|
||||||
___Glob = o -- ressurrect object!
|
___Glob = o -- resurrect object!
|
||||||
setmetatable({}, tt) -- creates a new one with same metatable
|
setmetatable({}, tt) -- creates a new one with same metatable
|
||||||
print(">>> closing state " .. "<<<\n")
|
print(">>> closing state " .. "<<<\n")
|
||||||
end
|
end
|
||||||
@@ -688,4 +707,46 @@ end
|
|||||||
|
|
||||||
collectgarbage(oldmode)
|
collectgarbage(oldmode)
|
||||||
|
|
||||||
|
|
||||||
|
if T then
|
||||||
|
print("testing stack issues when calling finalizers")
|
||||||
|
|
||||||
|
local X
|
||||||
|
local obj
|
||||||
|
|
||||||
|
local function initobj ()
|
||||||
|
X = false
|
||||||
|
obj = setmetatable({}, {__gc = function () X = true end})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loop (n)
|
||||||
|
if n > 0 then loop(n - 1) end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- should not try to call finalizer without a CallInfo available
|
||||||
|
initobj()
|
||||||
|
loop(20) -- ensure stack space
|
||||||
|
T.resetCI() -- remove extra CallInfos
|
||||||
|
T.alloccount(0) -- cannot allocate more CallInfos
|
||||||
|
obj = nil
|
||||||
|
collectgarbage() -- will not call finalizer
|
||||||
|
T.alloccount()
|
||||||
|
assert(X == false)
|
||||||
|
collectgarbage() -- now will call finalizer (it was still pending)
|
||||||
|
assert(X == true)
|
||||||
|
|
||||||
|
-- should not try to call finalizer without stack space available
|
||||||
|
initobj()
|
||||||
|
loop(5) -- ensure enough CallInfos
|
||||||
|
T.reallocstack(0) -- remove extra stack slots
|
||||||
|
T.alloccount(0) -- cannot reallocate stack
|
||||||
|
obj = nil
|
||||||
|
collectgarbage() -- will not call finalizer
|
||||||
|
T.alloccount()
|
||||||
|
assert(X == false)
|
||||||
|
collectgarbage() -- now will call finalizer (it was still pending)
|
||||||
|
assert(X == true)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
print('OK')
|
print('OK')
|
||||||
|
|||||||
+42
-18
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/gengc.lua $
|
-- $Id: testes/gengc.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print('testing generational garbage collection')
|
print('testing generational garbage collection')
|
||||||
|
|
||||||
@@ -24,12 +24,12 @@ do
|
|||||||
assert(not T or (T.gcage(U) == "touched1" and T.gcage(U[1]) == "new"))
|
assert(not T or (T.gcage(U) == "touched1" and T.gcage(U[1]) == "new"))
|
||||||
|
|
||||||
-- both U and the table survive one more collection
|
-- both U and the table survive one more collection
|
||||||
collectgarbage("step", 0)
|
collectgarbage("step")
|
||||||
assert(not T or (T.gcage(U) == "touched2" and T.gcage(U[1]) == "survival"))
|
assert(not T or (T.gcage(U) == "touched2" and T.gcage(U[1]) == "survival"))
|
||||||
|
|
||||||
-- both U and the table survive yet another collection
|
-- both U and the table survive yet another collection
|
||||||
-- now everything is old
|
-- now everything is old
|
||||||
collectgarbage("step", 0)
|
collectgarbage("step")
|
||||||
assert(not T or (T.gcage(U) == "old" and T.gcage(U[1]) == "old1"))
|
assert(not T or (T.gcage(U) == "old" and T.gcage(U[1]) == "old1"))
|
||||||
|
|
||||||
-- data was not corrupted
|
-- data was not corrupted
|
||||||
@@ -46,10 +46,10 @@ do
|
|||||||
assert(not T or T.gcage(old) == "old")
|
assert(not T or T.gcage(old) == "old")
|
||||||
setmetatable(old, {}) -- new table becomes OLD0 (barrier)
|
setmetatable(old, {}) -- new table becomes OLD0 (barrier)
|
||||||
assert(not T or T.gcage(getmetatable(old)) == "old0")
|
assert(not T or T.gcage(getmetatable(old)) == "old0")
|
||||||
collectgarbage("step", 0) -- new table becomes OLD1 and firstold1
|
collectgarbage("step") -- new table becomes OLD1 and firstold1
|
||||||
assert(not T or T.gcage(getmetatable(old)) == "old1")
|
assert(not T or T.gcage(getmetatable(old)) == "old1")
|
||||||
setmetatable(getmetatable(old), {__gc = foo}) -- get it out of allgc list
|
setmetatable(getmetatable(old), {__gc = foo}) -- get it out of allgc list
|
||||||
collectgarbage("step", 0) -- should not seg. fault
|
collectgarbage("step") -- should not seg. fault
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -65,18 +65,18 @@ do -- bug in 5.4.0
|
|||||||
A[1] = obj -- anchor object
|
A[1] = obj -- anchor object
|
||||||
assert(not T or T.gcage(obj) == "old1")
|
assert(not T or T.gcage(obj) == "old1")
|
||||||
obj = nil -- remove it from the stack
|
obj = nil -- remove it from the stack
|
||||||
collectgarbage("step", 0) -- do a young collection
|
collectgarbage("step") -- do a young collection
|
||||||
print(getmetatable(A[1]).x) -- metatable was collected
|
print(getmetatable(A[1]).x) -- metatable was collected
|
||||||
end
|
end
|
||||||
|
|
||||||
collectgarbage() -- make A old
|
collectgarbage() -- make A old
|
||||||
local obj = {} -- create a new object
|
local obj = {} -- create a new object
|
||||||
collectgarbage("step", 0) -- make it a survival
|
collectgarbage("step") -- make it a survival
|
||||||
assert(not T or T.gcage(obj) == "survival")
|
assert(not T or T.gcage(obj) == "survival")
|
||||||
setmetatable(obj, {__gc = gcf, x = "+"}) -- create its metatable
|
setmetatable(obj, {__gc = gcf, x = "+"}) -- create its metatable
|
||||||
assert(not T or T.gcage(getmetatable(obj)) == "new")
|
assert(not T or T.gcage(getmetatable(obj)) == "new")
|
||||||
obj = nil -- clear object
|
obj = nil -- clear object
|
||||||
collectgarbage("step", 0) -- will call obj's finalizer
|
collectgarbage("step") -- will call obj's finalizer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -94,13 +94,13 @@ do -- another bug in 5.4.0
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
local _, f = coroutine.resume(co) -- create closure over 'x' in coroutine
|
local _, f = coroutine.resume(co) -- create closure over 'x' in coroutine
|
||||||
collectgarbage("step", 0) -- make upvalue a survival
|
collectgarbage("step") -- make upvalue a survival
|
||||||
old[1] = {"hello"} -- 'old' go to grayagain as 'touched1'
|
old[1] = {"hello"} -- 'old' go to grayagain as 'touched1'
|
||||||
coroutine.resume(co, {123}) -- its value will be new
|
coroutine.resume(co, {123}) -- its value will be new
|
||||||
co = nil
|
co = nil
|
||||||
collectgarbage("step", 0) -- hit the barrier
|
collectgarbage("step") -- hit the barrier
|
||||||
assert(f() == 123 and old[1][1] == "hello")
|
assert(f() == 123 and old[1][1] == "hello")
|
||||||
collectgarbage("step", 0) -- run the collector once more
|
collectgarbage("step") -- run the collector once more
|
||||||
-- make sure old[1] was not collected
|
-- make sure old[1] was not collected
|
||||||
assert(f() == 123 and old[1][1] == "hello")
|
assert(f() == 123 and old[1][1] == "hello")
|
||||||
end
|
end
|
||||||
@@ -112,12 +112,12 @@ do -- bug introduced in commit 9cf3299fa
|
|||||||
assert(not T or T.gcage(t) == "old")
|
assert(not T or T.gcage(t) == "old")
|
||||||
t[1] = {10}
|
t[1] = {10}
|
||||||
assert(not T or (T.gcage(t) == "touched1" and T.gccolor(t) == "gray"))
|
assert(not T or (T.gcage(t) == "touched1" and T.gccolor(t) == "gray"))
|
||||||
collectgarbage("step", 0) -- minor collection
|
collectgarbage("step") -- minor collection
|
||||||
assert(not T or (T.gcage(t) == "touched2" and T.gccolor(t) == "black"))
|
assert(not T or (T.gcage(t) == "touched2" and T.gccolor(t) == "black"))
|
||||||
collectgarbage("step", 0) -- minor collection
|
collectgarbage("step") -- minor collection
|
||||||
assert(not T or T.gcage(t) == "old") -- t should be black, but it was gray
|
assert(not T or T.gcage(t) == "old") -- t should be black, but it was gray
|
||||||
t[1] = {10} -- no barrier here, so t was still old
|
t[1] = {10} -- no barrier here, so t was still old
|
||||||
collectgarbage("step", 0) -- minor collection
|
collectgarbage("step") -- minor collection
|
||||||
-- t, being old, is ignored by the collection, so it is not cleared
|
-- t, being old, is ignored by the collection, so it is not cleared
|
||||||
assert(t[1] == nil) -- fails with the bug
|
assert(t[1] == nil) -- fails with the bug
|
||||||
end
|
end
|
||||||
@@ -144,13 +144,13 @@ do
|
|||||||
T.gcage(debug.getuservalue(U)) == "new")
|
T.gcage(debug.getuservalue(U)) == "new")
|
||||||
|
|
||||||
-- both U and the table survive one more collection
|
-- both U and the table survive one more collection
|
||||||
collectgarbage("step", 0)
|
collectgarbage("step")
|
||||||
assert(T.gcage(U) == "touched2" and
|
assert(T.gcage(U) == "touched2" and
|
||||||
T.gcage(debug.getuservalue(U)) == "survival")
|
T.gcage(debug.getuservalue(U)) == "survival")
|
||||||
|
|
||||||
-- both U and the table survive yet another collection
|
-- both U and the table survive yet another collection
|
||||||
-- now everything is old
|
-- now everything is old
|
||||||
collectgarbage("step", 0)
|
collectgarbage("step")
|
||||||
assert(T.gcage(U) == "old" and
|
assert(T.gcage(U) == "old" and
|
||||||
T.gcage(debug.getuservalue(U)) == "old1")
|
T.gcage(debug.getuservalue(U)) == "old1")
|
||||||
|
|
||||||
@@ -162,9 +162,33 @@ end
|
|||||||
assert(collectgarbage'isrunning')
|
assert(collectgarbage'isrunning')
|
||||||
|
|
||||||
|
|
||||||
|
do print"testing stop-the-world collection"
|
||||||
|
local step = collectgarbage("param", "stepsize", 0);
|
||||||
|
collectgarbage("incremental")
|
||||||
|
assert(collectgarbage("param", "stepsize") == 0)
|
||||||
|
|
||||||
-- just to make sure
|
-- each step does a complete cycle
|
||||||
assert(collectgarbage'isrunning')
|
assert(collectgarbage("step"))
|
||||||
|
assert(collectgarbage("step"))
|
||||||
|
|
||||||
|
-- back to default value
|
||||||
|
collectgarbage("param", "stepsize", step);
|
||||||
|
assert(collectgarbage("param", "stepsize") == step)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if T then -- test GC parameter codification
|
||||||
|
for _, percentage in ipairs{5, 10, 12, 20, 50, 100, 200, 500} do
|
||||||
|
local param = T.codeparam(percentage) -- codify percentage
|
||||||
|
for _, value in ipairs{1, 2, 10, 100, 257, 1023, 6500, 100000} do
|
||||||
|
local exact = value*percentage // 100
|
||||||
|
local aprox = T.applyparam(param, value) -- apply percentage
|
||||||
|
-- difference is at most 10% (+1 compensates difference due to
|
||||||
|
-- rounding to integers)
|
||||||
|
assert(math.abs(aprox - exact) <= exact/10 + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
collectgarbage(oldmode)
|
collectgarbage(oldmode)
|
||||||
|
|
||||||
|
|||||||
+224
-18
@@ -1,5 +1,11 @@
|
|||||||
-- $Id: testes/goto.lua $
|
-- $Id: testes/goto.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global<const> require
|
||||||
|
global<const> print, load, assert, string, setmetatable
|
||||||
|
global<const> collectgarbage, error
|
||||||
|
|
||||||
|
print("testing goto and global declarations")
|
||||||
|
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
|
|
||||||
@@ -17,15 +23,18 @@ errmsg([[ ::l1:: ::l1:: ]], "label 'l1'")
|
|||||||
errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'")
|
errmsg([[ ::l1:: do ::l1:: end]], "label 'l1'")
|
||||||
|
|
||||||
|
|
||||||
-- undefined label
|
|
||||||
errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'")
|
|
||||||
|
|
||||||
-- jumping over variable definition
|
-- jumping over variable declaration
|
||||||
|
errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "scope of 'aa'")
|
||||||
|
|
||||||
|
errmsg([[ goto l2; global *; ::l1:: ::l2:: print(3) ]], "scope of '*'")
|
||||||
|
|
||||||
errmsg([[
|
errmsg([[
|
||||||
do local bb, cc; goto l1; end
|
do local bb, cc; goto l1; end
|
||||||
local aa
|
local aa
|
||||||
::l1:: print(3)
|
::l1:: print(3)
|
||||||
]], "local 'aa'")
|
]], "scope of 'aa'")
|
||||||
|
|
||||||
|
|
||||||
-- jumping into a block
|
-- jumping into a block
|
||||||
errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'")
|
errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'")
|
||||||
@@ -38,7 +47,7 @@ errmsg([[
|
|||||||
local xuxu = 10
|
local xuxu = 10
|
||||||
::cont::
|
::cont::
|
||||||
until xuxu < x
|
until xuxu < x
|
||||||
]], "local 'xuxu'")
|
]], "scope of 'xuxu'")
|
||||||
|
|
||||||
-- simple gotos
|
-- simple gotos
|
||||||
local x
|
local x
|
||||||
@@ -250,22 +259,219 @@ assert(testG(3) == "3")
|
|||||||
assert(testG(4) == 5)
|
assert(testG(4) == 5)
|
||||||
assert(testG(5) == 10)
|
assert(testG(5) == 10)
|
||||||
|
|
||||||
do
|
do -- test goto's around to-be-closed variable
|
||||||
-- if x back goto out of scope of upvalue
|
|
||||||
local X
|
|
||||||
goto L1
|
|
||||||
|
|
||||||
::L2:: goto L3
|
global *
|
||||||
|
|
||||||
::L1:: do
|
-- set 'var' and return an object that will reset 'var' when
|
||||||
local a <close> = setmetatable({}, {__close = function () X = true end})
|
-- it goes out of scope
|
||||||
assert(X == nil)
|
local function newobj (var)
|
||||||
if a then goto L2 end -- jumping back out of scope of 'a'
|
_ENV[var] = true
|
||||||
|
return setmetatable({}, {__close = function ()
|
||||||
|
_ENV[var] = nil
|
||||||
|
end})
|
||||||
end
|
end
|
||||||
|
|
||||||
::L3:: assert(X == true) -- checks that 'a' was correctly closed
|
goto L1
|
||||||
end
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
::L4:: assert(not varX); goto L5 -- varX dead here
|
||||||
|
|
||||||
|
::L1::
|
||||||
|
local varX <close> = newobj("X")
|
||||||
|
assert(varX); goto L2 -- varX alive here
|
||||||
|
|
||||||
|
::L3::
|
||||||
|
assert(varX); goto L4 -- varX alive here
|
||||||
|
|
||||||
|
::L2:: assert(varX); goto L3 -- varX alive here
|
||||||
|
|
||||||
|
::L5:: -- return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo()
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- check for compilation errors
|
||||||
|
local function checkerr (code, err)
|
||||||
|
local st, msg = load(code)
|
||||||
|
assert(not st and string.find(msg, err))
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
global T<const>
|
||||||
|
|
||||||
|
-- globals must be declared, after a global declaration
|
||||||
|
checkerr("global none; X = 1", "variable 'X'")
|
||||||
|
checkerr("global none; function XX() end", "variable 'XX'")
|
||||||
|
|
||||||
|
-- global variables cannot be to-be-closed
|
||||||
|
checkerr("global X<close>", "cannot be")
|
||||||
|
checkerr("global <close> *", "cannot be")
|
||||||
|
|
||||||
|
do
|
||||||
|
local X = 10
|
||||||
|
do global X; X = 20 end
|
||||||
|
assert(X == 10) -- local X
|
||||||
|
end
|
||||||
|
assert(_ENV.X == 20) -- global X
|
||||||
|
|
||||||
|
-- '_ENV' cannot be global
|
||||||
|
checkerr("global _ENV, a; a = 10", "variable 'a'")
|
||||||
|
|
||||||
|
-- global declarations inside functions
|
||||||
|
checkerr([[
|
||||||
|
global none
|
||||||
|
local function foo () XXX = 1 end --< ERROR]], "variable 'XXX'")
|
||||||
|
|
||||||
|
if not T then -- when not in "test mode", "global" isn't reserved
|
||||||
|
assert(load("global = 1; return global")() == 1)
|
||||||
|
print " ('global' is not a reserved word)"
|
||||||
|
else
|
||||||
|
-- "global" reserved, cannot be used as a variable
|
||||||
|
assert(not load("global = 1; return global"))
|
||||||
|
end
|
||||||
|
|
||||||
|
local foo = 20
|
||||||
|
do
|
||||||
|
global function foo (x)
|
||||||
|
if x == 0 then return 1 else return 2 * foo(x - 1) end
|
||||||
|
end
|
||||||
|
assert(foo == _ENV.foo and foo(4) == 16)
|
||||||
|
end
|
||||||
|
assert(_ENV.foo(4) == 16)
|
||||||
|
assert(foo == 20) -- local one is in context here
|
||||||
|
|
||||||
|
do
|
||||||
|
global foo;
|
||||||
|
function foo (x) return end -- Ok after declaration
|
||||||
|
end
|
||||||
|
|
||||||
|
checkerr([[
|
||||||
|
global<const> foo;
|
||||||
|
function foo (x) return end -- ERROR: foo is read-only
|
||||||
|
]], "assign to const variable 'foo'")
|
||||||
|
|
||||||
|
checkerr([[
|
||||||
|
global foo <const>;
|
||||||
|
function foo (x) -- ERROR: foo is read-only
|
||||||
|
return
|
||||||
|
end
|
||||||
|
]], "%:2%:") -- correct line in error message
|
||||||
|
|
||||||
|
checkerr([[
|
||||||
|
global<const> *;
|
||||||
|
print(X) -- Ok to use
|
||||||
|
Y = 1 -- ERROR
|
||||||
|
]], "assign to const variable 'Y'")
|
||||||
|
|
||||||
|
checkerr([[
|
||||||
|
global *;
|
||||||
|
Y = X -- Ok to use
|
||||||
|
global<const> *;
|
||||||
|
Y = 1 -- ERROR
|
||||||
|
]], "assign to const variable 'Y'")
|
||||||
|
|
||||||
|
global *
|
||||||
|
Y = 10
|
||||||
|
assert(_ENV.Y == 10)
|
||||||
|
global<const> *
|
||||||
|
local x = Y
|
||||||
|
global *
|
||||||
|
Y = x + Y
|
||||||
|
assert(_ENV.Y == 20)
|
||||||
|
Y = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- Ok to declare hundreds of globals
|
||||||
|
global table
|
||||||
|
local code = {}
|
||||||
|
for i = 1, 1000 do
|
||||||
|
code[#code + 1] = ";global x" .. i
|
||||||
|
end
|
||||||
|
code[#code + 1] = "; return x990"
|
||||||
|
code = table.concat(code)
|
||||||
|
_ENV.x990 = 11
|
||||||
|
assert(load(code)() == 11)
|
||||||
|
_ENV.x990 = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- mixing lots of global/local declarations
|
||||||
|
global table
|
||||||
|
local code = {}
|
||||||
|
for i = 1, 200 do
|
||||||
|
code[#code + 1] = ";global x" .. i
|
||||||
|
code[#code + 1] = ";local y" .. i .. "=" .. (2*i)
|
||||||
|
end
|
||||||
|
code[#code + 1] = "; return x200 + y200"
|
||||||
|
code = table.concat(code)
|
||||||
|
_ENV.x200 = 11
|
||||||
|
assert(assert(load(code))() == 2*200 + 11)
|
||||||
|
_ENV.x200 = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
do print "testing initialization in global declarations"
|
||||||
|
global<const> a, b, c = 10, 20, 30
|
||||||
|
assert(_ENV.a == 10 and b == 20 and c == 30)
|
||||||
|
_ENV.a = nil; _ENV.b = nil; _ENV.c = nil;
|
||||||
|
|
||||||
|
global<const> a, b, c = 10
|
||||||
|
assert(_ENV.a == 10 and b == nil and c == nil)
|
||||||
|
_ENV.a = nil; _ENV.b = nil; _ENV.c = nil;
|
||||||
|
|
||||||
|
global table
|
||||||
|
global a, b, c, d = table.unpack{1, 2, 3, 6, 5}
|
||||||
|
assert(_ENV.a == 1 and b == 2 and c == 3 and d == 6)
|
||||||
|
a = nil; b = nil; c = nil; d = nil
|
||||||
|
|
||||||
|
local a, b = 100, 200
|
||||||
|
do
|
||||||
|
global a, b = a, b
|
||||||
|
end
|
||||||
|
assert(_ENV.a == 100 and _ENV.b == 200)
|
||||||
|
_ENV.a = nil; _ENV.b = nil
|
||||||
|
|
||||||
|
|
||||||
|
assert(_ENV.a == nil and _ENV.b == nil and _ENV.c == nil and _ENV.d == nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
global table, string
|
||||||
|
-- global initialization when names don't fit in K
|
||||||
|
|
||||||
|
-- to fill constant table
|
||||||
|
local code = {}
|
||||||
|
for i = 1, 300 do code[i] = "'" .. i .. "'" end
|
||||||
|
code = table.concat(code, ",")
|
||||||
|
code = string.format([[
|
||||||
|
return function (_ENV)
|
||||||
|
local dummy = {%s} -- fill initial positions in constant table,
|
||||||
|
-- so that initialization must use registers for global names
|
||||||
|
global a, b, c = 10, 20, 30
|
||||||
|
end]], code)
|
||||||
|
|
||||||
|
local fun = assert(load(code))()
|
||||||
|
|
||||||
|
local env = {}
|
||||||
|
fun(env)
|
||||||
|
assert(env.a == 10 and env.b == 20 and env.c == 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- testing global redefinitions
|
||||||
|
-- cannot use 'checkerr' as errors are not compile time
|
||||||
|
global pcall
|
||||||
|
local f = assert(load("global print = 10"))
|
||||||
|
local st, msg = pcall(f)
|
||||||
|
assert(string.find(msg, "global 'print' already defined"))
|
||||||
|
|
||||||
|
local f = assert(load("local _ENV = {AA = false}; global AA = 10"))
|
||||||
|
local st, msg = pcall(f)
|
||||||
|
assert(string.find(msg, "global 'AA' already defined"))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
print'OK'
|
print'OK'
|
||||||
|
|
||||||
|
|||||||
+12
-10
@@ -1,5 +1,7 @@
|
|||||||
-- $Id: heavy.lua,v 1.7 2017/12/29 15:42:15 roberto Exp $
|
-- $Id: testes/heavy.lua,v $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
local function teststring ()
|
local function teststring ()
|
||||||
print("creating a string too long")
|
print("creating a string too long")
|
||||||
@@ -47,9 +49,9 @@ local function loadrep (x, what)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function controlstruct ()
|
local function controlstruct ()
|
||||||
print("control structure too long")
|
print("control structure too long")
|
||||||
local lim = ((1 << 24) - 2) // 3
|
local lim = ((1 << 24) - 2) // 4
|
||||||
local s = string.rep("a = a + 1\n", lim)
|
local s = string.rep("a = a + 1\n", lim)
|
||||||
s = "while true do " .. s .. "end"
|
s = "while true do " .. s .. "end"
|
||||||
assert(load(s))
|
assert(load(s))
|
||||||
@@ -63,7 +65,7 @@ function controlstruct ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function manylines ()
|
local function manylines ()
|
||||||
print("loading chunk with too many lines")
|
print("loading chunk with too many lines")
|
||||||
local st, msg = loadrep("\n", "lines")
|
local st, msg = loadrep("\n", "lines")
|
||||||
assert(not st and string.find(msg, "too many lines"))
|
assert(not st and string.find(msg, "too many lines"))
|
||||||
@@ -71,7 +73,7 @@ function manylines ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function hugeid ()
|
local function hugeid ()
|
||||||
print("loading chunk with huge identifier")
|
print("loading chunk with huge identifier")
|
||||||
local st, msg = loadrep("a", "chars")
|
local st, msg = loadrep("a", "chars")
|
||||||
assert(not st and
|
assert(not st and
|
||||||
@@ -80,7 +82,7 @@ function hugeid ()
|
|||||||
print('+')
|
print('+')
|
||||||
end
|
end
|
||||||
|
|
||||||
function toomanyinst ()
|
local function toomanyinst ()
|
||||||
print("loading chunk with too many instructions")
|
print("loading chunk with too many instructions")
|
||||||
local st, msg = loadrep("a = 10; ", "instructions")
|
local st, msg = loadrep("a = 10; ", "instructions")
|
||||||
print('+')
|
print('+')
|
||||||
@@ -107,7 +109,7 @@ local function loadrepfunc (prefix, f)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function toomanyconst ()
|
local function toomanyconst ()
|
||||||
print("loading function with too many constants")
|
print("loading function with too many constants")
|
||||||
loadrepfunc("function foo () return {0,",
|
loadrepfunc("function foo () return {0,",
|
||||||
function (n)
|
function (n)
|
||||||
@@ -126,7 +128,7 @@ function toomanyconst ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function toomanystr ()
|
local function toomanystr ()
|
||||||
local a = {}
|
local a = {}
|
||||||
local st, msg = pcall(function ()
|
local st, msg = pcall(function ()
|
||||||
for i = 1, math.huge do
|
for i = 1, math.huge do
|
||||||
@@ -144,7 +146,7 @@ function toomanystr ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function toomanyidx ()
|
local function toomanyidx ()
|
||||||
local a = {}
|
local a = {}
|
||||||
local st, msg = pcall(function ()
|
local st, msg = pcall(function ()
|
||||||
for i = 1, math.huge do
|
for i = 1, math.huge do
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
/* function from lib1.c */
|
/* function from lib1.c */
|
||||||
int lib1_export (lua_State *L);
|
LUAMOD_API int lib1_export (lua_State *L);
|
||||||
|
|
||||||
LUAMOD_API int luaopen_lib11 (lua_State *L) {
|
LUAMOD_API int luaopen_lib11 (lua_State *L) {
|
||||||
return lib1_export(L);
|
return lib1_export(L);
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
/* implementation for lib2-v2 */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
|
|
||||||
@@ -8,8 +12,54 @@ static int id (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct STR {
|
||||||
|
void *ud;
|
||||||
|
lua_Alloc allocf;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void *t_freestr (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
|
struct STR *blk = (struct STR*)ptr - 1;
|
||||||
|
blk->allocf(blk->ud, blk, sizeof(struct STR) + osize, 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int newstr (lua_State *L) {
|
||||||
|
size_t len;
|
||||||
|
const char *str = luaL_checklstring(L, 1, &len);
|
||||||
|
void *ud;
|
||||||
|
lua_Alloc allocf = lua_getallocf(L, &ud);
|
||||||
|
struct STR *blk = (struct STR*)allocf(ud, NULL, 0,
|
||||||
|
len + 1 + sizeof(struct STR));
|
||||||
|
if (blk == NULL) { /* allocation error? */
|
||||||
|
lua_pushliteral(L, "not enough memory");
|
||||||
|
lua_error(L); /* raise a memory error */
|
||||||
|
}
|
||||||
|
blk->ud = ud; blk->allocf = allocf;
|
||||||
|
memcpy(blk + 1, str, len + 1);
|
||||||
|
lua_pushexternalstring(L, (char *)(blk + 1), len, t_freestr, L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Create an external string and keep it in the registry, so that it
|
||||||
|
** will test that the library code is still available (to deallocate
|
||||||
|
** this string) when closing the state.
|
||||||
|
*/
|
||||||
|
static void initstr (lua_State *L) {
|
||||||
|
lua_pushcfunction(L, newstr);
|
||||||
|
lua_pushstring(L,
|
||||||
|
"012345678901234567890123456789012345678901234567890123456789");
|
||||||
|
lua_call(L, 1, 1); /* call newstr("0123...") */
|
||||||
|
luaL_ref(L, LUA_REGISTRYINDEX); /* keep string in the registry */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct luaL_Reg funcs[] = {
|
static const struct luaL_Reg funcs[] = {
|
||||||
{"id", id},
|
{"id", id},
|
||||||
|
{"newstr", newstr},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,6 +68,7 @@ LUAMOD_API int luaopen_lib2 (lua_State *L) {
|
|||||||
lua_settop(L, 2);
|
lua_settop(L, 2);
|
||||||
lua_setglobal(L, "y"); /* y gets 2nd parameter */
|
lua_setglobal(L, "y"); /* y gets 2nd parameter */
|
||||||
lua_setglobal(L, "x"); /* x gets 1st parameter */
|
lua_setglobal(L, "x"); /* x gets 1st parameter */
|
||||||
|
initstr(L);
|
||||||
luaL_newlib(L, funcs);
|
luaL_newlib(L, funcs);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,23 +5,23 @@ LUA_DIR = ../../
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
# compilation should generate Dynamic-Link Libraries
|
# compilation should generate Dynamic-Link Libraries
|
||||||
CFLAGS = -Wall -std=gnu99 -O2 -I$(LUA_DIR) -fPIC -shared
|
CFLAGS = -Wall -O2 -I$(LUA_DIR) -fPIC -shared
|
||||||
|
|
||||||
# libraries used by the tests
|
# libraries used by the tests
|
||||||
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
|
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
|
||||||
touch all
|
touch all
|
||||||
|
|
||||||
lib1.so: lib1.c $(LUA_DIR)/luaconf.h
|
lib1.so: lib1.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
|
||||||
$(CC) $(CFLAGS) -o lib1.so lib1.c
|
$(CC) $(CFLAGS) -o lib1.so lib1.c
|
||||||
|
|
||||||
lib11.so: lib11.c $(LUA_DIR)/luaconf.h
|
lib11.so: lib11.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
|
||||||
$(CC) $(CFLAGS) -o lib11.so lib11.c
|
$(CC) $(CFLAGS) -o lib11.so lib11.c
|
||||||
|
|
||||||
lib2.so: lib2.c $(LUA_DIR)/luaconf.h
|
lib2.so: lib2.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
|
||||||
$(CC) $(CFLAGS) -o lib2.so lib2.c
|
$(CC) $(CFLAGS) -o lib2.so lib2.c
|
||||||
|
|
||||||
lib21.so: lib21.c $(LUA_DIR)/luaconf.h
|
lib21.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
|
||||||
$(CC) $(CFLAGS) -o lib21.so lib21.c
|
$(CC) $(CFLAGS) -o lib21.so lib21.c
|
||||||
|
|
||||||
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h
|
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
|
||||||
$(CC) $(CFLAGS) -o lib2-v2.so lib22.c
|
$(CC) $(CFLAGS) -o lib2-v2.so lib22.c
|
||||||
|
|||||||
+20
-17
@@ -1,8 +1,10 @@
|
|||||||
-- $Id: testes/literals.lua $
|
-- $Id: testes/literals.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print('testing scanner')
|
print('testing scanner')
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
local debug = require "debug"
|
local debug = require "debug"
|
||||||
|
|
||||||
|
|
||||||
@@ -10,6 +12,7 @@ local function dostring (x) return assert(load(x), "")() end
|
|||||||
|
|
||||||
dostring("x \v\f = \t\r 'a\0a' \v\f\f")
|
dostring("x \v\f = \t\r 'a\0a' \v\f\f")
|
||||||
assert(x == 'a\0a' and string.len(x) == 3)
|
assert(x == 'a\0a' and string.len(x) == 3)
|
||||||
|
_G.x = nil
|
||||||
|
|
||||||
-- escape sequences
|
-- escape sequences
|
||||||
assert('\n\"\'\\' == [[
|
assert('\n\"\'\\' == [[
|
||||||
@@ -129,16 +132,16 @@ end
|
|||||||
|
|
||||||
-- long variable names
|
-- long variable names
|
||||||
|
|
||||||
var1 = string.rep('a', 15000) .. '1'
|
local var1 = string.rep('a', 15000) .. '1'
|
||||||
var2 = string.rep('a', 15000) .. '2'
|
local var2 = string.rep('a', 15000) .. '2'
|
||||||
prog = string.format([[
|
local prog = string.format([[
|
||||||
%s = 5
|
%s = 5
|
||||||
%s = %s + 1
|
%s = %s + 1
|
||||||
return function () return %s - %s end
|
return function () return %s - %s end
|
||||||
]], var1, var2, var1, var1, var2)
|
]], var1, var2, var1, var1, var2)
|
||||||
local f = dostring(prog)
|
local f = dostring(prog)
|
||||||
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
|
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
|
||||||
var1, var2, f = nil
|
_G[var1], _G[var2] = nil
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
-- escapes --
|
-- escapes --
|
||||||
@@ -150,13 +153,13 @@ assert([[
|
|||||||
$debug]] == "\n $debug")
|
$debug]] == "\n $debug")
|
||||||
assert([[ [ ]] ~= [[ ] ]])
|
assert([[ [ ]] ~= [[ ] ]])
|
||||||
-- long strings --
|
-- long strings --
|
||||||
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
|
local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
|
||||||
assert(string.len(b) == 960)
|
assert(string.len(b) == 960)
|
||||||
prog = [=[
|
prog = [=[
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
a1 = [["this is a 'string' with several 'quotes'"]]
|
local a1 = [["this is a 'string' with several 'quotes'"]]
|
||||||
a2 = "'quotes'"
|
local a2 = "'quotes'"
|
||||||
|
|
||||||
assert(string.find(a1, a2) == 34)
|
assert(string.find(a1, a2) == 34)
|
||||||
print('+')
|
print('+')
|
||||||
@@ -164,12 +167,13 @@ print('+')
|
|||||||
a1 = [==[temp = [[an arbitrary value]]; ]==]
|
a1 = [==[temp = [[an arbitrary value]]; ]==]
|
||||||
assert(load(a1))()
|
assert(load(a1))()
|
||||||
assert(temp == 'an arbitrary value')
|
assert(temp == 'an arbitrary value')
|
||||||
|
_G.temp = nil
|
||||||
-- long strings --
|
-- long strings --
|
||||||
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
|
local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
|
||||||
assert(string.len(b) == 960)
|
assert(string.len(b) == 960)
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
local a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||||
@@ -199,13 +203,11 @@ x = 1
|
|||||||
]=]
|
]=]
|
||||||
|
|
||||||
print('+')
|
print('+')
|
||||||
x = nil
|
_G.x = nil
|
||||||
dostring(prog)
|
dostring(prog)
|
||||||
assert(x)
|
assert(x)
|
||||||
|
_G.x = nil
|
||||||
|
|
||||||
prog = nil
|
|
||||||
a = nil
|
|
||||||
b = nil
|
|
||||||
|
|
||||||
|
|
||||||
do -- reuse of long strings
|
do -- reuse of long strings
|
||||||
@@ -234,8 +236,8 @@ end
|
|||||||
|
|
||||||
-- testing line ends
|
-- testing line ends
|
||||||
prog = [[
|
prog = [[
|
||||||
a = 1 -- a comment
|
local a = 1 -- a comment
|
||||||
b = 2
|
local b = 2
|
||||||
|
|
||||||
|
|
||||||
x = [=[
|
x = [=[
|
||||||
@@ -252,10 +254,11 @@ for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
|
|||||||
assert(dostring(prog) == nn)
|
assert(dostring(prog) == nn)
|
||||||
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
|
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
|
||||||
end
|
end
|
||||||
|
_G.x, _G.y = nil
|
||||||
|
|
||||||
|
|
||||||
-- testing comments and strings with long brackets
|
-- testing comments and strings with long brackets
|
||||||
a = [==[]=]==]
|
local a = [==[]=]==]
|
||||||
assert(a == "]=")
|
assert(a == "]=")
|
||||||
|
|
||||||
a = [==[[===[[=[]]=][====[]]===]===]==]
|
a = [==[[===[[=[]]=][====[]]===]===]==]
|
||||||
|
|||||||
+120
-30
@@ -1,5 +1,7 @@
|
|||||||
-- $Id: testes/locals.lua $
|
-- $Id: testes/locals.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
print('testing local variables and environments')
|
print('testing local variables and environments')
|
||||||
|
|
||||||
@@ -37,11 +39,13 @@ end
|
|||||||
f = nil
|
f = nil
|
||||||
|
|
||||||
local f
|
local f
|
||||||
x = 1
|
local x = 1
|
||||||
|
|
||||||
a = nil
|
do
|
||||||
load('local a = {}')()
|
global a; a = nil
|
||||||
assert(a == nil)
|
load('local a = {}')()
|
||||||
|
assert(a == nil)
|
||||||
|
end
|
||||||
|
|
||||||
function f (a)
|
function f (a)
|
||||||
local _1, _2, _3, _4, _5
|
local _1, _2, _3, _4, _5
|
||||||
@@ -152,9 +156,9 @@ local dummy
|
|||||||
local _ENV = (function (...) return ... end)(_G, dummy) -- {
|
local _ENV = (function (...) return ... end)(_G, dummy) -- {
|
||||||
|
|
||||||
do local _ENV = {assert=assert}; assert(true) end
|
do local _ENV = {assert=assert}; assert(true) end
|
||||||
mt = {_G = _G}
|
local mt = {_G = _G}
|
||||||
local foo,x
|
local foo,x
|
||||||
A = false -- "declare" A
|
global A; A = false -- "declare" A
|
||||||
do local _ENV = mt
|
do local _ENV = mt
|
||||||
function foo (x)
|
function foo (x)
|
||||||
A = x
|
A = x
|
||||||
@@ -174,21 +178,30 @@ do local _ENV = {assert=assert, A=10};
|
|||||||
end
|
end
|
||||||
assert(x==20)
|
assert(x==20)
|
||||||
|
|
||||||
|
A = nil
|
||||||
|
|
||||||
do -- constants
|
|
||||||
|
do print("testing local constants")
|
||||||
|
global assert<const>, load, string, X
|
||||||
|
X = 1 -- not a constant
|
||||||
local a<const>, b, c<const> = 10, 20, 30
|
local a<const>, b, c<const> = 10, 20, 30
|
||||||
b = a + c + b -- 'b' is not constant
|
b = a + c + b -- 'b' is not constant
|
||||||
assert(a == 10 and b == 60 and c == 30)
|
assert(a == 10 and b == 60 and c == 30)
|
||||||
|
|
||||||
local function checkro (name, code)
|
local function checkro (name, code)
|
||||||
local st, msg = load(code)
|
local st, msg = load(code)
|
||||||
local gab = string.format("attempt to assign to const variable '%s'", name)
|
local gab = string.format("attempt to assign to const variable '%s'", name)
|
||||||
assert(not st and string.find(msg, gab))
|
assert(not st and string.find(msg, gab))
|
||||||
end
|
end
|
||||||
|
|
||||||
checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
|
checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
|
||||||
checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
|
checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
|
||||||
checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
|
checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
|
||||||
checkro("foo", "local foo <const> = 10; function foo() end")
|
checkro("foo", "local<const> foo = 10; function foo() end")
|
||||||
checkro("foo", "local foo <const> = {}; function foo() end")
|
checkro("foo", "local<const> foo <const> = {}; function foo() end")
|
||||||
|
checkro("foo", "global<const> foo <const>; function foo() end")
|
||||||
|
checkro("XX", "global XX <const>; XX = 10")
|
||||||
|
checkro("XX", "local _ENV; global XX <const>; XX = 10")
|
||||||
|
|
||||||
checkro("z", [[
|
checkro("z", [[
|
||||||
local a, z <const>, b = 10;
|
local a, z <const>, b = 10;
|
||||||
@@ -199,11 +212,26 @@ do -- constants
|
|||||||
local a, var1 <const> = 10;
|
local a, var1 <const> = 10;
|
||||||
function foo() a = 20; z = function () var1 = 12; end end
|
function foo() a = 20; z = function () var1 = 12; end end
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
checkro("var1", [[
|
||||||
|
global a, var1 <const>, z;
|
||||||
|
local function foo() a = 20; z = function () var1 = 12; end end
|
||||||
|
]])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print"testing to-be-closed variables"
|
print"testing to-be-closed variables"
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
local st, msg = load("local <close> a, b")
|
||||||
|
assert(not st and string.find(msg, "multiple"))
|
||||||
|
|
||||||
|
local st, msg = load("local a<close>, b<close>")
|
||||||
|
assert(not st and string.find(msg, "multiple"))
|
||||||
|
end
|
||||||
|
|
||||||
local function stack(n) n = ((n == 0) or stack(n - 1)) end
|
local function stack(n) n = ((n == 0) or stack(n - 1)) end
|
||||||
|
|
||||||
local function func2close (f, x, y)
|
local function func2close (f, x, y)
|
||||||
@@ -278,6 +306,31 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- testing presence of second argument
|
||||||
|
local function foo (howtoclose, obj, n)
|
||||||
|
local ca -- copy of 'a' visible inside its close metamethod
|
||||||
|
do
|
||||||
|
local a <close> = func2close(function (...t)
|
||||||
|
assert(select("#", ...) == n)
|
||||||
|
assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj))
|
||||||
|
ca = 15 -- final value to be returned if howtoclose=="scope"
|
||||||
|
end)
|
||||||
|
ca = a
|
||||||
|
if howtoclose == "ret" then return obj -- 'a' closed by return
|
||||||
|
elseif howtoclose == "err" then error(obj) -- 'a' closed by error
|
||||||
|
end
|
||||||
|
end -- 'a' closed by end of scope
|
||||||
|
return ca -- ca now should be 15
|
||||||
|
end
|
||||||
|
-- with no errors, closing methods receive no extra argument
|
||||||
|
assert(foo("scope", nil, 1) == 15) -- close by end of scope
|
||||||
|
assert(foo("ret", 32, 1) == 32) -- close by return
|
||||||
|
-- with errors, they do
|
||||||
|
local st, msg = pcall(foo, "err", 23, 2) -- close by error
|
||||||
|
assert(not st and msg == 23)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- testing to-be-closed x compile-time constants
|
-- testing to-be-closed x compile-time constants
|
||||||
-- (there were some bugs here in Lua 5.4-rc3, due to a confusion
|
-- (there were some bugs here in Lua 5.4-rc3, due to a confusion
|
||||||
-- between compile levels and stack levels of variables)
|
-- between compile levels and stack levels of variables)
|
||||||
@@ -360,6 +413,26 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
|
||||||
|
-- leaving a loop block.
|
||||||
|
|
||||||
|
local closed = false
|
||||||
|
|
||||||
|
local o1 = setmetatable({}, {__close=function() closed = true end})
|
||||||
|
|
||||||
|
local function test()
|
||||||
|
for k, v in next, {}, nil, o1 do
|
||||||
|
local function f() return k end -- create an upvalue
|
||||||
|
break
|
||||||
|
end
|
||||||
|
assert(closed)
|
||||||
|
end
|
||||||
|
|
||||||
|
test()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
do print("testing errors in __close")
|
do print("testing errors in __close")
|
||||||
|
|
||||||
-- original error is in __close
|
-- original error is in __close
|
||||||
@@ -592,6 +665,28 @@ end
|
|||||||
|
|
||||||
if rawget(_G, "T") then
|
if rawget(_G, "T") then
|
||||||
|
|
||||||
|
do
|
||||||
|
-- bug in 5.4.3
|
||||||
|
-- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
|
||||||
|
|
||||||
|
-- reduce stack size
|
||||||
|
collectgarbage(); collectgarbage(); collectgarbage()
|
||||||
|
|
||||||
|
-- force a stack reallocation
|
||||||
|
local function loop (n)
|
||||||
|
if n < 400 then loop(n + 1) end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- close metamethod will reallocate the stack
|
||||||
|
local o = setmetatable({}, {__close = function () loop(0) end})
|
||||||
|
|
||||||
|
local script = [[toclose 2; settop 1; return 1]]
|
||||||
|
|
||||||
|
assert(T.testC(script, o) == script)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- memory error inside closing function
|
-- memory error inside closing function
|
||||||
local function foo ()
|
local function foo ()
|
||||||
local y <close> = func2close(function () T.alloccount() end)
|
local y <close> = func2close(function () T.alloccount() end)
|
||||||
@@ -669,7 +764,7 @@ if rawget(_G, "T") then
|
|||||||
|
|
||||||
collectgarbage(); collectgarbage()
|
collectgarbage(); collectgarbage()
|
||||||
|
|
||||||
m = T.totalmem()
|
local m = T.totalmem()
|
||||||
collectgarbage("stop")
|
collectgarbage("stop")
|
||||||
|
|
||||||
-- error in the first buffer allocation
|
-- error in the first buffer allocation
|
||||||
@@ -684,14 +779,8 @@ if rawget(_G, "T") then
|
|||||||
-- first buffer was released by 'toclose'
|
-- first buffer was released by 'toclose'
|
||||||
assert(T.totalmem() - m <= extra)
|
assert(T.totalmem() - m <= extra)
|
||||||
|
|
||||||
-- error in creation of final string
|
-- userdata, buffer, final string
|
||||||
T.totalmem(m + 2 * lim + extra)
|
T.totalmem(m + 2*lim + extra)
|
||||||
assert(not pcall(table.concat, a))
|
|
||||||
-- second buffer was released by 'toclose'
|
|
||||||
assert(T.totalmem() - m <= extra)
|
|
||||||
|
|
||||||
-- userdata, buffer, buffer, final string
|
|
||||||
T.totalmem(m + 4*lim + extra)
|
|
||||||
assert(#table.concat(a) == 2*lim)
|
assert(#table.concat(a) == 2*lim)
|
||||||
|
|
||||||
T.totalmem(0) -- remove memory limit
|
T.totalmem(0) -- remove memory limit
|
||||||
@@ -821,14 +910,15 @@ do
|
|||||||
|
|
||||||
local extrares -- result from extra yield (if any)
|
local extrares -- result from extra yield (if any)
|
||||||
|
|
||||||
local function check (body, extra, ...)
|
local function check (body, extra, ...t)
|
||||||
local t = table.pack(...) -- expected returns
|
|
||||||
local co = coroutine.wrap(body)
|
local co = coroutine.wrap(body)
|
||||||
if extra then
|
if extra then
|
||||||
extrares = co() -- runs until first (extra) yield
|
extrares = co() -- runs until first (extra) yield
|
||||||
end
|
end
|
||||||
local res = table.pack(co()) -- runs until yield inside '__close'
|
local res = table.pack(co()) -- runs until "regular" yield
|
||||||
assert(res.n == 2 and res[2] == nil)
|
-- regular yield will yield all values passed to the close function;
|
||||||
|
-- without errors, that is only the object being closed.
|
||||||
|
assert(res.n == 1 and type(res[1]) == "table")
|
||||||
local res2 = table.pack(co()) -- runs until end of function
|
local res2 = table.pack(co()) -- runs until end of function
|
||||||
assert(res2.n == t.n)
|
assert(res2.n == t.n)
|
||||||
for i = 1, #t do
|
for i = 1, #t do
|
||||||
@@ -841,10 +931,10 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function foo ()
|
local function foo ()
|
||||||
local x <close> = func2close(coroutine.yield)
|
local x <close> = func2close(coroutine.yield) -- "regular" yield
|
||||||
local extra <close> = func2close(function (self)
|
local extra <close> = func2close(function (self)
|
||||||
assert(self == extrares)
|
assert(self == extrares)
|
||||||
coroutine.yield(100)
|
coroutine.yield(100) -- first (extra) yield
|
||||||
end)
|
end)
|
||||||
extrares = extra
|
extrares = extra
|
||||||
return table.unpack{10, x, 30}
|
return table.unpack{10, x, 30}
|
||||||
@@ -853,21 +943,21 @@ do
|
|||||||
assert(extrares == 100)
|
assert(extrares == 100)
|
||||||
|
|
||||||
local function foo ()
|
local function foo ()
|
||||||
local x <close> = func2close(coroutine.yield)
|
local x <close> = func2close(coroutine.yield) -- "regular" yield
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
check(foo, false)
|
check(foo, false)
|
||||||
|
|
||||||
local function foo ()
|
local function foo ()
|
||||||
local x <close> = func2close(coroutine.yield)
|
local x <close> = func2close(coroutine.yield) -- "regular" yield
|
||||||
local y, z = 20, 30
|
local y, z = 20, 30
|
||||||
return x
|
return x
|
||||||
end
|
end
|
||||||
check(foo, false, "x")
|
check(foo, false, "x")
|
||||||
|
|
||||||
local function foo ()
|
local function foo ()
|
||||||
local x <close> = func2close(coroutine.yield)
|
local x <close> = func2close(coroutine.yield) -- "regular" yield
|
||||||
local extra <close> = func2close(coroutine.yield)
|
local extra <close> = func2close(coroutine.yield) -- extra yield
|
||||||
return table.unpack({}, 1, 100) -- 100 nils
|
return table.unpack({}, 1, 100) -- 100 nils
|
||||||
end
|
end
|
||||||
check(foo, true, table.unpack({}, 1, 100))
|
check(foo, true, table.unpack({}, 1, 100))
|
||||||
@@ -1096,7 +1186,7 @@ do
|
|||||||
local function open (x)
|
local function open (x)
|
||||||
numopen = numopen + 1
|
numopen = numopen + 1
|
||||||
return
|
return
|
||||||
function () -- iteraction function
|
function () -- iteration function
|
||||||
x = x - 1
|
x = x - 1
|
||||||
if x > 0 then return x end
|
if x > 0 then return x end
|
||||||
end,
|
end,
|
||||||
|
|||||||
+113
-41
@@ -1,6 +1,6 @@
|
|||||||
# testing special comment on first line
|
# testing special comment on first line
|
||||||
-- $Id: testes/main.lua $
|
-- $Id: testes/main.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
-- most (all?) tests here assume a reasonable "Unix-like" shell
|
-- most (all?) tests here assume a reasonable "Unix-like" shell
|
||||||
if _port then return end
|
if _port then return end
|
||||||
@@ -27,17 +27,19 @@ do
|
|||||||
end
|
end
|
||||||
print("progname: "..progname)
|
print("progname: "..progname)
|
||||||
|
|
||||||
local prepfile = function (s, p)
|
|
||||||
p = p or prog
|
local prepfile = function (s, mod, p)
|
||||||
io.output(p)
|
mod = mod and "wb" or "w" -- mod true means binary files
|
||||||
io.write(s)
|
p = p or prog -- file to write the program
|
||||||
assert(io.close())
|
local f = io.open(p, mod)
|
||||||
|
f:write(s)
|
||||||
|
assert(f:close())
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getoutput ()
|
local function getoutput ()
|
||||||
io.input(out)
|
local f = io.open(out)
|
||||||
local t = io.read("a")
|
local t = f:read("a")
|
||||||
io.input():close()
|
f:close()
|
||||||
assert(os.remove(out))
|
assert(os.remove(out))
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
@@ -65,16 +67,20 @@ local function RUN (p, ...)
|
|||||||
assert(os.execute(s))
|
assert(os.execute(s))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function NoRun (msg, p, ...)
|
local function NoRun (msg, p, ...)
|
||||||
p = string.gsub(p, "lua", '"'..progname..'"', 1)
|
p = string.gsub(p, "lua", '"'..progname..'"', 1)
|
||||||
local s = string.format(p, ...)
|
local s = string.format(p, ...)
|
||||||
s = string.format("%s 2> %s", s, out) -- will send error to 'out'
|
s = string.format("%s >%s 2>&1", s, out) -- send output and error to 'out'
|
||||||
assert(not os.execute(s))
|
assert(not os.execute(s))
|
||||||
assert(string.find(getoutput(), msg, 1, true)) -- check error message
|
assert(string.find(getoutput(), msg, 1, true)) -- check error message
|
||||||
end
|
end
|
||||||
|
|
||||||
RUN('lua -v')
|
RUN('lua -v')
|
||||||
|
|
||||||
|
RUN('lua -v > %s', out)
|
||||||
|
local release = string.match(getoutput(), "Lua (%d+%.%d+%.%d+)")
|
||||||
|
|
||||||
print(string.format("(temporary program file used in these tests: %s)", prog))
|
print(string.format("(temporary program file used in these tests: %s)", prog))
|
||||||
|
|
||||||
-- running stdin as a file
|
-- running stdin as a file
|
||||||
@@ -87,13 +93,40 @@ prepfile[[
|
|||||||
1, a
|
1, a
|
||||||
)
|
)
|
||||||
]]
|
]]
|
||||||
RUN('lua - < %s > %s', prog, out)
|
RUN('lua - -- < %s > %s', prog, out)
|
||||||
checkout("1\tnil\n")
|
checkout("1\tnil\n")
|
||||||
|
|
||||||
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
|
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
|
||||||
checkout("10\n2\n")
|
checkout("10\n2\n")
|
||||||
|
|
||||||
|
|
||||||
|
-- testing BOM
|
||||||
|
prepfile("\xEF\xBB\xBF")
|
||||||
|
RUN('lua %s > %s', prog, out)
|
||||||
|
checkout("")
|
||||||
|
|
||||||
|
prepfile("\xEF\xBB\xBFprint(3)")
|
||||||
|
RUN('lua %s > %s', prog, out)
|
||||||
|
checkout("3\n")
|
||||||
|
|
||||||
|
prepfile("\xEF\xBB\xBF# comment!!\nprint(3)")
|
||||||
|
RUN('lua %s > %s', prog, out)
|
||||||
|
checkout("3\n")
|
||||||
|
|
||||||
|
-- bad BOMs
|
||||||
|
prepfile("\xEF", true)
|
||||||
|
NoRun("unexpected symbol", 'lua %s', prog)
|
||||||
|
|
||||||
|
prepfile("\xEF\xBB", true)
|
||||||
|
NoRun("unexpected symbol", 'lua %s', prog)
|
||||||
|
|
||||||
|
prepfile("\xEFprint(3)", true)
|
||||||
|
NoRun("unexpected symbol", 'lua %s', prog)
|
||||||
|
|
||||||
|
prepfile("\xEF\xBBprint(3)", true)
|
||||||
|
NoRun("unexpected symbol", 'lua %s', prog)
|
||||||
|
|
||||||
|
|
||||||
-- test option '-'
|
-- test option '-'
|
||||||
RUN('echo "print(arg[1])" | lua - -h > %s', out)
|
RUN('echo "print(arg[1])" | lua - -h > %s', out)
|
||||||
checkout("-h\n")
|
checkout("-h\n")
|
||||||
@@ -103,11 +136,11 @@ checkout("-h\n")
|
|||||||
prepfile("print(package.path)")
|
prepfile("print(package.path)")
|
||||||
|
|
||||||
-- test LUA_PATH
|
-- test LUA_PATH
|
||||||
RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out)
|
RUN('env LUA_INIT= LUA_PATH=x lua -- %s > %s', prog, out)
|
||||||
checkout("x\n")
|
checkout("x\n")
|
||||||
|
|
||||||
-- test LUA_PATH_version
|
-- test LUA_PATH_version
|
||||||
RUN('env LUA_INIT= LUA_PATH_5_4=y LUA_PATH=x lua %s > %s', prog, out)
|
RUN('env LUA_INIT= LUA_PATH_5_5=y LUA_PATH=x lua %s > %s', prog, out)
|
||||||
checkout("y\n")
|
checkout("y\n")
|
||||||
|
|
||||||
-- test LUA_CPATH
|
-- test LUA_CPATH
|
||||||
@@ -116,7 +149,7 @@ RUN('env LUA_INIT= LUA_CPATH=xuxu lua %s > %s', prog, out)
|
|||||||
checkout("xuxu\n")
|
checkout("xuxu\n")
|
||||||
|
|
||||||
-- test LUA_CPATH_version
|
-- test LUA_CPATH_version
|
||||||
RUN('env LUA_INIT= LUA_CPATH_5_4=yacc LUA_CPATH=x lua %s > %s', prog, out)
|
RUN('env LUA_INIT= LUA_CPATH_5_5=yacc LUA_CPATH=x lua %s > %s', prog, out)
|
||||||
checkout("yacc\n")
|
checkout("yacc\n")
|
||||||
|
|
||||||
-- test LUA_INIT (and its access to 'arg' table)
|
-- test LUA_INIT (and its access to 'arg' table)
|
||||||
@@ -126,7 +159,7 @@ checkout("3.2\n")
|
|||||||
|
|
||||||
-- test LUA_INIT_version
|
-- test LUA_INIT_version
|
||||||
prepfile("print(X)")
|
prepfile("print(X)")
|
||||||
RUN('env LUA_INIT_5_4="X=10" LUA_INIT="X=3" lua %s > %s', prog, out)
|
RUN('env LUA_INIT_5_5="X=10" LUA_INIT="X=3" lua %s > %s', prog, out)
|
||||||
checkout("10\n")
|
checkout("10\n")
|
||||||
|
|
||||||
-- test LUA_INIT for files
|
-- test LUA_INIT for files
|
||||||
@@ -137,7 +170,9 @@ checkout("10\n11\n")
|
|||||||
-- test errors in LUA_INIT
|
-- test errors in LUA_INIT
|
||||||
NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
|
NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
|
||||||
|
|
||||||
-- test option '-E'
|
|
||||||
|
print("testing option '-E'")
|
||||||
|
|
||||||
local defaultpath, defaultCpath
|
local defaultpath, defaultCpath
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -162,6 +197,22 @@ assert(not string.find(defaultpath, "xxx") and
|
|||||||
string.find(defaultCpath, "lua"))
|
string.find(defaultCpath, "lua"))
|
||||||
|
|
||||||
|
|
||||||
|
-- (LUA_READLINELIB was introduced in 5.5.1)
|
||||||
|
if release >= "5.5.1" then
|
||||||
|
print"testing readline library name"
|
||||||
|
-- should generate a warning when trying to load inexistent library "xuxu"
|
||||||
|
local env = [[LUA_READLINELIB=xuxu LUA_INIT="warn('@allow')"]]
|
||||||
|
local code = 'echo " " | env %s lua %s -W -i >%s 2>&1'
|
||||||
|
RUN(code, env, "", out) -- run code with no extra options
|
||||||
|
assert(string.find(getoutput(),
|
||||||
|
"warning: unable to load readline library 'xuxu'"))
|
||||||
|
|
||||||
|
RUN(code, env, "-E", out) -- run again with option -E
|
||||||
|
-- no warning when LUA_READLINELIB is to be ignored
|
||||||
|
assert(not string.find(getoutput(), "warning"))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test replacement of ';;' to default path
|
-- test replacement of ';;' to default path
|
||||||
local function convert (p)
|
local function convert (p)
|
||||||
prepfile("print(package.path)")
|
prepfile("print(package.path)")
|
||||||
@@ -186,7 +237,7 @@ convert("a;b;;c")
|
|||||||
|
|
||||||
-- test -l over multiple libraries
|
-- test -l over multiple libraries
|
||||||
prepfile("print(1); a=2; return {x=15}")
|
prepfile("print(1); a=2; return {x=15}")
|
||||||
prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog)
|
prepfile(("print(a); print(_G['%s'].x)"):format(prog), false, otherprog)
|
||||||
RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out)
|
RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out)
|
||||||
checkout("1\n2\n15\n2\n15\n")
|
checkout("1\n2\n15\n2\n15\n")
|
||||||
|
|
||||||
@@ -195,6 +246,13 @@ prepfile("print(str.upper'alo alo', m.max(10, 20))")
|
|||||||
RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out)
|
RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out)
|
||||||
checkout("0.0\nALO ALO\t20\n")
|
checkout("0.0\nALO ALO\t20\n")
|
||||||
|
|
||||||
|
|
||||||
|
-- test module names with version suffix ("libs/lib2-v2")
|
||||||
|
RUN("env LUA_CPATH='./libs/?.so' lua -l lib2-v2 -e 'print(lib2.id())' > %s",
|
||||||
|
out)
|
||||||
|
checkout("true\n")
|
||||||
|
|
||||||
|
|
||||||
-- test 'arg' table
|
-- test 'arg' table
|
||||||
local a = [[
|
local a = [[
|
||||||
assert(#arg == 3 and arg[1] == 'a' and
|
assert(#arg == 3 and arg[1] == 'a' and
|
||||||
@@ -210,7 +268,7 @@ RUN('lua "-e " -- %s a b c', prog) -- "-e " runs an empty command
|
|||||||
|
|
||||||
-- test 'arg' availability in libraries
|
-- test 'arg' availability in libraries
|
||||||
prepfile"assert(arg)"
|
prepfile"assert(arg)"
|
||||||
prepfile("assert(arg)", otherprog)
|
prepfile("assert(arg)", false, otherprog)
|
||||||
RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog)
|
RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog)
|
||||||
|
|
||||||
-- test messing up the 'arg' table
|
-- test messing up the 'arg' table
|
||||||
@@ -226,6 +284,15 @@ assert(string.find(getoutput(), "error calling 'print'"))
|
|||||||
RUN('echo "io.stderr:write(1000)\ncont" | lua -e "require\'debug\'.debug()" 2> %s', out)
|
RUN('echo "io.stderr:write(1000)\ncont" | lua -e "require\'debug\'.debug()" 2> %s', out)
|
||||||
checkout("lua_debug> 1000lua_debug> ")
|
checkout("lua_debug> 1000lua_debug> ")
|
||||||
|
|
||||||
|
do -- test warning for locals
|
||||||
|
RUN('echo " local x" | lua -i > %s 2>&1', out)
|
||||||
|
assert(string.find(getoutput(), "warning: "))
|
||||||
|
|
||||||
|
RUN('echo "local1 = 10\nlocal1 + 3" | lua -i > %s 2>&1', out)
|
||||||
|
local t = getoutput()
|
||||||
|
assert(not string.find(t, "warning"))
|
||||||
|
assert(string.find(t, "13"))
|
||||||
|
end
|
||||||
|
|
||||||
print("testing warnings")
|
print("testing warnings")
|
||||||
|
|
||||||
@@ -264,8 +331,11 @@ checkprogout("ZYX)\nXYZ)\n")
|
|||||||
-- bug since 5.2: finalizer called when closing a state could
|
-- bug since 5.2: finalizer called when closing a state could
|
||||||
-- subvert finalization order
|
-- subvert finalization order
|
||||||
prepfile[[
|
prepfile[[
|
||||||
-- should be called last
|
-- ensure tables will be collected only at the end of the program
|
||||||
|
collectgarbage"stop"
|
||||||
|
|
||||||
print("creating 1")
|
print("creating 1")
|
||||||
|
-- this finalizer should be called last
|
||||||
setmetatable({}, {__gc = function () print(1) end})
|
setmetatable({}, {__gc = function () print(1) end})
|
||||||
|
|
||||||
print("creating 2")
|
print("creating 2")
|
||||||
@@ -275,7 +345,7 @@ setmetatable({}, {__gc = function ()
|
|||||||
-- this finalizer should not be called, as object will be
|
-- this finalizer should not be called, as object will be
|
||||||
-- created after 'lua_close' has been called
|
-- created after 'lua_close' has been called
|
||||||
setmetatable({}, {__gc = function () print(3) end})
|
setmetatable({}, {__gc = function () print(3) end})
|
||||||
print(collectgarbage()) -- cannot call collector here
|
print(collectgarbage() or false) -- cannot call collector here
|
||||||
os.exit(0, true)
|
os.exit(0, true)
|
||||||
end})
|
end})
|
||||||
]]
|
]]
|
||||||
@@ -285,7 +355,7 @@ creating 1
|
|||||||
creating 2
|
creating 2
|
||||||
2
|
2
|
||||||
creating 3
|
creating 3
|
||||||
nil
|
false
|
||||||
1
|
1
|
||||||
]]
|
]]
|
||||||
|
|
||||||
@@ -298,7 +368,7 @@ checkout("a\n")
|
|||||||
RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out)
|
RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out)
|
||||||
checkout("1\n3\n")
|
checkout("1\n3\n")
|
||||||
|
|
||||||
-- test iteractive mode
|
-- test interactive mode
|
||||||
prepfile[[
|
prepfile[[
|
||||||
(6*2-6) -- ===
|
(6*2-6) -- ===
|
||||||
a =
|
a =
|
||||||
@@ -308,11 +378,16 @@ a]]
|
|||||||
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
||||||
checkprogout("6\n10\n10\n\n")
|
checkprogout("6\n10\n10\n\n")
|
||||||
|
|
||||||
prepfile("a = [[b\nc\nd\ne]]\n=a")
|
prepfile("a = [[b\nc\nd\ne]]\na")
|
||||||
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i -- < %s > %s]], prog, out)
|
||||||
checkprogout("b\nc\nd\ne\n\n")
|
checkprogout("b\nc\nd\ne\n\n")
|
||||||
|
|
||||||
prompt = "alo"
|
-- input interrupted in continuation line
|
||||||
|
prepfile("a.\n")
|
||||||
|
RUN([[lua -i < %s > /dev/null 2> %s]], prog, out)
|
||||||
|
checkprogout("near <eof>\n")
|
||||||
|
|
||||||
|
local prompt = "alo"
|
||||||
prepfile[[ --
|
prepfile[[ --
|
||||||
a = 2
|
a = 2
|
||||||
]]
|
]]
|
||||||
@@ -331,20 +406,18 @@ assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt))
|
|||||||
|
|
||||||
|
|
||||||
-- non-string prompt
|
-- non-string prompt
|
||||||
prompt =
|
prompt = [[
|
||||||
"local C = 0;\z
|
local C = 'X';
|
||||||
_PROMPT=setmetatable({},{__tostring = function () \z
|
_PROMPT=setmetatable({},{__tostring = function ()
|
||||||
C = C + 1; return C end})"
|
C = C .. 'X'; return C end})
|
||||||
|
]]
|
||||||
prepfile[[ --
|
prepfile[[ --
|
||||||
a = 2
|
a = 2
|
||||||
]]
|
]]
|
||||||
RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out)
|
RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out)
|
||||||
local t = getoutput()
|
local t = getoutput()
|
||||||
assert(string.find(t, [[
|
-- skip version line and then check the presence of the three prompts
|
||||||
1 --
|
assert(string.find(t, "^.-\nXX[^\nX]*\n?XXX[^\nX]*\n?XXXX\n?$"))
|
||||||
2a = 2
|
|
||||||
3
|
|
||||||
]], 1, true))
|
|
||||||
|
|
||||||
|
|
||||||
-- test for error objects
|
-- test for error objects
|
||||||
@@ -363,7 +436,7 @@ NoRun("error object is a table value", [[lua %s]], prog)
|
|||||||
|
|
||||||
|
|
||||||
-- chunk broken in many lines
|
-- chunk broken in many lines
|
||||||
s = [=[ --
|
local s = [=[ --
|
||||||
function f ( x )
|
function f ( x )
|
||||||
local a = [[
|
local a = [[
|
||||||
xuxu
|
xuxu
|
||||||
@@ -385,12 +458,10 @@ checkprogout("101\n13\t22\n\n")
|
|||||||
prepfile[[#comment in 1st line without \n at the end]]
|
prepfile[[#comment in 1st line without \n at the end]]
|
||||||
RUN('lua %s', prog)
|
RUN('lua %s', prog)
|
||||||
|
|
||||||
prepfile[[#test line number when file starts with comment line
|
-- first-line comment with binary file
|
||||||
debug = require"debug"
|
prepfile("#comment\n" .. string.dump(load("print(3)")), true)
|
||||||
print(debug.getinfo(1).currentline)
|
|
||||||
]]
|
|
||||||
RUN('lua %s > %s', prog, out)
|
RUN('lua %s > %s', prog, out)
|
||||||
checkprogout('3\n')
|
checkout('3\n')
|
||||||
|
|
||||||
-- close Lua with an open file
|
-- close Lua with an open file
|
||||||
prepfile(string.format([[io.output(%q); io.write('alo')]], out))
|
prepfile(string.format([[io.output(%q); io.write('alo')]], out))
|
||||||
@@ -438,12 +509,13 @@ assert(not os.remove(out))
|
|||||||
-- invalid options
|
-- invalid options
|
||||||
NoRun("unrecognized option '-h'", "lua -h")
|
NoRun("unrecognized option '-h'", "lua -h")
|
||||||
NoRun("unrecognized option '---'", "lua ---")
|
NoRun("unrecognized option '---'", "lua ---")
|
||||||
NoRun("unrecognized option '-Ex'", "lua -Ex")
|
NoRun("unrecognized option '-Ex'", "lua -Ex --")
|
||||||
NoRun("unrecognized option '-vv'", "lua -vv")
|
NoRun("unrecognized option '-vv'", "lua -vv")
|
||||||
NoRun("unrecognized option '-iv'", "lua -iv")
|
NoRun("unrecognized option '-iv'", "lua -iv")
|
||||||
NoRun("'-e' needs argument", "lua -e")
|
NoRun("'-e' needs argument", "lua -e")
|
||||||
NoRun("syntax error", "lua -e a")
|
NoRun("syntax error", "lua -e a")
|
||||||
NoRun("'-l' needs argument", "lua -l")
|
NoRun("'-l' needs argument", "lua -l")
|
||||||
|
NoRun("-i", "lua -- -i") -- handles -i as a script name
|
||||||
|
|
||||||
|
|
||||||
if T then -- test library?
|
if T then -- test library?
|
||||||
|
|||||||
+133
-12
@@ -1,10 +1,17 @@
|
|||||||
-- $Id: testes/math.lua $
|
-- $Id: testes/math.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print("testing numbers and math lib")
|
print("testing numbers and math lib")
|
||||||
|
|
||||||
local minint <const> = math.mininteger
|
local math = require "math"
|
||||||
local maxint <const> = math.maxinteger
|
local string = require "string"
|
||||||
|
|
||||||
|
global none
|
||||||
|
|
||||||
|
global<const> print, assert, pcall, type, pairs, load
|
||||||
|
global<const> tonumber, tostring, select
|
||||||
|
|
||||||
|
local<const> minint, maxint = math.mininteger, math.maxinteger
|
||||||
|
|
||||||
local intbits <const> = math.floor(math.log(maxint, 2) + 0.5) + 1
|
local intbits <const> = math.floor(math.log(maxint, 2) + 0.5) + 1
|
||||||
assert((1 << intbits) == 0)
|
assert((1 << intbits) == 0)
|
||||||
@@ -22,6 +29,18 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- maximum exponent for a floating-point number
|
||||||
|
local maxexp = 0
|
||||||
|
do
|
||||||
|
local p = 2.0
|
||||||
|
while p < math.huge do
|
||||||
|
maxexp = maxexp + 1
|
||||||
|
p = p + p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local function isNaN (x)
|
local function isNaN (x)
|
||||||
return (x ~= x)
|
return (x ~= x)
|
||||||
end
|
end
|
||||||
@@ -34,8 +53,8 @@ do
|
|||||||
local x = 2.0^floatbits
|
local x = 2.0^floatbits
|
||||||
assert(x > x - 1.0 and x == x + 1.0)
|
assert(x > x - 1.0 and x == x + 1.0)
|
||||||
|
|
||||||
print(string.format("%d-bit integers, %d-bit (mantissa) floats",
|
local msg = " %d-bit integers, %d-bit*2^%d floats"
|
||||||
intbits, floatbits))
|
print(string.format(msg, intbits, floatbits, maxexp))
|
||||||
end
|
end
|
||||||
|
|
||||||
assert(math.type(0) == "integer" and math.type(0.0) == "float"
|
assert(math.type(0) == "integer" and math.type(0.0) == "float"
|
||||||
@@ -50,7 +69,7 @@ end
|
|||||||
local msgf2i = "number.* has no integer representation"
|
local msgf2i = "number.* has no integer representation"
|
||||||
|
|
||||||
-- float equality
|
-- float equality
|
||||||
function eq (a,b,limit)
|
local function eq (a,b,limit)
|
||||||
if not limit then
|
if not limit then
|
||||||
if floatbits >= 50 then limit = 1E-11
|
if floatbits >= 50 then limit = 1E-11
|
||||||
else limit = 1E-5
|
else limit = 1E-5
|
||||||
@@ -62,7 +81,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- equality with types
|
-- equality with types
|
||||||
function eqT (a,b)
|
local function eqT (a,b)
|
||||||
return a == b and math.type(a) == math.type(b)
|
return a == b and math.type(a) == math.type(b)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -83,7 +102,7 @@ end
|
|||||||
do
|
do
|
||||||
local x = -1
|
local x = -1
|
||||||
local mz = 0/x -- minus zero
|
local mz = 0/x -- minus zero
|
||||||
t = {[0] = 10, 20, 30, 40, 50}
|
local t = {[0] = 10, 20, 30, 40, 50}
|
||||||
assert(t[mz] == t[0] and t[-0] == t[0])
|
assert(t[mz] == t[0] and t[-0] == t[0])
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -172,7 +191,7 @@ do
|
|||||||
for i = -3, 3 do -- variables avoid constant folding
|
for i = -3, 3 do -- variables avoid constant folding
|
||||||
for j = -3, 3 do
|
for j = -3, 3 do
|
||||||
-- domain errors (0^(-n)) are not portable
|
-- domain errors (0^(-n)) are not portable
|
||||||
if not _port or i ~= 0 or j > 0 then
|
if not _ENV._port or i ~= 0 or j > 0 then
|
||||||
assert(eq(i^j, 1 / i^(-j)))
|
assert(eq(i^j, 1 / i^(-j)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -418,7 +437,7 @@ for i = 2,36 do
|
|||||||
assert(tonumber('\t10000000000\t', i) == i10)
|
assert(tonumber('\t10000000000\t', i) == i10)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not _soft then
|
if not _ENV._soft then
|
||||||
-- tests with very long numerals
|
-- tests with very long numerals
|
||||||
assert(tonumber("0x"..string.rep("f", 13)..".0") == 2.0^(4*13) - 1)
|
assert(tonumber("0x"..string.rep("f", 13)..".0") == 2.0^(4*13) - 1)
|
||||||
assert(tonumber("0x"..string.rep("f", 150)..".0") == 2.0^(4*150) - 1)
|
assert(tonumber("0x"..string.rep("f", 150)..".0") == 2.0^(4*150) - 1)
|
||||||
@@ -620,7 +639,7 @@ assert(maxint % -2 == -1)
|
|||||||
|
|
||||||
-- non-portable tests because Windows C library cannot compute
|
-- non-portable tests because Windows C library cannot compute
|
||||||
-- fmod(1, huge) correctly
|
-- fmod(1, huge) correctly
|
||||||
if not _port then
|
if not _ENV._port then
|
||||||
local function anan (x) assert(isNaN(x)) end -- assert Not a Number
|
local function anan (x) assert(isNaN(x)) end -- assert Not a Number
|
||||||
anan(0.0 % 0)
|
anan(0.0 % 0)
|
||||||
anan(1.3 % 0)
|
anan(1.3 % 0)
|
||||||
@@ -666,6 +685,18 @@ assert(eq(math.exp(0), 1))
|
|||||||
assert(eq(math.sin(10), math.sin(10%(2*math.pi))))
|
assert(eq(math.sin(10), math.sin(10%(2*math.pi))))
|
||||||
|
|
||||||
|
|
||||||
|
do print("testing ldexp/frexp")
|
||||||
|
global ipairs
|
||||||
|
for _, x in ipairs{0, 10, 32, -math.pi, 1e10, 1e-10, math.huge, -math.huge} do
|
||||||
|
local m, p = math.frexp(x)
|
||||||
|
assert(math.ldexp(m, p) == x)
|
||||||
|
local am = math.abs(m)
|
||||||
|
assert(m == x or (0.5 <= am and am < 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
assert(tonumber(' 1.3e-2 ') == 1.3e-2)
|
assert(tonumber(' 1.3e-2 ') == 1.3e-2)
|
||||||
assert(tonumber(' -1.00000000000001 ') == -1.00000000000001)
|
assert(tonumber(' -1.00000000000001 ') == -1.00000000000001)
|
||||||
|
|
||||||
@@ -767,6 +798,7 @@ assert(a == '10' and b == '20')
|
|||||||
|
|
||||||
do
|
do
|
||||||
print("testing -0 and NaN")
|
print("testing -0 and NaN")
|
||||||
|
global rawset, undef
|
||||||
local mz <const> = -0.0
|
local mz <const> = -0.0
|
||||||
local z <const> = 0.0
|
local z <const> = 0.0
|
||||||
assert(mz == z)
|
assert(mz == z)
|
||||||
@@ -803,7 +835,11 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
print("testing 'math.random'")
|
--
|
||||||
|
-- [[==================================================================
|
||||||
|
print("testing 'math.random'")
|
||||||
|
-- -===================================================================
|
||||||
|
--
|
||||||
|
|
||||||
local random, max, min = math.random, math.max, math.min
|
local random, max, min = math.random, math.max, math.min
|
||||||
|
|
||||||
@@ -1019,6 +1055,91 @@ assert(not pcall(random, minint + 1, minint))
|
|||||||
assert(not pcall(random, maxint, maxint - 1))
|
assert(not pcall(random, maxint, maxint - 1))
|
||||||
assert(not pcall(random, maxint, minint))
|
assert(not pcall(random, maxint, minint))
|
||||||
|
|
||||||
|
-- ]]==================================================================
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- [[==================================================================
|
||||||
|
print("testing precision of 'tostring'")
|
||||||
|
-- -===================================================================
|
||||||
|
--
|
||||||
|
|
||||||
|
-- number of decimal digits supported by float precision
|
||||||
|
local decdig = math.floor(floatbits * math.log(2, 10))
|
||||||
|
print(string.format(" %d-digit float numbers with full precision",
|
||||||
|
decdig))
|
||||||
|
-- number of decimal digits supported by integer precision
|
||||||
|
local Idecdig = math.floor(math.log(maxint, 10))
|
||||||
|
print(string.format(" %d-digit integer numbers with full precision",
|
||||||
|
Idecdig))
|
||||||
|
|
||||||
|
do
|
||||||
|
-- Any number should print so that reading it back gives itself:
|
||||||
|
-- tonumber(tostring(x)) == x
|
||||||
|
|
||||||
|
-- Mersenne fractions
|
||||||
|
local p = 1.0
|
||||||
|
for i = 1, maxexp do
|
||||||
|
p = p + p
|
||||||
|
local x = 1 / (p - 1)
|
||||||
|
assert(x == tonumber(tostring(x)))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- some random numbers in [0,1)
|
||||||
|
for i = 1, 100 do
|
||||||
|
local x = math.random()
|
||||||
|
assert(x == tonumber(tostring(x)))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- different numbers should print differently.
|
||||||
|
-- check pairs of floats with minimum detectable difference
|
||||||
|
local p = floatbits - 1
|
||||||
|
global ipairs
|
||||||
|
for i = 1, maxexp - 1 do
|
||||||
|
for _, i in ipairs{-i, i} do
|
||||||
|
local x = 2^i
|
||||||
|
local diff = 2^(i - p) -- least significant bit for 'x'
|
||||||
|
local y = x + diff
|
||||||
|
local fy = tostring(y)
|
||||||
|
assert(x ~= y and tostring(x) ~= fy)
|
||||||
|
assert(tonumber(fy) == y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- "reasonable" numerals should be printed like themselves
|
||||||
|
|
||||||
|
-- create random float numerals with 5 digits, with a decimal point
|
||||||
|
-- inserted in all places. (With more than 5, things like "0.00001"
|
||||||
|
-- reformats like "1e-5".)
|
||||||
|
for i = 1, 1000 do
|
||||||
|
-- random numeral with 5 digits
|
||||||
|
local x = string.format("%.5d", math.random(0, 99999))
|
||||||
|
for i = 2, #x do
|
||||||
|
-- insert decimal point at position 'i'
|
||||||
|
local y = string.sub(x, 1, i - 1) .. "." .. string.sub(x, i, -1)
|
||||||
|
y = string.gsub(y, "^0*(%d.-%d)0*$", "%1") -- trim extra zeros
|
||||||
|
assert(y == tostring(tonumber(y)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- all-random floats
|
||||||
|
local Fsz = string.packsize("n") -- size of floats in bytes
|
||||||
|
|
||||||
|
for i = 1, 400 do
|
||||||
|
local s = string.pack("j", math.random(0)) -- a random string of bits
|
||||||
|
while #s < Fsz do -- make 's' long enough
|
||||||
|
s = s .. string.pack("j", math.random(0))
|
||||||
|
end
|
||||||
|
local n = string.unpack("n", s) -- read 's' as a float
|
||||||
|
s = tostring(n)
|
||||||
|
if string.find(s, "^%-?%d") then -- avoid NaN, inf, -inf
|
||||||
|
assert(tonumber(s) == n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
-- ]]==================================================================
|
||||||
|
|
||||||
|
|
||||||
print('OK')
|
print('OK')
|
||||||
|
|||||||
@@ -0,0 +1,309 @@
|
|||||||
|
-- $Id: testes/memerr.lua $
|
||||||
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
|
||||||
|
local function checkerr (msg, f, ...)
|
||||||
|
local stat, err = pcall(f, ...)
|
||||||
|
assert(not stat and string.find(err, msg))
|
||||||
|
end
|
||||||
|
|
||||||
|
if T==nil then
|
||||||
|
(Message or print)
|
||||||
|
('\n >>> testC not active: skipping memory error tests <<<\n')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print("testing memory-allocation errors")
|
||||||
|
|
||||||
|
local debug = require "debug"
|
||||||
|
|
||||||
|
local pack = table.pack
|
||||||
|
|
||||||
|
-- standard error message for memory errors
|
||||||
|
local MEMERRMSG = "not enough memory"
|
||||||
|
|
||||||
|
|
||||||
|
-- memory error in panic function
|
||||||
|
T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
|
||||||
|
assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
|
||||||
|
T.totalmem(0) -- restore high limit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- {==================================================================
|
||||||
|
-- Testing memory limits
|
||||||
|
-- ===================================================================
|
||||||
|
|
||||||
|
checkerr("block too big", T.newuserdata, math.maxinteger)
|
||||||
|
collectgarbage()
|
||||||
|
local f = load"local a={}; for i=1,100000 do a[i]=i end"
|
||||||
|
T.alloccount(10)
|
||||||
|
checkerr(MEMERRMSG, f)
|
||||||
|
T.alloccount() -- remove limit
|
||||||
|
|
||||||
|
|
||||||
|
-- preallocate stack space
|
||||||
|
local function deep (n) if n > 0 then deep(n - 1) end end
|
||||||
|
|
||||||
|
|
||||||
|
-- test memory errors; increase limit for maximum memory by steps,
|
||||||
|
-- so that we get memory errors in all allocations of a given
|
||||||
|
-- task, until there is enough memory to complete the task without
|
||||||
|
-- errors.
|
||||||
|
local function testbytes (s, f)
|
||||||
|
collectgarbage()
|
||||||
|
local M = T.totalmem()
|
||||||
|
local oldM = M
|
||||||
|
local a,b = nil
|
||||||
|
while true do
|
||||||
|
collectgarbage(); collectgarbage()
|
||||||
|
deep(4)
|
||||||
|
T.totalmem(M)
|
||||||
|
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
||||||
|
T.totalmem(0) -- remove limit
|
||||||
|
if a and b == "OK" then break end -- stop when no more errors
|
||||||
|
if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
|
||||||
|
error(a, 0) -- propagate it
|
||||||
|
end
|
||||||
|
M = M + 7 -- increase memory limit
|
||||||
|
end
|
||||||
|
print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
|
||||||
|
-- test memory errors; increase limit for number of allocations one
|
||||||
|
-- by one, so that we get memory errors in all allocations of a given
|
||||||
|
-- task, until there is enough allocations to complete the task without
|
||||||
|
-- errors.
|
||||||
|
|
||||||
|
local function testalloc (s, f)
|
||||||
|
collectgarbage()
|
||||||
|
local M = 0
|
||||||
|
local a,b = nil
|
||||||
|
while true do
|
||||||
|
collectgarbage(); collectgarbage()
|
||||||
|
deep(4)
|
||||||
|
T.alloccount(M)
|
||||||
|
a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
||||||
|
T.alloccount() -- remove limit
|
||||||
|
if a and b == "OK" then break end -- stop when no more errors
|
||||||
|
if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
|
||||||
|
error(a, 0) -- propagate it
|
||||||
|
end
|
||||||
|
M = M + 1 -- increase allocation limit
|
||||||
|
end
|
||||||
|
print(string.format("minimum allocations for %s: %d allocations", s, M))
|
||||||
|
return M
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function testamem (s, f)
|
||||||
|
local aloc = testalloc(s, f)
|
||||||
|
local res = testbytes(s, f)
|
||||||
|
return {aloc = aloc, res = res}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local b = testamem("function call", function () return 10 end)
|
||||||
|
assert(b.res == 10 and b.aloc == 0)
|
||||||
|
|
||||||
|
testamem("state creation", function ()
|
||||||
|
local st = T.newstate()
|
||||||
|
if st then T.closestate(st) end -- close new state
|
||||||
|
return st
|
||||||
|
end)
|
||||||
|
|
||||||
|
testamem("empty-table creation", function ()
|
||||||
|
return {}
|
||||||
|
end)
|
||||||
|
|
||||||
|
testamem("string creation", function ()
|
||||||
|
return "XXX" .. "YYY"
|
||||||
|
end)
|
||||||
|
|
||||||
|
testamem("coroutine creation", function()
|
||||||
|
return coroutine.create(print)
|
||||||
|
end)
|
||||||
|
|
||||||
|
do -- vararg tables
|
||||||
|
local function pack (...t) return t end
|
||||||
|
local b = testamem("vararg table", function ()
|
||||||
|
return pack(10, 20, 30, 40, "hello")
|
||||||
|
end)
|
||||||
|
assert(b.aloc == 3) -- new table uses three memory blocks
|
||||||
|
-- table optimized away
|
||||||
|
local function sel (n, ...arg) return arg[n] + arg.n end
|
||||||
|
local b = testamem("optimized vararg table",
|
||||||
|
function () return sel(2.0, 20, 30) end)
|
||||||
|
assert(b.res == 32 and b.aloc == 0) -- no memory needed for this case
|
||||||
|
end
|
||||||
|
|
||||||
|
-- testing to-be-closed variables
|
||||||
|
testamem("to-be-closed variables", function()
|
||||||
|
local flag
|
||||||
|
do
|
||||||
|
local x <close> =
|
||||||
|
setmetatable({}, {__close = function () flag = true end})
|
||||||
|
flag = false
|
||||||
|
local x = {}
|
||||||
|
end
|
||||||
|
return flag
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- testing threads
|
||||||
|
|
||||||
|
-- get main thread from registry
|
||||||
|
local mt = T.testC("rawgeti R !M; return 1")
|
||||||
|
assert(type(mt) == "thread" and coroutine.running() == mt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function expand (n,s)
|
||||||
|
if n==0 then return "" end
|
||||||
|
local e = string.rep("=", n)
|
||||||
|
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
|
||||||
|
e, s, expand(n-1,s), e)
|
||||||
|
end
|
||||||
|
|
||||||
|
G=0; collectgarbage()
|
||||||
|
load(expand(20,"G=G+1"))()
|
||||||
|
assert(G==20); collectgarbage()
|
||||||
|
G = nil
|
||||||
|
|
||||||
|
testamem("running code on new thread", function ()
|
||||||
|
return T.doonnewstack("local x=1") == 0 -- try to create thread
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
do -- external strings
|
||||||
|
local str = string.rep("a", 100)
|
||||||
|
testamem("creating external strings", function ()
|
||||||
|
return T.externstr(str)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- testing memory x compiler
|
||||||
|
|
||||||
|
testamem("loadstring", function ()
|
||||||
|
return load("x=1") -- try to do load a string
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
local testprog = [[
|
||||||
|
local function foo () return end
|
||||||
|
local t = {"x"}
|
||||||
|
AA = "aaa"
|
||||||
|
for i = 1, #t do AA = AA .. t[i] end
|
||||||
|
return true
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- testing memory x dofile
|
||||||
|
_G.AA = nil
|
||||||
|
local t =os.tmpname()
|
||||||
|
local f = assert(io.open(t, "w"))
|
||||||
|
f:write(testprog)
|
||||||
|
f:close()
|
||||||
|
testamem("dofile", function ()
|
||||||
|
local a = loadfile(t)
|
||||||
|
return a and a()
|
||||||
|
end)
|
||||||
|
assert(os.remove(t))
|
||||||
|
assert(_G.AA == "aaax")
|
||||||
|
|
||||||
|
|
||||||
|
-- other generic tests
|
||||||
|
|
||||||
|
testamem("gsub", function ()
|
||||||
|
local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
|
||||||
|
return (a == 'ablo ablo')
|
||||||
|
end)
|
||||||
|
|
||||||
|
testamem("dump/undump", function ()
|
||||||
|
local a = load(testprog)
|
||||||
|
local b = a and string.dump(a)
|
||||||
|
a = b and load(b)
|
||||||
|
return a and a()
|
||||||
|
end)
|
||||||
|
|
||||||
|
_G.AA = nil
|
||||||
|
|
||||||
|
local t = os.tmpname()
|
||||||
|
testamem("file creation", function ()
|
||||||
|
local f = assert(io.open(t, 'w'))
|
||||||
|
assert (not io.open"nomenaoexistente")
|
||||||
|
io.close(f);
|
||||||
|
return not loadfile'nomenaoexistente'
|
||||||
|
end)
|
||||||
|
assert(os.remove(t))
|
||||||
|
|
||||||
|
testamem("table creation", function ()
|
||||||
|
local a, lim = {}, 10
|
||||||
|
for i=1,lim do a[i] = i; a[i..'a'] = {} end
|
||||||
|
return (type(a[lim..'a']) == 'table' and a[lim] == lim)
|
||||||
|
end)
|
||||||
|
|
||||||
|
testamem("constructors", function ()
|
||||||
|
local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
|
||||||
|
return (type(a) == 'table' and a.e == 5)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local a = 1
|
||||||
|
local close = nil
|
||||||
|
testamem("closure creation", function ()
|
||||||
|
function close (b)
|
||||||
|
return function (x) return b + x end
|
||||||
|
end
|
||||||
|
return (close(2)(4) == 6)
|
||||||
|
end)
|
||||||
|
|
||||||
|
testamem("using coroutines", function ()
|
||||||
|
local a = coroutine.wrap(function ()
|
||||||
|
coroutine.yield(string.rep("a", 10))
|
||||||
|
return {}
|
||||||
|
end)
|
||||||
|
assert(string.len(a()) == 10)
|
||||||
|
return a()
|
||||||
|
end)
|
||||||
|
|
||||||
|
do -- auxiliary buffer
|
||||||
|
local lim = 100
|
||||||
|
local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
|
||||||
|
testamem("auxiliary buffer", function ()
|
||||||
|
return (#table.concat(a, ",") == 20*lim + lim - 1)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
testamem("growing stack", function ()
|
||||||
|
local function foo (n)
|
||||||
|
if n == 0 then return 1 else return 1 + foo(n - 1) end
|
||||||
|
end
|
||||||
|
return foo(100)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
collectgarbage()
|
||||||
|
collectgarbage()
|
||||||
|
global io, T, setmetatable, collectgarbage, print
|
||||||
|
|
||||||
|
local Count = 0
|
||||||
|
testamem("finalizers", function ()
|
||||||
|
local X = false
|
||||||
|
local obj = setmetatable({}, {__gc = function () X = true end})
|
||||||
|
obj = nil
|
||||||
|
T.resetCI() -- remove extra CallInfos
|
||||||
|
T.reallocstack(18) -- remove extra stack slots
|
||||||
|
Count = Count + 1
|
||||||
|
io.stderr:write(Count, "\n")
|
||||||
|
T.trick(io)
|
||||||
|
collectgarbage()
|
||||||
|
return X
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- }==================================================================
|
||||||
|
|
||||||
|
|
||||||
|
print "Ok"
|
||||||
|
|
||||||
|
|
||||||
+205
-53
@@ -1,5 +1,7 @@
|
|||||||
-- $Id: testes/nextvar.lua $
|
-- $Id: testes/nextvar.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
print('testing tables, next, and for')
|
print('testing tables, next, and for')
|
||||||
|
|
||||||
@@ -9,6 +11,38 @@ local function checkerror (msg, f, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
local function printTable (t)
|
||||||
|
local a, h = T.querytab(t)
|
||||||
|
print("array:")
|
||||||
|
for i = 1, a do
|
||||||
|
print("", T.querytab(t, i - 1))
|
||||||
|
end
|
||||||
|
print("hash:")
|
||||||
|
for i = 1, h do
|
||||||
|
print("", T.querytab(t, a + i - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
----------------------------------------------------------------
|
||||||
|
local function countentries (t)
|
||||||
|
local e = 0
|
||||||
|
for _ in pairs(t) do e = e + 1 end
|
||||||
|
return e
|
||||||
|
end
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
local function check (t, na, nh)
|
||||||
|
if not T then return end
|
||||||
|
local a, h = T.querytab(t)
|
||||||
|
if a ~= na or h ~= nh then
|
||||||
|
print(na, nh, a, h)
|
||||||
|
assert(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local a = {}
|
local a = {}
|
||||||
|
|
||||||
-- make sure table has lots of space in hash part
|
-- make sure table has lots of space in hash part
|
||||||
@@ -20,6 +54,44 @@ for i=1,100 do
|
|||||||
assert(#a == i)
|
assert(#a == i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- rehash moving elements from array to hash
|
||||||
|
local a = {}
|
||||||
|
for i = 1, 100 do a[i] = i end
|
||||||
|
check(a, 128, 0)
|
||||||
|
|
||||||
|
for i = 5, 95 do a[i] = nil end
|
||||||
|
check(a, 128, 0)
|
||||||
|
|
||||||
|
a[129] = 1 -- force a re-hash
|
||||||
|
check(a, 4, 8) -- keys larger than 4 go to the hash part
|
||||||
|
|
||||||
|
for i = 1, 4 do assert(a[i] == i) end
|
||||||
|
for i = 5, 95 do assert(a[i] == nil) end
|
||||||
|
for i = 96, 100 do assert(a[i] == i) end
|
||||||
|
assert(a[129] == 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- growing hash part keeping array part
|
||||||
|
local a = table.create(1000)
|
||||||
|
check(a, 1000, 0)
|
||||||
|
a.x = 10
|
||||||
|
check(a, 1000, 1) -- array part keeps its elements
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- "growing" length of a prebuilt table
|
||||||
|
local N = 100
|
||||||
|
local a = table.create(N)
|
||||||
|
for i = 1, N do
|
||||||
|
a[#a + 1] = true
|
||||||
|
assert(#a == i)
|
||||||
|
end
|
||||||
|
check(a, N, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- testing ipairs
|
-- testing ipairs
|
||||||
local x = 0
|
local x = 0
|
||||||
for k,v in ipairs{10,20,30;x=12} do
|
for k,v in ipairs{10,20,30;x=12} do
|
||||||
@@ -51,6 +123,24 @@ do -- overflow (must wrap-around)
|
|||||||
assert(k == nil)
|
assert(k == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- alternate insertions and deletions in an almost full hash.
|
||||||
|
-- In versions pre-5.5, that causes constant rehashings and
|
||||||
|
-- takes a long time to complete.
|
||||||
|
local a = {}
|
||||||
|
for i = 1, 2^11 - 1 do
|
||||||
|
a[i .. ""] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 1e5 do
|
||||||
|
local key = i .. "."
|
||||||
|
a[key] = true
|
||||||
|
a[key] = nil
|
||||||
|
end
|
||||||
|
assert(countentries(a) == 2^11 - 1)
|
||||||
|
end
|
||||||
|
|
||||||
if not T then
|
if not T then
|
||||||
(Message or print)
|
(Message or print)
|
||||||
('\n >>> testC not active: skipping tests for table sizes <<<\n')
|
('\n >>> testC not active: skipping tests for table sizes <<<\n')
|
||||||
@@ -58,22 +148,14 @@ else --[
|
|||||||
-- testing table sizes
|
-- testing table sizes
|
||||||
|
|
||||||
|
|
||||||
local function mp2 (n) -- minimum power of 2 >= n
|
-- minimum power of 2 (or zero) >= n
|
||||||
|
local function mp2 (n)
|
||||||
local mp = 2^math.ceil(math.log(n, 2))
|
local mp = 2^math.ceil(math.log(n, 2))
|
||||||
assert(n == 0 or (mp/2 < n and n <= mp))
|
assert((mp == 0 or mp/2 < n) and n <= mp)
|
||||||
return mp
|
return mp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function check (t, na, nh)
|
|
||||||
local a, h = T.querytab(t)
|
|
||||||
if a ~= na or h ~= nh then
|
|
||||||
print(na, nh, a, h)
|
|
||||||
assert(nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- testing C library sizes
|
-- testing C library sizes
|
||||||
do
|
do
|
||||||
local s = 0
|
local s = 0
|
||||||
@@ -84,7 +166,7 @@ end
|
|||||||
|
|
||||||
-- testing constructor sizes
|
-- testing constructor sizes
|
||||||
local sizes = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17,
|
local sizes = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17,
|
||||||
30, 31, 32, 33, 34, 254, 255, 256, 500, 1000}
|
30, 31, 32, 33, 34, 254, 255, 256, 257, 500, 1001}
|
||||||
|
|
||||||
for _, sa in ipairs(sizes) do -- 'sa' is size of the array part
|
for _, sa in ipairs(sizes) do -- 'sa' is size of the array part
|
||||||
local arr = {"return {"}
|
local arr = {"return {"}
|
||||||
@@ -128,8 +210,9 @@ end
|
|||||||
|
|
||||||
-- testing tables dynamically built
|
-- testing tables dynamically built
|
||||||
local lim = 130
|
local lim = 130
|
||||||
local a = {}; a[2] = 1; check(a, 0, 1)
|
local a = {}; a[2] = 1; check(a, 2, 0)
|
||||||
a = {}; a[0] = 1; check(a, 0, 1); a[2] = 1; check(a, 0, 2)
|
a = {}; a[0] = 1; check(a, 0, 1);
|
||||||
|
a[2] = 1; check(a, 2, 1)
|
||||||
a = {}; a[0] = 1; a[1] = 1; check(a, 1, 1)
|
a = {}; a[0] = 1; a[1] = 1; check(a, 1, 1)
|
||||||
a = {}
|
a = {}
|
||||||
for i = 1,lim do
|
for i = 1,lim do
|
||||||
@@ -145,31 +228,85 @@ for i = 1,lim do
|
|||||||
check(a, 0, mp2(i))
|
check(a, 0, mp2(i))
|
||||||
end
|
end
|
||||||
|
|
||||||
a = {}
|
|
||||||
for i=1,16 do a[i] = i end
|
-- insert and delete elements until a rehash occur. Caller must ensure
|
||||||
check(a, 16, 0)
|
-- that a rehash will change the shape of the table. Must repeat because
|
||||||
|
-- the insertion may collide with the deleted element, and then there is
|
||||||
|
-- no rehash.
|
||||||
|
local function forcerehash (t)
|
||||||
|
local na, nh = T.querytab(t)
|
||||||
|
local i = 10000
|
||||||
|
repeat
|
||||||
|
i = i + 1
|
||||||
|
t[i] = true
|
||||||
|
t[i] = undef
|
||||||
|
local nna, nnh = T.querytab(t)
|
||||||
|
until nna ~= na or nnh ~= nh
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
|
local a = {}
|
||||||
|
for i=1,16 do a[i] = i end
|
||||||
|
check(a, 16, 0)
|
||||||
for i=1,11 do a[i] = undef end
|
for i=1,11 do a[i] = undef end
|
||||||
for i=30,50 do a[i] = true; a[i] = undef end -- force a rehash (?)
|
check(a, 16, 0)
|
||||||
check(a, 0, 8) -- 5 elements in the table
|
a[30] = true -- force a rehash
|
||||||
|
a[30] = undef
|
||||||
|
check(a, 0, 8) -- 5 elements in the hash part: [12]-[16]
|
||||||
a[10] = 1
|
a[10] = 1
|
||||||
for i=30,50 do a[i] = true; a[i] = undef end -- force a rehash (?)
|
forcerehash(a)
|
||||||
check(a, 0, 8) -- only 6 elements in the table
|
check(a, 16, 1)
|
||||||
for i=1,14 do a[i] = true; a[i] = undef end
|
for i=1,14 do a[i] = true; a[i] = undef end
|
||||||
for i=18,50 do a[i] = true; a[i] = undef end -- force a rehash (?)
|
check(a, 16, 1) -- no rehash...
|
||||||
check(a, 0, 4) -- only 2 elements ([15] and [16])
|
a[31] = true; a[32] = true -- force a rehash
|
||||||
|
check(a, 0, 4) -- [15], [16], [31], [32]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- reverse filling
|
-- reverse filling
|
||||||
for i=1,lim do
|
do
|
||||||
|
local N = 2^10
|
||||||
local a = {}
|
local a = {}
|
||||||
for i=i,1,-1 do a[i] = i end -- fill in reverse
|
for i = N, 1, -1 do a[i] = i end -- fill in reverse
|
||||||
check(a, mp2(i), 0)
|
check(a, mp2(N), 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- "almost sparse" arrays
|
||||||
|
-- create table with holes in 1/3 of its entries; all its
|
||||||
|
-- elements are always in the array part
|
||||||
|
local a = {}
|
||||||
|
for i = 1, 257 do
|
||||||
|
if i % 3 ~= 1 then
|
||||||
|
a[i] = true
|
||||||
|
check(a, mp2(i), 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
-- alternate insertions and deletions should give some extra
|
||||||
|
-- space for the hash part. Otherwise, a mix of insertions/deletions
|
||||||
|
-- could cause too many rehashes. (See the other test for "alternate
|
||||||
|
-- insertions and deletions" in this file.)
|
||||||
|
local a = {}
|
||||||
|
for i = 1, 256 do
|
||||||
|
a[i .. ""] = true
|
||||||
|
end
|
||||||
|
check(a, 0, 256) -- hash part is full
|
||||||
|
a["256"] = nil -- delete a key
|
||||||
|
forcerehash(a)
|
||||||
|
-- table has only 255 elements, but it got some extra space;
|
||||||
|
-- otherwise, almost each delete-insert would rehash the table again.
|
||||||
|
assert(countentries(a) == 255)
|
||||||
|
check(a, 0, 512)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- size tests for vararg
|
-- size tests for vararg
|
||||||
lim = 35
|
lim = 35
|
||||||
function foo (n, ...)
|
local function foo (n, ...)
|
||||||
local arg = {...}
|
local arg = {...}
|
||||||
check(arg, n, 0)
|
check(arg, n, 0)
|
||||||
assert(select('#', ...) == n)
|
assert(select('#', ...) == n)
|
||||||
@@ -181,21 +318,6 @@ end
|
|||||||
local a = {}
|
local a = {}
|
||||||
for i=1,lim do a[i] = true; foo(i, table.unpack(a)) end
|
for i=1,lim do a[i] = true; foo(i, table.unpack(a)) end
|
||||||
|
|
||||||
|
|
||||||
-- Table length with limit smaller than maximum value at array
|
|
||||||
local a = {}
|
|
||||||
for i = 1,64 do a[i] = true end -- make its array size 64
|
|
||||||
for i = 1,64 do a[i] = nil end -- erase all elements
|
|
||||||
assert(T.querytab(a) == 64) -- array part has 64 elements
|
|
||||||
a[32] = true; a[48] = true; -- binary search will find these ones
|
|
||||||
a[51] = true -- binary search will miss this one
|
|
||||||
assert(#a == 48) -- this will set the limit
|
|
||||||
assert(select(4, T.querytab(a)) == 48) -- this is the limit now
|
|
||||||
a[50] = true -- this will set a new limit
|
|
||||||
assert(select(4, T.querytab(a)) == 50) -- this is the limit now
|
|
||||||
-- but the size is larger (and still inside the array part)
|
|
||||||
assert(#a == 51)
|
|
||||||
|
|
||||||
end --]
|
end --]
|
||||||
|
|
||||||
|
|
||||||
@@ -209,13 +331,36 @@ assert(#{1, 2, 3, nil, nil} == 3)
|
|||||||
print'+'
|
print'+'
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
local s1, s2 = math.randomseed()
|
||||||
|
print(string.format(
|
||||||
|
"testing length for some random tables (seeds 0X%x:%x)", s1, s2))
|
||||||
|
local N = 130
|
||||||
|
for i = 1, 1e3 do -- create that many random tables
|
||||||
|
local a = table.create(math.random(N)) -- initiate with random size
|
||||||
|
for j = 1, math.random(N) do -- add random number of random entries
|
||||||
|
a[math.random(N)] = true
|
||||||
|
end
|
||||||
|
assert(#a == 0 or a[#a] and not a[#a + 1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do print("testing attack on table length")
|
||||||
|
local t = {}
|
||||||
|
local lim = math.floor(math.log(math.maxinteger, 2)) - 1
|
||||||
|
for i = lim, 0, -1 do
|
||||||
|
t[2^i] = true
|
||||||
|
end
|
||||||
|
assert(t[1 << lim])
|
||||||
|
-- next loop should not take forever
|
||||||
|
for i = 1, #t do end
|
||||||
|
end
|
||||||
|
|
||||||
local nofind = {}
|
local nofind = {}
|
||||||
|
|
||||||
a,b,c = 1,2,3
|
|
||||||
a,b,c = nil
|
|
||||||
|
|
||||||
|
-- next uses always the same iteration function
|
||||||
-- next uses always the same iteraction function
|
|
||||||
assert(next{} == next{})
|
assert(next{} == next{})
|
||||||
|
|
||||||
local function find (name)
|
local function find (name)
|
||||||
@@ -262,7 +407,7 @@ for i=0,10000 do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
n = {n=0}
|
local n = {n=0}
|
||||||
for i,v in pairs(a) do
|
for i,v in pairs(a) do
|
||||||
n.n = n.n+1
|
n.n = n.n+1
|
||||||
assert(i and v and a[i] == v)
|
assert(i and v and a[i] == v)
|
||||||
@@ -589,10 +734,12 @@ do
|
|||||||
a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1)
|
a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1)
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- changing the control variable
|
do -- attempt to change the control variable
|
||||||
local a
|
local st, msg = load "for i = 1, 10 do i = 10 end"
|
||||||
a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10)
|
assert(not st and string.find(msg, "assign to const variable 'i'"))
|
||||||
a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10)
|
|
||||||
|
local st, msg = load "for v, k in pairs{} do v = 10 end"
|
||||||
|
assert(not st and string.find(msg, "assign to const variable 'v'"))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- conversion
|
-- conversion
|
||||||
@@ -758,13 +905,18 @@ local function foo1 (e,i)
|
|||||||
if i <= e.n then return i,a[i] end
|
if i <= e.n then return i,a[i] end
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(a, {__pairs = function (x) return foo, x, 0 end})
|
local closed = false
|
||||||
|
setmetatable(a, {__pairs = function (x)
|
||||||
|
local tbc = setmetatable({}, {__close = function () closed = true end})
|
||||||
|
return foo, x, 0, tbc
|
||||||
|
end})
|
||||||
|
|
||||||
local i = 0
|
local i = 0
|
||||||
for k,v in pairs(a) do
|
for k,v in pairs(a) do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
assert(k == i and v == k+1)
|
assert(k == i and v == k+1)
|
||||||
end
|
end
|
||||||
|
assert(closed) -- 'tbc' has been closed
|
||||||
|
|
||||||
a.n = 5
|
a.n = 5
|
||||||
a[3] = 30
|
a[3] = 30
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ $NAME/literals.lua \
|
|||||||
$NAME/locals.lua \
|
$NAME/locals.lua \
|
||||||
$NAME/main.lua \
|
$NAME/main.lua \
|
||||||
$NAME/math.lua \
|
$NAME/math.lua \
|
||||||
|
$NAME/memerr.lua \
|
||||||
$NAME/nextvar.lua \
|
$NAME/nextvar.lua \
|
||||||
$NAME/pm.lua \
|
$NAME/pm.lua \
|
||||||
$NAME/sort.lua \
|
$NAME/sort.lua \
|
||||||
|
|||||||
+67
-36
@@ -1,28 +1,33 @@
|
|||||||
-- $Id: testes/pm.lua $
|
-- $Id: testes/pm.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
-- UTF-8 file
|
||||||
|
|
||||||
|
|
||||||
print('testing pattern matching')
|
print('testing pattern matching')
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
local function checkerror (msg, f, ...)
|
local function checkerror (msg, f, ...)
|
||||||
local s, err = pcall(f, ...)
|
local s, err = pcall(f, ...)
|
||||||
assert(not s and string.find(err, msg))
|
assert(not s and string.find(err, msg))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function f(s, p)
|
local function f (s, p)
|
||||||
local i,e = string.find(s, p)
|
local i,e = string.find(s, p)
|
||||||
if i then return string.sub(s, i, e) end
|
if i then return string.sub(s, i, e) end
|
||||||
end
|
end
|
||||||
|
|
||||||
a,b = string.find('', '') -- empty patterns are tricky
|
local a,b = string.find('', '') -- empty patterns are tricky
|
||||||
assert(a == 1 and b == 0);
|
assert(a == 1 and b == 0);
|
||||||
a,b = string.find('alo', '')
|
a,b = string.find('alo', '')
|
||||||
assert(a == 1 and b == 0)
|
assert(a == 1 and b == 0)
|
||||||
a,b = string.find('a\0o a\0o a\0o', 'a', 1) -- first position
|
a,b = string.find('a\0o a\0o a\0o', 'a', 1) -- first position
|
||||||
assert(a == 1 and b == 1)
|
assert(a == 1 and b == 1)
|
||||||
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2) -- starts in the midle
|
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2) -- starts in the middle
|
||||||
assert(a == 5 and b == 7)
|
assert(a == 5 and b == 7)
|
||||||
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9) -- starts in the midle
|
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9) -- starts in the middle
|
||||||
assert(a == 9 and b == 11)
|
assert(a == 9 and b == 11)
|
||||||
a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2); -- finds at the end
|
a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2); -- finds at the end
|
||||||
assert(a == 9 and b == 11);
|
assert(a == 9 and b == 11);
|
||||||
@@ -50,6 +55,20 @@ assert(f('aLo_ALO', '%a*') == 'aLo')
|
|||||||
|
|
||||||
assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu")
|
assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu")
|
||||||
|
|
||||||
|
|
||||||
|
-- Adapt a pattern to UTF-8
|
||||||
|
local function PU (p)
|
||||||
|
-- distribute '?' into each individual byte of a character.
|
||||||
|
-- (For instance, "á?" becomes "\195?\161?".)
|
||||||
|
p = string.gsub(p, "(" .. utf8.charpattern .. ")%?", function (c)
|
||||||
|
return string.gsub(c, ".", "%0?")
|
||||||
|
end)
|
||||||
|
-- change '.' to utf-8 character patterns
|
||||||
|
p = string.gsub(p, "%.", utf8.charpattern)
|
||||||
|
return p
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
assert(f('aaab', 'a*') == 'aaa');
|
assert(f('aaab', 'a*') == 'aaa');
|
||||||
assert(f('aaa', '^.*$') == 'aaa');
|
assert(f('aaa', '^.*$') == 'aaa');
|
||||||
assert(f('aaa', 'b*') == '');
|
assert(f('aaa', 'b*') == '');
|
||||||
@@ -73,22 +92,22 @@ assert(f('aaa', '^.-$') == 'aaa')
|
|||||||
assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab')
|
assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab')
|
||||||
assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab')
|
assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab')
|
||||||
assert(f('alo xo', '.o$') == 'xo')
|
assert(f('alo xo', '.o$') == 'xo')
|
||||||
assert(f(' \n isto é assim', '%S%S*') == 'isto')
|
assert(f(' \n isto é assim', '%S%S*') == 'isto')
|
||||||
assert(f(' \n isto é assim', '%S*$') == 'assim')
|
assert(f(' \n isto é assim', '%S*$') == 'assim')
|
||||||
assert(f(' \n isto é assim', '[a-z]*$') == 'assim')
|
assert(f(' \n isto é assim', '[a-z]*$') == 'assim')
|
||||||
assert(f('um caracter ? extra', '[^%sa-z]') == '?')
|
assert(f('um caracter ? extra', '[^%sa-z]') == '?')
|
||||||
assert(f('', 'a?') == '')
|
assert(f('', 'a?') == '')
|
||||||
assert(f('á', 'á?') == 'á')
|
assert(f('á', PU'á?') == 'á')
|
||||||
assert(f('ábl', 'á?b?l?') == 'ábl')
|
assert(f('ábl', PU'á?b?l?') == 'ábl')
|
||||||
assert(f(' ábl', 'á?b?l?') == '')
|
assert(f(' ábl', PU'á?b?l?') == '')
|
||||||
assert(f('aa', '^aa?a?a') == 'aa')
|
assert(f('aa', '^aa?a?a') == 'aa')
|
||||||
assert(f(']]]áb', '[^]]') == 'á')
|
assert(f(']]]áb', '[^]]+') == 'áb')
|
||||||
assert(f("0alo alo", "%x*") == "0a")
|
assert(f("0alo alo", "%x*") == "0a")
|
||||||
assert(f("alo alo", "%C+") == "alo alo")
|
assert(f("alo alo", "%C+") == "alo alo")
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
|
|
||||||
function f1(s, p)
|
local function f1 (s, p)
|
||||||
p = string.gsub(p, "%%([0-9])", function (s)
|
p = string.gsub(p, "%%([0-9])", function (s)
|
||||||
return "%" .. (tonumber(s)+1)
|
return "%" .. (tonumber(s)+1)
|
||||||
end)
|
end)
|
||||||
@@ -113,7 +132,7 @@ local abc = string.char(range(0, 127)) .. string.char(range(128, 255));
|
|||||||
|
|
||||||
assert(string.len(abc) == 256)
|
assert(string.len(abc) == 256)
|
||||||
|
|
||||||
function strset (p)
|
local function strset (p)
|
||||||
local res = {s=''}
|
local res = {s=''}
|
||||||
string.gsub(abc, p, function (c) res.s = res.s .. c end)
|
string.gsub(abc, p, function (c) res.s = res.s .. c end)
|
||||||
return res.s
|
return res.s
|
||||||
@@ -136,28 +155,28 @@ assert(string.match("alo xyzK", "(%w+)K") == "xyz")
|
|||||||
assert(string.match("254 K", "(%d*)K") == "")
|
assert(string.match("254 K", "(%d*)K") == "")
|
||||||
assert(string.match("alo ", "(%w*)$") == "")
|
assert(string.match("alo ", "(%w*)$") == "")
|
||||||
assert(not string.match("alo ", "(%w+)$"))
|
assert(not string.match("alo ", "(%w+)$"))
|
||||||
assert(string.find("(álo)", "%(á") == 1)
|
assert(string.find("(álo)", "%(á") == 1)
|
||||||
local a, b, c, d, e = string.match("âlo alo", "^(((.).).* (%w*))$")
|
local a, b, c, d, e = string.match("âlo alo", PU"^(((.).). (%w*))$")
|
||||||
assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil)
|
assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil)
|
||||||
a, b, c, d = string.match('0123456789', '(.+(.?)())')
|
a, b, c, d = string.match('0123456789', '(.+(.?)())')
|
||||||
assert(a == '0123456789' and b == '' and c == 11 and d == nil)
|
assert(a == '0123456789' and b == '' and c == 11 and d == nil)
|
||||||
print('+')
|
print('+')
|
||||||
|
|
||||||
assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
|
assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
|
||||||
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
|
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
|
||||||
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
|
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
|
||||||
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
|
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
|
||||||
t = "abç d"
|
local t = "abç d"
|
||||||
a, b = string.gsub(t, '(.)', '%1@')
|
a, b = string.gsub(t, PU'(.)', '%1@')
|
||||||
assert('@'..a == string.gsub(t, '', '@') and b == 5)
|
assert(a == "a@b@ç@ @d@" and b == 5)
|
||||||
a, b = string.gsub('abçd', '(.)', '%0@', 2)
|
a, b = string.gsub('abçd', PU'(.)', '%0@', 2)
|
||||||
assert(a == 'a@b@çd' and b == 2)
|
assert(a == 'a@b@çd' and b == 2)
|
||||||
assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o')
|
assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o')
|
||||||
assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") ==
|
assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") ==
|
||||||
"xyz=abc-abc=xyz")
|
"xyz=abc-abc=xyz")
|
||||||
assert(string.gsub("abc", "%w", "%1%0") == "aabbcc")
|
assert(string.gsub("abc", "%w", "%1%0") == "aabbcc")
|
||||||
assert(string.gsub("abc", "%w+", "%0%1") == "abcabc")
|
assert(string.gsub("abc", "%w+", "%0%1") == "abcabc")
|
||||||
assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú')
|
assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú')
|
||||||
assert(string.gsub('', '^', 'r') == 'r')
|
assert(string.gsub('', '^', 'r') == 'r')
|
||||||
assert(string.gsub('', '$', 'r') == 'r')
|
assert(string.gsub('', '$', 'r') == 'r')
|
||||||
print('+')
|
print('+')
|
||||||
@@ -184,31 +203,33 @@ do
|
|||||||
local function setglobal (n,v) rawset(_G, n, v) end
|
local function setglobal (n,v) rawset(_G, n, v) end
|
||||||
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
|
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
|
||||||
assert(_G.a=="roberto" and _G.roberto=="a")
|
assert(_G.a=="roberto" and _G.roberto=="a")
|
||||||
|
_G.a = nil; _G.roberto = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function f(a,b) return string.gsub(a,'.',b) end
|
function f(a,b) return string.gsub(a,'.',b) end
|
||||||
assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) ==
|
assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) ==
|
||||||
"trocar tudo em bbbbb é alalalalalal")
|
"trocar tudo em bbbbb é alalalalalal")
|
||||||
|
|
||||||
local function dostring (s) return load(s, "")() or "" end
|
local function dostring (s) return load(s, "")() or "" end
|
||||||
assert(string.gsub("alo $a='x'$ novamente $return a$",
|
assert(string.gsub("alo $a='x'$ novamente $return a$",
|
||||||
"$([^$]*)%$",
|
"$([^$]*)%$",
|
||||||
dostring) == "alo novamente x")
|
dostring) == "alo novamente x")
|
||||||
|
|
||||||
x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
|
local x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
|
||||||
"$([^$]*)%$", dostring)
|
"$([^$]*)%$", dostring)
|
||||||
assert(x == ' assim vai para ALO')
|
assert(x == ' assim vai para ALO')
|
||||||
|
_G.a, _G.x = nil
|
||||||
|
|
||||||
t = {}
|
local t = {}
|
||||||
s = 'a alo jose joao'
|
local s = 'a alo jose joao'
|
||||||
r = string.gsub(s, '()(%w+)()', function (a,w,b)
|
local r = string.gsub(s, '()(%w+)()', function (a,w,b)
|
||||||
assert(string.len(w) == b-a);
|
assert(string.len(w) == b-a);
|
||||||
t[a] = b-a;
|
t[a] = b-a;
|
||||||
end)
|
end)
|
||||||
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
|
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
|
||||||
|
|
||||||
|
|
||||||
function isbalanced (s)
|
local function isbalanced (s)
|
||||||
return not string.find(string.gsub(s, "%b()", ""), "[()]")
|
return not string.find(string.gsub(s, "%b()", ""), "[()]")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -251,7 +272,7 @@ if not _soft then
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- recursive nest of gsubs
|
-- recursive nest of gsubs
|
||||||
function rev (s)
|
local function rev (s)
|
||||||
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
|
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -326,6 +347,16 @@ do -- init parameter in gmatch
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- bug since 5.3
|
||||||
|
local N = 20000
|
||||||
|
local iter = string.gmatch(string.rep("a", N), string.rep("a?", N))
|
||||||
|
pcall(iter) -- error for pattern too complex
|
||||||
|
-- calling function again found recursion count ('matchdepth') equal
|
||||||
|
-- to -1, so it did not detect next C-stack overflow
|
||||||
|
pcall(iter)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- tests for `%f' (`frontiers')
|
-- tests for `%f' (`frontiers')
|
||||||
|
|
||||||
assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
|
assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
|
||||||
|
|||||||
+61
-17
@@ -1,12 +1,8 @@
|
|||||||
-- $Id: testes/sort.lua $
|
-- $Id: testes/sort.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
print "testing (parts of) table library"
|
print "testing (parts of) table library"
|
||||||
|
|
||||||
print "testing unpack"
|
|
||||||
|
|
||||||
local unpack = table.unpack
|
|
||||||
|
|
||||||
local maxI = math.maxinteger
|
local maxI = math.maxinteger
|
||||||
local minI = math.mininteger
|
local minI = math.mininteger
|
||||||
|
|
||||||
@@ -17,10 +13,44 @@ local function checkerror (msg, f, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do print "testing 'table.create'"
|
||||||
|
local N = 10000
|
||||||
|
collectgarbage()
|
||||||
|
local m = collectgarbage("count") * 1024
|
||||||
|
local t = table.create(N)
|
||||||
|
local memdiff = collectgarbage("count") * 1024 - m
|
||||||
|
assert(memdiff > N * 4)
|
||||||
|
for i = 1, 20 do
|
||||||
|
assert(#t == i - 1)
|
||||||
|
t[i] = 0
|
||||||
|
end
|
||||||
|
for i = 1, 20 do t[#t + 1] = i * 10 end
|
||||||
|
assert(#t == 40 and t[39] == 190)
|
||||||
|
assert(not T or T.querytab(t) == N)
|
||||||
|
t = nil
|
||||||
|
collectgarbage()
|
||||||
|
m = collectgarbage("count") * 1024
|
||||||
|
t = table.create(0, 1024)
|
||||||
|
memdiff = collectgarbage("count") * 1024 - m
|
||||||
|
assert(memdiff > 1024 * 12)
|
||||||
|
assert(not T or select(2, T.querytab(t)) == 1024)
|
||||||
|
|
||||||
|
local maxint1 = 1 << (string.packsize("i") * 8 - 1)
|
||||||
|
checkerror("out of range", table.create, maxint1)
|
||||||
|
checkerror("out of range", table.create, 0, maxint1)
|
||||||
|
checkerror("table overflow", table.create, 0, maxint1 - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
print "testing unpack"
|
||||||
|
|
||||||
|
local unpack = table.unpack
|
||||||
|
|
||||||
|
|
||||||
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
|
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
|
||||||
|
|
||||||
local x,y,z,a,n
|
local x,y,z,a,n
|
||||||
a = {}; lim = _soft and 200 or 2000
|
a = {}; local lim = _soft and 200 or 2000
|
||||||
for i=1, lim do a[i]=i end
|
for i=1, lim do a[i]=i end
|
||||||
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
|
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
|
||||||
x = unpack(a)
|
x = unpack(a)
|
||||||
@@ -42,6 +72,19 @@ assert(a==1 and x==nil)
|
|||||||
a,x = unpack({1,2}, 1, 1)
|
a,x = unpack({1,2}, 1, 1)
|
||||||
assert(a==1 and x==nil)
|
assert(a==1 and x==nil)
|
||||||
|
|
||||||
|
|
||||||
|
do -- unpack with non-tables
|
||||||
|
local debug = require"debug"
|
||||||
|
local oldmt = debug.getmetatable(0)
|
||||||
|
local str = "hello"
|
||||||
|
debug.setmetatable(0,
|
||||||
|
{ __len = function () return #str end,
|
||||||
|
__index = function (_, i) return string.sub(str, i, i) end})
|
||||||
|
assert(table.concat({table.unpack(0)}) == str)
|
||||||
|
debug.setmetatable(0, oldmt) -- restore original metatable for numbers
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
|
local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
|
||||||
local mini = -(1 << 31) -- minimum value for an int (usually)
|
local mini = -(1 << 31) -- minimum value for an int (usually)
|
||||||
@@ -169,7 +212,7 @@ do
|
|||||||
__index = function (_,k) pos1 = k end,
|
__index = function (_,k) pos1 = k end,
|
||||||
__newindex = function (_,k) pos2 = k; error() end, })
|
__newindex = function (_,k) pos2 = k; error() end, })
|
||||||
local st, msg = pcall(table.move, a, f, e, t)
|
local st, msg = pcall(table.move, a, f, e, t)
|
||||||
assert(not st and not msg and pos1 == x and pos2 == y)
|
assert(not st and pos1 == x and pos2 == y)
|
||||||
end
|
end
|
||||||
checkmove(1, maxI, 0, 1, 0)
|
checkmove(1, maxI, 0, 1, 0)
|
||||||
checkmove(0, maxI - 1, 1, maxI - 1, maxI)
|
checkmove(0, maxI - 1, 1, maxI - 1, maxI)
|
||||||
@@ -222,7 +265,7 @@ a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
|
|||||||
table.sort(a)
|
table.sort(a)
|
||||||
check(a)
|
check(a)
|
||||||
|
|
||||||
function perm (s, n)
|
local function perm (s, n)
|
||||||
n = n or #s
|
n = n or #s
|
||||||
if n == 1 then
|
if n == 1 then
|
||||||
local t = {unpack(s)}
|
local t = {unpack(s)}
|
||||||
@@ -248,7 +291,7 @@ perm{1,2,3,3,5}
|
|||||||
perm{1,2,3,4,5,6}
|
perm{1,2,3,4,5,6}
|
||||||
perm{2,2,3,3,5,6}
|
perm{2,2,3,3,5,6}
|
||||||
|
|
||||||
function timesort (a, n, func, msg, pre)
|
local function timesort (a, n, func, msg, pre)
|
||||||
local x = os.clock()
|
local x = os.clock()
|
||||||
table.sort(a, func)
|
table.sort(a, func)
|
||||||
x = (os.clock() - x) * 1000
|
x = (os.clock() - x) * 1000
|
||||||
@@ -257,7 +300,7 @@ function timesort (a, n, func, msg, pre)
|
|||||||
check(a, func)
|
check(a, func)
|
||||||
end
|
end
|
||||||
|
|
||||||
limit = 50000
|
local limit = 50000
|
||||||
if _soft then limit = 5000 end
|
if _soft then limit = 5000 end
|
||||||
|
|
||||||
a = {}
|
a = {}
|
||||||
@@ -274,7 +317,7 @@ for i=1,limit do
|
|||||||
a[i] = math.random()
|
a[i] = math.random()
|
||||||
end
|
end
|
||||||
|
|
||||||
x = os.clock(); i=0
|
local x = os.clock(); local i = 0
|
||||||
table.sort(a, function(x,y) i=i+1; return y<x end)
|
table.sort(a, function(x,y) i=i+1; return y<x end)
|
||||||
x = (os.clock() - x) * 1000
|
x = (os.clock() - x) * 1000
|
||||||
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
|
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
|
||||||
@@ -289,18 +332,19 @@ timesort(a, limit, function(x,y) return nil end, "equal")
|
|||||||
|
|
||||||
for i,v in pairs(a) do assert(v == false) end
|
for i,v in pairs(a) do assert(v == false) end
|
||||||
|
|
||||||
A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
|
AA = {"\xE1lo", "\0first :-)", "alo", "then this one", "45", "and a new"}
|
||||||
table.sort(A)
|
table.sort(AA)
|
||||||
check(A)
|
check(AA)
|
||||||
|
|
||||||
table.sort(A, function (x, y)
|
table.sort(AA, function (x, y)
|
||||||
load(string.format("A[%q] = ''", x), "")()
|
load(string.format("AA[%q] = ''", x), "")()
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
return x<y
|
return x<y
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
_G.AA = nil
|
||||||
|
|
||||||
tt = {__lt = function (a,b) return a.val < b.val end}
|
local tt = {__lt = function (a,b) return a.val < b.val end}
|
||||||
a = {}
|
a = {}
|
||||||
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
|
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
|
||||||
table.sort(a)
|
table.sort(a)
|
||||||
|
|||||||
+58
-13
@@ -1,5 +1,9 @@
|
|||||||
-- $Id: testes/strings.lua $
|
-- $Id: testes/strings.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
|
-- ISO Latin encoding
|
||||||
|
|
||||||
|
global <const> *
|
||||||
|
|
||||||
print('testing strings and string library')
|
print('testing strings and string library')
|
||||||
|
|
||||||
@@ -52,7 +56,7 @@ assert(("\000123456789"):sub(8) == "789")
|
|||||||
|
|
||||||
-- testing string.find
|
-- testing string.find
|
||||||
assert(string.find("123456789", "345") == 3)
|
assert(string.find("123456789", "345") == 3)
|
||||||
a,b = string.find("123456789", "345")
|
local a,b = string.find("123456789", "345")
|
||||||
assert(string.sub("123456789", a, b) == "345")
|
assert(string.sub("123456789", a, b) == "345")
|
||||||
assert(string.find("1234567890123456789", "345", 3) == 3)
|
assert(string.find("1234567890123456789", "345", 3) == 3)
|
||||||
assert(string.find("1234567890123456789", "345", 4) == 13)
|
assert(string.find("1234567890123456789", "345", 4) == 13)
|
||||||
@@ -106,10 +110,9 @@ assert(string.rep('teste', 0) == '')
|
|||||||
assert(string.rep('tés\00tê', 2) == 'tés\0têtés\000tê')
|
assert(string.rep('tés\00tê', 2) == 'tés\0têtés\000tê')
|
||||||
assert(string.rep('', 10) == '')
|
assert(string.rep('', 10) == '')
|
||||||
|
|
||||||
if string.packsize("i") == 4 then
|
do
|
||||||
-- result length would be 2^31 (int overflow)
|
checkerror("too large", string.rep, 'aa', math.maxinteger);
|
||||||
checkerror("too large", string.rep, 'aa', (1 << 30))
|
checkerror("too large", string.rep, 'a', math.maxinteger, ',')
|
||||||
checkerror("too large", string.rep, 'a', (1 << 30), ',')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- repetitions with separator
|
-- repetitions with separator
|
||||||
@@ -154,6 +157,12 @@ else -- compatible coercion
|
|||||||
assert(tostring(-1203 + 0.0) == "-1203")
|
assert(tostring(-1203 + 0.0) == "-1203")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function topointer (s)
|
||||||
|
return string.format("%p", s)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- tests for '%p' format
|
do -- tests for '%p' format
|
||||||
-- not much to test, as C does not specify what '%p' does.
|
-- not much to test, as C does not specify what '%p' does.
|
||||||
-- ("The value of the pointer is converted to a sequence of printing
|
-- ("The value of the pointer is converted to a sequence of printing
|
||||||
@@ -177,22 +186,22 @@ do -- tests for '%p' format
|
|||||||
|
|
||||||
do
|
do
|
||||||
local t1 = {}; local t2 = {}
|
local t1 = {}; local t2 = {}
|
||||||
assert(string.format("%p", t1) ~= string.format("%p", t2))
|
assert(topointer(t1) ~= topointer(t2))
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- short strings are internalized
|
do -- short strings are internalized
|
||||||
local s1 = string.rep("a", 10)
|
local s1 = string.rep("a", 10)
|
||||||
local s2 = string.rep("aa", 5)
|
local s2 = string.rep("aa", 5)
|
||||||
assert(string.format("%p", s1) == string.format("%p", s2))
|
assert(topointer(s1) == topointer(s2))
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- long strings aren't internalized
|
do -- long strings aren't internalized
|
||||||
local s1 = string.rep("a", 300); local s2 = string.rep("a", 300)
|
local s1 = string.rep("a", 300); local s2 = string.rep("a", 300)
|
||||||
assert(string.format("%p", s1) ~= string.format("%p", s2))
|
assert(topointer(s1) ~= topointer(s2))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
x = '"ílo"\n\\'
|
local x = '"ílo"\n\\'
|
||||||
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
|
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
|
||||||
assert(string.format('%q', "\0") == [["\0"]])
|
assert(string.format('%q', "\0") == [["\0"]])
|
||||||
assert(load(string.format('return %q', x))() == x)
|
assert(load(string.format('return %q', x))() == x)
|
||||||
@@ -346,13 +355,18 @@ assert(string.format("%013i", -100) == "-000000000100")
|
|||||||
assert(string.format("%2.5d", -100) == "-00100")
|
assert(string.format("%2.5d", -100) == "-00100")
|
||||||
assert(string.format("%.u", 0) == "")
|
assert(string.format("%.u", 0) == "")
|
||||||
assert(string.format("%+#014.0f", 100) == "+000000000100.")
|
assert(string.format("%+#014.0f", 100) == "+000000000100.")
|
||||||
assert(string.format("% 1.0E", 100) == " 1E+02")
|
|
||||||
assert(string.format("%-16c", 97) == "a ")
|
assert(string.format("%-16c", 97) == "a ")
|
||||||
assert(string.format("%+.3G", 1.5) == "+1.5")
|
assert(string.format("%+.3G", 1.5) == "+1.5")
|
||||||
assert(string.format("% .1g", 2^10) == " 1e+03")
|
|
||||||
assert(string.format("%.0s", "alo") == "")
|
assert(string.format("%.0s", "alo") == "")
|
||||||
assert(string.format("%.s", "alo") == "")
|
assert(string.format("%.s", "alo") == "")
|
||||||
|
|
||||||
|
-- ISO C89 says that "The exponent always contains at least two digits",
|
||||||
|
-- but unlike ISO C99 it does not ensure that it contains "only as many
|
||||||
|
-- more digits as necessary".
|
||||||
|
assert(string.match(string.format("% 1.0E", 100), "^ 1E%+0+2$"))
|
||||||
|
assert(string.match(string.format("% .1g", 2^10), "^ 1e%+0+3$"))
|
||||||
|
|
||||||
|
|
||||||
-- errors in format
|
-- errors in format
|
||||||
|
|
||||||
local function check (fmt, msg)
|
local function check (fmt, msg)
|
||||||
@@ -447,7 +461,7 @@ end
|
|||||||
do
|
do
|
||||||
local f = string.gmatch("1 2 3 4 5", "%d+")
|
local f = string.gmatch("1 2 3 4 5", "%d+")
|
||||||
assert(f() == "1")
|
assert(f() == "1")
|
||||||
co = coroutine.wrap(f)
|
local co = coroutine.wrap(f)
|
||||||
assert(co() == "2")
|
assert(co() == "2")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -513,6 +527,37 @@ else
|
|||||||
testpfs("P", str, {})
|
testpfs("P", str, {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if T == nil then
|
||||||
|
(Message or print)('\n >>> testC not active: skipping external strings tests <<<\n')
|
||||||
|
else
|
||||||
|
print("testing external strings")
|
||||||
|
local x = T.externKstr("hello") -- external fixed short string
|
||||||
|
assert(x == "hello")
|
||||||
|
local x = T.externstr("hello") -- external allocated short string
|
||||||
|
assert(x == "hello")
|
||||||
|
x = string.rep("a", 100) -- long string
|
||||||
|
local y = T.externKstr(x) -- external fixed long string
|
||||||
|
assert(y == x)
|
||||||
|
local z = T.externstr(x) -- external allocated long string
|
||||||
|
assert(z == y)
|
||||||
|
|
||||||
|
local e = T.externstr("") -- empty external string
|
||||||
|
assert(e .. "x" == "x" and "x" .. e == "x")
|
||||||
|
assert(e .. e == "" and #e == 0)
|
||||||
|
|
||||||
|
-- external string as the "n" key in vararg table
|
||||||
|
local n = T.externstr("n")
|
||||||
|
local n0 = T.externstr("n\0")
|
||||||
|
local function aux (...t) assert(t[n0] == nil); return t[n] end
|
||||||
|
assert(aux(10, 20, 30) == 3)
|
||||||
|
|
||||||
|
-- external string as mode in weak table
|
||||||
|
local t = setmetatable({}, {__mode = T.externstr("kv")})
|
||||||
|
t[{}] = {}
|
||||||
|
assert(next(t))
|
||||||
|
collectgarbage()
|
||||||
|
assert(next(t) == nil)
|
||||||
|
end
|
||||||
|
|
||||||
print('OK')
|
print('OK')
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -1,5 +1,5 @@
|
|||||||
-- $Id: testes/tpack.lua $
|
-- $Id: testes/tpack.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file lua.h
|
||||||
|
|
||||||
local pack = string.pack
|
local pack = string.pack
|
||||||
local packsize = string.packsize
|
local packsize = string.packsize
|
||||||
@@ -35,7 +35,7 @@ print("\talignment: " .. align)
|
|||||||
|
|
||||||
|
|
||||||
-- check errors in arguments
|
-- check errors in arguments
|
||||||
function checkerror (msg, f, ...)
|
local function checkerror (msg, f, ...)
|
||||||
local status, err = pcall(f, ...)
|
local status, err = pcall(f, ...)
|
||||||
-- print(status, err, msg)
|
-- print(status, err, msg)
|
||||||
assert(not status and string.find(err, msg))
|
assert(not status and string.find(err, msg))
|
||||||
@@ -135,15 +135,15 @@ checkerror("variable%-length format", packsize, "z")
|
|||||||
-- overflow in option size (error will be in digit after limit)
|
-- overflow in option size (error will be in digit after limit)
|
||||||
checkerror("invalid format", packsize, "c1" .. string.rep("0", 40))
|
checkerror("invalid format", packsize, "c1" .. string.rep("0", 40))
|
||||||
|
|
||||||
if packsize("i") == 4 then
|
do
|
||||||
-- result would be 2^31 (2^3 repetitions of 2^28 strings)
|
local maxsize = (packsize("j") <= packsize("T")) and
|
||||||
local s = string.rep("c268435456", 2^3)
|
math.maxinteger or (1 << (packsize("T") * 8))
|
||||||
checkerror("too large", packsize, s)
|
assert (packsize(string.format("c%d", maxsize - 9)) == maxsize - 9)
|
||||||
-- one less is OK
|
checkerror("too large", packsize, string.format("c%dc10", maxsize - 9))
|
||||||
s = string.rep("c268435456", 2^3 - 1) .. "c268435455"
|
checkerror("too long", pack, string.format("xxxxxxxxxx c%d", maxsize - 9))
|
||||||
assert(packsize(s) == 0x7fffffff)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- overflow in packing
|
-- overflow in packing
|
||||||
for i = 1, sizeLI - 1 do
|
for i = 1, sizeLI - 1 do
|
||||||
local umax = (1 << (i * 8)) - 1
|
local umax = (1 << (i * 8)) - 1
|
||||||
@@ -229,8 +229,9 @@ do
|
|||||||
assert(pack("c3", "123") == "123")
|
assert(pack("c3", "123") == "123")
|
||||||
assert(pack("c0", "") == "")
|
assert(pack("c0", "") == "")
|
||||||
assert(pack("c8", "123456") == "123456\0\0")
|
assert(pack("c8", "123456") == "123456\0\0")
|
||||||
assert(pack("c88", "") == string.rep("\0", 88))
|
assert(pack("c88 c1", "", "X") == string.rep("\0", 88) .. "X")
|
||||||
assert(pack("c188", "ab") == "ab" .. string.rep("\0", 188 - 2))
|
assert(pack("c188 c2", "ab", "X\1") ==
|
||||||
|
"ab" .. string.rep("\0", 188 - 2) .. "X\1")
|
||||||
local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz")
|
local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz")
|
||||||
assert(a == "abcdefghi" and b == "xyz" and c == 14)
|
assert(a == "abcdefghi" and b == "xyz" and c == 14)
|
||||||
checkerror("longer than", pack, "c3", "1234")
|
checkerror("longer than", pack, "c3", "1234")
|
||||||
|
|||||||
+8
-3
@@ -1,12 +1,17 @@
|
|||||||
-- track collections
|
-- track collections
|
||||||
|
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
-- import list
|
-- import list
|
||||||
local setmetatable, stderr, collectgarbage =
|
local stderr, collectgarbage = io.stderr, collectgarbage
|
||||||
setmetatable, io.stderr, collectgarbage
|
|
||||||
|
|
||||||
_ENV = nil
|
-- the debug version of setmetatable does not create any object (such as
|
||||||
|
-- a '__metatable' string), and so it is more appropriate to be used in
|
||||||
|
-- a finalizer
|
||||||
|
local setmetatable = require"debug".setmetatable
|
||||||
|
|
||||||
|
global none
|
||||||
|
|
||||||
local active = false
|
local active = false
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user