| 1354 | |
| 1355 | |
| 1356 | static void forstat (LexState *ls, int line) { |
| 1357 | /* forstat -> FOR (fornum | forlist) END */ |
| 1358 | FuncState *fs = ls->fs; |
| 1359 | TString *varname; |
| 1360 | BlockCnt bl; |
| 1361 | enterblock(fs, &bl, 1); /* scope for loop and control variables */ |
| 1362 | luaX_next(ls); /* skip `for' */ |
| 1363 | varname = str_checkname(ls); /* first variable name */ |
| 1364 | switch (ls->t.token) { |
| 1365 | case '=': fornum(ls, varname, line); break; |
| 1366 | case ',': case TK_IN: forlist(ls, varname); break; |
| 1367 | default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); |
| 1368 | } |
| 1369 | check_match(ls, TK_END, TK_FOR, line); |
| 1370 | leaveblock(fs); /* loop scope (`break' jumps to this point) */ |
| 1371 | } |
| 1372 | |
| 1373 | |
| 1374 | static void test_then_block (LexState *ls, int *escapelist) { |
| 1375 | /* test_then_block -> [IF | ELSEIF] cond THEN block */ |
| 1376 | BlockCnt bl; |
| 1377 | FuncState *fs = ls->fs; |
| 1378 | expdesc v; |
| 1379 | int jf; /* instruction to skip 'then' code (if condition is false) */ |
| 1380 | luaX_next(ls); /* skip IF or ELSEIF */ |
| 1381 | expr(ls, &v); /* read condition */ |
| 1382 | checknext(ls, TK_THEN); |
| 1383 | if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { |
| 1384 | luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ |
| 1385 | enterblock(fs, &bl, 0); /* must enter block before 'goto' */ |
| 1386 | gotostat(ls, v.t); /* handle goto/break */ |
| 1387 | skipnoopstat(ls); /* skip other no-op statements */ |
| 1388 | if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ |
| 1389 | leaveblock(fs); |
| 1390 | return; /* and that is it */ |
| 1391 | } |
| 1392 | else /* must skip over 'then' part if condition is false */ |
| 1393 | jf = luaK_jump(fs); |
| 1394 | } |
| 1395 | else { /* regular case (not goto/break) */ |
| 1396 | luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ |
| 1397 | enterblock(fs, &bl, 0); |
| 1398 | jf = v.f; |
| 1399 | } |
| 1400 | statlist(ls); /* `then' part */ |
| 1401 | leaveblock(fs); |
| 1402 | if (ls->t.token == TK_ELSE || |
| 1403 | ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ |
| 1404 | luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ |
| 1405 | luaK_patchtohere(fs, jf); |
| 1406 | } |
| 1407 | |
| 1408 | |
| 1409 | static void ifstat (LexState *ls, int line) { |
| 1410 | /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ |
| 1411 | FuncState *fs = ls->fs; |
| 1412 | int escapelist = NO_JUMP; /* exit list for finished parts */ |
| 1413 | test_then_block(ls, &escapelist); /* IF cond THEN block */ |
no test coverage detected