diff options
| -rw-r--r-- | lvm.c | 87 | ||||
| -rw-r--r-- | testes/nextvar.lua | 6 |
2 files changed, 49 insertions, 44 deletions
| @@ -150,35 +150,36 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { | |||
| 150 | ** Try to convert a 'for' limit to an integer, preserving the semantics | 150 | ** Try to convert a 'for' limit to an integer, preserving the semantics |
| 151 | ** of the loop. (The following explanation assumes a positive step; | 151 | ** of the loop. (The following explanation assumes a positive step; |
| 152 | ** it is valid for negative steps mutatis mutandis.) | 152 | ** it is valid for negative steps mutatis mutandis.) |
| 153 | ** Return true if the loop must not run. | ||
| 153 | ** If the limit is an integer or can be converted to an integer, | 154 | ** If the limit is an integer or can be converted to an integer, |
| 154 | ** rounding down, that is it. | 155 | ** rounding down, that is the limit. |
| 155 | ** Otherwise, check whether the limit can be converted to a float. If | 156 | ** Otherwise, check whether the limit can be converted to a float. If |
| 156 | ** the float is too large, clip it to LUA_MAXINTEGER. If the float | 157 | ** the float is too large, clip it to LUA_MAXINTEGER. If the float |
| 157 | ** is too negative, the loop should not run, because any initial | 158 | ** is too negative, the loop should not run, because any initial |
| 158 | ** integer value is greater than such limit; so, it sets 'stopnow'. | 159 | ** integer value is greater than such limit; so, it returns true to |
| 160 | ** signal that. | ||
| 159 | ** (For this latter case, no integer limit would be correct; even a | 161 | ** (For this latter case, no integer limit would be correct; even a |
| 160 | ** limit of LUA_MININTEGER would run the loop once for an initial | 162 | ** limit of LUA_MININTEGER would run the loop once for an initial |
| 161 | ** value equal to LUA_MININTEGER.) | 163 | ** value equal to LUA_MININTEGER.) |
| 162 | */ | 164 | */ |
| 163 | static int forlimit (const TValue *lim, lua_Integer *p, lua_Integer step, | 165 | static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, |
| 164 | int *stopnow) { | 166 | lua_Integer *p, lua_Integer step) { |
| 165 | *stopnow = 0; /* usually, let loops run */ | ||
| 166 | if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) { | 167 | if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) { |
| 167 | /* not coercible to in integer */ | 168 | /* not coercible to in integer */ |
| 168 | lua_Number flim; /* try to convert to float */ | 169 | lua_Number flim; /* try to convert to float */ |
| 169 | if (!tonumber(lim, &flim)) /* cannot convert to float? */ | 170 | if (!tonumber(lim, &flim)) /* cannot convert to float? */ |
| 170 | return 0; /* not a number */ | 171 | luaG_forerror(L, lim, "limit"); |
| 171 | /* 'flim' is a float out of integer bounds */ | 172 | /* else 'flim' is a float out of integer bounds */ |
| 172 | if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ | 173 | if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ |
| 174 | if (step < 0) return 1; /* initial value must be less than it */ | ||
| 173 | *p = LUA_MAXINTEGER; /* truncate */ | 175 | *p = LUA_MAXINTEGER; /* truncate */ |
| 174 | if (step < 0) *stopnow = 1; /* initial value must be less than it */ | ||
| 175 | } | 176 | } |
| 176 | else { /* it is less than min integer */ | 177 | else { /* it is less than min integer */ |
| 178 | if (step > 0) return 1; /* initial value must be greater than it */ | ||
| 177 | *p = LUA_MININTEGER; /* truncate */ | 179 | *p = LUA_MININTEGER; /* truncate */ |
| 178 | if (step > 0) *stopnow = 1; /* initial value must be greater than it */ | ||
| 179 | } | 180 | } |
| 180 | } | 181 | } |
| 181 | return 1; | 182 | return (step > 0 ? init > *p : init < *p); /* not to run? */ |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | 185 | ||
| @@ -1637,24 +1638,26 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1637 | } | 1638 | } |
| 1638 | vmcase(OP_FORLOOP) { | 1639 | vmcase(OP_FORLOOP) { |
| 1639 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ | 1640 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ |
| 1640 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra))); | 1641 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); |
| 1641 | if (count > 0) { /* still more iterations? */ | 1642 | if (count > 0) { /* still more iterations? */ |
| 1642 | lua_Integer step = ivalue(s2v(ra + 2)); | 1643 | lua_Integer step = ivalue(s2v(ra + 2)); |
| 1643 | lua_Integer idx = ivalue(s2v(ra + 3)); | 1644 | lua_Integer idx = ivalue(s2v(ra)); /* internal index */ |
| 1645 | chgivalue(s2v(ra + 1), count - 1); /* update counter */ | ||
| 1644 | idx = intop(+, idx, step); /* add step to index */ | 1646 | idx = intop(+, idx, step); /* add step to index */ |
| 1645 | chgivalue(s2v(ra), count - 1); /* update counter... */ | 1647 | chgivalue(s2v(ra), idx); /* update internal index */ |
| 1646 | setivalue(s2v(ra + 3), idx); /* ...and index */ | 1648 | setivalue(s2v(ra + 3), idx); /* and control variable */ |
| 1647 | pc -= GETARG_Bx(i); /* jump back */ | 1649 | pc -= GETARG_Bx(i); /* jump back */ |
| 1648 | } | 1650 | } |
| 1649 | } | 1651 | } |
| 1650 | else { /* floating loop */ | 1652 | else { /* floating loop */ |
| 1651 | lua_Number step = fltvalue(s2v(ra + 2)); | 1653 | lua_Number step = fltvalue(s2v(ra + 2)); |
| 1652 | lua_Number limit = fltvalue(s2v(ra + 1)); | 1654 | lua_Number limit = fltvalue(s2v(ra + 1)); |
| 1653 | lua_Number idx = fltvalue(s2v(ra + 3)); | 1655 | lua_Number idx = fltvalue(s2v(ra)); |
| 1654 | idx = luai_numadd(L, idx, step); /* inc. index */ | 1656 | idx = luai_numadd(L, idx, step); /* increment index */ |
| 1655 | if (luai_numlt(0, step) ? luai_numle(idx, limit) | 1657 | if (luai_numlt(0, step) ? luai_numle(idx, limit) |
| 1656 | : luai_numle(limit, idx)) { | 1658 | : luai_numle(limit, idx)) { |
| 1657 | setfltvalue(s2v(ra + 3), idx); /* update index */ | 1659 | chgfltvalue(s2v(ra), idx); /* update internal index */ |
| 1660 | setfltvalue(s2v(ra + 3), idx); /* and control variable */ | ||
| 1658 | pc -= GETARG_Bx(i); /* jump back */ | 1661 | pc -= GETARG_Bx(i); /* jump back */ |
| 1659 | } | 1662 | } |
| 1660 | } | 1663 | } |
| @@ -1665,56 +1668,52 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1665 | TValue *pinit = s2v(ra); | 1668 | TValue *pinit = s2v(ra); |
| 1666 | TValue *plimit = s2v(ra + 1); | 1669 | TValue *plimit = s2v(ra + 1); |
| 1667 | TValue *pstep = s2v(ra + 2); | 1670 | TValue *pstep = s2v(ra + 2); |
| 1668 | lua_Integer ilimit; | ||
| 1669 | int stopnow; | ||
| 1670 | savestate(L, ci); /* in case of errors */ | 1671 | savestate(L, ci); /* in case of errors */ |
| 1671 | if (ttisinteger(pinit) && ttisinteger(pstep) && | 1672 | if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */ |
| 1672 | forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { | ||
| 1673 | /* integer loop */ | ||
| 1674 | lua_Integer init = ivalue(pinit); | 1673 | lua_Integer init = ivalue(pinit); |
| 1675 | lua_Integer step = ivalue(pstep); | 1674 | lua_Integer step = ivalue(pstep); |
| 1676 | setivalue(s2v(ra + 3), init); /* control variable */ | 1675 | lua_Integer limit; |
| 1677 | if (step == 0) | 1676 | if (step == 0) |
| 1678 | luaG_runerror(L, "'for' step is zero"); | 1677 | luaG_runerror(L, "'for' step is zero"); |
| 1679 | else if (stopnow) | 1678 | setivalue(s2v(ra + 3), init); /* control variable */ |
| 1679 | if (forlimit(L, init, plimit, &limit, step)) | ||
| 1680 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | 1680 | pc += GETARG_Bx(i) + 1; /* skip the loop */ |
| 1681 | else if (step > 0) { /* ascending loop? */ | 1681 | else { /* prepare loop counter */ |
| 1682 | if (init > ilimit) | 1682 | lua_Unsigned count; |
| 1683 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | 1683 | if (step > 0) { /* ascending loop? */ |
| 1684 | else { | 1684 | count = l_castS2U(limit) - l_castS2U(init); |
| 1685 | lua_Unsigned count = l_castS2U(ilimit) - l_castS2U(init); | ||
| 1686 | if (step != 1) /* avoid division in the too common case */ | 1685 | if (step != 1) /* avoid division in the too common case */ |
| 1687 | count /= l_castS2U(step); | 1686 | count /= l_castS2U(step); |
| 1688 | setivalue(s2v(ra), count); | ||
| 1689 | } | 1687 | } |
| 1690 | } | 1688 | else { /* step < 0; descending loop */ |
| 1691 | else { /* descending loop */ | 1689 | count = l_castS2U(init) - l_castS2U(limit); |
| 1692 | if (init < ilimit) | ||
| 1693 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
| 1694 | else { | ||
| 1695 | lua_Unsigned count = l_castS2U(init) - l_castS2U(ilimit); | ||
| 1696 | count /= -l_castS2U(step); | 1690 | count /= -l_castS2U(step); |
| 1697 | setivalue(s2v(ra), count); | ||
| 1698 | } | 1691 | } |
| 1692 | /* store the counter in place of the limit (which won't be | ||
| 1693 | needed anymore */ | ||
| 1694 | setivalue(plimit, l_castU2S(count)); | ||
| 1699 | } | 1695 | } |
| 1700 | } | 1696 | } |
| 1701 | else { /* try making all values floats */ | 1697 | else { /* try making all values floats */ |
| 1702 | lua_Number init; lua_Number flimit; lua_Number step; | 1698 | lua_Number init; lua_Number limit; lua_Number step; |
| 1703 | if (unlikely(!tonumber(plimit, &flimit))) | 1699 | if (unlikely(!tonumber(plimit, &limit))) |
| 1704 | luaG_forerror(L, plimit, "limit"); | 1700 | luaG_forerror(L, plimit, "limit"); |
| 1705 | setfltvalue(plimit, flimit); | ||
| 1706 | if (unlikely(!tonumber(pstep, &step))) | 1701 | if (unlikely(!tonumber(pstep, &step))) |
| 1707 | luaG_forerror(L, pstep, "step"); | 1702 | luaG_forerror(L, pstep, "step"); |
| 1708 | setfltvalue(pstep, step); | ||
| 1709 | if (unlikely(!tonumber(pinit, &init))) | 1703 | if (unlikely(!tonumber(pinit, &init))) |
| 1710 | luaG_forerror(L, pinit, "initial value"); | 1704 | luaG_forerror(L, pinit, "initial value"); |
| 1711 | if (step == 0) | 1705 | if (step == 0) |
| 1712 | luaG_runerror(L, "'for' step is zero"); | 1706 | luaG_runerror(L, "'for' step is zero"); |
| 1713 | if (luai_numlt(0, step) ? luai_numlt(flimit, init) | 1707 | if (luai_numlt(0, step) ? luai_numlt(limit, init) |
| 1714 | : luai_numlt(init, flimit)) | 1708 | : luai_numlt(init, limit)) |
| 1715 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | 1709 | pc += GETARG_Bx(i) + 1; /* skip the loop */ |
| 1716 | else | 1710 | else { |
| 1711 | /* make sure internal values are all float */ | ||
| 1712 | setfltvalue(plimit, limit); | ||
| 1713 | setfltvalue(pstep, step); | ||
| 1714 | setfltvalue(s2v(ra), init); /* internal index */ | ||
| 1717 | setfltvalue(s2v(ra + 3), init); /* control variable */ | 1715 | setfltvalue(s2v(ra + 3), init); /* control variable */ |
| 1716 | } | ||
| 1718 | } | 1717 | } |
| 1719 | vmbreak; | 1718 | vmbreak; |
| 1720 | } | 1719 | } |
diff --git a/testes/nextvar.lua b/testes/nextvar.lua index e769ccdd..87a6bfa8 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua | |||
| @@ -544,6 +544,12 @@ do | |||
| 544 | a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) | 544 | a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) |
| 545 | end | 545 | end |
| 546 | 546 | ||
| 547 | do -- changing the control variable | ||
| 548 | local a | ||
| 549 | a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10) | ||
| 550 | a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10) | ||
| 551 | end | ||
| 552 | |||
| 547 | -- conversion | 553 | -- conversion |
| 548 | a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5) | 554 | a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5) |
| 549 | 555 | ||
