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 |
---|