diff --git a/lcode.c b/lcode.c index 149114cf..54c6857b 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.73 2013/12/16 14:30:22 roberto Exp roberto $ +** $Id: lcode.c,v 2.74 2013/12/16 19:06:52 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -750,18 +750,27 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { } +/* return false if folding can raise an error */ +static int validop (OpCode op, TValue *v1, TValue *v2) { + lua_Integer i; + switch (op) { + case OP_IDIV: /* division by 0 and conversion errors */ + return (tointeger(v1, &i) && tointeger(v2, &i) && i != 0); + case OP_BAND: case OP_BOR: case OP_BXOR: /* conversion errors */ + return (tointeger(v1, &i) && tointeger(v2, &i)); + case OP_MOD: /* integer module by 0 */ + return !(ttisinteger(v1) && ttisinteger(v2) && ivalue(v2) == 0); + case OP_POW: /* negative integer exponentiation */ + return !(ttisinteger(v1) && ttisinteger(v2) && ivalue(v2) < 0); + default: return 1; /* everything else is valid */ + } +} + + static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { TValue v1, v2, res; - lua_Integer i; - if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2)) - return 0; /* non-numeric operands */ - if (op == OP_IDIV && - (!tointeger(&v1, &i) || !tointeger(&v2, &i) || i == 0)) - return 0; /* avoid division by 0 and conversion errors */ - if (ttisinteger(&v1) && ttisinteger(&v2) && /* for integer operations... */ - ((op == OP_MOD && ivalue(&v2) == 0) || /* ...avoid module by 0... */ - (op == OP_POW && ivalue(&v2) < 0))) /* ...and negative exponents */ - return 0; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ lua_assert(OP_IDIV - OP_ADD + LUA_OPADD == LUA_OPIDIV); luaO_arith(NULL, op - OP_ADD + LUA_OPADD, &v1, &v2, &res); if (ttisinteger(&res)) { @@ -853,7 +862,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_IDIV: - case OPR_MOD: case OPR_POW: { + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: { if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v); break; } @@ -897,7 +907,8 @@ void luaK_posfix (FuncState *fs, BinOpr op, break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_IDIV: case OPR_MOD: case OPR_POW: { + case OPR_IDIV: case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: { codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); break; } diff --git a/lcode.h b/lcode.h index 65416637..713f76aa 100644 --- a/lcode.h +++ b/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.60 2013/04/26 13:07:53 roberto Exp roberto $ +** $Id: lcode.h,v 1.61 2013/12/16 19:06:52 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -27,6 +27,7 @@ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, OPR_DIV, OPR_IDIV, + OPR_BAND, OPR_BOR, OPR_BXOR, OPR_CONCAT, OPR_EQ, OPR_LT, OPR_LE, OPR_NE, OPR_GT, OPR_GE, diff --git a/lobject.c b/lobject.c index 32f4a191..92c4d678 100644 --- a/lobject.c +++ b/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.68 2013/07/10 17:15:12 roberto Exp roberto $ +** $Id: lobject.c,v 2.69 2013/12/16 14:30:22 roberto Exp roberto $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -78,6 +78,10 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, case LUA_OPMUL:return intop(*, v1, v2); case LUA_OPMOD: return luaV_mod(L, v1, v2); case LUA_OPPOW: return luaV_pow(L, v1, v2); + case LUA_OPIDIV: return luaV_div(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); case LUA_OPUNM: return intop(-, 0, v1); default: lua_assert(0); return 0; } @@ -100,25 +104,36 @@ static lua_Number numarith (int op, lua_Number v1, lua_Number v2) { void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, TValue *res) { - if (op == LUA_OPIDIV) { /* operates only on integers */ - lua_Integer i1; lua_Integer i2; - if (tointeger(p1, &i1) && tointeger(p2, &i2)) { - setivalue(res, luaV_div(L, i1, i2)); - return; + switch (op) { + case LUA_OPIDIV: case LUA_OPBAND: case LUA_OPBOR: + case LUA_OPBXOR: { /* operates only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return; + } + else break; /* go to the end */ } - /* else go to the end */ - } - else { /* other operations */ - lua_Number n1; lua_Number n2; - if (ttisinteger(p1) && ttisinteger(p2) && op != LUA_OPDIV) { - setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); - return; + case LUA_OPDIV: { /* operates only on floats */ + lua_Number n1; lua_Number n2; + if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setnvalue(res, numarith(op, n1, n2)); + return; + } + else break; /* go to the end */ } - else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setnvalue(res, numarith(op, n1, n2)); - return; + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setnvalue(res, numarith(op, n1, n2)); + return; + } + else break; /* go to the end */ } - /* else go to the end */ } /* could not perform raw operation; try metmethod */ lua_assert(L != NULL); /* should not fail when folding (compile time) */ diff --git a/lopcodes.c b/lopcodes.c index fd2261fb..ba7b9017 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.50 2013/04/26 13:07:53 roberto Exp roberto $ +** $Id: lopcodes.c,v 1.51 2013/12/16 19:06:52 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -35,6 +35,9 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "POW", "DIV", "IDIV", + "BAND", + "BOR", + "BXOR", "UNM", "NOT", "LEN", @@ -84,6 +87,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ diff --git a/lopcodes.h b/lopcodes.h index a5673ade..6894f45f 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.143 2013/04/26 13:07:53 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.144 2013/12/16 19:06:52 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -191,6 +191,9 @@ OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ OP_IDIV,/* A B C R(A) := RK(B) // RK(C) */ +OP_BAND,/* A B C R(A) := RK(B) & RK(C) */ +OP_BOR,/* A B C R(A) := RK(B) | RK(C) */ +OP_BXOR,/* A B C R(A) := RK(B) ~ RK(C) */ OP_UNM,/* A B R(A) := -R(B) */ OP_NOT,/* A B R(A) := not R(B) */ OP_LEN,/* A B R(A) := length of R(B) */ diff --git a/lparser.c b/lparser.c index c23b2dde..fce6a04b 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.135 2013/08/30 16:01:37 roberto Exp roberto $ +** $Id: lparser.c,v 2.136 2013/12/16 19:06:52 roberto Exp roberto $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -994,6 +994,9 @@ static BinOpr getbinopr (int op) { case '^': return OPR_POW; case '/': return OPR_DIV; case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; @@ -1012,17 +1015,18 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, /* '+' '-' */ - {7, 7}, {7, 7}, /* '*' '%' */ - {10, 9}, /* '^' (right associative) */ - {7, 7}, {7, 7}, /* '/' '//' */ - {5, 4}, /* '..' (right associative) */ + {8, 8}, {8, 8}, /* '+' '-' */ + {9, 9}, {9, 9}, /* '*' '%' */ + {12, 11}, /* '^' (right associative) */ + {9, 9}, {9, 9}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 6}, /* '..' (right associative) */ {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ {2, 2}, {1, 1} /* and, or */ }; -#define UNARY_PRIORITY 8 /* priority for unary operators */ +#define UNARY_PRIORITY 10 /* priority for unary operators */ /* diff --git a/ltests.c b/ltests.c index a4462798..1dccc934 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.159 2013/09/11 14:47:08 roberto Exp roberto $ +** $Id: ltests.c,v 2.160 2013/12/16 19:06:52 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -1198,7 +1198,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { } } else if EQ("arith") { - static char ops[] = "+-*%^/\\_"; /* '\' -> '//'; '_' -> '..' */ + static char ops[] = "+-*%^/\\&|~_"; /* '\' -> '//'; '_' -> '..' */ int op; skip(&pc); op = strchr(ops, *pc++) - ops; diff --git a/ltm.c b/ltm.c index 8eb504d1..6ca7e9d3 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.22 2013/08/27 18:53:35 roberto Exp roberto $ +** $Id: ltm.c,v 2.23 2013/12/16 19:06:52 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -38,6 +38,7 @@ void luaT_init (lua_State *L) { "__gc", "__mode", "__len", "__eq", "__add", "__sub", "__mul", "__mod", "__pow", "__div", "__idiv", + "__band", "__bor", "__bxor", "__unm", "__lt", "__le", "__concat", "__call" }; diff --git a/ltm.h b/ltm.h index 196825b9..237acc7f 100644 --- a/ltm.h +++ b/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.16 2013/04/29 16:56:50 roberto Exp roberto $ +** $Id: ltm.h,v 2.17 2013/12/16 19:06:52 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -29,6 +29,9 @@ typedef enum { TM_POW, TM_DIV, TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, TM_UNM, TM_LT, TM_LE, diff --git a/lua.h b/lua.h index a44a1d9a..bfb713a7 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.295 2013/12/09 14:21:10 roberto Exp roberto $ +** $Id: lua.h,v 1.296 2013/12/16 19:06:52 roberto Exp roberto $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -189,7 +189,10 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx); #define LUA_OPPOW 4 #define LUA_OPDIV 5 #define LUA_OPIDIV 6 -#define LUA_OPUNM 7 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPUNM 10 LUA_API void (lua_arith) (lua_State *L, int op); diff --git a/lvm.c b/lvm.c index 354f40d9..b18ed3fd 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.180 2013/08/29 13:49:57 roberto Exp roberto $ +** $Id: lvm.c,v 2.181 2013/12/16 14:30:22 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -437,6 +437,7 @@ void luaV_finishOp (lua_State *L) { OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: + case OP_BAND: case OP_BOR: case OP_BXOR: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); @@ -671,6 +672,33 @@ void luaV_execute (lua_State *L) { } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } ) + vmcase(OP_BAND, + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(&, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } + ) + vmcase(OP_BOR, + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(|, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } + ) + vmcase(OP_BXOR, + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(^, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } + ) vmcase(OP_MOD, TValue *rb = RKB(i); TValue *rc = RKC(i);