diff --git a/lcode.c b/lcode.c index 1872ede2..1e36e584 100644 --- a/lcode.c +++ b/lcode.c @@ -179,8 +179,8 @@ void luaK_ret (FuncState *fs, int first, int nret) { ** Code a "conditional jump", that is, a test or comparison opcode ** followed by a jump. Return jump position. */ -static int condjump (FuncState *fs, OpCode op, int A, int B, int k) { - luaK_codeABCk(fs, op, A, B, 0, k); +static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) { + luaK_codeABCk(fs, op, A, B, C, k); return luaK_jump(fs); } @@ -799,7 +799,7 @@ static int need_value (FuncState *fs, int list) { /* ** Ensures final expression result (which includes results from its -** jump ** lists) is in register 'reg'. +** jump lists) is in register 'reg'. ** If expression has jumps, need to patch these jumps either to ** its final position or to "load" instructions (for those tests ** that do not produce values). @@ -814,8 +814,9 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); - p_f = code_loadbool(fs, reg, 0, 1); - p_t = code_loadbool(fs, reg, 1, 0); + p_f = code_loadbool(fs, reg, 0, 1); /* load false and skip next i. */ + p_t = code_loadbool(fs, reg, 1, 0); /* load true */ + /* jump around these booleans if 'e' is not a test */ luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); @@ -1005,13 +1006,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { Instruction ie = getinstruction(fs, e); if (GET_OPCODE(ie) == OP_NOT) { removelastinstruction(fs); /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + return condjump(fs, OP_TEST, GETARG_B(ie), 0, 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, 0, cond); } @@ -1139,13 +1140,15 @@ static int isSCint (expdesc *e) { /* ** Check whether expression 'e' is a literal integer or float in -** proper range to fit in register sC +** proper range to fit in a register (sB or sC). */ -static int isSCnumber (expdesc *e, lua_Integer *i) { +static int isSCnumber (expdesc *e, lua_Integer *i, int *isfloat) { if (e->k == VKINT) *i = e->u.ival; else if (!(e->k == VKFLT && floatI(e->u.nval, i))) return 0; /* not a number */ + else + *isfloat = 1; if (!hasjumps(e) && fitsC(*i)) { *i += OFFSET_sC; return 1; @@ -1372,21 +1375,20 @@ static void codeshift (FuncState *fs, OpCode op, /* -** Emit code for order comparisons. -** When the first operand A is an integral value in the proper range, -** change (A < B) to (B > A) and (A <= B) to (B >= A) so that -** it can use an immediate operand. +** Emit code for order comparisons. When using an immediate operand, +** 'isfloat' tells whether the original value was a float. */ static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { int r1, r2; lua_Integer im; - if (isSCnumber(e2, &im)) { + int isfloat = 0; + if (isSCnumber(e2, &im, &isfloat)) { /* use immediate operand */ r1 = luaK_exp2anyreg(fs, e1); r2 = cast_int(im); op = cast(OpCode, (op - OP_LT) + OP_LTI); } - else if (isSCnumber(e1, &im)) { + else if (isSCnumber(e1, &im, &isfloat)) { /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ r1 = luaK_exp2anyreg(fs, e2); r2 = cast_int(im); @@ -1397,7 +1399,7 @@ static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { r2 = luaK_exp2anyreg(fs, e2); } freeexps(fs, e1, e2); - e1->u.info = condjump(fs, op, r1, r2, 1); + e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); e1->k = VJMP; } @@ -1409,13 +1411,14 @@ static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { int r1, r2; lua_Integer im; + int isfloat = 0; /* not needed here, but kept for symmetry */ OpCode op; if (e1->k != VNONRELOC) { lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT); swapexps(e1, e2); } r1 = luaK_exp2anyreg(fs, e1); /* 1nd expression must be in register */ - if (isSCnumber(e2, &im)) { + if (isSCnumber(e2, &im, &isfloat)) { op = OP_EQI; r2 = cast_int(im); /* immediate operand */ } @@ -1428,7 +1431,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { r2 = luaK_exp2anyreg(fs, e2); } freeexps(fs, e1, e2); - e1->u.info = condjump(fs, op, r1, r2, (opr == OPR_EQ)); + e1->u.info = condjump(fs, op, r1, r2, isfloat, (opr == OPR_EQ)); e1->k = VJMP; } @@ -1489,7 +1492,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { case OPR_LT: case OPR_LE: case OPR_GT: case OPR_GE: { lua_Integer dummy; - if (!isSCnumber(v, &dummy)) + int dummy2; + if (!isSCnumber(v, &dummy, &dummy2)) luaK_exp2anyreg(fs, v); /* else keep numeral, which may be an immediate operand */ break; diff --git a/ljumptab.h b/ljumptab.h index fa4277cc..2d4cf28b 100644 --- a/ljumptab.h +++ b/ljumptab.h @@ -107,7 +107,7 @@ static void *disptab[NUM_OPCODES] = { &&L_OP_SETLIST, &&L_OP_CLOSURE, &&L_OP_VARARG, -&&L_OP_PREPVARARG, +&&L_OP_VARARGPREP, &&L_OP_EXTRAARG }; diff --git a/llimits.h b/llimits.h index 9d35d1c7..155bb160 100644 --- a/llimits.h +++ b/llimits.h @@ -325,6 +325,8 @@ typedef l_uint32 Instruction; #define luai_numeq(a,b) ((a)==(b)) #define luai_numlt(a,b) ((a)<(b)) #define luai_numle(a,b) ((a)<=(b)) +#define luai_numgt(a,b) ((a)>(b)) +#define luai_numge(a,b) ((a)>=(b)) #define luai_numisnan(a) (!luai_numeq((a), (a))) #endif diff --git a/lopcodes.c b/lopcodes.c index c35a0aaf..23c3a6e4 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -101,7 +101,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, 0, 0, iABC) /* OP_SETLIST */ ,opmode(0, 0, 0, 1, iABx) /* OP_CLOSURE */ ,opmode(1, 0, 0, 1, iABC) /* OP_VARARG */ - ,opmode(0, 0, 0, 1, iABC) /* OP_PREPVARARG */ + ,opmode(0, 0, 0, 1, iABC) /* OP_VARARGPREP */ ,opmode(0, 0, 0, 0, iAx) /* OP_EXTRAARG */ }; diff --git a/lopcodes.h b/lopcodes.h index f867a01b..bbdd6897 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -294,7 +294,7 @@ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ OP_VARARG,/* A C R(A), R(A+1), ..., R(A+C-2) = vararg */ -OP_PREPVARARG,/*A (adjust vararg parameters) */ +OP_VARARGPREP,/*A (adjust vararg parameters) */ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ } OpCode; @@ -331,6 +331,9 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ C > 0 means the function is vararg and (C - 1) is its number of fixed parameters. + (*) In comparisons with an immediate operand, C signals whether the + original operand was a float. + ===========================================================================*/ diff --git a/lopnames.h b/lopnames.h index dfca34d1..28535fe2 100644 --- a/lopnames.h +++ b/lopnames.h @@ -92,7 +92,7 @@ static const char *const opnames[] = { "SETLIST", "CLOSURE", "VARARG", - "PREPVARARG", + "VARARGPREP", "EXTRAARG", NULL }; diff --git a/lparser.c b/lparser.c index 8ffd9742..4c2ddbfe 100644 --- a/lparser.c +++ b/lparser.c @@ -817,7 +817,7 @@ static void constructor (LexState *ls, expdesc *t) { static void setvararg (FuncState *fs, int nparams) { fs->f->is_vararg = 1; - luaK_codeABC(fs, OP_PREPVARARG, nparams, 0, 0); + luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0); } diff --git a/ltm.c b/ltm.c index 23a97a62..c4fd762b 100644 --- a/ltm.c +++ b/ltm.c @@ -205,9 +205,13 @@ int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, - int inv, TMS event) { + int inv, int isfloat, TMS event) { TValue aux; const TValue *p2; - setivalue(&aux, v2); + if (isfloat) { + setfltvalue(&aux, cast_num(v2)); + } + else + setivalue(&aux, v2); if (inv) { /* arguments were exchanged? */ p2 = p1; p1 = &aux; /* correct them */ } diff --git a/ltm.h b/ltm.h index fad47842..e308fb80 100644 --- a/ltm.h +++ b/ltm.h @@ -82,7 +82,7 @@ LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event); LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, - int inv, TMS event); + int inv, int isfloat, TMS event); LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, struct CallInfo *ci, const Proto *p); diff --git a/lvm.c b/lvm.c index 31b4dc36..47bc67c9 100644 --- a/lvm.c +++ b/lvm.c @@ -772,11 +772,10 @@ void luaV_finishOp (lua_State *L) { /* ** {================================================================== -** Macros for arithmetic/bitwise opcodes in 'luaV_execute' +** Macros for arithmetic/bitwise/comparison opcodes in 'luaV_execute' ** =================================================================== */ - #define l_addi(L,a,b) intop(+, a, b) #define l_subi(L,a,b) intop(-, a, b) #define l_muli(L,a,b) intop(*, a, b) @@ -784,6 +783,11 @@ void luaV_finishOp (lua_State *L) { #define l_bor(L,a,b) intop(|, a, b) #define l_bxor(L,a,b) intop(^, a, b) +#define l_lti(a,b) (a < b) +#define l_lei(a,b) (a <= b) +#define l_gti(a,b) (a > b) +#define l_gei(a,b) (a >= b) + /* ** Auxiliary macro for arithmetic operations over floats and others @@ -916,6 +920,36 @@ void luaV_finishOp (lua_State *L) { else \ Protect(luaT_trybinTM(L, v1, v2, ra, tm)); } + +/* +** Order operations with register operands. +*/ +#define op_order(L,opi,opf,other) { \ + TValue *rb = vRB(i); \ + if (ttisinteger(s2v(ra)) && ttisinteger(rb)) \ + cond = opi(ivalue(s2v(ra)), ivalue(rb)); \ + else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \ + cond = opf(s2v(ra), rb); \ + else \ + Protect(cond = other(L, s2v(ra), rb)); \ + docondjump(); } + + +/* +** Order operations with immediate operand. +*/ +#define op_orderI(L,opi,opf,inv,tm) { \ + int im = GETARG_sB(i); \ + if (ttisinteger(s2v(ra))) \ + cond = opi(ivalue(s2v(ra)), im); \ + else if (ttisfloat(s2v(ra))) \ + cond = opf(fltvalue(s2v(ra)), cast_num(im)); \ + else { \ + int isf = GETARG_C(i); \ + Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \ + } \ + docondjump(); } + /* }================================================================== */ @@ -1034,7 +1068,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { pc = ci->u.l.savedpc; if (trap) { if (cl->p->is_vararg) - trap = 0; /* hooks will start after PREPVARARG instruction */ + trap = 0; /* hooks will start after VARARGPREP instruction */ else if (pc == cl->p->code) /* first instruction (not resuming)? */ luaD_hookcall(L, ci); ci->u.l.trap = 1; /* there may be other hooks */ @@ -1447,25 +1481,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_LT) { - TValue *rb = vRB(i); - if (ttisinteger(s2v(ra)) && ttisinteger(rb)) - cond = (ivalue(s2v(ra)) < ivalue(rb)); - else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) - cond = LTnum(s2v(ra), rb); - else - Protect(cond = lessthanothers(L, s2v(ra), rb)); - docondjump(); + op_order(L, l_lti, LTnum, lessthanothers); vmbreak; } vmcase(OP_LE) { - TValue *rb = vRB(i); - if (ttisinteger(s2v(ra)) && ttisinteger(rb)) - cond = (ivalue(s2v(ra)) <= ivalue(rb)); - else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) - cond = LEnum(s2v(ra), rb); - else - Protect(cond = lessequalothers(L, s2v(ra), rb)); - docondjump(); + op_order(L, l_lei, LEnum, lessequalothers); vmbreak; } vmcase(OP_EQK) { @@ -1487,47 +1507,19 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_LTI) { - int im = GETARG_sB(i); - if (ttisinteger(s2v(ra))) - cond = (ivalue(s2v(ra)) < im); - else if (ttisfloat(s2v(ra))) - cond = luai_numlt(fltvalue(s2v(ra)), cast_num(im)); - else - Protect(cond = luaT_callorderiTM(L, s2v(ra), im, 0, TM_LT)); - docondjump(); + op_orderI(L, l_lti, luai_numlt, 0, TM_LT); vmbreak; } vmcase(OP_LEI) { - int im = GETARG_sB(i); - if (ttisinteger(s2v(ra))) - cond = (ivalue(s2v(ra)) <= im); - else if (ttisfloat(s2v(ra))) - cond = luai_numle(fltvalue(s2v(ra)), cast_num(im)); - else - Protect(cond = luaT_callorderiTM(L, s2v(ra), im, 0, TM_LE)); - docondjump(); + op_orderI(L, l_lei, luai_numle, 0, TM_LE); vmbreak; } vmcase(OP_GTI) { - int im = GETARG_sB(i); - if (ttisinteger(s2v(ra))) - cond = (im < ivalue(s2v(ra))); - else if (ttisfloat(s2v(ra))) - cond = luai_numlt(cast_num(im), fltvalue(s2v(ra))); - else - Protect(cond = luaT_callorderiTM(L, s2v(ra), im, 1, TM_LT)); - docondjump(); + op_orderI(L, l_gti, luai_numgt, 1, TM_LT); vmbreak; } vmcase(OP_GEI) { - int im = GETARG_sB(i); - if (ttisinteger(s2v(ra))) - cond = (im <= ivalue(s2v(ra))); - else if (ttisfloat(s2v(ra))) - cond = luai_numle(cast_num(im), fltvalue(s2v(ra))); - else - Protect(cond = luaT_callorderiTM(L, s2v(ra), im, 1, TM_LE)); - docondjump(); + op_orderI(L, l_gei, luai_numge, 1, TM_LE); vmbreak; } vmcase(OP_TEST) { @@ -1787,7 +1779,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { Protect(luaT_getvarargs(L, ci, ra, n)); vmbreak; } - vmcase(OP_PREPVARARG) { + vmcase(OP_VARARGPREP) { luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p); updatetrap(ci); if (trap) { diff --git a/onelua.c b/onelua.c new file mode 100644 index 00000000..3c605981 --- /dev/null +++ b/onelua.c @@ -0,0 +1,107 @@ +/* +* one.c -- Lua core, libraries, and interpreter in a single file +*/ + +/* default is to build the full interpreter */ +#ifndef MAKE_LIB +#ifndef MAKE_LUAC +#ifndef MAKE_LUA +#define MAKE_LUA +#endif +#endif +#endif + +/* choose suitable platform-specific features */ +/* some of these may need extra libraries such as -ldl -lreadline -lncurses */ +#if 0 +#define LUA_USE_LINUX +#define LUA_USE_MACOSX +#define LUA_USE_POSIX +#define LUA_ANSI +#endif + +/* no need to change anything below this line ----------------------------- */ + +#include "lprefix.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* setup for luaconf.h */ +#define LUA_CORE +#define LUA_LIB +#define ltable_c +#define lvm_c +#include "luaconf.h" + +/* do not export internal symbols */ +#undef LUAI_FUNC +#undef LUAI_DDEC +#undef LUAI_DDEF +#define LUAI_FUNC static +#define LUAI_DDEC(def) /* empty */ +#define LUAI_DDEF static + +/* core -- used by all */ +#include "lzio.c" +#include "lctype.c" +#include "lopcodes.c" +#include "lmem.c" +#include "lundump.c" +#include "ldump.c" +#include "lstate.c" +#include "lgc.c" +#include "llex.c" +#include "lcode.c" +#include "lparser.c" +#include "ldebug.c" +#include "lfunc.c" +#include "lobject.c" +#include "ltm.c" +#include "lstring.c" +#include "ltable.c" +#include "ldo.c" +#include "lvm.c" +#include "lapi.c" + +/* auxiliary library -- used by all */ +#include "lauxlib.c" + +/* standard library -- not used by luac */ +#ifndef MAKE_LUAC +#include "lbaselib.c" +#include "lcorolib.c" +#include "ldblib.c" +#include "liolib.c" +#include "lmathlib.c" +#include "loadlib.c" +#include "loslib.c" +#include "lstrlib.c" +#include "ltablib.c" +#include "lutf8lib.c" +#include "linit.c" +#endif + +/* lua */ +#ifdef MAKE_LUA +#include "lua.c" +#endif + +/* luac */ +#ifdef MAKE_LUAC +#include "luac.c" +#endif diff --git a/testes/db.lua b/testes/db.lua index 0858dd20..95275fb4 100644 --- a/testes/db.lua +++ b/testes/db.lua @@ -162,7 +162,7 @@ test([[for i,v in pairs{'a','b'} do end ]], {1,2,1,2,1,3}) -test([[for i=1,4 do a=1 end]], {1,1,1,1}, true) +test([[for i=1,4 do a=1 end]], {1,1,1,1}) do -- testing line info/trace with large gaps in source diff --git a/testes/events.lua b/testes/events.lua index ac630d89..cf68d1e9 100644 --- a/testes/events.lua +++ b/testes/events.lua @@ -138,64 +138,55 @@ t.__bxor = f("bxor") t.__shl = f("shl") t.__shr = f("shr") t.__bnot = f("bnot") +t.__lt = f("lt") +t.__le = f("le") + + +local function checkcap (t) + assert(#cap + 1 == #t) + for i = 1, #t do + assert(cap[i - 1] == t[i]) + assert(math.type(cap[i - 1]) == math.type(t[i])) + end +end -- Some tests are done inside small anonymous functions to ensure -- that constants go to constant table even in debug compilation, -- when the constant table is very small. -assert(b+5 == b) -assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==undef) -assert(5.2 + b == 5.2) -assert(cap[0] == "add" and cap[1] == 5.2 and cap[2] == b and cap[3]==undef) -assert(b+'5' == b) -assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==undef) -assert(5+b == 5) -assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==undef) -assert('5'+b == '5') -assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==undef) -b=b-3; assert(getmetatable(b) == t) -assert(cap[0] == "sub" and cap[1] == b and cap[2] == 3 and cap[3]==undef) -assert(5-a == 5) -assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==undef) -assert('5'-a == '5') -assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==undef) -assert(a*a == a) -assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==undef) -assert(a/0 == a) -assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==undef) -assert(a%2 == a) -assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==undef) -assert(a // (1/0) == a) -assert(cap[0] == "idiv" and cap[1] == a and cap[2] == 1/0 and cap[3]==undef) -;(function () assert(a & "hi" == a) end)() -assert(cap[0] == "band" and cap[1] == a and cap[2] == "hi" and cap[3]==undef) -;(function () assert(10 & a == 10) end)() -assert(cap[0] == "band" and cap[1] == 10 and cap[2] == a and cap[3]==undef) -;(function () assert(a | 10 == a) end)() -assert(cap[0] == "bor" and cap[1] == a and cap[2] == 10 and cap[3]==undef) -assert(a | "hi" == a) -assert(cap[0] == "bor" and cap[1] == a and cap[2] == "hi" and cap[3]==undef) -assert("hi" ~ a == "hi") -assert(cap[0] == "bxor" and cap[1] == "hi" and cap[2] == a and cap[3]==undef) -;(function () assert(10 ~ a == 10) end)() -assert(cap[0] == "bxor" and cap[1] == 10 and cap[2] == a and cap[3]==undef) -assert(-a == a) -assert(cap[0] == "unm" and cap[1] == a) -assert(a^4 == a) -assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==undef) -assert(a^'4' == a) -assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==undef) -assert(4^a == 4) -assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==undef) -assert('4'^a == '4') -assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==undef) -assert(#a == a) -assert(cap[0] == "len" and cap[1] == a) -assert(~a == a) -assert(cap[0] == "bnot" and cap[1] == a) -assert(a << 3 == a) -assert(cap[0] == "shl" and cap[1] == a and cap[2] == 3) -assert(1.5 >> a == 1.5) -assert(cap[0] == "shr" and cap[1] == 1.5 and cap[2] == a) +assert(b+5 == b); checkcap{"add", b, 5} +assert(5.2 + b == 5.2); checkcap{"add", 5.2, b} +assert(b+'5' == b); checkcap{"add", b, '5'} +assert(5+b == 5); checkcap{"add", 5, b} +assert('5'+b == '5'); checkcap{"add", '5', b} +b=b-3; assert(getmetatable(b) == t); checkcap{"sub", b, 3} +assert(5-a == 5); checkcap{"sub", 5, a} +assert('5'-a == '5'); checkcap{"sub", '5', a} +assert(a*a == a); checkcap{"mul", a, a} +assert(a/0 == a); checkcap{"div", a, 0} +assert(a/0.0 == a); checkcap{"div", a, 0.0} +assert(a%2 == a); checkcap{"mod", a, 2} +assert(a // (1/0) == a); checkcap{"idiv", a, 1/0} +;(function () assert(a & "hi" == a) end)(); checkcap{"band", a, "hi"} +;(function () assert(10 & a == 10) end)(); checkcap{"band", 10, a} +;(function () assert(a | 10 == a) end)(); checkcap{"bor", a, 10} +assert(a | "hi" == a); checkcap{"bor", a, "hi"} +assert("hi" ~ a == "hi"); checkcap{"bxor", "hi", a} +;(function () assert(10 ~ a == 10) end)(); checkcap{"bxor", 10, a} +assert(-a == a); checkcap{"unm", a, a} +assert(a^4.0 == a); checkcap{"pow", a, 4.0} +assert(a^'4' == a); checkcap{"pow", a, '4'} +assert(4^a == 4); checkcap{"pow", 4, a} +assert('4'^a == '4'); checkcap{"pow", '4', a} +assert(#a == a); checkcap{"len", a, a} +assert(~a == a); checkcap{"bnot", a, a} +assert(a << 3 == a); checkcap{"shl", a, 3} +assert(1.5 >> a == 1.5); checkcap{"shr", 1.5, a} + +-- for comparsion operators, all results are true +assert(5.0 > a); checkcap{"lt", a, 5.0} +assert(a >= 10); checkcap{"le", 10, a} +assert(a <= -10.0); checkcap{"le", a, -10.0} +assert(a < -10); checkcap{"lt", a, -10} -- test for rawlen