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