aboutsummaryrefslogtreecommitdiff
path: root/lparser.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-19 10:53:18 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-19 10:53:18 -0300
commit9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0 (patch)
tree2a6b0f6c1c2eb962bb383175eb0a67ea81a4564d /lparser.c
parent1e0c73d5b643707335b06abd2546a83d9439d14c (diff)
downloadlua-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.tar.gz
lua-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.tar.bz2
lua-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.zip
New semantics for the integer 'for' loop
The numerical 'for' loop over integers now uses a precomputed counter to control its number of iteractions. This change eliminates several weird cases caused by overflows (wrap-around) in the control variable. (It also ensures that every integer loop halts.) Also, the special opcodes for the usual case of step==1 were removed. (The new code is already somewhat complex for the usual case, but efficient.)
Diffstat (limited to 'lparser.c')
-rw-r--r--lparser.c42
1 files changed, 16 insertions, 26 deletions
diff --git a/lparser.c b/lparser.c
index 3887958e..8ffd9742 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1371,18 +1371,14 @@ static void repeatstat (LexState *ls, int line) {
1371 1371
1372/* 1372/*
1373** Read an expression and generate code to put its results in next 1373** Read an expression and generate code to put its results in next
1374** stack slot. Return true if expression is a constant integer and, 1374** stack slot.
1375** if 'i' is not-zero, its value is equal to 'i'.
1376** 1375**
1377*/ 1376*/
1378static int exp1 (LexState *ls, int i) { 1377static void exp1 (LexState *ls) {
1379 expdesc e; 1378 expdesc e;
1380 int res;
1381 expr(ls, &e); 1379 expr(ls, &e);
1382 res = luaK_isKint(&e) && (i == 0 || i == e.u.ival);
1383 luaK_exp2nextreg(ls->fs, &e); 1380 luaK_exp2nextreg(ls->fs, &e);
1384 lua_assert(e.k == VNONRELOC); 1381 lua_assert(e.k == VNONRELOC);
1385 return res;
1386} 1382}
1387 1383
1388 1384
@@ -1403,31 +1399,29 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) {
1403 1399
1404 1400
1405/* 1401/*
1406** Generate code for a 'for' loop. 'kind' can be zero (a common for 1402** Generate code for a 'for' loop.
1407** loop), one (a basic for loop, with integer values and increment of
1408** 1), or two (a generic for loop).
1409*/ 1403*/
1410static void forbody (LexState *ls, int base, int line, int nvars, int kind) { 1404static void forbody (LexState *ls, int base, int line, int nvars, int isgen) {
1411 /* forbody -> DO block */ 1405 /* forbody -> DO block */
1412 static OpCode forprep[3] = {OP_FORPREP, OP_FORPREP1, OP_TFORPREP}; 1406 static OpCode forprep[2] = {OP_FORPREP, OP_TFORPREP};
1413 static OpCode forloop[3] = {OP_FORLOOP, OP_FORLOOP1, OP_TFORLOOP}; 1407 static OpCode forloop[2] = {OP_FORLOOP, OP_TFORLOOP};
1414 BlockCnt bl; 1408 BlockCnt bl;
1415 FuncState *fs = ls->fs; 1409 FuncState *fs = ls->fs;
1416 int prep, endfor; 1410 int prep, endfor;
1417 checknext(ls, TK_DO); 1411 checknext(ls, TK_DO);
1418 prep = luaK_codeABx(fs, forprep[kind], base, 0); 1412 prep = luaK_codeABx(fs, forprep[isgen], base, 0);
1419 enterblock(fs, &bl, 0); /* scope for declared variables */ 1413 enterblock(fs, &bl, 0); /* scope for declared variables */
1420 adjustlocalvars(ls, nvars); 1414 adjustlocalvars(ls, nvars);
1421 luaK_reserveregs(fs, nvars); 1415 luaK_reserveregs(fs, nvars);
1422 block(ls); 1416 block(ls);
1423 leaveblock(fs); /* end of scope for declared variables */ 1417 leaveblock(fs); /* end of scope for declared variables */
1424 fixforjump(fs, prep, luaK_getlabel(fs), 0); 1418 fixforjump(fs, prep, luaK_getlabel(fs), 0);
1425 if (kind == 2) { /* generic for? */ 1419 if (isgen) { /* generic for? */
1426 luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); 1420 luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
1427 luaK_fixline(fs, line); 1421 luaK_fixline(fs, line);
1428 base += 2; /* base for 'OP_TFORLOOP' (skips function and state) */ 1422 base += 2; /* base for 'OP_TFORLOOP' (skips function and state) */
1429 } 1423 }
1430 endfor = luaK_codeABx(fs, forloop[kind], base, 0); 1424 endfor = luaK_codeABx(fs, forloop[isgen], base, 0);
1431 fixforjump(fs, endfor, prep + 1, 1); 1425 fixforjump(fs, endfor, prep + 1, 1);
1432 luaK_fixline(fs, line); 1426 luaK_fixline(fs, line);
1433} 1427}
@@ -1437,26 +1431,22 @@ static void fornum (LexState *ls, TString *varname, int line) {
1437 /* fornum -> NAME = exp,exp[,exp] forbody */ 1431 /* fornum -> NAME = exp,exp[,exp] forbody */
1438 FuncState *fs = ls->fs; 1432 FuncState *fs = ls->fs;
1439 int base = fs->freereg; 1433 int base = fs->freereg;
1440 int basicfor = 1; /* true if it is a "basic" 'for' (integer + 1) */
1441 new_localvarliteral(ls, "(for index)"); 1434 new_localvarliteral(ls, "(for index)");
1442 new_localvarliteral(ls, "(for limit)"); 1435 new_localvarliteral(ls, "(for limit)");
1443 new_localvarliteral(ls, "(for step)"); 1436 new_localvarliteral(ls, "(for step)");
1444 new_localvar(ls, varname); 1437 new_localvar(ls, varname);
1445 checknext(ls, '='); 1438 checknext(ls, '=');
1446 if (!exp1(ls, 0)) /* initial value not an integer? */ 1439 exp1(ls); /* initial value */
1447 basicfor = 0; /* not a basic 'for' */
1448 checknext(ls, ','); 1440 checknext(ls, ',');
1449 exp1(ls, 0); /* limit */ 1441 exp1(ls); /* limit */
1450 if (testnext(ls, ',')) { 1442 if (testnext(ls, ','))
1451 if (!exp1(ls, 1)) /* optional step not 1? */ 1443 exp1(ls); /* optional step */
1452 basicfor = 0; /* not a basic 'for' */
1453 }
1454 else { /* default step = 1 */ 1444 else { /* default step = 1 */
1455 luaK_int(fs, fs->freereg, 1); 1445 luaK_int(fs, fs->freereg, 1);
1456 luaK_reserveregs(fs, 1); 1446 luaK_reserveregs(fs, 1);
1457 } 1447 }
1458 adjustlocalvars(ls, 3); /* control variables */ 1448 adjustlocalvars(ls, 3); /* control variables */
1459 forbody(ls, base, line, 1, basicfor); 1449 forbody(ls, base, line, 1, 0);
1460} 1450}
1461 1451
1462 1452
@@ -1484,7 +1474,7 @@ static void forlist (LexState *ls, TString *indexname) {
1484 adjust_assign(ls, 4, explist(ls, &e), &e); 1474 adjust_assign(ls, 4, explist(ls, &e), &e);
1485 adjustlocalvars(ls, 4); /* control variables */ 1475 adjustlocalvars(ls, 4); /* control variables */
1486 luaK_checkstack(fs, 3); /* extra space to call generator */ 1476 luaK_checkstack(fs, 3); /* extra space to call generator */
1487 forbody(ls, base, line, nvars - 4, 2); 1477 forbody(ls, base, line, nvars - 4, 1);
1488} 1478}
1489 1479
1490 1480
@@ -1633,7 +1623,7 @@ static void tocloselocalstat (LexState *ls) {
1633 luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); 1623 luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr)));
1634 new_localvar(ls, str_checkname(ls)); 1624 new_localvar(ls, str_checkname(ls));
1635 checknext(ls, '='); 1625 checknext(ls, '=');
1636 exp1(ls, 0); 1626 exp1(ls);
1637 markupval(fs, fs->nactvar); 1627 markupval(fs, fs->nactvar);
1638 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ 1628 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1639 adjustlocalvars(ls, 1); 1629 adjustlocalvars(ls, 1);