[1803] | 1 | /* |
---|
| 2 | ** $Id: ltests.c,v 1.158 2003/04/07 14:35:00 roberto Exp $ |
---|
| 3 | ** Internal Module for Debugging of the Lua Implementation |
---|
| 4 | ** See Copyright Notice in lua.h |
---|
| 5 | */ |
---|
| 6 | |
---|
| 7 | |
---|
| 8 | #include <ctype.h> |
---|
| 9 | #include <limits.h> |
---|
| 10 | #include <stdio.h> |
---|
| 11 | #include <stdlib.h> |
---|
| 12 | #include <string.h> |
---|
| 13 | |
---|
| 14 | #define ltests_c |
---|
| 15 | |
---|
| 16 | #include "lua.h" |
---|
| 17 | |
---|
| 18 | #include "lapi.h" |
---|
| 19 | #include "lauxlib.h" |
---|
| 20 | #include "lcode.h" |
---|
| 21 | #include "ldebug.h" |
---|
| 22 | #include "ldo.h" |
---|
| 23 | #include "lfunc.h" |
---|
| 24 | #include "lmem.h" |
---|
| 25 | #include "lopcodes.h" |
---|
| 26 | #include "lstate.h" |
---|
| 27 | #include "lstring.h" |
---|
| 28 | #include "ltable.h" |
---|
| 29 | #include "lualib.h" |
---|
| 30 | |
---|
| 31 | |
---|
| 32 | |
---|
| 33 | /* |
---|
| 34 | ** The whole module only makes sense with LUA_DEBUG on |
---|
| 35 | */ |
---|
| 36 | #ifdef LUA_DEBUG |
---|
| 37 | |
---|
| 38 | |
---|
| 39 | #define lua_pushintegral(L,i) lua_pushnumber(L, cast(lua_Number, (i))) |
---|
| 40 | |
---|
| 41 | |
---|
| 42 | static lua_State *lua_state = NULL; |
---|
| 43 | |
---|
| 44 | int islocked = 0; |
---|
| 45 | |
---|
| 46 | |
---|
| 47 | #define func_at(L,k) (L->ci->base+(k) - 1) |
---|
| 48 | |
---|
| 49 | |
---|
| 50 | static void setnameval (lua_State *L, const char *name, int val) { |
---|
| 51 | lua_pushstring(L, name); |
---|
| 52 | lua_pushintegral(L, val); |
---|
| 53 | lua_settable(L, -3); |
---|
| 54 | } |
---|
| 55 | |
---|
| 56 | |
---|
| 57 | /* |
---|
| 58 | ** {====================================================================== |
---|
| 59 | ** Controlled version for realloc. |
---|
| 60 | ** ======================================================================= |
---|
| 61 | */ |
---|
| 62 | |
---|
| 63 | #define MARK 0x55 /* 01010101 (a nice pattern) */ |
---|
| 64 | |
---|
| 65 | #ifndef EXTERNMEMCHECK |
---|
| 66 | /* full memory check */ |
---|
| 67 | #define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ |
---|
| 68 | #define MARKSIZE 16 /* size of marks after each block */ |
---|
| 69 | #define blockhead(b) (cast(char *, b) - HEADER) |
---|
| 70 | #define setsize(newblock, size) (*cast(size_t *, newblock) = size) |
---|
| 71 | #define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b)))) |
---|
| 72 | #define fillmem(mem,size) memset(mem, -MARK, size) |
---|
| 73 | #else |
---|
| 74 | /* external memory check: don't do it twice */ |
---|
| 75 | #define HEADER 0 |
---|
| 76 | #define MARKSIZE 0 |
---|
| 77 | #define blockhead(b) (b) |
---|
| 78 | #define setsize(newblock, size) /* empty */ |
---|
| 79 | #define checkblocksize(b,size) (1) |
---|
| 80 | #define fillmem(mem,size) /* empty */ |
---|
| 81 | #endif |
---|
| 82 | |
---|
| 83 | unsigned long memdebug_numblocks = 0; |
---|
| 84 | unsigned long memdebug_total = 0; |
---|
| 85 | unsigned long memdebug_maxmem = 0; |
---|
| 86 | unsigned long memdebug_memlimit = ULONG_MAX; |
---|
| 87 | |
---|
| 88 | |
---|
| 89 | static void *checkblock (void *block, size_t size) { |
---|
| 90 | void *b = blockhead(block); |
---|
| 91 | int i; |
---|
| 92 | for (i=0;i<MARKSIZE;i++) |
---|
| 93 | lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */ |
---|
| 94 | return b; |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | |
---|
| 98 | static void freeblock (void *block, size_t size) { |
---|
| 99 | if (block) { |
---|
| 100 | lua_assert(checkblocksize(block, size)); |
---|
| 101 | block = checkblock(block, size); |
---|
| 102 | fillmem(block, size+HEADER+MARKSIZE); /* erase block */ |
---|
| 103 | free(block); /* free original block */ |
---|
| 104 | memdebug_numblocks--; |
---|
| 105 | memdebug_total -= size; |
---|
| 106 | } |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | |
---|
| 110 | void *debug_realloc (void *block, size_t oldsize, size_t size) { |
---|
| 111 | lua_assert(oldsize == 0 || checkblocksize(block, oldsize)); |
---|
| 112 | /* ISO does not specify what realloc(NULL, 0) does */ |
---|
| 113 | lua_assert(block != NULL || size > 0); |
---|
| 114 | if (size == 0) { |
---|
| 115 | freeblock(block, oldsize); |
---|
| 116 | return NULL; |
---|
| 117 | } |
---|
| 118 | else if (size > oldsize && memdebug_total+size-oldsize > memdebug_memlimit) |
---|
| 119 | return NULL; /* to test memory allocation errors */ |
---|
| 120 | else { |
---|
| 121 | void *newblock; |
---|
| 122 | int i; |
---|
| 123 | size_t realsize = HEADER+size+MARKSIZE; |
---|
| 124 | size_t commonsize = (oldsize < size) ? oldsize : size; |
---|
| 125 | if (realsize < size) return NULL; /* overflow! */ |
---|
| 126 | newblock = malloc(realsize); /* alloc a new block */ |
---|
| 127 | if (newblock == NULL) return NULL; |
---|
| 128 | if (block) { |
---|
| 129 | memcpy(cast(char *, newblock)+HEADER, block, commonsize); |
---|
| 130 | freeblock(block, oldsize); /* erase (and check) old copy */ |
---|
| 131 | } |
---|
| 132 | /* initialize new part of the block with something `weird' */ |
---|
| 133 | fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); |
---|
| 134 | memdebug_total += size; |
---|
| 135 | if (memdebug_total > memdebug_maxmem) |
---|
| 136 | memdebug_maxmem = memdebug_total; |
---|
| 137 | memdebug_numblocks++; |
---|
| 138 | setsize(newblock, size); |
---|
| 139 | for (i=0;i<MARKSIZE;i++) |
---|
| 140 | *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i); |
---|
| 141 | return cast(char *, newblock)+HEADER; |
---|
| 142 | } |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | |
---|
| 146 | /* }====================================================================== */ |
---|
| 147 | |
---|
| 148 | |
---|
| 149 | |
---|
| 150 | /* |
---|
| 151 | ** {====================================================== |
---|
| 152 | ** Disassembler |
---|
| 153 | ** ======================================================= |
---|
| 154 | */ |
---|
| 155 | |
---|
| 156 | |
---|
| 157 | static char *buildop (Proto *p, int pc, char *buff) { |
---|
| 158 | Instruction i = p->code[pc]; |
---|
| 159 | OpCode o = GET_OPCODE(i); |
---|
| 160 | const char *name = luaP_opnames[o]; |
---|
| 161 | int line = getline(p, pc); |
---|
| 162 | sprintf(buff, "(%4d) %4d - ", line, pc); |
---|
| 163 | switch (getOpMode(o)) { |
---|
| 164 | case iABC: |
---|
| 165 | sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, |
---|
| 166 | GETARG_A(i), GETARG_B(i), GETARG_C(i)); |
---|
| 167 | break; |
---|
| 168 | case iABx: |
---|
| 169 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); |
---|
| 170 | break; |
---|
| 171 | case iAsBx: |
---|
| 172 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); |
---|
| 173 | break; |
---|
| 174 | } |
---|
| 175 | return buff; |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | |
---|
| 179 | #if 0 |
---|
| 180 | void luaI_printcode (Proto *pt, int size) { |
---|
| 181 | int pc; |
---|
| 182 | for (pc=0; pc<size; pc++) { |
---|
| 183 | char buff[100]; |
---|
| 184 | printf("%s\n", buildop(pt, pc, buff)); |
---|
| 185 | } |
---|
| 186 | printf("-------\n"); |
---|
| 187 | } |
---|
| 188 | #endif |
---|
| 189 | |
---|
| 190 | |
---|
| 191 | static int listcode (lua_State *L) { |
---|
| 192 | int pc; |
---|
| 193 | Proto *p; |
---|
| 194 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), |
---|
| 195 | 1, "Lua function expected"); |
---|
| 196 | p = clvalue(func_at(L, 1))->l.p; |
---|
| 197 | lua_newtable(L); |
---|
| 198 | setnameval(L, "maxstack", p->maxstacksize); |
---|
| 199 | setnameval(L, "numparams", p->numparams); |
---|
| 200 | for (pc=0; pc<p->sizecode; pc++) { |
---|
| 201 | char buff[100]; |
---|
| 202 | lua_pushintegral(L, pc+1); |
---|
| 203 | lua_pushstring(L, buildop(p, pc, buff)); |
---|
| 204 | lua_settable(L, -3); |
---|
| 205 | } |
---|
| 206 | return 1; |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | |
---|
| 210 | static int listk (lua_State *L) { |
---|
| 211 | Proto *p; |
---|
| 212 | int i; |
---|
| 213 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), |
---|
| 214 | 1, "Lua function expected"); |
---|
| 215 | p = clvalue(func_at(L, 1))->l.p; |
---|
| 216 | lua_newtable(L); |
---|
| 217 | for (i=0; i<p->sizek; i++) { |
---|
| 218 | lua_pushintegral(L, i+1); |
---|
| 219 | luaA_pushobject(L, p->k+i); |
---|
| 220 | lua_settable(L, -3); |
---|
| 221 | } |
---|
| 222 | return 1; |
---|
| 223 | } |
---|
| 224 | |
---|
| 225 | |
---|
| 226 | static int listlocals (lua_State *L) { |
---|
| 227 | Proto *p; |
---|
| 228 | int pc = luaL_checkint(L, 2) - 1; |
---|
| 229 | int i = 0; |
---|
| 230 | const char *name; |
---|
| 231 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), |
---|
| 232 | 1, "Lua function expected"); |
---|
| 233 | p = clvalue(func_at(L, 1))->l.p; |
---|
| 234 | while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) |
---|
| 235 | lua_pushstring(L, name); |
---|
| 236 | return i-1; |
---|
| 237 | } |
---|
| 238 | |
---|
| 239 | /* }====================================================== */ |
---|
| 240 | |
---|
| 241 | |
---|
| 242 | |
---|
| 243 | |
---|
| 244 | static int get_limits (lua_State *L) { |
---|
| 245 | lua_newtable(L); |
---|
| 246 | setnameval(L, "BITS_INT", BITS_INT); |
---|
| 247 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); |
---|
| 248 | setnameval(L, "MAXVARS", MAXVARS); |
---|
| 249 | setnameval(L, "MAXPARAMS", MAXPARAMS); |
---|
| 250 | setnameval(L, "MAXSTACK", MAXSTACK); |
---|
| 251 | setnameval(L, "MAXUPVALUES", MAXUPVALUES); |
---|
| 252 | return 1; |
---|
| 253 | } |
---|
| 254 | |
---|
| 255 | |
---|
| 256 | static int mem_query (lua_State *L) { |
---|
| 257 | if (lua_isnone(L, 1)) { |
---|
| 258 | lua_pushintegral(L, memdebug_total); |
---|
| 259 | lua_pushintegral(L, memdebug_numblocks); |
---|
| 260 | lua_pushintegral(L, memdebug_maxmem); |
---|
| 261 | return 3; |
---|
| 262 | } |
---|
| 263 | else { |
---|
| 264 | memdebug_memlimit = luaL_checkint(L, 1); |
---|
| 265 | return 0; |
---|
| 266 | } |
---|
| 267 | } |
---|
| 268 | |
---|
| 269 | |
---|
| 270 | static int hash_query (lua_State *L) { |
---|
| 271 | if (lua_isnone(L, 2)) { |
---|
| 272 | luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); |
---|
| 273 | lua_pushintegral(L, tsvalue(func_at(L, 1))->tsv.hash); |
---|
| 274 | } |
---|
| 275 | else { |
---|
| 276 | TObject *o = func_at(L, 1); |
---|
| 277 | Table *t; |
---|
| 278 | luaL_checktype(L, 2, LUA_TTABLE); |
---|
| 279 | t = hvalue(func_at(L, 2)); |
---|
| 280 | lua_pushintegral(L, luaH_mainposition(t, o) - t->node); |
---|
| 281 | } |
---|
| 282 | return 1; |
---|
| 283 | } |
---|
| 284 | |
---|
| 285 | |
---|
| 286 | static int stacklevel (lua_State *L) { |
---|
| 287 | unsigned long a = 0; |
---|
| 288 | lua_pushintegral(L, (int)(L->top - L->stack)); |
---|
| 289 | lua_pushintegral(L, (int)(L->stack_last - L->stack)); |
---|
| 290 | lua_pushintegral(L, (int)(L->ci - L->base_ci)); |
---|
| 291 | lua_pushintegral(L, (int)(L->end_ci - L->base_ci)); |
---|
| 292 | lua_pushintegral(L, (unsigned long)&a); |
---|
| 293 | return 5; |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | |
---|
| 297 | static int table_query (lua_State *L) { |
---|
| 298 | const Table *t; |
---|
| 299 | int i = luaL_optint(L, 2, -1); |
---|
| 300 | luaL_checktype(L, 1, LUA_TTABLE); |
---|
| 301 | t = hvalue(func_at(L, 1)); |
---|
| 302 | if (i == -1) { |
---|
| 303 | lua_pushintegral(L, t->sizearray); |
---|
| 304 | lua_pushintegral(L, sizenode(t)); |
---|
| 305 | lua_pushintegral(L, t->firstfree - t->node); |
---|
| 306 | } |
---|
| 307 | else if (i < t->sizearray) { |
---|
| 308 | lua_pushintegral(L, i); |
---|
| 309 | luaA_pushobject(L, &t->array[i]); |
---|
| 310 | lua_pushnil(L); |
---|
| 311 | } |
---|
| 312 | else if ((i -= t->sizearray) < sizenode(t)) { |
---|
| 313 | if (!ttisnil(gval(gnode(t, i))) || |
---|
| 314 | ttisnil(gkey(gnode(t, i))) || |
---|
| 315 | ttisnumber(gkey(gnode(t, i)))) { |
---|
| 316 | luaA_pushobject(L, gkey(gnode(t, i))); |
---|
| 317 | } |
---|
| 318 | else |
---|
| 319 | lua_pushstring(L, "<undef>"); |
---|
| 320 | luaA_pushobject(L, gval(gnode(t, i))); |
---|
| 321 | if (t->node[i].next) |
---|
| 322 | lua_pushintegral(L, t->node[i].next - t->node); |
---|
| 323 | else |
---|
| 324 | lua_pushnil(L); |
---|
| 325 | } |
---|
| 326 | return 3; |
---|
| 327 | } |
---|
| 328 | |
---|
| 329 | |
---|
| 330 | static int string_query (lua_State *L) { |
---|
| 331 | stringtable *tb = &G(L)->strt; |
---|
| 332 | int s = luaL_optint(L, 2, 0) - 1; |
---|
| 333 | if (s==-1) { |
---|
| 334 | lua_pushintegral(L ,tb->nuse); |
---|
| 335 | lua_pushintegral(L ,tb->size); |
---|
| 336 | return 2; |
---|
| 337 | } |
---|
| 338 | else if (s < tb->size) { |
---|
| 339 | GCObject *ts; |
---|
| 340 | int n = 0; |
---|
| 341 | for (ts = tb->hash[s]; ts; ts = ts->gch.next) { |
---|
| 342 | setsvalue2s(L->top, gcotots(ts)); |
---|
| 343 | incr_top(L); |
---|
| 344 | n++; |
---|
| 345 | } |
---|
| 346 | return n; |
---|
| 347 | } |
---|
| 348 | return 0; |
---|
| 349 | } |
---|
| 350 | |
---|
| 351 | |
---|
| 352 | static int tref (lua_State *L) { |
---|
| 353 | int level = lua_gettop(L); |
---|
| 354 | int lock = luaL_optint(L, 2, 1); |
---|
| 355 | luaL_checkany(L, 1); |
---|
| 356 | lua_pushvalue(L, 1); |
---|
| 357 | lua_pushintegral(L, lua_ref(L, lock)); |
---|
| 358 | assert(lua_gettop(L) == level+1); /* +1 for result */ |
---|
| 359 | return 1; |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | static int getref (lua_State *L) { |
---|
| 363 | int level = lua_gettop(L); |
---|
| 364 | lua_getref(L, luaL_checkint(L, 1)); |
---|
| 365 | assert(lua_gettop(L) == level+1); |
---|
| 366 | return 1; |
---|
| 367 | } |
---|
| 368 | |
---|
| 369 | static int unref (lua_State *L) { |
---|
| 370 | int level = lua_gettop(L); |
---|
| 371 | lua_unref(L, luaL_checkint(L, 1)); |
---|
| 372 | assert(lua_gettop(L) == level); |
---|
| 373 | return 0; |
---|
| 374 | } |
---|
| 375 | |
---|
| 376 | static int metatable (lua_State *L) { |
---|
| 377 | luaL_checkany(L, 1); |
---|
| 378 | if (lua_isnone(L, 2)) { |
---|
| 379 | if (lua_getmetatable(L, 1) == 0) |
---|
| 380 | lua_pushnil(L); |
---|
| 381 | } |
---|
| 382 | else { |
---|
| 383 | lua_settop(L, 2); |
---|
| 384 | luaL_checktype(L, 2, LUA_TTABLE); |
---|
| 385 | lua_setmetatable(L, 1); |
---|
| 386 | } |
---|
| 387 | return 1; |
---|
| 388 | } |
---|
| 389 | |
---|
| 390 | |
---|
| 391 | static int upvalue (lua_State *L) { |
---|
| 392 | int n = luaL_checkint(L, 2); |
---|
| 393 | luaL_checktype(L, 1, LUA_TFUNCTION); |
---|
| 394 | if (lua_isnone(L, 3)) { |
---|
| 395 | const char *name = lua_getupvalue(L, 1, n); |
---|
| 396 | if (name == NULL) return 0; |
---|
| 397 | lua_pushstring(L, name); |
---|
| 398 | return 2; |
---|
| 399 | } |
---|
| 400 | else { |
---|
| 401 | const char *name = lua_setupvalue(L, 1, n); |
---|
| 402 | lua_pushstring(L, name); |
---|
| 403 | return 1; |
---|
| 404 | } |
---|
| 405 | } |
---|
| 406 | |
---|
| 407 | |
---|
| 408 | static int newuserdata (lua_State *L) { |
---|
| 409 | size_t size = luaL_checkint(L, 1); |
---|
| 410 | char *p = cast(char *, lua_newuserdata(L, size)); |
---|
| 411 | while (size--) *p++ = '\0'; |
---|
| 412 | return 1; |
---|
| 413 | } |
---|
| 414 | |
---|
| 415 | |
---|
| 416 | static int pushuserdata (lua_State *L) { |
---|
| 417 | lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1))); |
---|
| 418 | return 1; |
---|
| 419 | } |
---|
| 420 | |
---|
| 421 | |
---|
| 422 | static int udataval (lua_State *L) { |
---|
| 423 | lua_pushintegral(L, cast(int, lua_touserdata(L, 1))); |
---|
| 424 | return 1; |
---|
| 425 | } |
---|
| 426 | |
---|
| 427 | |
---|
| 428 | static int doonnewstack (lua_State *L) { |
---|
| 429 | lua_State *L1 = lua_newthread(L); |
---|
| 430 | size_t l; |
---|
| 431 | const char *s = luaL_checklstring(L, 1, &l); |
---|
| 432 | int status = luaL_loadbuffer(L1, s, l, s); |
---|
| 433 | if (status == 0) |
---|
| 434 | status = lua_pcall(L1, 0, 0, 0); |
---|
| 435 | lua_pushintegral(L, status); |
---|
| 436 | return 1; |
---|
| 437 | } |
---|
| 438 | |
---|
| 439 | |
---|
| 440 | static int s2d (lua_State *L) { |
---|
| 441 | lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); |
---|
| 442 | return 1; |
---|
| 443 | } |
---|
| 444 | |
---|
| 445 | static int d2s (lua_State *L) { |
---|
| 446 | double d = luaL_checknumber(L, 1); |
---|
| 447 | lua_pushlstring(L, cast(char *, &d), sizeof(d)); |
---|
| 448 | return 1; |
---|
| 449 | } |
---|
| 450 | |
---|
| 451 | |
---|
| 452 | static int newstate (lua_State *L) { |
---|
| 453 | lua_State *L1 = lua_open(); |
---|
| 454 | if (L1) { |
---|
| 455 | lua_userstateopen(L1); /* init lock */ |
---|
| 456 | lua_pushintegral(L, (unsigned long)L1); |
---|
| 457 | } |
---|
| 458 | else |
---|
| 459 | lua_pushnil(L); |
---|
| 460 | return 1; |
---|
| 461 | } |
---|
| 462 | |
---|
| 463 | |
---|
| 464 | static int loadlib (lua_State *L) { |
---|
| 465 | static const luaL_reg libs[] = { |
---|
| 466 | {"mathlibopen", luaopen_math}, |
---|
| 467 | {"strlibopen", luaopen_string}, |
---|
| 468 | {"iolibopen", luaopen_io}, |
---|
| 469 | {"tablibopen", luaopen_table}, |
---|
| 470 | {"dblibopen", luaopen_debug}, |
---|
| 471 | {"baselibopen", luaopen_base}, |
---|
| 472 | {NULL, NULL} |
---|
| 473 | }; |
---|
| 474 | lua_State *L1 = cast(lua_State *, |
---|
| 475 | cast(unsigned long, luaL_checknumber(L, 1))); |
---|
| 476 | lua_pushvalue(L1, LUA_GLOBALSINDEX); |
---|
| 477 | luaL_openlib(L1, NULL, libs, 0); |
---|
| 478 | return 0; |
---|
| 479 | } |
---|
| 480 | |
---|
| 481 | static int closestate (lua_State *L) { |
---|
| 482 | lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1))); |
---|
| 483 | lua_close(L1); |
---|
| 484 | lua_unlock(L); /* close cannot unlock that */ |
---|
| 485 | return 0; |
---|
| 486 | } |
---|
| 487 | |
---|
| 488 | static int doremote (lua_State *L) { |
---|
| 489 | lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1))); |
---|
| 490 | size_t lcode; |
---|
| 491 | const char *code = luaL_checklstring(L, 2, &lcode); |
---|
| 492 | int status; |
---|
| 493 | lua_settop(L1, 0); |
---|
| 494 | status = luaL_loadbuffer(L1, code, lcode, code); |
---|
| 495 | if (status == 0) |
---|
| 496 | status = lua_pcall(L1, 0, LUA_MULTRET, 0); |
---|
| 497 | if (status != 0) { |
---|
| 498 | lua_pushnil(L); |
---|
| 499 | lua_pushintegral(L, status); |
---|
| 500 | lua_pushstring(L, lua_tostring(L1, -1)); |
---|
| 501 | return 3; |
---|
| 502 | } |
---|
| 503 | else { |
---|
| 504 | int i = 0; |
---|
| 505 | while (!lua_isnone(L1, ++i)) |
---|
| 506 | lua_pushstring(L, lua_tostring(L1, i)); |
---|
| 507 | lua_pop(L1, i-1); |
---|
| 508 | return i-1; |
---|
| 509 | } |
---|
| 510 | } |
---|
| 511 | |
---|
| 512 | |
---|
| 513 | static int log2_aux (lua_State *L) { |
---|
| 514 | lua_pushintegral(L, luaO_log2(luaL_checkint(L, 1))); |
---|
| 515 | return 1; |
---|
| 516 | } |
---|
| 517 | |
---|
| 518 | static int int2fb_aux (lua_State *L) { |
---|
| 519 | int b = luaO_int2fb(luaL_checkint(L, 1)); |
---|
| 520 | lua_pushintegral(L, b); |
---|
| 521 | lua_pushintegral(L, fb2int(b)); |
---|
| 522 | return 2; |
---|
| 523 | } |
---|
| 524 | |
---|
| 525 | |
---|
| 526 | static int test_do (lua_State *L) { |
---|
| 527 | const char *p = luaL_checkstring(L, 1); |
---|
| 528 | if (*p == '@') |
---|
| 529 | lua_dofile(L, p+1); |
---|
| 530 | else |
---|
| 531 | lua_dostring(L, p); |
---|
| 532 | return lua_gettop(L); |
---|
| 533 | } |
---|
| 534 | |
---|
| 535 | |
---|
| 536 | |
---|
| 537 | /* |
---|
| 538 | ** {====================================================== |
---|
| 539 | ** function to test the API with C. It interprets a kind of assembler |
---|
| 540 | ** language with calls to the API, so the test can be driven by Lua code |
---|
| 541 | ** ======================================================= |
---|
| 542 | */ |
---|
| 543 | |
---|
| 544 | static const char *const delimits = " \t\n,;"; |
---|
| 545 | |
---|
| 546 | static void skip (const char **pc) { |
---|
| 547 | while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; |
---|
| 548 | } |
---|
| 549 | |
---|
| 550 | static int getnum_aux (lua_State *L, const char **pc) { |
---|
| 551 | int res = 0; |
---|
| 552 | int sig = 1; |
---|
| 553 | skip(pc); |
---|
| 554 | if (**pc == '.') { |
---|
| 555 | res = cast(int, lua_tonumber(L, -1)); |
---|
| 556 | lua_pop(L, 1); |
---|
| 557 | (*pc)++; |
---|
| 558 | return res; |
---|
| 559 | } |
---|
| 560 | else if (**pc == '-') { |
---|
| 561 | sig = -1; |
---|
| 562 | (*pc)++; |
---|
| 563 | } |
---|
| 564 | while (isdigit(cast(int, **pc))) res = res*10 + (*(*pc)++) - '0'; |
---|
| 565 | return sig*res; |
---|
| 566 | } |
---|
| 567 | |
---|
| 568 | static const char *getname_aux (char *buff, const char **pc) { |
---|
| 569 | int i = 0; |
---|
| 570 | skip(pc); |
---|
| 571 | while (**pc != '\0' && !strchr(delimits, **pc)) |
---|
| 572 | buff[i++] = *(*pc)++; |
---|
| 573 | buff[i] = '\0'; |
---|
| 574 | return buff; |
---|
| 575 | } |
---|
| 576 | |
---|
| 577 | |
---|
| 578 | #define EQ(s1) (strcmp(s1, inst) == 0) |
---|
| 579 | |
---|
| 580 | #define getnum (getnum_aux(L, &pc)) |
---|
| 581 | #define getname (getname_aux(buff, &pc)) |
---|
| 582 | |
---|
| 583 | |
---|
| 584 | static int testC (lua_State *L) { |
---|
| 585 | char buff[30]; |
---|
| 586 | const char *pc = luaL_checkstring(L, 1); |
---|
| 587 | for (;;) { |
---|
| 588 | const char *inst = getname; |
---|
| 589 | if EQ("") return 0; |
---|
| 590 | else if EQ("isnumber") { |
---|
| 591 | lua_pushintegral(L, lua_isnumber(L, getnum)); |
---|
| 592 | } |
---|
| 593 | else if EQ("isstring") { |
---|
| 594 | lua_pushintegral(L, lua_isstring(L, getnum)); |
---|
| 595 | } |
---|
| 596 | else if EQ("istable") { |
---|
| 597 | lua_pushintegral(L, lua_istable(L, getnum)); |
---|
| 598 | } |
---|
| 599 | else if EQ("iscfunction") { |
---|
| 600 | lua_pushintegral(L, lua_iscfunction(L, getnum)); |
---|
| 601 | } |
---|
| 602 | else if EQ("isfunction") { |
---|
| 603 | lua_pushintegral(L, lua_isfunction(L, getnum)); |
---|
| 604 | } |
---|
| 605 | else if EQ("isuserdata") { |
---|
| 606 | lua_pushintegral(L, lua_isuserdata(L, getnum)); |
---|
| 607 | } |
---|
| 608 | else if EQ("isudataval") { |
---|
| 609 | lua_pushintegral(L, lua_islightuserdata(L, getnum)); |
---|
| 610 | } |
---|
| 611 | else if EQ("isnil") { |
---|
| 612 | lua_pushintegral(L, lua_isnil(L, getnum)); |
---|
| 613 | } |
---|
| 614 | else if EQ("isnull") { |
---|
| 615 | lua_pushintegral(L, lua_isnone(L, getnum)); |
---|
| 616 | } |
---|
| 617 | else if EQ("tonumber") { |
---|
| 618 | lua_pushnumber(L, lua_tonumber(L, getnum)); |
---|
| 619 | } |
---|
| 620 | else if EQ("tostring") { |
---|
| 621 | const char *s = lua_tostring(L, getnum); |
---|
| 622 | lua_pushstring(L, s); |
---|
| 623 | } |
---|
| 624 | else if EQ("strlen") { |
---|
| 625 | lua_pushintegral(L, lua_strlen(L, getnum)); |
---|
| 626 | } |
---|
| 627 | else if EQ("tocfunction") { |
---|
| 628 | lua_pushcfunction(L, lua_tocfunction(L, getnum)); |
---|
| 629 | } |
---|
| 630 | else if EQ("return") { |
---|
| 631 | return getnum; |
---|
| 632 | } |
---|
| 633 | else if EQ("gettop") { |
---|
| 634 | lua_pushintegral(L, lua_gettop(L)); |
---|
| 635 | } |
---|
| 636 | else if EQ("settop") { |
---|
| 637 | lua_settop(L, getnum); |
---|
| 638 | } |
---|
| 639 | else if EQ("pop") { |
---|
| 640 | lua_pop(L, getnum); |
---|
| 641 | } |
---|
| 642 | else if EQ("pushnum") { |
---|
| 643 | lua_pushintegral(L, getnum); |
---|
| 644 | } |
---|
| 645 | else if EQ("pushnil") { |
---|
| 646 | lua_pushnil(L); |
---|
| 647 | } |
---|
| 648 | else if EQ("pushbool") { |
---|
| 649 | lua_pushboolean(L, getnum); |
---|
| 650 | } |
---|
| 651 | else if EQ("tobool") { |
---|
| 652 | lua_pushintegral(L, lua_toboolean(L, getnum)); |
---|
| 653 | } |
---|
| 654 | else if EQ("pushvalue") { |
---|
| 655 | lua_pushvalue(L, getnum); |
---|
| 656 | } |
---|
| 657 | else if EQ("pushcclosure") { |
---|
| 658 | lua_pushcclosure(L, testC, getnum); |
---|
| 659 | } |
---|
| 660 | else if EQ("pushupvalues") { |
---|
| 661 | lua_pushupvalues(L); |
---|
| 662 | } |
---|
| 663 | else if EQ("remove") { |
---|
| 664 | lua_remove(L, getnum); |
---|
| 665 | } |
---|
| 666 | else if EQ("insert") { |
---|
| 667 | lua_insert(L, getnum); |
---|
| 668 | } |
---|
| 669 | else if EQ("replace") { |
---|
| 670 | lua_replace(L, getnum); |
---|
| 671 | } |
---|
| 672 | else if EQ("gettable") { |
---|
| 673 | lua_gettable(L, getnum); |
---|
| 674 | } |
---|
| 675 | else if EQ("settable") { |
---|
| 676 | lua_settable(L, getnum); |
---|
| 677 | } |
---|
| 678 | else if EQ("next") { |
---|
| 679 | lua_next(L, -2); |
---|
| 680 | } |
---|
| 681 | else if EQ("concat") { |
---|
| 682 | lua_concat(L, getnum); |
---|
| 683 | } |
---|
| 684 | else if EQ("lessthan") { |
---|
| 685 | int a = getnum; |
---|
| 686 | lua_pushboolean(L, lua_lessthan(L, a, getnum)); |
---|
| 687 | } |
---|
| 688 | else if EQ("equal") { |
---|
| 689 | int a = getnum; |
---|
| 690 | lua_pushboolean(L, lua_equal(L, a, getnum)); |
---|
| 691 | } |
---|
| 692 | else if EQ("rawcall") { |
---|
| 693 | int narg = getnum; |
---|
| 694 | int nres = getnum; |
---|
| 695 | lua_call(L, narg, nres); |
---|
| 696 | } |
---|
| 697 | else if EQ("call") { |
---|
| 698 | int narg = getnum; |
---|
| 699 | int nres = getnum; |
---|
| 700 | lua_pcall(L, narg, nres, 0); |
---|
| 701 | } |
---|
| 702 | else if EQ("loadstring") { |
---|
| 703 | size_t sl; |
---|
| 704 | const char *s = luaL_checklstring(L, getnum, &sl); |
---|
| 705 | luaL_loadbuffer(L, s, sl, s); |
---|
| 706 | } |
---|
| 707 | else if EQ("loadfile") { |
---|
| 708 | luaL_loadfile(L, luaL_checkstring(L, getnum)); |
---|
| 709 | } |
---|
| 710 | else if EQ("setmetatable") { |
---|
| 711 | lua_setmetatable(L, getnum); |
---|
| 712 | } |
---|
| 713 | else if EQ("getmetatable") { |
---|
| 714 | if (lua_getmetatable(L, getnum) == 0) |
---|
| 715 | lua_pushnil(L); |
---|
| 716 | } |
---|
| 717 | else if EQ("type") { |
---|
| 718 | lua_pushstring(L, lua_typename(L, lua_type(L, getnum))); |
---|
| 719 | } |
---|
| 720 | else if EQ("getn") { |
---|
| 721 | int i = getnum; |
---|
| 722 | lua_pushintegral(L, luaL_getn(L, i)); |
---|
| 723 | } |
---|
| 724 | else if EQ("setn") { |
---|
| 725 | int i = getnum; |
---|
| 726 | int n = cast(int, lua_tonumber(L, -1)); |
---|
| 727 | luaL_setn(L, i, n); |
---|
| 728 | lua_pop(L, 1); |
---|
| 729 | } |
---|
| 730 | else luaL_error(L, "unknown instruction %s", buff); |
---|
| 731 | } |
---|
| 732 | return 0; |
---|
| 733 | } |
---|
| 734 | |
---|
| 735 | /* }====================================================== */ |
---|
| 736 | |
---|
| 737 | |
---|
| 738 | /* |
---|
| 739 | ** {====================================================== |
---|
| 740 | ** tests for yield inside hooks |
---|
| 741 | ** ======================================================= |
---|
| 742 | */ |
---|
| 743 | |
---|
| 744 | static void yieldf (lua_State *L, lua_Debug *ar) { |
---|
| 745 | lua_yield(L, 0); |
---|
| 746 | } |
---|
| 747 | |
---|
| 748 | static int setyhook (lua_State *L) { |
---|
| 749 | if (lua_isnoneornil(L, 1)) |
---|
| 750 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ |
---|
| 751 | else { |
---|
| 752 | const char *smask = luaL_checkstring(L, 1); |
---|
| 753 | int count = luaL_optint(L, 2, 0); |
---|
| 754 | int mask = 0; |
---|
| 755 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; |
---|
| 756 | if (count > 0) mask |= LUA_MASKCOUNT; |
---|
| 757 | lua_sethook(L, yieldf, mask, count); |
---|
| 758 | } |
---|
| 759 | return 0; |
---|
| 760 | } |
---|
| 761 | |
---|
| 762 | |
---|
| 763 | static int coresume (lua_State *L) { |
---|
| 764 | int status; |
---|
| 765 | lua_State *co = lua_tothread(L, 1); |
---|
| 766 | luaL_argcheck(L, co, 1, "coroutine expected"); |
---|
| 767 | status = lua_resume(co, 0); |
---|
| 768 | if (status != 0) { |
---|
| 769 | lua_pushboolean(L, 0); |
---|
| 770 | lua_insert(L, -2); |
---|
| 771 | return 2; /* return false + error message */ |
---|
| 772 | } |
---|
| 773 | else { |
---|
| 774 | lua_pushboolean(L, 1); |
---|
| 775 | return 1; |
---|
| 776 | } |
---|
| 777 | } |
---|
| 778 | |
---|
| 779 | /* }====================================================== */ |
---|
| 780 | |
---|
| 781 | |
---|
| 782 | |
---|
| 783 | static const struct luaL_reg tests_funcs[] = { |
---|
| 784 | {"hash", hash_query}, |
---|
| 785 | {"limits", get_limits}, |
---|
| 786 | {"listcode", listcode}, |
---|
| 787 | {"listk", listk}, |
---|
| 788 | {"listlocals", listlocals}, |
---|
| 789 | {"loadlib", loadlib}, |
---|
| 790 | {"stacklevel", stacklevel}, |
---|
| 791 | {"querystr", string_query}, |
---|
| 792 | {"querytab", table_query}, |
---|
| 793 | {"doit", test_do}, |
---|
| 794 | {"testC", testC}, |
---|
| 795 | {"ref", tref}, |
---|
| 796 | {"getref", getref}, |
---|
| 797 | {"unref", unref}, |
---|
| 798 | {"d2s", d2s}, |
---|
| 799 | {"s2d", s2d}, |
---|
| 800 | {"metatable", metatable}, |
---|
| 801 | {"upvalue", upvalue}, |
---|
| 802 | {"newuserdata", newuserdata}, |
---|
| 803 | {"pushuserdata", pushuserdata}, |
---|
| 804 | {"udataval", udataval}, |
---|
| 805 | {"doonnewstack", doonnewstack}, |
---|
| 806 | {"newstate", newstate}, |
---|
| 807 | {"closestate", closestate}, |
---|
| 808 | {"doremote", doremote}, |
---|
| 809 | {"log2", log2_aux}, |
---|
| 810 | {"int2fb", int2fb_aux}, |
---|
| 811 | {"totalmem", mem_query}, |
---|
| 812 | {"resume", coresume}, |
---|
| 813 | {"setyhook", setyhook}, |
---|
| 814 | {NULL, NULL} |
---|
| 815 | }; |
---|
| 816 | |
---|
| 817 | |
---|
| 818 | static void fim (void) { |
---|
| 819 | if (!islocked) |
---|
| 820 | lua_close(lua_state); |
---|
| 821 | lua_assert(memdebug_numblocks == 0); |
---|
| 822 | lua_assert(memdebug_total == 0); |
---|
| 823 | } |
---|
| 824 | |
---|
| 825 | |
---|
| 826 | static int l_panic (lua_State *L) { |
---|
| 827 | UNUSED(L); |
---|
| 828 | fprintf(stderr, "unable to recover; exiting\n"); |
---|
| 829 | return 0; |
---|
| 830 | } |
---|
| 831 | |
---|
| 832 | |
---|
| 833 | int luaB_opentests (lua_State *L) { |
---|
| 834 | lua_atpanic(L, l_panic); |
---|
| 835 | lua_userstateopen(L); /* init lock */ |
---|
| 836 | lua_state = L; /* keep first state to be opened */ |
---|
| 837 | luaL_openlib(L, "T", tests_funcs, 0); |
---|
| 838 | atexit(fim); |
---|
| 839 | return 0; |
---|
| 840 | } |
---|
| 841 | |
---|
| 842 | |
---|
| 843 | #undef main |
---|
| 844 | int main (int argc, char *argv[]) { |
---|
| 845 | char *limit = getenv("MEMLIMIT"); |
---|
| 846 | if (limit) |
---|
| 847 | memdebug_memlimit = strtoul(limit, NULL, 10); |
---|
| 848 | l_main(argc, argv); |
---|
| 849 | return 0; |
---|
| 850 | } |
---|
| 851 | |
---|
| 852 | #endif |
---|