瀏覽代碼

Keep correct type for immediate operands in comparisons

When calling metamethods for things like 'a < 3.0', which generates
the opcode OP_LTI, the C register tells that the operand was
converted to an integer, so that it can be corrected to float when
calling a metamethod.

This commit also includes some other stuff:
- file 'onelua.c' added to the project
- opcode OP_PREPVARARG renamed to OP_VARARGPREP
- comparison opcodes rewritten through macros
Roberto Ierusalimschy 6 年之前
父節點
當前提交
23e6bac8a0
共有 13 個文件被更改,包括 237 次插入134 次删除
  1. 23 19
      lcode.c
  2. 1 1
      ljumptab.h
  3. 2 0
      llimits.h
  4. 1 1
      lopcodes.c
  5. 4 1
      lopcodes.h
  6. 1 1
      lopnames.h
  7. 1 1
      lparser.c
  8. 6 2
      ltm.c
  9. 1 1
      ltm.h
  10. 44 52
      lvm.c
  11. 107 0
      onelua.c
  12. 1 1
      testes/db.lua
  13. 45 54
      testes/events.lua

+ 23 - 19
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;

+ 1 - 1
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
 
 };

+ 2 - 0
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
 

+ 1 - 1
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 */
 };
 

+ 4 - 1
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.
+
 ===========================================================================*/
 
 

+ 1 - 1
lopnames.h

@@ -92,7 +92,7 @@ static const char *const opnames[] = {
   "SETLIST",
   "CLOSURE",
   "VARARG",
-  "PREPVARARG",
+  "VARARGPREP",
   "EXTRAARG",
   NULL
 };

+ 1 - 1
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);
 }
 
 

+ 6 - 2
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 */
   }

+ 1 - 1
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);

+ 44 - 52
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) {

+ 107 - 0
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 <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <limits.h>
+#include <locale.h>
+#include <math.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+/* 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

+ 1 - 1
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

+ 45 - 54
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