diff options
Diffstat (limited to 'ltests.c')
-rw-r--r-- | ltests.c | 1506 |
1 files changed, 1506 insertions, 0 deletions
diff --git a/ltests.c b/ltests.c new file mode 100644 index 00000000..ff62cbe6 --- /dev/null +++ b/ltests.c | |||
@@ -0,0 +1,1506 @@ | |||
1 | /* | ||
2 | ** $Id: ltests.c,v 2.135 2013/03/16 21:10:18 roberto Exp $ | ||
3 | ** Internal Module for Debugging of the Lua Implementation | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <limits.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | |||
13 | #define ltests_c | ||
14 | #define LUA_CORE | ||
15 | |||
16 | #include "lua.h" | ||
17 | |||
18 | #include "lapi.h" | ||
19 | #include "lauxlib.h" | ||
20 | #include "lcode.h" | ||
21 | #include "lctype.h" | ||
22 | #include "ldebug.h" | ||
23 | #include "ldo.h" | ||
24 | #include "lfunc.h" | ||
25 | #include "lmem.h" | ||
26 | #include "lopcodes.h" | ||
27 | #include "lstate.h" | ||
28 | #include "lstring.h" | ||
29 | #include "ltable.h" | ||
30 | #include "lualib.h" | ||
31 | |||
32 | |||
33 | |||
34 | /* | ||
35 | ** The whole module only makes sense with LUA_DEBUG on | ||
36 | */ | ||
37 | #if defined(LUA_DEBUG) | ||
38 | |||
39 | |||
40 | void *l_Trick = 0; | ||
41 | |||
42 | |||
43 | int islocked = 0; | ||
44 | |||
45 | |||
46 | #define obj_at(L,k) (L->ci->func + (k)) | ||
47 | |||
48 | |||
49 | static void setnameval (lua_State *L, const char *name, int val) { | ||
50 | lua_pushstring(L, name); | ||
51 | lua_pushinteger(L, val); | ||
52 | lua_settable(L, -3); | ||
53 | } | ||
54 | |||
55 | |||
56 | static void pushobject (lua_State *L, const TValue *o) { | ||
57 | setobj2s(L, L->top, o); | ||
58 | api_incr_top(L); | ||
59 | } | ||
60 | |||
61 | |||
62 | static int tpanic (lua_State *L) { | ||
63 | fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", | ||
64 | lua_tostring(L, -1)); | ||
65 | return (exit(EXIT_FAILURE), 0); /* do not return to Lua */ | ||
66 | } | ||
67 | |||
68 | |||
69 | /* | ||
70 | ** {====================================================================== | ||
71 | ** Controlled version for realloc. | ||
72 | ** ======================================================================= | ||
73 | */ | ||
74 | |||
75 | #define MARK 0x55 /* 01010101 (a nice pattern) */ | ||
76 | |||
77 | typedef union Header { | ||
78 | L_Umaxalign a; /* ensures maximum alignment for Header */ | ||
79 | struct { | ||
80 | size_t size; | ||
81 | int type; | ||
82 | } d; | ||
83 | } Header; | ||
84 | |||
85 | |||
86 | #if !defined(EXTERNMEMCHECK) | ||
87 | |||
88 | /* full memory check */ | ||
89 | #define MARKSIZE 16 /* size of marks after each block */ | ||
90 | #define fillmem(mem,size) memset(mem, -MARK, size) | ||
91 | |||
92 | #else | ||
93 | |||
94 | /* external memory check: don't do it twice */ | ||
95 | #define MARKSIZE 0 | ||
96 | #define fillmem(mem,size) /* empty */ | ||
97 | |||
98 | #endif | ||
99 | |||
100 | |||
101 | Memcontrol l_memcontrol = | ||
102 | {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; | ||
103 | |||
104 | |||
105 | static void freeblock (Memcontrol *mc, Header *block) { | ||
106 | if (block) { | ||
107 | size_t size = block->d.size; | ||
108 | int i; | ||
109 | for (i = 0; i < MARKSIZE; i++) /* check marks after block */ | ||
110 | lua_assert(*(cast(char *, block + 1) + size + i) == MARK); | ||
111 | mc->objcount[block->d.type]--; | ||
112 | fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ | ||
113 | free(block); /* actually free block */ | ||
114 | mc->numblocks--; /* update counts */ | ||
115 | mc->total -= size; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | |||
120 | void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { | ||
121 | Memcontrol *mc = cast(Memcontrol *, ud); | ||
122 | Header *block = cast(Header *, b); | ||
123 | int type; | ||
124 | if (mc->memlimit == 0) { /* first time? */ | ||
125 | char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ | ||
126 | mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; | ||
127 | } | ||
128 | if (block == NULL) { | ||
129 | type = (oldsize < LUA_NUMTAGS) ? oldsize : 0; | ||
130 | oldsize = 0; | ||
131 | } | ||
132 | else { | ||
133 | block--; /* go to real header */ | ||
134 | type = block->d.type; | ||
135 | lua_assert(oldsize == block->d.size); | ||
136 | } | ||
137 | if (size == 0) { | ||
138 | freeblock(mc, block); | ||
139 | return NULL; | ||
140 | } | ||
141 | else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) | ||
142 | return NULL; /* fake a memory allocation error */ | ||
143 | else { | ||
144 | Header *newblock; | ||
145 | int i; | ||
146 | size_t commonsize = (oldsize < size) ? oldsize : size; | ||
147 | size_t realsize = sizeof(Header) + size + MARKSIZE; | ||
148 | if (realsize < size) return NULL; /* arithmetic overflow! */ | ||
149 | newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ | ||
150 | if (newblock == NULL) return NULL; /* really out of memory? */ | ||
151 | if (block) { | ||
152 | memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ | ||
153 | freeblock(mc, block); /* erase (and check) old copy */ | ||
154 | } | ||
155 | /* initialize new part of the block with something `weird' */ | ||
156 | fillmem(cast(char *, newblock + 1) + commonsize, size - commonsize); | ||
157 | /* initialize marks after block */ | ||
158 | for (i = 0; i < MARKSIZE; i++) | ||
159 | *(cast(char *, newblock + 1) + size + i) = MARK; | ||
160 | newblock->d.size = size; | ||
161 | newblock->d.type = type; | ||
162 | mc->total += size; | ||
163 | if (mc->total > mc->maxmem) | ||
164 | mc->maxmem = mc->total; | ||
165 | mc->numblocks++; | ||
166 | mc->objcount[type]++; | ||
167 | return newblock + 1; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | |||
172 | /* }====================================================================== */ | ||
173 | |||
174 | |||
175 | |||
176 | /* | ||
177 | ** {====================================================== | ||
178 | ** Functions to check memory consistency | ||
179 | ** ======================================================= | ||
180 | */ | ||
181 | |||
182 | |||
183 | static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | ||
184 | if (isdead(g,t)) return 0; | ||
185 | if (!issweepphase(g)) | ||
186 | return !(isblack(f) && iswhite(t)); | ||
187 | else return 1; | ||
188 | } | ||
189 | |||
190 | |||
191 | static void printobj (global_State *g, GCObject *o) { | ||
192 | int i = 1; | ||
193 | GCObject *p; | ||
194 | for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++; | ||
195 | if (p == NULL) { | ||
196 | i = 1; | ||
197 | for (p = g->finobj; p != o && p != NULL; p = gch(p)->next) i++; | ||
198 | if (p == NULL) i = 0; /* zero means 'not found' */ | ||
199 | else i = -i; /* negative means 'found in findobj list */ | ||
200 | } | ||
201 | printf("||%d:%s(%p)-%c(%02X)||", i, ttypename(gch(o)->tt), (void *)o, | ||
202 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked); | ||
203 | } | ||
204 | |||
205 | |||
206 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { | ||
207 | int r = testobjref1(g,f,t); | ||
208 | if (!r) { | ||
209 | printf("%d(%02X) - ", g->gcstate, g->currentwhite); | ||
210 | printobj(g, f); | ||
211 | printf("\t-> "); | ||
212 | printobj(g, t); | ||
213 | printf("\n"); | ||
214 | } | ||
215 | return r; | ||
216 | } | ||
217 | |||
218 | #define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t))) | ||
219 | |||
220 | |||
221 | static void checkvalref (global_State *g, GCObject *f, const TValue *t) { | ||
222 | if (iscollectable(t)) { | ||
223 | lua_assert(righttt(t)); | ||
224 | lua_assert(testobjref(g, f, gcvalue(t))); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | |||
229 | static void checktable (global_State *g, Table *h) { | ||
230 | int i; | ||
231 | Node *n, *limit = gnode(h, sizenode(h)); | ||
232 | GCObject *hgc = obj2gco(h); | ||
233 | if (h->metatable) | ||
234 | checkobjref(g, hgc, h->metatable); | ||
235 | for (i = 0; i < h->sizearray; i++) | ||
236 | checkvalref(g, hgc, &h->array[i]); | ||
237 | for (n = gnode(h, 0); n < limit; n++) { | ||
238 | if (!ttisnil(gval(n))) { | ||
239 | lua_assert(!ttisnil(gkey(n))); | ||
240 | checkvalref(g, hgc, gkey(n)); | ||
241 | checkvalref(g, hgc, gval(n)); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | |||
247 | /* | ||
248 | ** All marks are conditional because a GC may happen while the | ||
249 | ** prototype is still being created | ||
250 | */ | ||
251 | static void checkproto (global_State *g, Proto *f) { | ||
252 | int i; | ||
253 | GCObject *fgc = obj2gco(f); | ||
254 | if (f->source) checkobjref(g, fgc, f->source); | ||
255 | for (i=0; i<f->sizek; i++) { | ||
256 | if (ttisstring(f->k+i)) | ||
257 | checkobjref(g, fgc, rawtsvalue(f->k+i)); | ||
258 | } | ||
259 | for (i=0; i<f->sizeupvalues; i++) { | ||
260 | if (f->upvalues[i].name) | ||
261 | checkobjref(g, fgc, f->upvalues[i].name); | ||
262 | } | ||
263 | for (i=0; i<f->sizep; i++) { | ||
264 | if (f->p[i]) | ||
265 | checkobjref(g, fgc, f->p[i]); | ||
266 | } | ||
267 | for (i=0; i<f->sizelocvars; i++) { | ||
268 | if (f->locvars[i].varname) | ||
269 | checkobjref(g, fgc, f->locvars[i].varname); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | |||
274 | |||
275 | static void checkCclosure (global_State *g, CClosure *cl) { | ||
276 | GCObject *clgc = obj2gco(cl); | ||
277 | int i; | ||
278 | for (i = 0; i < cl->nupvalues; i++) | ||
279 | checkvalref(g, clgc, &cl->upvalue[i]); | ||
280 | } | ||
281 | |||
282 | |||
283 | static void checkLclosure (global_State *g, LClosure *cl) { | ||
284 | GCObject *clgc = obj2gco(cl); | ||
285 | int i; | ||
286 | if (cl->p) checkobjref(g, clgc, cl->p); | ||
287 | for (i=0; i<cl->nupvalues; i++) { | ||
288 | if (cl->upvals[i]) { | ||
289 | lua_assert(cl->upvals[i]->tt == LUA_TUPVAL); | ||
290 | checkobjref(g, clgc, cl->upvals[i]); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | |||
296 | static int lua_checkpc (pCallInfo ci) { | ||
297 | if (!isLua(ci)) return 1; | ||
298 | else { | ||
299 | Proto *p = ci_func(ci)->p; | ||
300 | return p->code <= ci->u.l.savedpc && | ||
301 | ci->u.l.savedpc <= p->code + p->sizecode; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | |||
306 | static void checkstack (global_State *g, lua_State *L1) { | ||
307 | StkId o; | ||
308 | CallInfo *ci; | ||
309 | GCObject *uvo; | ||
310 | lua_assert(!isdead(g, obj2gco(L1))); | ||
311 | for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) { | ||
312 | UpVal *uv = gco2uv(uvo); | ||
313 | lua_assert(uv->v != &uv->u.value); /* must be open */ | ||
314 | lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ | ||
315 | } | ||
316 | for (ci = L1->ci; ci != NULL; ci = ci->previous) { | ||
317 | lua_assert(ci->top <= L1->stack_last); | ||
318 | lua_assert(lua_checkpc(ci)); | ||
319 | } | ||
320 | if (L1->stack) { | ||
321 | for (o = L1->stack; o < L1->top; o++) | ||
322 | checkliveness(g, o); | ||
323 | } | ||
324 | else lua_assert(L1->stacksize == 0); | ||
325 | } | ||
326 | |||
327 | |||
328 | static void checkobject (global_State *g, GCObject *o, int maybedead) { | ||
329 | if (isdead(g, o)) | ||
330 | lua_assert(maybedead); | ||
331 | else { | ||
332 | if (g->gcstate == GCSpause) | ||
333 | lua_assert(iswhite(o)); | ||
334 | switch (gch(o)->tt) { | ||
335 | case LUA_TUPVAL: { | ||
336 | UpVal *uv = gco2uv(o); | ||
337 | lua_assert(uv->v == &uv->u.value); /* must be closed */ | ||
338 | lua_assert(!isgray(o)); /* closed upvalues are never gray */ | ||
339 | checkvalref(g, o, uv->v); | ||
340 | break; | ||
341 | } | ||
342 | case LUA_TUSERDATA: { | ||
343 | Table *mt = gco2u(o)->metatable; | ||
344 | if (mt) checkobjref(g, o, mt); | ||
345 | break; | ||
346 | } | ||
347 | case LUA_TTABLE: { | ||
348 | checktable(g, gco2t(o)); | ||
349 | break; | ||
350 | } | ||
351 | case LUA_TTHREAD: { | ||
352 | checkstack(g, gco2th(o)); | ||
353 | break; | ||
354 | } | ||
355 | case LUA_TLCL: { | ||
356 | checkLclosure(g, gco2lcl(o)); | ||
357 | break; | ||
358 | } | ||
359 | case LUA_TCCL: { | ||
360 | checkCclosure(g, gco2ccl(o)); | ||
361 | break; | ||
362 | } | ||
363 | case LUA_TPROTO: { | ||
364 | checkproto(g, gco2p(o)); | ||
365 | break; | ||
366 | } | ||
367 | case LUA_TSHRSTR: | ||
368 | case LUA_TLNGSTR: break; | ||
369 | default: lua_assert(0); | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | |||
375 | #define TESTGRAYBIT 7 | ||
376 | |||
377 | static void checkgraylist (GCObject *l) { | ||
378 | while (l) { | ||
379 | lua_assert(isgray(l)); | ||
380 | lua_assert(!testbit(l->gch.marked, TESTGRAYBIT)); | ||
381 | l_setbit(l->gch.marked, TESTGRAYBIT); | ||
382 | switch (gch(l)->tt) { | ||
383 | case LUA_TTABLE: l = gco2t(l)->gclist; break; | ||
384 | case LUA_TLCL: l = gco2lcl(l)->gclist; break; | ||
385 | case LUA_TCCL: l = gco2ccl(l)->gclist; break; | ||
386 | case LUA_TTHREAD: l = gco2th(l)->gclist; break; | ||
387 | case LUA_TPROTO: l = gco2p(l)->gclist; break; | ||
388 | default: lua_assert(0); /* other objects cannot be gray */ | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
393 | |||
394 | /* | ||
395 | ** mark all objects in gray lists with the TESTGRAYBIT, so that | ||
396 | ** 'checkmemory' can check that all gray objects are in a gray list | ||
397 | */ | ||
398 | static void markgrays (global_State *g) { | ||
399 | if (!keepinvariant(g)) return; | ||
400 | checkgraylist(g->gray); | ||
401 | checkgraylist(g->grayagain); | ||
402 | checkgraylist(g->weak); | ||
403 | checkgraylist(g->ephemeron); | ||
404 | checkgraylist(g->allweak); | ||
405 | } | ||
406 | |||
407 | |||
408 | static void checkold (global_State *g, GCObject *o) { | ||
409 | int isold = 0; | ||
410 | for (; o != NULL; o = gch(o)->next) { | ||
411 | if (isold(o)) { /* old generation? */ | ||
412 | lua_assert(isgenerational(g)); | ||
413 | if (!issweepphase(g)) | ||
414 | isold = 1; | ||
415 | } | ||
416 | else lua_assert(!isold); /* non-old object cannot be after an old one */ | ||
417 | if (isgray(o)) { | ||
418 | lua_assert(!keepinvariant(g) || testbit(o->gch.marked, TESTGRAYBIT)); | ||
419 | resetbit(o->gch.marked, TESTGRAYBIT); | ||
420 | } | ||
421 | lua_assert(!testbit(o->gch.marked, TESTGRAYBIT)); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | |||
426 | int lua_checkmemory (lua_State *L) { | ||
427 | global_State *g = G(L); | ||
428 | GCObject *o; | ||
429 | UpVal *uv; | ||
430 | int maybedead; | ||
431 | if (keepinvariant(g)) { | ||
432 | lua_assert(!iswhite(obj2gco(g->mainthread))); | ||
433 | lua_assert(!iswhite(gcvalue(&g->l_registry))); | ||
434 | } | ||
435 | else /* generational mode keeps collector in 'propagate' state */ | ||
436 | lua_assert(!isgenerational(g)); | ||
437 | lua_assert(!isdead(g, gcvalue(&g->l_registry))); | ||
438 | checkstack(g, g->mainthread); | ||
439 | resetbit(g->mainthread->marked, TESTGRAYBIT); | ||
440 | /* check 'allgc' list */ | ||
441 | markgrays(g); | ||
442 | checkold(g, g->allgc); | ||
443 | lua_assert(g->sweepgc == NULL || issweepphase(g)); | ||
444 | maybedead = 0; | ||
445 | for (o = g->allgc; o != NULL; o = gch(o)->next) { | ||
446 | if (g->sweepgc && o == *g->sweepgc) | ||
447 | maybedead = 1; /* part of the list not yet swept */ | ||
448 | checkobject(g, o, maybedead); | ||
449 | lua_assert(!testbit(o->gch.marked, SEPARATED)); | ||
450 | } | ||
451 | /* check 'finobj' list */ | ||
452 | checkold(g, g->finobj); | ||
453 | for (o = g->finobj; o != NULL; o = gch(o)->next) { | ||
454 | lua_assert(testbit(o->gch.marked, SEPARATED)); | ||
455 | lua_assert(gch(o)->tt == LUA_TUSERDATA || | ||
456 | gch(o)->tt == LUA_TTABLE); | ||
457 | checkobject(g, o, 0); | ||
458 | } | ||
459 | /* check 'tobefnz' list */ | ||
460 | checkold(g, g->tobefnz); | ||
461 | for (o = g->tobefnz; o != NULL; o = gch(o)->next) { | ||
462 | lua_assert(!iswhite(o) || g->gcstate == GCSpause); | ||
463 | lua_assert(!isdead(g, o) && testbit(o->gch.marked, SEPARATED)); | ||
464 | lua_assert(gch(o)->tt == LUA_TUSERDATA || | ||
465 | gch(o)->tt == LUA_TTABLE); | ||
466 | } | ||
467 | /* check 'uvhead' list */ | ||
468 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | ||
469 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||
470 | lua_assert(uv->v != &uv->u.value); /* must be open */ | ||
471 | lua_assert(!isblack(obj2gco(uv))); /* open upvalues are never black */ | ||
472 | if (!isdead(g, obj2gco(uv))) | ||
473 | checkvalref(g, obj2gco(uv), uv->v); | ||
474 | } | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | /* }====================================================== */ | ||
479 | |||
480 | |||
481 | |||
482 | /* | ||
483 | ** {====================================================== | ||
484 | ** Disassembler | ||
485 | ** ======================================================= | ||
486 | */ | ||
487 | |||
488 | |||
489 | static char *buildop (Proto *p, int pc, char *buff) { | ||
490 | Instruction i = p->code[pc]; | ||
491 | OpCode o = GET_OPCODE(i); | ||
492 | const char *name = luaP_opnames[o]; | ||
493 | int line = getfuncline(p, pc); | ||
494 | sprintf(buff, "(%4d) %4d - ", line, pc); | ||
495 | switch (getOpMode(o)) { | ||
496 | case iABC: | ||
497 | sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, | ||
498 | GETARG_A(i), GETARG_B(i), GETARG_C(i)); | ||
499 | break; | ||
500 | case iABx: | ||
501 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); | ||
502 | break; | ||
503 | case iAsBx: | ||
504 | sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); | ||
505 | break; | ||
506 | case iAx: | ||
507 | sprintf(buff+strlen(buff), "%-12s%4d", name, GETARG_Ax(i)); | ||
508 | break; | ||
509 | } | ||
510 | return buff; | ||
511 | } | ||
512 | |||
513 | |||
514 | #if 0 | ||
515 | void luaI_printcode (Proto *pt, int size) { | ||
516 | int pc; | ||
517 | for (pc=0; pc<size; pc++) { | ||
518 | char buff[100]; | ||
519 | printf("%s\n", buildop(pt, pc, buff)); | ||
520 | } | ||
521 | printf("-------\n"); | ||
522 | } | ||
523 | |||
524 | |||
525 | void luaI_printinst (Proto *pt, int pc) { | ||
526 | char buff[100]; | ||
527 | printf("%s\n", buildop(pt, pc, buff)); | ||
528 | } | ||
529 | #endif | ||
530 | |||
531 | |||
532 | static int listcode (lua_State *L) { | ||
533 | int pc; | ||
534 | Proto *p; | ||
535 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
536 | 1, "Lua function expected"); | ||
537 | p = getproto(obj_at(L, 1)); | ||
538 | lua_newtable(L); | ||
539 | setnameval(L, "maxstack", p->maxstacksize); | ||
540 | setnameval(L, "numparams", p->numparams); | ||
541 | for (pc=0; pc<p->sizecode; pc++) { | ||
542 | char buff[100]; | ||
543 | lua_pushinteger(L, pc+1); | ||
544 | lua_pushstring(L, buildop(p, pc, buff)); | ||
545 | lua_settable(L, -3); | ||
546 | } | ||
547 | return 1; | ||
548 | } | ||
549 | |||
550 | |||
551 | static int listk (lua_State *L) { | ||
552 | Proto *p; | ||
553 | int i; | ||
554 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
555 | 1, "Lua function expected"); | ||
556 | p = getproto(obj_at(L, 1)); | ||
557 | lua_createtable(L, p->sizek, 0); | ||
558 | for (i=0; i<p->sizek; i++) { | ||
559 | pushobject(L, p->k+i); | ||
560 | lua_rawseti(L, -2, i+1); | ||
561 | } | ||
562 | return 1; | ||
563 | } | ||
564 | |||
565 | |||
566 | static int listlocals (lua_State *L) { | ||
567 | Proto *p; | ||
568 | int pc = luaL_checkint(L, 2) - 1; | ||
569 | int i = 0; | ||
570 | const char *name; | ||
571 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
572 | 1, "Lua function expected"); | ||
573 | p = getproto(obj_at(L, 1)); | ||
574 | while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) | ||
575 | lua_pushstring(L, name); | ||
576 | return i-1; | ||
577 | } | ||
578 | |||
579 | /* }====================================================== */ | ||
580 | |||
581 | |||
582 | |||
583 | |||
584 | static int get_limits (lua_State *L) { | ||
585 | lua_createtable(L, 0, 5); | ||
586 | setnameval(L, "BITS_INT", LUAI_BITSINT); | ||
587 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); | ||
588 | setnameval(L, "MAXSTACK", MAXSTACK); | ||
589 | setnameval(L, "NUM_OPCODES", NUM_OPCODES); | ||
590 | return 1; | ||
591 | } | ||
592 | |||
593 | |||
594 | static int mem_query (lua_State *L) { | ||
595 | if (lua_isnone(L, 1)) { | ||
596 | lua_pushinteger(L, l_memcontrol.total); | ||
597 | lua_pushinteger(L, l_memcontrol.numblocks); | ||
598 | lua_pushinteger(L, l_memcontrol.maxmem); | ||
599 | return 3; | ||
600 | } | ||
601 | else if (lua_isnumber(L, 1)) { | ||
602 | l_memcontrol.memlimit = luaL_checkint(L, 1); | ||
603 | return 0; | ||
604 | } | ||
605 | else { | ||
606 | const char *t = luaL_checkstring(L, 1); | ||
607 | int i; | ||
608 | for (i = LUA_NUMTAGS - 1; i >= 0; i--) { | ||
609 | if (strcmp(t, ttypename(i)) == 0) { | ||
610 | lua_pushinteger(L, l_memcontrol.objcount[i]); | ||
611 | return 1; | ||
612 | } | ||
613 | } | ||
614 | return luaL_error(L, "unkown type '%s'", t); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | |||
619 | static int settrick (lua_State *L) { | ||
620 | if (ttisnil(obj_at(L, 1))) | ||
621 | l_Trick = NULL; | ||
622 | else | ||
623 | l_Trick = gcvalue(obj_at(L, 1)); | ||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | |||
628 | static int get_gccolor (lua_State *L) { | ||
629 | TValue *o; | ||
630 | luaL_checkany(L, 1); | ||
631 | o = obj_at(L, 1); | ||
632 | if (!iscollectable(o)) | ||
633 | lua_pushstring(L, "no collectable"); | ||
634 | else { | ||
635 | int marked = gcvalue(o)->gch.marked; | ||
636 | int n = 1; | ||
637 | lua_pushstring(L, iswhite(gcvalue(o)) ? "white" : | ||
638 | isblack(gcvalue(o)) ? "black" : "grey"); | ||
639 | if (testbit(marked, FINALIZEDBIT)) { | ||
640 | lua_pushliteral(L, "/finalized"); n++; | ||
641 | } | ||
642 | if (testbit(marked, SEPARATED)) { | ||
643 | lua_pushliteral(L, "/separated"); n++; | ||
644 | } | ||
645 | if (testbit(marked, FIXEDBIT)) { | ||
646 | lua_pushliteral(L, "/fixed"); n++; | ||
647 | } | ||
648 | if (testbit(marked, OLDBIT)) { | ||
649 | lua_pushliteral(L, "/old"); n++; | ||
650 | } | ||
651 | lua_concat(L, n); | ||
652 | } | ||
653 | return 1; | ||
654 | } | ||
655 | |||
656 | |||
657 | static int gc_state (lua_State *L) { | ||
658 | static const char *statenames[] = {"propagate", "atomic", | ||
659 | "sweepstring", "sweepudata", "sweep", "pause", ""}; | ||
660 | int option = luaL_checkoption(L, 1, "", statenames); | ||
661 | if (option == GCSpause + 1) { | ||
662 | lua_pushstring(L, statenames[G(L)->gcstate]); | ||
663 | return 1; | ||
664 | } | ||
665 | else { | ||
666 | global_State *g = G(L); | ||
667 | if (g->gckind == KGC_GEN && option == GCSpause) | ||
668 | luaL_error(L, "cannot go to 'pause' state in generational mode"); | ||
669 | lua_lock(L); | ||
670 | if (option < g->gcstate) { /* must cross 'pause'? */ | ||
671 | luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ | ||
672 | if (g->gckind == KGC_GEN) | ||
673 | g->gcstate = GCSpropagate; /* skip pause in gen. mode */ | ||
674 | } | ||
675 | luaC_runtilstate(L, bitmask(option)); | ||
676 | lua_assert(G(L)->gcstate == option); | ||
677 | lua_unlock(L); | ||
678 | return 0; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | |||
683 | static int hash_query (lua_State *L) { | ||
684 | if (lua_isnone(L, 2)) { | ||
685 | luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); | ||
686 | lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash); | ||
687 | } | ||
688 | else { | ||
689 | TValue *o = obj_at(L, 1); | ||
690 | Table *t; | ||
691 | luaL_checktype(L, 2, LUA_TTABLE); | ||
692 | t = hvalue(obj_at(L, 2)); | ||
693 | lua_pushinteger(L, luaH_mainposition(t, o) - t->node); | ||
694 | } | ||
695 | return 1; | ||
696 | } | ||
697 | |||
698 | |||
699 | static int stacklevel (lua_State *L) { | ||
700 | unsigned long a = 0; | ||
701 | lua_pushinteger(L, (L->top - L->stack)); | ||
702 | lua_pushinteger(L, (L->stack_last - L->stack)); | ||
703 | lua_pushinteger(L, (unsigned long)&a); | ||
704 | return 5; | ||
705 | } | ||
706 | |||
707 | |||
708 | static int table_query (lua_State *L) { | ||
709 | const Table *t; | ||
710 | int i = luaL_optint(L, 2, -1); | ||
711 | luaL_checktype(L, 1, LUA_TTABLE); | ||
712 | t = hvalue(obj_at(L, 1)); | ||
713 | if (i == -1) { | ||
714 | lua_pushinteger(L, t->sizearray); | ||
715 | lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t)); | ||
716 | lua_pushinteger(L, t->lastfree - t->node); | ||
717 | } | ||
718 | else if (i < t->sizearray) { | ||
719 | lua_pushinteger(L, i); | ||
720 | pushobject(L, &t->array[i]); | ||
721 | lua_pushnil(L); | ||
722 | } | ||
723 | else if ((i -= t->sizearray) < sizenode(t)) { | ||
724 | if (!ttisnil(gval(gnode(t, i))) || | ||
725 | ttisnil(gkey(gnode(t, i))) || | ||
726 | ttisnumber(gkey(gnode(t, i)))) { | ||
727 | pushobject(L, gkey(gnode(t, i))); | ||
728 | } | ||
729 | else | ||
730 | lua_pushliteral(L, "<undef>"); | ||
731 | pushobject(L, gval(gnode(t, i))); | ||
732 | if (gnext(&t->node[i])) | ||
733 | lua_pushinteger(L, gnext(&t->node[i]) - t->node); | ||
734 | else | ||
735 | lua_pushnil(L); | ||
736 | } | ||
737 | return 3; | ||
738 | } | ||
739 | |||
740 | |||
741 | static int string_query (lua_State *L) { | ||
742 | stringtable *tb = &G(L)->strt; | ||
743 | int s = luaL_optint(L, 2, 0) - 1; | ||
744 | if (s==-1) { | ||
745 | lua_pushinteger(L ,tb->nuse); | ||
746 | lua_pushinteger(L ,tb->size); | ||
747 | return 2; | ||
748 | } | ||
749 | else if (s < tb->size) { | ||
750 | GCObject *ts; | ||
751 | int n = 0; | ||
752 | for (ts = tb->hash[s]; ts; ts = gch(ts)->next) { | ||
753 | setsvalue2s(L, L->top, rawgco2ts(ts)); | ||
754 | api_incr_top(L); | ||
755 | n++; | ||
756 | } | ||
757 | return n; | ||
758 | } | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | |||
763 | static int tref (lua_State *L) { | ||
764 | int level = lua_gettop(L); | ||
765 | luaL_checkany(L, 1); | ||
766 | lua_pushvalue(L, 1); | ||
767 | lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); | ||
768 | lua_assert(lua_gettop(L) == level+1); /* +1 for result */ | ||
769 | return 1; | ||
770 | } | ||
771 | |||
772 | static int getref (lua_State *L) { | ||
773 | int level = lua_gettop(L); | ||
774 | lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkint(L, 1)); | ||
775 | lua_assert(lua_gettop(L) == level+1); | ||
776 | return 1; | ||
777 | } | ||
778 | |||
779 | static int unref (lua_State *L) { | ||
780 | int level = lua_gettop(L); | ||
781 | luaL_unref(L, LUA_REGISTRYINDEX, luaL_checkint(L, 1)); | ||
782 | lua_assert(lua_gettop(L) == level); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | |||
787 | static int upvalue (lua_State *L) { | ||
788 | int n = luaL_checkint(L, 2); | ||
789 | luaL_checktype(L, 1, LUA_TFUNCTION); | ||
790 | if (lua_isnone(L, 3)) { | ||
791 | const char *name = lua_getupvalue(L, 1, n); | ||
792 | if (name == NULL) return 0; | ||
793 | lua_pushstring(L, name); | ||
794 | return 2; | ||
795 | } | ||
796 | else { | ||
797 | const char *name = lua_setupvalue(L, 1, n); | ||
798 | lua_pushstring(L, name); | ||
799 | return 1; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | |||
804 | static int newuserdata (lua_State *L) { | ||
805 | size_t size = luaL_checkint(L, 1); | ||
806 | char *p = cast(char *, lua_newuserdata(L, size)); | ||
807 | while (size--) *p++ = '\0'; | ||
808 | return 1; | ||
809 | } | ||
810 | |||
811 | |||
812 | static int pushuserdata (lua_State *L) { | ||
813 | lua_pushlightuserdata(L, cast(void *, luaL_checkinteger(L, 1))); | ||
814 | return 1; | ||
815 | } | ||
816 | |||
817 | |||
818 | static int udataval (lua_State *L) { | ||
819 | lua_pushinteger(L, cast(long, lua_touserdata(L, 1))); | ||
820 | return 1; | ||
821 | } | ||
822 | |||
823 | |||
824 | static int doonnewstack (lua_State *L) { | ||
825 | lua_State *L1 = lua_newthread(L); | ||
826 | size_t l; | ||
827 | const char *s = luaL_checklstring(L, 1, &l); | ||
828 | int status = luaL_loadbuffer(L1, s, l, s); | ||
829 | if (status == LUA_OK) | ||
830 | status = lua_pcall(L1, 0, 0, 0); | ||
831 | lua_pushinteger(L, status); | ||
832 | return 1; | ||
833 | } | ||
834 | |||
835 | |||
836 | static int s2d (lua_State *L) { | ||
837 | lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); | ||
838 | return 1; | ||
839 | } | ||
840 | |||
841 | |||
842 | static int d2s (lua_State *L) { | ||
843 | double d = luaL_checknumber(L, 1); | ||
844 | lua_pushlstring(L, cast(char *, &d), sizeof(d)); | ||
845 | return 1; | ||
846 | } | ||
847 | |||
848 | |||
849 | static int num2int (lua_State *L) { | ||
850 | lua_pushinteger(L, lua_tointeger(L, 1)); | ||
851 | return 1; | ||
852 | } | ||
853 | |||
854 | |||
855 | static int newstate (lua_State *L) { | ||
856 | void *ud; | ||
857 | lua_Alloc f = lua_getallocf(L, &ud); | ||
858 | lua_State *L1 = lua_newstate(f, ud); | ||
859 | if (L1) { | ||
860 | lua_atpanic(L1, tpanic); | ||
861 | lua_pushlightuserdata(L, L1); | ||
862 | } | ||
863 | else | ||
864 | lua_pushnil(L); | ||
865 | return 1; | ||
866 | } | ||
867 | |||
868 | |||
869 | static lua_State *getstate (lua_State *L) { | ||
870 | lua_State *L1 = cast(lua_State *, lua_touserdata(L, 1)); | ||
871 | luaL_argcheck(L, L1 != NULL, 1, "state expected"); | ||
872 | return L1; | ||
873 | } | ||
874 | |||
875 | |||
876 | static int loadlib (lua_State *L) { | ||
877 | static const luaL_Reg libs[] = { | ||
878 | {"_G", luaopen_base}, | ||
879 | {"coroutine", luaopen_coroutine}, | ||
880 | {"debug", luaopen_debug}, | ||
881 | {"io", luaopen_io}, | ||
882 | {"os", luaopen_os}, | ||
883 | {"math", luaopen_math}, | ||
884 | {"string", luaopen_string}, | ||
885 | {"table", luaopen_table}, | ||
886 | {NULL, NULL} | ||
887 | }; | ||
888 | lua_State *L1 = getstate(L); | ||
889 | int i; | ||
890 | luaL_requiref(L1, "package", luaopen_package, 1); | ||
891 | luaL_getsubtable(L1, LUA_REGISTRYINDEX, "_PRELOAD"); | ||
892 | for (i = 0; libs[i].name; i++) { | ||
893 | lua_pushcfunction(L1, libs[i].func); | ||
894 | lua_setfield(L1, -2, libs[i].name); | ||
895 | } | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | static int closestate (lua_State *L) { | ||
900 | lua_State *L1 = getstate(L); | ||
901 | lua_close(L1); | ||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | static int doremote (lua_State *L) { | ||
906 | lua_State *L1 = getstate(L); | ||
907 | size_t lcode; | ||
908 | const char *code = luaL_checklstring(L, 2, &lcode); | ||
909 | int status; | ||
910 | lua_settop(L1, 0); | ||
911 | status = luaL_loadbuffer(L1, code, lcode, code); | ||
912 | if (status == LUA_OK) | ||
913 | status = lua_pcall(L1, 0, LUA_MULTRET, 0); | ||
914 | if (status != LUA_OK) { | ||
915 | lua_pushnil(L); | ||
916 | lua_pushstring(L, lua_tostring(L1, -1)); | ||
917 | lua_pushinteger(L, status); | ||
918 | return 3; | ||
919 | } | ||
920 | else { | ||
921 | int i = 0; | ||
922 | while (!lua_isnone(L1, ++i)) | ||
923 | lua_pushstring(L, lua_tostring(L1, i)); | ||
924 | lua_pop(L1, i-1); | ||
925 | return i-1; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | |||
930 | static int int2fb_aux (lua_State *L) { | ||
931 | int b = luaO_int2fb(luaL_checkint(L, 1)); | ||
932 | lua_pushinteger(L, b); | ||
933 | lua_pushinteger(L, luaO_fb2int(b)); | ||
934 | return 2; | ||
935 | } | ||
936 | |||
937 | |||
938 | |||
939 | /* | ||
940 | ** {====================================================== | ||
941 | ** function to test the API with C. It interprets a kind of assembler | ||
942 | ** language with calls to the API, so the test can be driven by Lua code | ||
943 | ** ======================================================= | ||
944 | */ | ||
945 | |||
946 | |||
947 | static void sethookaux (lua_State *L, int mask, int count, const char *code); | ||
948 | |||
949 | static const char *const delimits = " \t\n,;"; | ||
950 | |||
951 | static void skip (const char **pc) { | ||
952 | for (;;) { | ||
953 | if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; | ||
954 | else if (**pc == '#') { | ||
955 | while (**pc != '\n' && **pc != '\0') (*pc)++; | ||
956 | } | ||
957 | else break; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) { | ||
962 | int res = 0; | ||
963 | int sig = 1; | ||
964 | skip(pc); | ||
965 | if (**pc == '.') { | ||
966 | res = lua_tointeger(L1, -1); | ||
967 | lua_pop(L1, 1); | ||
968 | (*pc)++; | ||
969 | return res; | ||
970 | } | ||
971 | else if (**pc == '-') { | ||
972 | sig = -1; | ||
973 | (*pc)++; | ||
974 | } | ||
975 | if (!lisdigit(cast_uchar(**pc))) | ||
976 | luaL_error(L, "number expected (%s)", *pc); | ||
977 | while (lisdigit(cast_uchar(**pc))) res = res*10 + (*(*pc)++) - '0'; | ||
978 | return sig*res; | ||
979 | } | ||
980 | |||
981 | static const char *getstring_aux (lua_State *L, char *buff, const char **pc) { | ||
982 | int i = 0; | ||
983 | skip(pc); | ||
984 | if (**pc == '"' || **pc == '\'') { /* quoted string? */ | ||
985 | int quote = *(*pc)++; | ||
986 | while (**pc != quote) { | ||
987 | if (**pc == '\0') luaL_error(L, "unfinished string in C script"); | ||
988 | buff[i++] = *(*pc)++; | ||
989 | } | ||
990 | (*pc)++; | ||
991 | } | ||
992 | else { | ||
993 | while (**pc != '\0' && !strchr(delimits, **pc)) | ||
994 | buff[i++] = *(*pc)++; | ||
995 | } | ||
996 | buff[i] = '\0'; | ||
997 | return buff; | ||
998 | } | ||
999 | |||
1000 | |||
1001 | static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) { | ||
1002 | skip(pc); | ||
1003 | switch (*(*pc)++) { | ||
1004 | case 'R': return LUA_REGISTRYINDEX; | ||
1005 | case 'G': return luaL_error(L, "deprecated index 'G'"); | ||
1006 | case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc)); | ||
1007 | default: (*pc)--; return getnum_aux(L, L1, pc); | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | static void pushcode (lua_State *L, int code) { | ||
1013 | static const char *const codes[] = {"OK", "YIELD", "ERRRUN", | ||
1014 | "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"}; | ||
1015 | lua_pushstring(L, codes[code]); | ||
1016 | } | ||
1017 | |||
1018 | |||
1019 | #define EQ(s1) (strcmp(s1, inst) == 0) | ||
1020 | |||
1021 | #define getnum (getnum_aux(L, L1, &pc)) | ||
1022 | #define getstring (getstring_aux(L, buff, &pc)) | ||
1023 | #define getindex (getindex_aux(L, L1, &pc)) | ||
1024 | |||
1025 | |||
1026 | static int testC (lua_State *L); | ||
1027 | static int Cfunck (lua_State *L); | ||
1028 | |||
1029 | static int runC (lua_State *L, lua_State *L1, const char *pc) { | ||
1030 | char buff[300]; | ||
1031 | int status = 0; | ||
1032 | if (pc == NULL) return luaL_error(L, "attempt to runC null script"); | ||
1033 | for (;;) { | ||
1034 | const char *inst = getstring; | ||
1035 | if EQ("") return 0; | ||
1036 | else if EQ("absindex") { | ||
1037 | lua_pushnumber(L1, lua_absindex(L1, getindex)); | ||
1038 | } | ||
1039 | else if EQ("isnumber") { | ||
1040 | lua_pushboolean(L1, lua_isnumber(L1, getindex)); | ||
1041 | } | ||
1042 | else if EQ("isstring") { | ||
1043 | lua_pushboolean(L1, lua_isstring(L1, getindex)); | ||
1044 | } | ||
1045 | else if EQ("istable") { | ||
1046 | lua_pushboolean(L1, lua_istable(L1, getindex)); | ||
1047 | } | ||
1048 | else if EQ("iscfunction") { | ||
1049 | lua_pushboolean(L1, lua_iscfunction(L1, getindex)); | ||
1050 | } | ||
1051 | else if EQ("isfunction") { | ||
1052 | lua_pushboolean(L1, lua_isfunction(L1, getindex)); | ||
1053 | } | ||
1054 | else if EQ("isuserdata") { | ||
1055 | lua_pushboolean(L1, lua_isuserdata(L1, getindex)); | ||
1056 | } | ||
1057 | else if EQ("isudataval") { | ||
1058 | lua_pushboolean(L1, lua_islightuserdata(L1, getindex)); | ||
1059 | } | ||
1060 | else if EQ("isnil") { | ||
1061 | lua_pushboolean(L1, lua_isnil(L1, getindex)); | ||
1062 | } | ||
1063 | else if EQ("isnull") { | ||
1064 | lua_pushboolean(L1, lua_isnone(L1, getindex)); | ||
1065 | } | ||
1066 | else if EQ("tonumber") { | ||
1067 | lua_pushnumber(L1, lua_tonumber(L1, getindex)); | ||
1068 | } | ||
1069 | else if EQ("topointer") { | ||
1070 | lua_pushnumber(L1, cast(size_t, lua_topointer(L1, getindex))); | ||
1071 | } | ||
1072 | else if EQ("tostring") { | ||
1073 | const char *s = lua_tostring(L1, getindex); | ||
1074 | const char *s1 = lua_pushstring(L1, s); | ||
1075 | lua_assert((s == NULL && s1 == NULL) || (strcmp)(s, s1) == 0); | ||
1076 | } | ||
1077 | else if EQ("objsize") { | ||
1078 | lua_pushinteger(L1, lua_rawlen(L1, getindex)); | ||
1079 | } | ||
1080 | else if EQ("len") { | ||
1081 | lua_len(L1, getindex); | ||
1082 | } | ||
1083 | else if EQ("Llen") { | ||
1084 | lua_pushinteger(L1, luaL_len(L1, getindex)); | ||
1085 | } | ||
1086 | else if EQ("tocfunction") { | ||
1087 | lua_pushcfunction(L1, lua_tocfunction(L1, getindex)); | ||
1088 | } | ||
1089 | else if EQ("func2num") { | ||
1090 | lua_CFunction func = lua_tocfunction(L1, getindex); | ||
1091 | lua_pushnumber(L1, cast(size_t, func)); | ||
1092 | } | ||
1093 | else if EQ("return") { | ||
1094 | int n = getnum; | ||
1095 | if (L1 != L) { | ||
1096 | int i; | ||
1097 | for (i = 0; i < n; i++) | ||
1098 | lua_pushstring(L, lua_tostring(L1, -(n - i))); | ||
1099 | } | ||
1100 | return n; | ||
1101 | } | ||
1102 | else if EQ("gettop") { | ||
1103 | lua_pushinteger(L1, lua_gettop(L1)); | ||
1104 | } | ||
1105 | else if EQ("settop") { | ||
1106 | lua_settop(L1, getnum); | ||
1107 | } | ||
1108 | else if EQ("pop") { | ||
1109 | lua_pop(L1, getnum); | ||
1110 | } | ||
1111 | else if EQ("pushnum") { | ||
1112 | lua_pushinteger(L1, getnum); | ||
1113 | } | ||
1114 | else if EQ("pushstring") { | ||
1115 | lua_pushstring(L1, getstring); | ||
1116 | } | ||
1117 | else if EQ("pushnil") { | ||
1118 | lua_pushnil(L1); | ||
1119 | } | ||
1120 | else if EQ("pushbool") { | ||
1121 | lua_pushboolean(L1, getnum); | ||
1122 | } | ||
1123 | else if EQ("newtable") { | ||
1124 | lua_newtable(L1); | ||
1125 | } | ||
1126 | else if EQ("newuserdata") { | ||
1127 | lua_newuserdata(L1, getnum); | ||
1128 | } | ||
1129 | else if EQ("tobool") { | ||
1130 | lua_pushboolean(L1, lua_toboolean(L1, getindex)); | ||
1131 | } | ||
1132 | else if EQ("pushvalue") { | ||
1133 | lua_pushvalue(L1, getindex); | ||
1134 | } | ||
1135 | else if EQ("pushcclosure") { | ||
1136 | lua_pushcclosure(L1, testC, getnum); | ||
1137 | } | ||
1138 | else if EQ("pushupvalueindex") { | ||
1139 | lua_pushinteger(L1, lua_upvalueindex(getnum)); | ||
1140 | } | ||
1141 | else if EQ("remove") { | ||
1142 | lua_remove(L1, getnum); | ||
1143 | } | ||
1144 | else if EQ("insert") { | ||
1145 | lua_insert(L1, getnum); | ||
1146 | } | ||
1147 | else if EQ("replace") { | ||
1148 | lua_replace(L1, getindex); | ||
1149 | } | ||
1150 | else if EQ("copy") { | ||
1151 | int f = getindex; | ||
1152 | lua_copy(L1, f, getindex); | ||
1153 | } | ||
1154 | else if EQ("gettable") { | ||
1155 | lua_gettable(L1, getindex); | ||
1156 | } | ||
1157 | else if EQ("getglobal") { | ||
1158 | lua_getglobal(L1, getstring); | ||
1159 | } | ||
1160 | else if EQ("getfield") { | ||
1161 | int t = getindex; | ||
1162 | lua_getfield(L1, t, getstring); | ||
1163 | } | ||
1164 | else if EQ("setfield") { | ||
1165 | int t = getindex; | ||
1166 | lua_setfield(L1, t, getstring); | ||
1167 | } | ||
1168 | else if EQ("rawgeti") { | ||
1169 | int t = getindex; | ||
1170 | lua_rawgeti(L1, t, getnum); | ||
1171 | } | ||
1172 | else if EQ("settable") { | ||
1173 | lua_settable(L1, getindex); | ||
1174 | } | ||
1175 | else if EQ("setglobal") { | ||
1176 | lua_setglobal(L1, getstring); | ||
1177 | } | ||
1178 | else if EQ("next") { | ||
1179 | lua_next(L1, -2); | ||
1180 | } | ||
1181 | else if EQ("concat") { | ||
1182 | lua_concat(L1, getnum); | ||
1183 | } | ||
1184 | else if EQ("print") { | ||
1185 | int n = getnum; | ||
1186 | if (n != 0) { | ||
1187 | printf("%s\n", luaL_tolstring(L1, n, NULL)); | ||
1188 | lua_pop(L1, 1); | ||
1189 | } | ||
1190 | else { | ||
1191 | int i; | ||
1192 | n = lua_gettop(L1); | ||
1193 | for (i = 1; i <= n; i++) { | ||
1194 | printf("%s ", luaL_tolstring(L1, i, NULL)); | ||
1195 | lua_pop(L1, 1); | ||
1196 | } | ||
1197 | printf("\n"); | ||
1198 | } | ||
1199 | } | ||
1200 | else if EQ("arith") { | ||
1201 | static char ops[] = "+-*/%^_"; | ||
1202 | int op; | ||
1203 | skip(&pc); | ||
1204 | op = strchr(ops, *pc++) - ops; | ||
1205 | lua_arith(L1, op); | ||
1206 | } | ||
1207 | else if EQ("compare") { | ||
1208 | int a = getindex; | ||
1209 | int b = getindex; | ||
1210 | lua_pushboolean(L1, lua_compare(L1, a, b, getnum)); | ||
1211 | } | ||
1212 | else if EQ("call") { | ||
1213 | int narg = getnum; | ||
1214 | int nres = getnum; | ||
1215 | lua_call(L1, narg, nres); | ||
1216 | } | ||
1217 | else if EQ("pcall") { | ||
1218 | int narg = getnum; | ||
1219 | int nres = getnum; | ||
1220 | status = lua_pcall(L1, narg, nres, 0); | ||
1221 | } | ||
1222 | else if EQ("pcallk") { | ||
1223 | int narg = getnum; | ||
1224 | int nres = getnum; | ||
1225 | int i = getindex; | ||
1226 | status = lua_pcallk(L1, narg, nres, 0, i, Cfunck); | ||
1227 | } | ||
1228 | else if EQ("callk") { | ||
1229 | int narg = getnum; | ||
1230 | int nres = getnum; | ||
1231 | int i = getindex; | ||
1232 | lua_callk(L1, narg, nres, i, Cfunck); | ||
1233 | } | ||
1234 | else if EQ("yield") { | ||
1235 | return lua_yield(L1, getnum); | ||
1236 | } | ||
1237 | else if EQ("yieldk") { | ||
1238 | int nres = getnum; | ||
1239 | int i = getindex; | ||
1240 | return lua_yieldk(L1, nres, i, Cfunck); | ||
1241 | } | ||
1242 | else if EQ("newthread") { | ||
1243 | lua_newthread(L1); | ||
1244 | } | ||
1245 | else if EQ("resume") { | ||
1246 | int i = getindex; | ||
1247 | status = lua_resume(lua_tothread(L1, i), L, getnum); | ||
1248 | } | ||
1249 | else if EQ("pushstatus") { | ||
1250 | pushcode(L1, status); | ||
1251 | } | ||
1252 | else if EQ("xmove") { | ||
1253 | int f = getindex; | ||
1254 | int t = getindex; | ||
1255 | lua_State *fs = (f == 0) ? L1 : lua_tothread(L1, f); | ||
1256 | lua_State *ts = (t == 0) ? L1 : lua_tothread(L1, t); | ||
1257 | int n = getnum; | ||
1258 | if (n == 0) n = lua_gettop(fs); | ||
1259 | lua_xmove(fs, ts, n); | ||
1260 | } | ||
1261 | else if EQ("loadstring") { | ||
1262 | size_t sl; | ||
1263 | const char *s = luaL_checklstring(L1, getnum, &sl); | ||
1264 | luaL_loadbuffer(L1, s, sl, s); | ||
1265 | } | ||
1266 | else if EQ("loadfile") { | ||
1267 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); | ||
1268 | } | ||
1269 | else if EQ("setmetatable") { | ||
1270 | lua_setmetatable(L1, getindex); | ||
1271 | } | ||
1272 | else if EQ("getmetatable") { | ||
1273 | if (lua_getmetatable(L1, getindex) == 0) | ||
1274 | lua_pushnil(L1); | ||
1275 | } | ||
1276 | else if EQ("type") { | ||
1277 | lua_pushstring(L1, luaL_typename(L1, getnum)); | ||
1278 | } | ||
1279 | else if EQ("append") { | ||
1280 | int t = getindex; | ||
1281 | int i = lua_rawlen(L1, t); | ||
1282 | lua_rawseti(L1, t, i + 1); | ||
1283 | } | ||
1284 | else if EQ("getctx") { | ||
1285 | int i = 0; | ||
1286 | int s = lua_getctx(L1, &i); | ||
1287 | pushcode(L1, s); | ||
1288 | lua_pushinteger(L1, i); | ||
1289 | } | ||
1290 | else if EQ("checkstack") { | ||
1291 | int sz = getnum; | ||
1292 | luaL_checkstack(L1, sz, getstring); | ||
1293 | } | ||
1294 | else if EQ("newmetatable") { | ||
1295 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); | ||
1296 | } | ||
1297 | else if EQ("testudata") { | ||
1298 | int i = getindex; | ||
1299 | lua_pushboolean(L1, luaL_testudata(L1, i, getstring) != NULL); | ||
1300 | } | ||
1301 | else if EQ("gsub") { | ||
1302 | int a = getnum; int b = getnum; int c = getnum; | ||
1303 | luaL_gsub(L1, lua_tostring(L1, a), | ||
1304 | lua_tostring(L1, b), | ||
1305 | lua_tostring(L1, c)); | ||
1306 | } | ||
1307 | else if EQ("sethook") { | ||
1308 | int mask = getnum; | ||
1309 | int count = getnum; | ||
1310 | sethookaux(L1, mask, count, getstring); | ||
1311 | } | ||
1312 | else if EQ("throw") { | ||
1313 | #if defined(__cplusplus) | ||
1314 | static struct X { int x; } x; | ||
1315 | throw x; | ||
1316 | #else | ||
1317 | luaL_error(L1, "C++"); | ||
1318 | #endif | ||
1319 | break; | ||
1320 | } | ||
1321 | else luaL_error(L, "unknown instruction %s", buff); | ||
1322 | } | ||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | static int testC (lua_State *L) { | ||
1328 | lua_State *L1; | ||
1329 | const char *pc; | ||
1330 | if (lua_isuserdata(L, 1)) { | ||
1331 | L1 = getstate(L); | ||
1332 | pc = luaL_checkstring(L, 2); | ||
1333 | } | ||
1334 | else if (lua_isthread(L, 1)) { | ||
1335 | L1 = lua_tothread(L, 1); | ||
1336 | pc = luaL_checkstring(L, 2); | ||
1337 | } | ||
1338 | else { | ||
1339 | L1 = L; | ||
1340 | pc = luaL_checkstring(L, 1); | ||
1341 | } | ||
1342 | return runC(L, L1, pc); | ||
1343 | } | ||
1344 | |||
1345 | |||
1346 | static int Cfunc (lua_State *L) { | ||
1347 | return runC(L, L, lua_tostring(L, lua_upvalueindex(1))); | ||
1348 | } | ||
1349 | |||
1350 | |||
1351 | static int Cfunck (lua_State *L) { | ||
1352 | int i = 0; | ||
1353 | lua_getctx(L, &i); | ||
1354 | return runC(L, L, lua_tostring(L, i)); | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | static int makeCfunc (lua_State *L) { | ||
1359 | luaL_checkstring(L, 1); | ||
1360 | lua_pushcclosure(L, Cfunc, lua_gettop(L)); | ||
1361 | return 1; | ||
1362 | } | ||
1363 | |||
1364 | |||
1365 | /* }====================================================== */ | ||
1366 | |||
1367 | |||
1368 | /* | ||
1369 | ** {====================================================== | ||
1370 | ** tests for C hooks | ||
1371 | ** ======================================================= | ||
1372 | */ | ||
1373 | |||
1374 | /* | ||
1375 | ** C hook that runs the C script stored in registry.C_HOOK[L] | ||
1376 | */ | ||
1377 | static void Chook (lua_State *L, lua_Debug *ar) { | ||
1378 | const char *scpt; | ||
1379 | const char *const events [] = {"call", "ret", "line", "count", "tailcall"}; | ||
1380 | lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); | ||
1381 | lua_pushlightuserdata(L, L); | ||
1382 | lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */ | ||
1383 | scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */ | ||
1384 | lua_pop(L, 2); /* remove C_HOOK and script */ | ||
1385 | lua_pushstring(L, events[ar->event]); /* may be used by script */ | ||
1386 | lua_pushinteger(L, ar->currentline); /* may be used by script */ | ||
1387 | runC(L, L, scpt); /* run script from C_HOOK[L] */ | ||
1388 | } | ||
1389 | |||
1390 | |||
1391 | /* | ||
1392 | ** sets registry.C_HOOK[L] = scpt and sets Chook as a hook | ||
1393 | */ | ||
1394 | static void sethookaux (lua_State *L, int mask, int count, const char *scpt) { | ||
1395 | if (*scpt == '\0') { /* no script? */ | ||
1396 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ | ||
1397 | return; | ||
1398 | } | ||
1399 | lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */ | ||
1400 | if (!lua_istable(L, -1)) { /* no hook table? */ | ||
1401 | lua_pop(L, 1); /* remove previous value */ | ||
1402 | lua_newtable(L); /* create new C_HOOK table */ | ||
1403 | lua_pushvalue(L, -1); | ||
1404 | lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */ | ||
1405 | } | ||
1406 | lua_pushlightuserdata(L, L); | ||
1407 | lua_pushstring(L, scpt); | ||
1408 | lua_settable(L, -3); /* C_HOOK[L] = script */ | ||
1409 | lua_sethook(L, Chook, mask, count); | ||
1410 | } | ||
1411 | |||
1412 | |||
1413 | static int sethook (lua_State *L) { | ||
1414 | if (lua_isnoneornil(L, 1)) | ||
1415 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ | ||
1416 | else { | ||
1417 | const char *scpt = luaL_checkstring(L, 1); | ||
1418 | const char *smask = luaL_checkstring(L, 2); | ||
1419 | int count = luaL_optint(L, 3, 0); | ||
1420 | int mask = 0; | ||
1421 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; | ||
1422 | if (strchr(smask, 'r')) mask |= LUA_MASKRET; | ||
1423 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; | ||
1424 | if (count > 0) mask |= LUA_MASKCOUNT; | ||
1425 | sethookaux(L, mask, count, scpt); | ||
1426 | } | ||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | |||
1431 | static int coresume (lua_State *L) { | ||
1432 | int status; | ||
1433 | lua_State *co = lua_tothread(L, 1); | ||
1434 | luaL_argcheck(L, co, 1, "coroutine expected"); | ||
1435 | status = lua_resume(co, L, 0); | ||
1436 | if (status != LUA_OK && status != LUA_YIELD) { | ||
1437 | lua_pushboolean(L, 0); | ||
1438 | lua_insert(L, -2); | ||
1439 | return 2; /* return false + error message */ | ||
1440 | } | ||
1441 | else { | ||
1442 | lua_pushboolean(L, 1); | ||
1443 | return 1; | ||
1444 | } | ||
1445 | } | ||
1446 | |||
1447 | /* }====================================================== */ | ||
1448 | |||
1449 | |||
1450 | |||
1451 | static const struct luaL_Reg tests_funcs[] = { | ||
1452 | {"checkmemory", lua_checkmemory}, | ||
1453 | {"closestate", closestate}, | ||
1454 | {"d2s", d2s}, | ||
1455 | {"doonnewstack", doonnewstack}, | ||
1456 | {"doremote", doremote}, | ||
1457 | {"gccolor", get_gccolor}, | ||
1458 | {"gcstate", gc_state}, | ||
1459 | {"getref", getref}, | ||
1460 | {"hash", hash_query}, | ||
1461 | {"int2fb", int2fb_aux}, | ||
1462 | {"limits", get_limits}, | ||
1463 | {"listcode", listcode}, | ||
1464 | {"listk", listk}, | ||
1465 | {"listlocals", listlocals}, | ||
1466 | {"loadlib", loadlib}, | ||
1467 | {"newstate", newstate}, | ||
1468 | {"newuserdata", newuserdata}, | ||
1469 | {"num2int", num2int}, | ||
1470 | {"pushuserdata", pushuserdata}, | ||
1471 | {"querystr", string_query}, | ||
1472 | {"querytab", table_query}, | ||
1473 | {"ref", tref}, | ||
1474 | {"resume", coresume}, | ||
1475 | {"s2d", s2d}, | ||
1476 | {"sethook", sethook}, | ||
1477 | {"stacklevel", stacklevel}, | ||
1478 | {"testC", testC}, | ||
1479 | {"makeCfunc", makeCfunc}, | ||
1480 | {"totalmem", mem_query}, | ||
1481 | {"trick", settrick}, | ||
1482 | {"udataval", udataval}, | ||
1483 | {"unref", unref}, | ||
1484 | {"upvalue", upvalue}, | ||
1485 | {NULL, NULL} | ||
1486 | }; | ||
1487 | |||
1488 | |||
1489 | static void checkfinalmem (void) { | ||
1490 | lua_assert(l_memcontrol.numblocks == 0); | ||
1491 | lua_assert(l_memcontrol.total == 0); | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | int luaB_opentests (lua_State *L) { | ||
1496 | void *ud; | ||
1497 | lua_atpanic(L, &tpanic); | ||
1498 | atexit(checkfinalmem); | ||
1499 | lua_assert(lua_getallocf(L, &ud) == debug_realloc); | ||
1500 | lua_assert(ud == cast(void *, &l_memcontrol)); | ||
1501 | lua_setallocf(L, lua_getallocf(L, NULL), ud); | ||
1502 | luaL_newlib(L, tests_funcs); | ||
1503 | return 1; | ||
1504 | } | ||
1505 | |||
1506 | #endif | ||