aboutsummaryrefslogtreecommitdiff
path: root/ldo.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-01-09 20:02:47 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-01-09 20:02:47 -0200
commitf083812c020186d0d919833100c1a0b6eda8c2c0 (patch)
tree29c2e1d25f05af62277aab03e8e070aaa1a0d664 /ldo.c
parent3533382a1ed7ba21f0233057c886be2dd8a71d92 (diff)
downloadlua-f083812c020186d0d919833100c1a0b6eda8c2c0.tar.gz
lua-f083812c020186d0d919833100c1a0b6eda8c2c0.tar.bz2
lua-f083812c020186d0d919833100c1a0b6eda8c2c0.zip
first implementation of coroutines
Diffstat (limited to 'ldo.c')
-rw-r--r--ldo.c126
1 files changed, 110 insertions, 16 deletions
diff --git a/ldo.c b/ldo.c
index fedc0e35..c161cfe8 100644
--- a/ldo.c
+++ b/ldo.c
@@ -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
117static CallInfo *growci (lua_State *L) { 116static 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
126static 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
127StkId luaD_precall (lua_State *L, StkId func) { 149StkId 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*/
180void luaD_call (lua_State *L, StkId func, int nResults) { 220void 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
233LUA_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
243LUA_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
263LUA_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*/
332void luaD_error (lua_State *L, const char *s) { 420void 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