diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-09-16 16:25:59 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-09-16 16:25:59 -0300 |
| commit | 43a2ee6ea1b7825c1892de614cb38a3fe487a19f (patch) | |
| tree | c2db158b379c56fb93c0c66ded2a6c8312102062 /ldo.c | |
| parent | 4b91e9cde630573cb35bb20101eb74cf5cf79a27 (diff) | |
| download | lua-43a2ee6ea1b7825c1892de614cb38a3fe487a19f.tar.gz lua-43a2ee6ea1b7825c1892de614cb38a3fe487a19f.tar.bz2 lua-43a2ee6ea1b7825c1892de614cb38a3fe487a19f.zip | |
Stack and Call structure of Lua
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 415 |
1 files changed, 415 insertions, 0 deletions
| @@ -0,0 +1,415 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: $ | ||
| 3 | ** Stack and Call structure of Lua | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | |||
| 8 | #include <setjmp.h> | ||
| 9 | #include <stdio.h> | ||
| 10 | #include <string.h> | ||
| 11 | |||
| 12 | #include "ldo.h" | ||
| 13 | #include "lgc.h" | ||
| 14 | #include "lmem.h" | ||
| 15 | #include "lobject.h" | ||
| 16 | #include "lparser.h" | ||
| 17 | #include "ltm.h" | ||
| 18 | #include "lua.h" | ||
| 19 | #include "luadebug.h" | ||
| 20 | #include "lundump.h" | ||
| 21 | #include "lvm.h" | ||
| 22 | #include "lzio.h" | ||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | #ifndef STACK_LIMIT | ||
| 27 | #define STACK_LIMIT 6000 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | |||
| 31 | static TObject initial_stack; | ||
| 32 | |||
| 33 | struct Stack luaD_stack = {&initial_stack+1, &initial_stack, &initial_stack}; | ||
| 34 | |||
| 35 | |||
| 36 | struct C_Lua_Stack luaD_Cstack = {0, 0, 0}; | ||
| 37 | |||
| 38 | static jmp_buf *errorJmp = NULL; /* current error recover point */ | ||
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | |||
| 44 | #define STACK_EXTRA 32 | ||
| 45 | |||
| 46 | static void initstack (int n) | ||
| 47 | { | ||
| 48 | int maxstack = STACK_EXTRA+n; | ||
| 49 | luaD_stack.stack = luaM_newvector(maxstack, TObject); | ||
| 50 | luaD_stack.last = luaD_stack.stack+(maxstack-1); | ||
| 51 | luaD_stack.top = luaD_stack.stack; | ||
| 52 | *(luaD_stack.top++) = initial_stack; | ||
| 53 | } | ||
| 54 | |||
| 55 | |||
| 56 | void luaD_checkstack (int n) | ||
| 57 | { | ||
| 58 | if (luaD_stack.stack == &initial_stack) | ||
| 59 | initstack(n); | ||
| 60 | else if (luaD_stack.last-luaD_stack.top <= n) { | ||
| 61 | static int limit = STACK_LIMIT; | ||
| 62 | StkId top = luaD_stack.top-luaD_stack.stack; | ||
| 63 | int stacksize = (luaD_stack.last-luaD_stack.stack)+1+STACK_EXTRA+n; | ||
| 64 | luaD_stack.stack = luaM_reallocvector(luaD_stack.stack, stacksize,TObject); | ||
| 65 | luaD_stack.last = luaD_stack.stack+(stacksize-1); | ||
| 66 | luaD_stack.top = luaD_stack.stack + top; | ||
| 67 | if (stacksize >= limit) { | ||
| 68 | limit = stacksize+STACK_EXTRA; /* extra space to run error handler */ | ||
| 69 | if (lua_stackedfunction(100) == LUA_NOOBJECT) { | ||
| 70 | /* less than 100 functions on the stack: cannot be recursive loop */ | ||
| 71 | lua_error("Lua2C - C2Lua overflow"); | ||
| 72 | } | ||
| 73 | else | ||
| 74 | lua_error(stackEM); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | |||
| 81 | /* | ||
| 82 | ** Adjust stack. Set top to the given value, pushing NILs if needed. | ||
| 83 | */ | ||
| 84 | void luaD_adjusttop (StkId newtop) | ||
| 85 | { | ||
| 86 | int diff = newtop-(luaD_stack.top-luaD_stack.stack); | ||
| 87 | if (diff <= 0) | ||
| 88 | luaD_stack.top += diff; | ||
| 89 | else { | ||
| 90 | luaD_checkstack(diff); | ||
| 91 | while (diff--) | ||
| 92 | ttype(luaD_stack.top++) = LUA_T_NIL; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | |||
| 97 | /* | ||
| 98 | ** Open a hole below "nelems" from the luaD_stack.top. | ||
| 99 | */ | ||
| 100 | void luaD_openstack (int nelems) | ||
| 101 | { | ||
| 102 | int i; | ||
| 103 | for (i=0; i<nelems; i++) | ||
| 104 | *(luaD_stack.top-i) = *(luaD_stack.top-i-1); | ||
| 105 | incr_top; | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | void luaD_lineHook (int line) | ||
| 110 | { | ||
| 111 | struct C_Lua_Stack oldCLS = luaD_Cstack; | ||
| 112 | StkId old_top = luaD_Cstack.lua2C = luaD_Cstack.base = luaD_stack.top-luaD_stack.stack; | ||
| 113 | luaD_Cstack.num = 0; | ||
| 114 | (*lua_linehook)(line); | ||
| 115 | luaD_stack.top = luaD_stack.stack+old_top; | ||
| 116 | luaD_Cstack = oldCLS; | ||
| 117 | } | ||
| 118 | |||
| 119 | |||
| 120 | void luaD_callHook (StkId base, lua_Type type, int isreturn) | ||
| 121 | { | ||
| 122 | struct C_Lua_Stack oldCLS = luaD_Cstack; | ||
| 123 | StkId old_top = luaD_Cstack.lua2C = luaD_Cstack.base = luaD_stack.top-luaD_stack.stack; | ||
| 124 | luaD_Cstack.num = 0; | ||
| 125 | if (isreturn) | ||
| 126 | (*lua_callhook)(LUA_NOOBJECT, "(return)", 0); | ||
| 127 | else { | ||
| 128 | TObject *f = luaD_stack.stack+base-1; | ||
| 129 | if (type == LUA_T_MARK) | ||
| 130 | (*lua_callhook)(Ref(f), f->value.tf->fileName->str, | ||
| 131 | f->value.tf->lineDefined); | ||
| 132 | else | ||
| 133 | (*lua_callhook)(Ref(f), "(C)", -1); | ||
| 134 | } | ||
| 135 | luaD_stack.top = luaD_stack.stack+old_top; | ||
| 136 | luaD_Cstack = oldCLS; | ||
| 137 | } | ||
| 138 | |||
| 139 | |||
| 140 | /* | ||
| 141 | ** Call a C function. luaD_Cstack.base will point to the luaD_stack.top of the luaD_stack.stack, | ||
| 142 | ** and luaD_Cstack.num is the number of parameters. Returns an index | ||
| 143 | ** to the first result from C. | ||
| 144 | */ | ||
| 145 | static StkId callC (lua_CFunction func, StkId base) | ||
| 146 | { | ||
| 147 | struct C_Lua_Stack oldCLS = luaD_Cstack; | ||
| 148 | StkId firstResult; | ||
| 149 | luaD_Cstack.num = (luaD_stack.top-luaD_stack.stack) - base; | ||
| 150 | /* incorporate parameters on the luaD_stack.stack */ | ||
| 151 | luaD_Cstack.lua2C = base; | ||
| 152 | luaD_Cstack.base = base+luaD_Cstack.num; /* == luaD_stack.top-luaD_stack.stack */ | ||
| 153 | if (lua_callhook) | ||
| 154 | luaD_callHook(base, LUA_T_CMARK, 0); | ||
| 155 | (*func)(); | ||
| 156 | if (lua_callhook) /* func may have changed lua_callhook */ | ||
| 157 | luaD_callHook(base, LUA_T_CMARK, 1); | ||
| 158 | firstResult = luaD_Cstack.base; | ||
| 159 | luaD_Cstack = oldCLS; | ||
| 160 | return firstResult; | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | void luaD_callTM (TObject *f, int nParams, int nResults) | ||
| 165 | { | ||
| 166 | luaD_openstack(nParams); | ||
| 167 | *(luaD_stack.top-nParams-1) = *f; | ||
| 168 | luaD_call((luaD_stack.top-luaD_stack.stack)-nParams, nResults); | ||
| 169 | } | ||
| 170 | |||
| 171 | |||
| 172 | /* | ||
| 173 | ** Call a function (C or Lua). The parameters must be on the luaD_stack.stack, | ||
| 174 | ** between [luaD_stack.stack+base,luaD_stack.top). The function to be called is at luaD_stack.stack+base-1. | ||
| 175 | ** When returns, the results are on the luaD_stack.stack, between [luaD_stack.stack+base-1,luaD_stack.top). | ||
| 176 | ** The number of results is nResults, unless nResults=MULT_RET. | ||
| 177 | */ | ||
| 178 | void luaD_call (StkId base, int nResults) | ||
| 179 | { | ||
| 180 | StkId firstResult; | ||
| 181 | TObject *func = luaD_stack.stack+base-1; | ||
| 182 | int i; | ||
| 183 | if (ttype(func) == LUA_T_CFUNCTION) { | ||
| 184 | ttype(func) = LUA_T_CMARK; | ||
| 185 | firstResult = callC(fvalue(func), base); | ||
| 186 | } | ||
| 187 | else if (ttype(func) == LUA_T_FUNCTION) { | ||
| 188 | ttype(func) = LUA_T_MARK; | ||
| 189 | firstResult = luaV_execute(func->value.cl, base); | ||
| 190 | } | ||
| 191 | else { /* func is not a function */ | ||
| 192 | /* Check the tag method for invalid functions */ | ||
| 193 | TObject *im = luaT_getimbyObj(func, IM_FUNCTION); | ||
| 194 | if (ttype(im) == LUA_T_NIL) | ||
| 195 | lua_error("call expression not a function"); | ||
| 196 | luaD_callTM(im, (luaD_stack.top-luaD_stack.stack)-(base-1), nResults); | ||
| 197 | return; | ||
| 198 | } | ||
| 199 | /* adjust the number of results */ | ||
| 200 | if (nResults != MULT_RET) | ||
| 201 | luaD_adjusttop(firstResult+nResults); | ||
| 202 | /* move results to base-1 (to erase parameters and function) */ | ||
| 203 | base--; | ||
| 204 | nResults = luaD_stack.top - (luaD_stack.stack+firstResult); /* actual number of results */ | ||
| 205 | for (i=0; i<nResults; i++) | ||
| 206 | *(luaD_stack.stack+base+i) = *(luaD_stack.stack+firstResult+i); | ||
| 207 | luaD_stack.top -= firstResult-base; | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | |||
| 212 | /* | ||
| 213 | ** Traverse all objects on luaD_stack.stack | ||
| 214 | */ | ||
| 215 | void luaD_travstack (int (*fn)(TObject *)) | ||
| 216 | { | ||
| 217 | StkId i; | ||
| 218 | for (i = (luaD_stack.top-1)-luaD_stack.stack; i>=0; i--) | ||
| 219 | fn (luaD_stack.stack+i); | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | /* | ||
| 224 | ** Error messages | ||
| 225 | */ | ||
| 226 | |||
| 227 | static void auxerrorim (char *form) | ||
| 228 | { | ||
| 229 | lua_Object s = lua_getparam(1); | ||
| 230 | if (lua_isstring(s)) | ||
| 231 | fprintf(stderr, form, lua_getstring(s)); | ||
| 232 | } | ||
| 233 | |||
| 234 | |||
| 235 | static void emergencyerrorf (void) | ||
| 236 | { | ||
| 237 | auxerrorim("THERE WAS AN ERROR INSIDE AN ERROR METHOD:\n%s\n"); | ||
| 238 | } | ||
| 239 | |||
| 240 | |||
| 241 | static void stderrorim (void) | ||
| 242 | { | ||
| 243 | auxerrorim("lua: %s\n"); | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | TObject luaD_errorim = {LUA_T_CFUNCTION, {stderrorim}}; | ||
| 248 | |||
| 249 | |||
| 250 | static void message (char *s) | ||
| 251 | { | ||
| 252 | TObject im = luaD_errorim; | ||
| 253 | if (ttype(&im) != LUA_T_NIL) { | ||
| 254 | luaD_errorim.ttype = LUA_T_CFUNCTION; | ||
| 255 | luaD_errorim.value.f = emergencyerrorf; | ||
| 256 | lua_pushstring(s); | ||
| 257 | luaD_callTM(&im, 1, 0); | ||
| 258 | luaD_errorim = im; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | /* | ||
| 263 | ** Reports an error, and jumps up to the available recover label | ||
| 264 | */ | ||
| 265 | void lua_error (char *s) | ||
| 266 | { | ||
| 267 | if (s) message(s); | ||
| 268 | if (errorJmp) | ||
| 269 | longjmp(*errorJmp, 1); | ||
| 270 | else { | ||
| 271 | fprintf (stderr, "lua: exit(1). Unable to recover\n"); | ||
| 272 | exit(1); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | /* | ||
| 277 | ** Call the function at luaD_Cstack.base, and incorporate results on | ||
| 278 | ** the Lua2C structure. | ||
| 279 | */ | ||
| 280 | static void do_callinc (int nResults) | ||
| 281 | { | ||
| 282 | StkId base = luaD_Cstack.base; | ||
| 283 | luaD_call(base+1, nResults); | ||
| 284 | luaD_Cstack.lua2C = base; /* position of the luaM_new results */ | ||
| 285 | luaD_Cstack.num = (luaD_stack.top-luaD_stack.stack) - base; /* number of results */ | ||
| 286 | luaD_Cstack.base = base + luaD_Cstack.num; /* incorporate results on luaD_stack.stack */ | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | /* | ||
| 291 | ** Execute a protected call. Assumes that function is at luaD_Cstack.base and | ||
| 292 | ** parameters are on luaD_stack.top of it. Leave nResults on the luaD_stack.stack. | ||
| 293 | */ | ||
| 294 | int luaD_protectedrun (int nResults) | ||
| 295 | { | ||
| 296 | jmp_buf myErrorJmp; | ||
| 297 | int status; | ||
| 298 | struct C_Lua_Stack oldCLS = luaD_Cstack; | ||
| 299 | jmp_buf *oldErr = errorJmp; | ||
| 300 | errorJmp = &myErrorJmp; | ||
| 301 | if (setjmp(myErrorJmp) == 0) { | ||
| 302 | do_callinc(nResults); | ||
| 303 | status = 0; | ||
| 304 | } | ||
| 305 | else { /* an error occurred: restore luaD_Cstack and luaD_stack.top */ | ||
| 306 | luaD_Cstack = oldCLS; | ||
| 307 | luaD_stack.top = luaD_stack.stack+luaD_Cstack.base; | ||
| 308 | status = 1; | ||
| 309 | } | ||
| 310 | errorJmp = oldErr; | ||
| 311 | return status; | ||
| 312 | } | ||
| 313 | |||
| 314 | |||
| 315 | /* | ||
| 316 | ** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load | ||
| 317 | */ | ||
| 318 | static int protectedparser (ZIO *z, char *chunkname, int bin) | ||
| 319 | { | ||
| 320 | int status; | ||
| 321 | TProtoFunc *tf; | ||
| 322 | jmp_buf myErrorJmp; | ||
| 323 | jmp_buf *oldErr = errorJmp; | ||
| 324 | errorJmp = &myErrorJmp; | ||
| 325 | if (setjmp(myErrorJmp) == 0) { | ||
| 326 | tf = bin ? luaU_undump1(z, chunkname) : luaY_parser(z, chunkname); | ||
| 327 | status = 0; | ||
| 328 | } | ||
| 329 | else { | ||
| 330 | tf = NULL; | ||
| 331 | status = 1; | ||
| 332 | } | ||
| 333 | errorJmp = oldErr; | ||
| 334 | if (status) return 1; /* error code */ | ||
| 335 | if (tf == NULL) return 2; /* 'natural' end */ | ||
| 336 | luaD_adjusttop(luaD_Cstack.base+1); /* one slot for the pseudo-function */ | ||
| 337 | luaD_stack.stack[luaD_Cstack.base].ttype = LUA_T_PROTO; | ||
| 338 | luaD_stack.stack[luaD_Cstack.base].value.tf = tf; | ||
| 339 | luaV_closure(); | ||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | |||
| 344 | static int do_main (ZIO *z, char *chunkname, int bin) | ||
| 345 | { | ||
| 346 | int status; | ||
| 347 | do { | ||
| 348 | long old_entities = (luaC_checkGC(), luaO_nentities); | ||
| 349 | status = protectedparser(z, chunkname, bin); | ||
| 350 | if (status == 1) return 1; /* error */ | ||
| 351 | else if (status == 2) return 0; /* 'natural' end */ | ||
| 352 | else { | ||
| 353 | long newelems2 = 2*(luaO_nentities-old_entities); | ||
| 354 | luaC_threshold += newelems2; | ||
| 355 | status = luaD_protectedrun(MULT_RET); | ||
| 356 | luaC_threshold -= newelems2; | ||
| 357 | } | ||
| 358 | } while (bin && status == 0); | ||
| 359 | return status; | ||
| 360 | } | ||
| 361 | |||
| 362 | |||
| 363 | void luaD_gcIM (TObject *o) | ||
| 364 | { | ||
| 365 | TObject *im = luaT_getimbyObj(o, IM_GC); | ||
| 366 | if (ttype(im) != LUA_T_NIL) { | ||
| 367 | *luaD_stack.top = *o; | ||
| 368 | incr_top; | ||
| 369 | luaD_callTM(im, 1, 0); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | |||
| 374 | int lua_dofile (char *filename) | ||
| 375 | { | ||
| 376 | ZIO z; | ||
| 377 | int status; | ||
| 378 | int c; | ||
| 379 | int bin; | ||
| 380 | FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); | ||
| 381 | if (f == NULL) | ||
| 382 | return 2; | ||
| 383 | if (filename == NULL) | ||
| 384 | filename = "(stdin)"; | ||
| 385 | c = fgetc(f); | ||
| 386 | ungetc(c, f); | ||
| 387 | bin = (c == ID_CHUNK); | ||
| 388 | if (bin) | ||
| 389 | f = freopen(filename, "rb", f); /* set binary mode */ | ||
| 390 | luaZ_Fopen(&z, f); | ||
| 391 | status = do_main(&z, filename, bin); | ||
| 392 | if (f != stdin) | ||
| 393 | fclose(f); | ||
| 394 | return status; | ||
| 395 | } | ||
| 396 | |||
| 397 | |||
| 398 | #define SIZE_PREF 20 /* size of string prefix to appear in error messages */ | ||
| 399 | |||
| 400 | |||
| 401 | int lua_dostring (char *str) | ||
| 402 | { | ||
| 403 | int status; | ||
| 404 | char buff[SIZE_PREF+25]; | ||
| 405 | char *temp; | ||
| 406 | ZIO z; | ||
| 407 | if (str == NULL) return 1; | ||
| 408 | sprintf(buff, "(dostring) >> %.20s", str); | ||
| 409 | temp = strchr(buff, '\n'); | ||
| 410 | if (temp) *temp = 0; /* end string after first line */ | ||
| 411 | luaZ_sopen(&z, str); | ||
| 412 | status = do_main(&z, buff, 0); | ||
| 413 | return status; | ||
| 414 | } | ||
| 415 | |||
