diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-01-09 20:02:47 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-01-09 20:02:47 -0200 |
commit | f083812c020186d0d919833100c1a0b6eda8c2c0 (patch) | |
tree | 29c2e1d25f05af62277aab03e8e070aaa1a0d664 /ldo.c | |
parent | 3533382a1ed7ba21f0233057c886be2dd8a71d92 (diff) | |
download | lua-f083812c020186d0d919833100c1a0b6eda8c2c0.tar.gz lua-f083812c020186d0d919833100c1a0b6eda8c2c0.tar.bz2 lua-f083812c020186d0d919833100c1a0b6eda8c2c0.zip |
first implementation of coroutines
Diffstat (limited to 'ldo.c')
-rw-r--r-- | ldo.c | 126 |
1 files changed, 110 insertions, 16 deletions
@@ -18,6 +18,7 @@ | |||
18 | #include "lgc.h" | 18 | #include "lgc.h" |
19 | #include "lmem.h" | 19 | #include "lmem.h" |
20 | #include "lobject.h" | 20 | #include "lobject.h" |
21 | #include "lopcodes.h" | ||
21 | #include "lparser.h" | 22 | #include "lparser.h" |
22 | #include "lstate.h" | 23 | #include "lstate.h" |
23 | #include "lstring.h" | 24 | #include "lstring.h" |
@@ -112,8 +113,6 @@ void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) { | |||
112 | } | 113 | } |
113 | 114 | ||
114 | 115 | ||
115 | #define newci(L) ((++L->ci == L->end_ci) ? growci(L) : L->ci) | ||
116 | |||
117 | static CallInfo *growci (lua_State *L) { | 116 | static CallInfo *growci (lua_State *L) { |
118 | lua_assert(L->ci == L->end_ci); | 117 | lua_assert(L->ci == L->end_ci); |
119 | luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo); | 118 | luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo); |
@@ -124,9 +123,32 @@ static CallInfo *growci (lua_State *L) { | |||
124 | } | 123 | } |
125 | 124 | ||
126 | 125 | ||
126 | static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { | ||
127 | int i; | ||
128 | Table *htab; | ||
129 | TObject n, nname; | ||
130 | StkId firstvar = base + nfixargs; /* position of first vararg */ | ||
131 | if (L->top < firstvar) { | ||
132 | luaD_checkstack(L, firstvar - L->top); | ||
133 | while (L->top < firstvar) | ||
134 | setnilvalue(L->top++); | ||
135 | } | ||
136 | htab = luaH_new(L, 0, 0); | ||
137 | for (i=0; firstvar+i<L->top; i++) | ||
138 | luaH_setnum(L, htab, i+1, firstvar+i); | ||
139 | /* store counter in field `n' */ | ||
140 | setnvalue(&n, i); | ||
141 | setsvalue(&nname, luaS_newliteral(L, "n")); | ||
142 | luaH_set(L, htab, &nname, &n); | ||
143 | L->top = firstvar; /* remove elements from the stack */ | ||
144 | sethvalue(L->top, htab); | ||
145 | incr_top; | ||
146 | } | ||
147 | |||
148 | |||
127 | StkId luaD_precall (lua_State *L, StkId func) { | 149 | StkId luaD_precall (lua_State *L, StkId func) { |
128 | CallInfo *ci; | 150 | CallInfo *ci; |
129 | int n; | 151 | LClosure *cl; |
130 | if (ttype(func) != LUA_TFUNCTION) { | 152 | if (ttype(func) != LUA_TFUNCTION) { |
131 | /* `func' is not a function; check the `function' tag method */ | 153 | /* `func' is not a function; check the `function' tag method */ |
132 | const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); | 154 | const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); |
@@ -135,21 +157,39 @@ StkId luaD_precall (lua_State *L, StkId func) { | |||
135 | luaD_openstack(L, func); | 157 | luaD_openstack(L, func); |
136 | setobj(func, tm); /* tag method is the new function to be called */ | 158 | setobj(func, tm); /* tag method is the new function to be called */ |
137 | } | 159 | } |
138 | ci = newci(L); | 160 | ci = ++L->ci; |
161 | if (L->ci == L->end_ci) ci = growci(L); | ||
139 | ci->base = func+1; | 162 | ci->base = func+1; |
140 | ci->savedpc = NULL; | ||
141 | if (L->callhook) | 163 | if (L->callhook) |
142 | luaD_callHook(L, L->callhook, "call"); | 164 | luaD_callHook(L, L->callhook, "call"); |
143 | if (!clvalue(func)->c.isC) return NULL; | 165 | cl = &clvalue(func)->l; |
144 | /* if is a C function, call it */ | 166 | if (!cl->isC) { /* Lua function? prepare its call */ |
145 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | 167 | StkId base = func+1; |
146 | lua_unlock(L); | 168 | Proto *p = cl->p; |
169 | ci->linehook = L->linehook; | ||
170 | ci->savedpc = p->code; /* starting point */ | ||
171 | if (p->is_vararg) /* varargs? */ | ||
172 | adjust_varargs(L, base, p->numparams); | ||
173 | if (base > L->stack_last - p->maxstacksize) | ||
174 | luaD_stackerror(L); | ||
175 | ci->top = base + p->maxstacksize; | ||
176 | while (L->top < ci->top) | ||
177 | setnilvalue(L->top++); | ||
178 | L->top = ci->top; | ||
179 | return NULL; | ||
180 | } | ||
181 | else { /* if is a C function, call it */ | ||
182 | int n; | ||
183 | ci->savedpc = NULL; | ||
184 | luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | ||
185 | lua_unlock(L); | ||
147 | #if LUA_COMPATUPVALUES | 186 | #if LUA_COMPATUPVALUES |
148 | lua_pushupvalues(L); | 187 | lua_pushupvalues(L); |
149 | #endif | 188 | #endif |
150 | n = (*clvalue(func)->c.f)(L); /* do the actual call */ | 189 | n = (*clvalue(func)->c.f)(L); /* do the actual call */ |
151 | lua_lock(L); | 190 | lua_lock(L); |
152 | return L->top - n; | 191 | return L->top - n; |
192 | } | ||
153 | } | 193 | } |
154 | 194 | ||
155 | 195 | ||
@@ -179,12 +219,60 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { | |||
179 | */ | 219 | */ |
180 | void luaD_call (lua_State *L, StkId func, int nResults) { | 220 | void luaD_call (lua_State *L, StkId func, int nResults) { |
181 | StkId firstResult = luaD_precall(L, func); | 221 | StkId firstResult = luaD_precall(L, func); |
182 | if (firstResult == NULL) /* is a Lua function? */ | 222 | if (firstResult == NULL) { /* is a Lua function? */ |
183 | firstResult = luaV_execute(L, &clvalue(func)->l, func+1); /* call it */ | 223 | firstResult = luaV_execute(L); /* call it */ |
224 | if (firstResult == NULL) { | ||
225 | luaD_poscall(L, 0, L->top); | ||
226 | luaD_error(L, "attempt to `yield' across tag-method/C-call boundary"); | ||
227 | } | ||
228 | } | ||
184 | luaD_poscall(L, nResults, firstResult); | 229 | luaD_poscall(L, nResults, firstResult); |
185 | } | 230 | } |
186 | 231 | ||
187 | 232 | ||
233 | LUA_API void lua_cobegin (lua_State *L, int nargs) { | ||
234 | StkId func; | ||
235 | lua_lock(L); | ||
236 | func = L->top - (nargs+1); /* coroutine main function */ | ||
237 | if (luaD_precall(L, func) != NULL) | ||
238 | luaD_error(L, "coroutine started with a C function"); | ||
239 | lua_unlock(L); | ||
240 | } | ||
241 | |||
242 | |||
243 | LUA_API void lua_resume (lua_State *L, lua_State *co) { | ||
244 | StkId firstResult; | ||
245 | lua_lock(L); | ||
246 | if (co->ci->savedpc == NULL) /* no activation record? */ | ||
247 | luaD_error(L, "thread is dead - cannot be resumed"); | ||
248 | lua_assert(co->errorJmp == NULL); | ||
249 | co->errorJmp = L->errorJmp; | ||
250 | firstResult = luaV_execute(co); | ||
251 | if (firstResult != NULL) /* `return'? */ | ||
252 | luaD_poscall(co, LUA_MULTRET, firstResult); /* ends this coroutine */ | ||
253 | else { /* `yield' */ | ||
254 | int nresults = GETARG_C(*((co->ci-1)->savedpc - 1)) - 1; | ||
255 | luaD_poscall(co, nresults, co->top); /* complete it */ | ||
256 | if (nresults >= 0) co->top = co->ci->top; | ||
257 | } | ||
258 | co->errorJmp = NULL; | ||
259 | lua_unlock(L); | ||
260 | } | ||
261 | |||
262 | |||
263 | LUA_API int lua_yield (lua_State *L, int nresults) { | ||
264 | CallInfo *ci; | ||
265 | int ibase; | ||
266 | lua_lock(L); | ||
267 | ci = L->ci - 1; /* call info of calling function */ | ||
268 | if (ci->pc == NULL) | ||
269 | luaD_error(L, "cannot `yield' a C function"); | ||
270 | ibase = L->top - ci->base; | ||
271 | lua_unlock(L); | ||
272 | return ibase; | ||
273 | } | ||
274 | |||
275 | |||
188 | /* | 276 | /* |
189 | ** Execute a protected call. | 277 | ** Execute a protected call. |
190 | */ | 278 | */ |
@@ -330,7 +418,13 @@ static void message (lua_State *L, const char *s) { | |||
330 | ** Reports an error, and jumps up to the available recovery label | 418 | ** Reports an error, and jumps up to the available recovery label |
331 | */ | 419 | */ |
332 | void luaD_error (lua_State *L, const char *s) { | 420 | void luaD_error (lua_State *L, const char *s) { |
333 | if (s) message(L, s); | 421 | if (s) { |
422 | if (L->ci->savedpc) { /* error in Lua function preamble? */ | ||
423 | L->ci->savedpc = NULL; /* pretend function was already running */ | ||
424 | L->ci->pc = NULL; | ||
425 | } | ||
426 | message(L, s); | ||
427 | } | ||
334 | luaD_breakrun(L, LUA_ERRRUN); | 428 | luaD_breakrun(L, LUA_ERRRUN); |
335 | } | 429 | } |
336 | 430 | ||