diff options
| -rw-r--r-- | lcode.c | 62 | ||||
| -rw-r--r-- | lcode.h | 1 | ||||
| -rw-r--r-- | lparser.c | 34 | ||||
| -rw-r--r-- | lparser.h | 2 |
4 files changed, 73 insertions, 26 deletions
| @@ -52,7 +52,7 @@ l_noret luaK_semerror (LexState *ls, const char *msg) { | |||
| 52 | ** If expression is a numeric constant, fills 'v' with its value | 52 | ** If expression is a numeric constant, fills 'v' with its value |
| 53 | ** and returns 1. Otherwise, returns 0. | 53 | ** and returns 1. Otherwise, returns 0. |
| 54 | */ | 54 | */ |
| 55 | static int tonumeral(const expdesc *e, TValue *v) { | 55 | int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v) { |
| 56 | if (hasjumps(e)) | 56 | if (hasjumps(e)) |
| 57 | return 0; /* not a numeral */ | 57 | return 0; /* not a numeral */ |
| 58 | switch (e->k) { | 58 | switch (e->k) { |
| @@ -62,12 +62,42 @@ static int tonumeral(const expdesc *e, TValue *v) { | |||
| 62 | case VKFLT: | 62 | case VKFLT: |
| 63 | if (v) setfltvalue(v, e->u.nval); | 63 | if (v) setfltvalue(v, e->u.nval); |
| 64 | return 1; | 64 | return 1; |
| 65 | case VUPVAL: { /* may be a constant */ | ||
| 66 | Vardesc *vd = luaY_getvardesc(&fs, e); | ||
| 67 | if (v && vd && !ttisnil(&vd->val)) { | ||
| 68 | setobj(fs->ls->L, v, &vd->val); | ||
| 69 | return 1; | ||
| 70 | } /* else */ | ||
| 71 | } /* FALLTHROUGH */ | ||
| 65 | default: return 0; | 72 | default: return 0; |
| 66 | } | 73 | } |
| 67 | } | 74 | } |
| 68 | 75 | ||
| 69 | 76 | ||
| 70 | /* | 77 | /* |
| 78 | ** If expression 'e' is a constant, change 'e' to represent | ||
| 79 | ** the constant value. | ||
| 80 | */ | ||
| 81 | static int const2exp (FuncState *fs, expdesc *e) { | ||
| 82 | Vardesc *vd = luaY_getvardesc(&fs, e); | ||
| 83 | if (vd) { | ||
| 84 | TValue *v = &vd->val; | ||
| 85 | switch (ttypetag(v)) { | ||
| 86 | case LUA_TNUMINT: | ||
| 87 | e->k = VKINT; | ||
| 88 | e->u.ival = ivalue(v); | ||
| 89 | return 1; | ||
| 90 | case LUA_TNUMFLT: | ||
| 91 | e->k = VKFLT; | ||
| 92 | e->u.nval = fltvalue(v); | ||
| 93 | return 1; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | /* | ||
| 71 | ** Return the previous instruction of the current code. If there | 101 | ** Return the previous instruction of the current code. If there |
| 72 | ** may be a jump target between the current instruction and the | 102 | ** may be a jump target between the current instruction and the |
| 73 | ** previous one, return an invalid instruction (to avoid wrong | 103 | ** previous one, return an invalid instruction (to avoid wrong |
| @@ -683,8 +713,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { | |||
| 683 | break; | 713 | break; |
| 684 | } | 714 | } |
| 685 | case VUPVAL: { /* move value to some (pending) register */ | 715 | case VUPVAL: { /* move value to some (pending) register */ |
| 686 | e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0); | 716 | if (!const2exp(fs, e)) { |
| 687 | e->k = VRELOC; | 717 | e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0); |
| 718 | e->k = VRELOC; | ||
| 719 | } | ||
| 688 | break; | 720 | break; |
| 689 | } | 721 | } |
| 690 | case VINDEXUP: { | 722 | case VINDEXUP: { |
| @@ -1218,9 +1250,11 @@ static int validop (int op, TValue *v1, TValue *v2) { | |||
| 1218 | ** (In this case, 'e1' has the final result.) | 1250 | ** (In this case, 'e1' has the final result.) |
| 1219 | */ | 1251 | */ |
| 1220 | static int constfolding (FuncState *fs, int op, expdesc *e1, | 1252 | static int constfolding (FuncState *fs, int op, expdesc *e1, |
| 1221 | const expdesc *e2) { | 1253 | const expdesc *e2) { |
| 1222 | TValue v1, v2, res; | 1254 | TValue v1, v2, res; |
| 1223 | if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) | 1255 | if (!luaK_tonumeral(fs, e1, &v1) || |
| 1256 | !luaK_tonumeral(fs, e2, &v2) || | ||
| 1257 | !validop(op, &v1, &v2)) | ||
| 1224 | return 0; /* non-numeric operands or not safe to fold */ | 1258 | return 0; /* non-numeric operands or not safe to fold */ |
| 1225 | luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ | 1259 | luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ |
| 1226 | if (ttisinteger(&res)) { | 1260 | if (ttisinteger(&res)) { |
| @@ -1307,7 +1341,7 @@ static void codearith (FuncState *fs, OpCode op, | |||
| 1307 | expdesc *e1, expdesc *e2, int flip, int line) { | 1341 | expdesc *e1, expdesc *e2, int flip, int line) { |
| 1308 | if (isSCint(e2)) /* immediate operand? */ | 1342 | if (isSCint(e2)) /* immediate operand? */ |
| 1309 | codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line); | 1343 | codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line); |
| 1310 | else if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ | 1344 | else if (luaK_tonumeral(fs, e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ |
| 1311 | int v2 = e2->u.info; /* K index */ | 1345 | int v2 = e2->u.info; /* K index */ |
| 1312 | op = cast(OpCode, op - OP_ADD + OP_ADDK); | 1346 | op = cast(OpCode, op - OP_ADD + OP_ADDK); |
| 1313 | finishbinexpval(fs, e1, e2, op, v2, flip, line); | 1347 | finishbinexpval(fs, e1, e2, op, v2, flip, line); |
| @@ -1328,7 +1362,7 @@ static void codearith (FuncState *fs, OpCode op, | |||
| 1328 | static void codecommutative (FuncState *fs, OpCode op, | 1362 | static void codecommutative (FuncState *fs, OpCode op, |
| 1329 | expdesc *e1, expdesc *e2, int line) { | 1363 | expdesc *e1, expdesc *e2, int line) { |
| 1330 | int flip = 0; | 1364 | int flip = 0; |
| 1331 | if (tonumeral(e1, NULL)) { /* is first operand a numeric constant? */ | 1365 | if (luaK_tonumeral(fs, e1, NULL)) { /* is first operand a numeric constant? */ |
| 1332 | swapexps(e1, e2); /* change order */ | 1366 | swapexps(e1, e2); /* change order */ |
| 1333 | flip = 1; | 1367 | flip = 1; |
| 1334 | } | 1368 | } |
| @@ -1451,7 +1485,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { | |||
| 1451 | case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ | 1485 | case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ |
| 1452 | if (constfolding(fs, op + LUA_OPUNM, e, &ef)) | 1486 | if (constfolding(fs, op + LUA_OPUNM, e, &ef)) |
| 1453 | break; | 1487 | break; |
| 1454 | /* FALLTHROUGH */ | 1488 | /* else */ /* FALLTHROUGH */ |
| 1455 | case OPR_LEN: | 1489 | case OPR_LEN: |
| 1456 | codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); | 1490 | codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); |
| 1457 | break; | 1491 | break; |
| @@ -1466,6 +1500,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { | |||
| 1466 | ** 2nd operand. | 1500 | ** 2nd operand. |
| 1467 | */ | 1501 | */ |
| 1468 | void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { | 1502 | void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { |
| 1503 | luaK_dischargevars(fs, v); | ||
| 1469 | switch (op) { | 1504 | switch (op) { |
| 1470 | case OPR_AND: { | 1505 | case OPR_AND: { |
| 1471 | luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ | 1506 | luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ |
| @@ -1484,13 +1519,13 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { | |||
| 1484 | case OPR_MOD: case OPR_POW: | 1519 | case OPR_MOD: case OPR_POW: |
| 1485 | case OPR_BAND: case OPR_BOR: case OPR_BXOR: | 1520 | case OPR_BAND: case OPR_BOR: case OPR_BXOR: |
| 1486 | case OPR_SHL: case OPR_SHR: { | 1521 | case OPR_SHL: case OPR_SHR: { |
| 1487 | if (!tonumeral(v, NULL)) | 1522 | if (!luaK_tonumeral(fs, v, NULL)) |
| 1488 | luaK_exp2anyreg(fs, v); | 1523 | luaK_exp2anyreg(fs, v); |
| 1489 | /* else keep numeral, which may be folded with 2nd operand */ | 1524 | /* else keep numeral, which may be folded with 2nd operand */ |
| 1490 | break; | 1525 | break; |
| 1491 | } | 1526 | } |
| 1492 | case OPR_EQ: case OPR_NE: { | 1527 | case OPR_EQ: case OPR_NE: { |
| 1493 | if (!tonumeral(v, NULL)) | 1528 | if (!luaK_tonumeral(fs, v, NULL)) |
| 1494 | luaK_exp2RK(fs, v); | 1529 | luaK_exp2RK(fs, v); |
| 1495 | /* else keep numeral, which may be an immediate operand */ | 1530 | /* else keep numeral, which may be an immediate operand */ |
| 1496 | break; | 1531 | break; |
| @@ -1535,17 +1570,16 @@ static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) { | |||
| 1535 | */ | 1570 | */ |
| 1536 | void luaK_posfix (FuncState *fs, BinOpr opr, | 1571 | void luaK_posfix (FuncState *fs, BinOpr opr, |
| 1537 | expdesc *e1, expdesc *e2, int line) { | 1572 | expdesc *e1, expdesc *e2, int line) { |
| 1573 | luaK_dischargevars(fs, e2); | ||
| 1538 | switch (opr) { | 1574 | switch (opr) { |
| 1539 | case OPR_AND: { | 1575 | case OPR_AND: { |
| 1540 | lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ | 1576 | lua_assert(e1->t == NO_JUMP); /* list closed by 'luaK_infix' */ |
| 1541 | luaK_dischargevars(fs, e2); | ||
| 1542 | luaK_concat(fs, &e2->f, e1->f); | 1577 | luaK_concat(fs, &e2->f, e1->f); |
| 1543 | *e1 = *e2; | 1578 | *e1 = *e2; |
| 1544 | break; | 1579 | break; |
| 1545 | } | 1580 | } |
| 1546 | case OPR_OR: { | 1581 | case OPR_OR: { |
| 1547 | lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ | 1582 | lua_assert(e1->f == NO_JUMP); /* list closed by 'luaK_infix' */ |
| 1548 | luaK_dischargevars(fs, e2); | ||
| 1549 | luaK_concat(fs, &e2->t, e1->t); | 1583 | luaK_concat(fs, &e2->t, e1->t); |
| 1550 | *e1 = *e2; | 1584 | *e1 = *e2; |
| 1551 | break; | 1585 | break; |
| @@ -51,6 +51,7 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; | |||
| 51 | 51 | ||
| 52 | #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) | 52 | #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) |
| 53 | 53 | ||
| 54 | LUAI_FUNC int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v); | ||
| 54 | LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); | 55 | LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); |
| 55 | LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); | 56 | LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); |
| 56 | LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, | 57 | LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, |
| @@ -206,6 +206,7 @@ static Vardesc *new_localvar (LexState *ls, TString *name) { | |||
| 206 | var = &dyd->actvar.arr[dyd->actvar.n++]; | 206 | var = &dyd->actvar.arr[dyd->actvar.n++]; |
| 207 | var->idx = cast(short, reg); | 207 | var->idx = cast(short, reg); |
| 208 | var->ro = 0; | 208 | var->ro = 0; |
| 209 | setnilvalue(&var->val); | ||
| 209 | return var; | 210 | return var; |
| 210 | } | 211 | } |
| 211 | 212 | ||
| @@ -238,7 +239,7 @@ static LocVar *getlocvar (FuncState *fs, int i) { | |||
| 238 | ** where that variable was defined. Return NULL if expression | 239 | ** where that variable was defined. Return NULL if expression |
| 239 | ** is neither a local variable nor an upvalue. | 240 | ** is neither a local variable nor an upvalue. |
| 240 | */ | 241 | */ |
| 241 | static Vardesc *getvardesc (FuncState **fs, expdesc *e) { | 242 | Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e) { |
| 242 | if (e->k == VLOCAL) | 243 | if (e->k == VLOCAL) |
| 243 | return getlocalvardesc(*fs, e->u.var.idx); | 244 | return getlocalvardesc(*fs, e->u.var.idx); |
| 244 | else if (e->k != VUPVAL) | 245 | else if (e->k != VUPVAL) |
| @@ -261,7 +262,7 @@ static Vardesc *getvardesc (FuncState **fs, expdesc *e) { | |||
| 261 | 262 | ||
| 262 | static void check_readonly (LexState *ls, expdesc *e) { | 263 | static void check_readonly (LexState *ls, expdesc *e) { |
| 263 | FuncState *fs = ls->fs; | 264 | FuncState *fs = ls->fs; |
| 264 | Vardesc *vardesc = getvardesc(&fs, e); | 265 | Vardesc *vardesc = luaY_getvardesc(&fs, e); |
| 265 | if (vardesc && vardesc->ro) { /* is variable local and const? */ | 266 | if (vardesc && vardesc->ro) { /* is variable local and const? */ |
| 266 | const char *msg = luaO_pushfstring(ls->L, | 267 | const char *msg = luaO_pushfstring(ls->L, |
| 267 | "attempt to assign to const variable '%s'", | 268 | "attempt to assign to const variable '%s'", |
| @@ -1678,20 +1679,13 @@ static void commonlocalstat (LexState *ls) { | |||
| 1678 | static void tocloselocalstat (LexState *ls, Vardesc *var) { | 1679 | static void tocloselocalstat (LexState *ls, Vardesc *var) { |
| 1679 | FuncState *fs = ls->fs; | 1680 | FuncState *fs = ls->fs; |
| 1680 | var->ro = 1; /* to-be-closed variables are always read-only */ | 1681 | var->ro = 1; /* to-be-closed variables are always read-only */ |
| 1681 | markupval(fs, fs->nactvar); | 1682 | markupval(fs, fs->nactvar + 1); |
| 1682 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | 1683 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ |
| 1683 | luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); | 1684 | luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0); |
| 1684 | } | 1685 | } |
| 1685 | 1686 | ||
| 1686 | 1687 | ||
| 1687 | static void attriblocalstat (LexState *ls) { | 1688 | static void checkattrib (LexState *ls, TString *attr, Vardesc *var) { |
| 1688 | Vardesc *var; | ||
| 1689 | TString *attr = str_checkname(ls); | ||
| 1690 | testnext(ls, '>'); | ||
| 1691 | var = new_localvar(ls, str_checkname(ls)); | ||
| 1692 | checknext(ls, '='); | ||
| 1693 | exp1(ls); | ||
| 1694 | adjustlocalvars(ls, 1); | ||
| 1695 | if (strcmp(getstr(attr), "const") == 0) | 1689 | if (strcmp(getstr(attr), "const") == 0) |
| 1696 | var->ro = 1; /* set variable as read-only */ | 1690 | var->ro = 1; /* set variable as read-only */ |
| 1697 | else if (strcmp(getstr(attr), "toclose") == 0) | 1691 | else if (strcmp(getstr(attr), "toclose") == 0) |
| @@ -1702,6 +1696,22 @@ static void attriblocalstat (LexState *ls) { | |||
| 1702 | } | 1696 | } |
| 1703 | 1697 | ||
| 1704 | 1698 | ||
| 1699 | static void attriblocalstat (LexState *ls) { | ||
| 1700 | FuncState *fs = ls->fs; | ||
| 1701 | Vardesc *var; | ||
| 1702 | expdesc e; | ||
| 1703 | TString *attr = str_checkname(ls); | ||
| 1704 | testnext(ls, '>'); | ||
| 1705 | var = new_localvar(ls, str_checkname(ls)); | ||
| 1706 | checknext(ls, '='); | ||
| 1707 | expr(ls, &e); | ||
| 1708 | checkattrib(ls, attr, var); | ||
| 1709 | luaK_tonumeral(fs, &e, &var->val); | ||
| 1710 | luaK_exp2nextreg(fs, &e); | ||
| 1711 | adjustlocalvars(ls, 1); | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | |||
| 1705 | static void localstat (LexState *ls) { | 1715 | static void localstat (LexState *ls) { |
| 1706 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] | 1716 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] |
| 1707 | | LOCAL *toclose NAME '=' exp */ | 1717 | | LOCAL *toclose NAME '=' exp */ |
| @@ -81,6 +81,7 @@ typedef struct expdesc { | |||
| 81 | 81 | ||
| 82 | /* description of an active local variable */ | 82 | /* description of an active local variable */ |
| 83 | typedef struct Vardesc { | 83 | typedef struct Vardesc { |
| 84 | TValue val; /* constant value (if variable is 'const') */ | ||
| 84 | short idx; /* index of the variable in the Proto's 'locvars' array */ | 85 | short idx; /* index of the variable in the Proto's 'locvars' array */ |
| 85 | lu_byte ro; /* true if variable is 'const' */ | 86 | lu_byte ro; /* true if variable is 'const' */ |
| 86 | } Vardesc; | 87 | } Vardesc; |
| @@ -143,6 +144,7 @@ typedef struct FuncState { | |||
| 143 | } FuncState; | 144 | } FuncState; |
| 144 | 145 | ||
| 145 | 146 | ||
| 147 | LUAI_FUNC Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e); | ||
| 146 | LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, | 148 | LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, |
| 147 | Dyndata *dyd, const char *name, int firstchar); | 149 | Dyndata *dyd, const char *name, int firstchar); |
| 148 | 150 | ||
