diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-02-05 20:39:12 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-02-05 20:39:12 -0200 |
commit | 38b0e6128da7796300e2e8621e87835e16539f5b (patch) | |
tree | 5b0a7ad2b0fb850d47f0566fd06b8cda013bbc8b /lvm.c | |
parent | addbe8c8b0587fd316f33fb013034e035f9217ed (diff) | |
download | lua-38b0e6128da7796300e2e8621e87835e16539f5b.tar.gz lua-38b0e6128da7796300e2e8621e87835e16539f5b.tar.bz2 lua-38b0e6128da7796300e2e8621e87835e16539f5b.zip |
simpler implementation for `for' loops
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 67 |
1 files changed, 32 insertions, 35 deletions
@@ -26,6 +26,9 @@ | |||
26 | #include "lvm.h" | 26 | #include "lvm.h" |
27 | 27 | ||
28 | 28 | ||
29 | /* limit for table tag-method chains (to avoid loops) */ | ||
30 | #define MAXTAGLOOP 10000 | ||
31 | |||
29 | 32 | ||
30 | static void luaV_checkGC (lua_State *L, StkId top) { | 33 | static void luaV_checkGC (lua_State *L, StkId top) { |
31 | if (G(L)->nblocks >= G(L)->GCthreshold) { | 34 | if (G(L)->nblocks >= G(L)->GCthreshold) { |
@@ -65,6 +68,8 @@ static void traceexec (lua_State *L, lua_Hook linehook) { | |||
65 | int *lineinfo = ci_func(ci)->l.p->lineinfo; | 68 | int *lineinfo = ci_func(ci)->l.p->lineinfo; |
66 | int pc = cast(int, *ci->pc - ci_func(ci)->l.p->code) - 1; | 69 | int pc = cast(int, *ci->pc - ci_func(ci)->l.p->code) - 1; |
67 | int newline; | 70 | int newline; |
71 | if (testOpMode(GET_OPCODE(*(*ci->pc - 1)), OpModeNoTrace)) | ||
72 | return; | ||
68 | if (ci->line == -1) return; /* no linehooks for this function */ | 73 | if (ci->line == -1) return; /* no linehooks for this function */ |
69 | else if (ci->line == 0) { /* first linehook? */ | 74 | else if (ci->line == 0) { /* first linehook? */ |
70 | if (pc == 0) { /* function is starting now? */ | 75 | if (pc == 0) { /* function is starting now? */ |
@@ -123,6 +128,7 @@ static void callTM (lua_State *L, const TObject *f, | |||
123 | */ | 128 | */ |
124 | void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | 129 | void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { |
125 | const TObject *tm; | 130 | const TObject *tm; |
131 | int loop = 0; | ||
126 | init: | 132 | init: |
127 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ | 133 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ |
128 | Table *et = hvalue(t)->metatable; | 134 | Table *et = hvalue(t)->metatable; |
@@ -145,6 +151,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | |||
145 | if (ttype(tm) == LUA_TFUNCTION) | 151 | if (ttype(tm) == LUA_TFUNCTION) |
146 | callTMres(L, tm, t, key, res); | 152 | callTMres(L, tm, t, key, res); |
147 | else { | 153 | else { |
154 | if (++loop == MAXTAGLOOP) luaD_error(L, "loop in gettable"); | ||
148 | t = (StkId)tm; /* ?? */ | 155 | t = (StkId)tm; /* ?? */ |
149 | goto init; /* return luaV_gettable(L, tm, key, res); */ | 156 | goto init; /* return luaV_gettable(L, tm, key, res); */ |
150 | } | 157 | } |
@@ -156,6 +163,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | |||
156 | */ | 163 | */ |
157 | void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { | 164 | void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { |
158 | const TObject *tm; | 165 | const TObject *tm; |
166 | int loop = 0; | ||
159 | init: | 167 | init: |
160 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ | 168 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ |
161 | Table *et = hvalue(t)->metatable; | 169 | Table *et = hvalue(t)->metatable; |
@@ -173,6 +181,7 @@ void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { | |||
173 | if (ttype(tm) == LUA_TFUNCTION) | 181 | if (ttype(tm) == LUA_TFUNCTION) |
174 | callTM(L, tm, t, key, val); | 182 | callTM(L, tm, t, key, val); |
175 | else { | 183 | else { |
184 | if (++loop == MAXTAGLOOP) luaD_error(L, "loop in settable"); | ||
176 | t = (StkId)tm; /* ?? */ | 185 | t = (StkId)tm; /* ?? */ |
177 | goto init; /* luaV_settable(L, tm, key, val); */ | 186 | goto init; /* luaV_settable(L, tm, key, val); */ |
178 | } | 187 | } |
@@ -301,8 +310,8 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
301 | #define Arith(op, optm) { \ | 310 | #define Arith(op, optm) { \ |
302 | const TObject *b = RB(i); const TObject *c = RKC(i); \ | 311 | const TObject *b = RB(i); const TObject *c = RKC(i); \ |
303 | TObject tempb, tempc; \ | 312 | TObject tempb, tempc; \ |
304 | if ((ttype(b) == LUA_TNUMBER || (b = luaV_tonumber(b, &tempb)) != NULL) && \ | 313 | if ((b = luaV_tonumber(b, &tempb)) != NULL && \ |
305 | (ttype(c) == LUA_TNUMBER || (c = luaV_tonumber(c, &tempc)) != NULL)) { \ | 314 | (c = luaV_tonumber(c, &tempc)) != NULL) { \ |
306 | setnvalue(ra, nvalue(b) op nvalue(c)); \ | 315 | setnvalue(ra, nvalue(b) op nvalue(c)); \ |
307 | } else \ | 316 | } else \ |
308 | call_arith(L, RB(i), RKC(i), ra, optm); \ | 317 | call_arith(L, RB(i), RKC(i), ra, optm); \ |
@@ -423,7 +432,7 @@ StkId luaV_execute (lua_State *L) { | |||
423 | } | 432 | } |
424 | case OP_UNM: { | 433 | case OP_UNM: { |
425 | const TObject *rb = RB(i); | 434 | const TObject *rb = RB(i); |
426 | if (ttype(rb) == LUA_TNUMBER || (rb=luaV_tonumber(rb, ra)) != NULL) { | 435 | if ((rb=luaV_tonumber(rb, ra)) != NULL) { |
427 | setnvalue(ra, -nvalue(rb)); | 436 | setnvalue(ra, -nvalue(rb)); |
428 | } | 437 | } |
429 | else { | 438 | else { |
@@ -441,7 +450,7 @@ StkId luaV_execute (lua_State *L) { | |||
441 | case OP_CONCAT: { | 450 | case OP_CONCAT: { |
442 | int b = GETARG_B(i); | 451 | int b = GETARG_B(i); |
443 | int c = GETARG_C(i); | 452 | int c = GETARG_C(i); |
444 | luaV_strconc(L, c-b+1, c); /* this call may change `base' (and `ra') */ | 453 | luaV_strconc(L, c-b+1, c); /* may change `base' (and `ra') */ |
445 | setobj(base+GETARG_A(i), base+b); | 454 | setobj(base+GETARG_A(i), base+b); |
446 | luaV_checkGC(L, base+c+1); | 455 | luaV_checkGC(L, base+c+1); |
447 | break; | 456 | break; |
@@ -532,53 +541,41 @@ StkId luaV_execute (lua_State *L) { | |||
532 | } | 541 | } |
533 | break; | 542 | break; |
534 | } | 543 | } |
535 | case OP_FORPREP: { | 544 | case OP_FORLOOP: { |
536 | if (luaV_tonumber(ra, ra) == NULL) | 545 | lua_Number step, index, limit; |
546 | int j = GETARG_sBc(i); | ||
547 | pc += j; /* jump back before tests (for error messages) */ | ||
548 | if (ttype(ra) != LUA_TNUMBER) | ||
537 | luaD_error(L, "`for' initial value must be a number"); | 549 | luaD_error(L, "`for' initial value must be a number"); |
538 | if (luaV_tonumber(ra+1, ra+1) == NULL) | 550 | if (luaV_tonumber(ra+1, ra+1) == NULL) |
539 | luaD_error(L, "`for' limit must be a number"); | 551 | luaD_error(L, "`for' limit must be a number"); |
540 | if (luaV_tonumber(ra+2, ra+2) == NULL) | 552 | if (luaV_tonumber(ra+2, ra+2) == NULL) |
541 | luaD_error(L, "`for' step must be a number"); | 553 | luaD_error(L, "`for' step must be a number"); |
542 | /* decrement index (to be incremented) */ | 554 | step = nvalue(ra+2); |
543 | chgnvalue(ra, nvalue(ra) - nvalue(ra+2)); | 555 | index = nvalue(ra) + step; /* increment index */ |
544 | pc += -GETARG_sBc(i); /* `jump' to loop end (delta is negated here) */ | 556 | limit = nvalue(ra+1); |
545 | /* store in `ra+1' total number of repetitions */ | 557 | if (step > 0 ? index <= limit : index >= limit) |
546 | chgnvalue(ra+1, (nvalue(ra+1)-nvalue(ra))/nvalue(ra+2)); | 558 | chgnvalue(ra, index); /* update index */ |
547 | /* go through */ | 559 | else |
548 | } | 560 | pc -= j; /* undo jump */ |
549 | case OP_FORLOOP: { | ||
550 | runtime_check(L, ttype(ra+1) == LUA_TNUMBER && | ||
551 | ttype(ra+2) == LUA_TNUMBER); | ||
552 | if (ttype(ra) != LUA_TNUMBER) | ||
553 | luaD_error(L, "`for' index must be a number"); | ||
554 | chgnvalue(ra+1, nvalue(ra+1) - 1); /* decrement counter */ | ||
555 | if (nvalue(ra+1) >= 0) { | ||
556 | chgnvalue(ra, nvalue(ra) + nvalue(ra+2)); /* increment index */ | ||
557 | dojump(pc, i); /* repeat loop */ | ||
558 | } | ||
559 | break; | 561 | break; |
560 | } | 562 | } |
561 | case OP_TFORPREP: { | ||
562 | if (ttype(ra) != LUA_TTABLE) | ||
563 | luaD_error(L, "`for' table must be a table"); | ||
564 | setnvalue(ra+1, -1); /* initial index */ | ||
565 | setnilvalue(ra+2); | ||
566 | setnilvalue(ra+3); | ||
567 | pc += -GETARG_sBc(i); /* `jump' to loop end (delta is negated here) */ | ||
568 | /* go through */ | ||
569 | } | ||
570 | case OP_TFORLOOP: { | 563 | case OP_TFORLOOP: { |
571 | Table *t; | 564 | Table *t; |
572 | int n; | 565 | int n; |
573 | runtime_check(L, ttype(ra) == LUA_TTABLE && | 566 | int j = GETARG_sBc(i); |
574 | ttype(ra+1) == LUA_TNUMBER); | 567 | pc += j; /* jump back before tests (for error messages) */ |
568 | if (ttype(ra) != LUA_TTABLE) | ||
569 | luaD_error(L, "`for' table must be a table"); | ||
570 | runtime_check(L, ttype(ra+1) == LUA_TNUMBER); | ||
575 | t = hvalue(ra); | 571 | t = hvalue(ra); |
576 | n = cast(int, nvalue(ra+1)); | 572 | n = cast(int, nvalue(ra+1)); |
577 | n = luaH_nexti(t, n, ra+2); | 573 | n = luaH_nexti(t, n, ra+2); |
578 | if (n != -1) { /* repeat loop? */ | 574 | if (n != -1) { /* repeat loop? */ |
579 | setnvalue(ra+1, n); /* index */ | 575 | setnvalue(ra+1, n); /* index */ |
580 | dojump(pc, i); /* repeat loop */ | ||
581 | } | 576 | } |
577 | else | ||
578 | pc -= j; /* undo jump */ | ||
582 | break; | 579 | break; |
583 | } | 580 | } |
584 | case OP_SETLIST: | 581 | case OP_SETLIST: |