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
This commit is contained in:
Roberto Ierusalimschy 2019-03-22 13:37:17 -03:00
parent 682054920d
commit 23e6bac8a0
13 changed files with 237 additions and 134 deletions

42
lcode.c
View File

@ -179,8 +179,8 @@ void luaK_ret (FuncState *fs, int first, int nret) {
** Code a "conditional jump", that is, a test or comparison opcode ** Code a "conditional jump", that is, a test or comparison opcode
** followed by a jump. Return jump position. ** followed by a jump. Return jump position.
*/ */
static int condjump (FuncState *fs, OpCode op, int A, int B, int k) { static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) {
luaK_codeABCk(fs, op, A, B, 0, k); luaK_codeABCk(fs, op, A, B, C, k);
return luaK_jump(fs); 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 ** 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 ** If expression has jumps, need to patch these jumps either to
** its final position or to "load" instructions (for those tests ** its final position or to "load" instructions (for those tests
** that do not produce values). ** 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 */ int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) { if (need_value(fs, e->t) || need_value(fs, e->f)) {
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
p_f = code_loadbool(fs, reg, 0, 1); p_f = code_loadbool(fs, reg, 0, 1); /* load false and skip next i. */
p_t = code_loadbool(fs, reg, 1, 0); p_t = code_loadbool(fs, reg, 1, 0); /* load true */
/* jump around these booleans if 'e' is not a test */
luaK_patchtohere(fs, fj); luaK_patchtohere(fs, fj);
} }
final = luaK_getlabel(fs); final = luaK_getlabel(fs);
@ -1005,13 +1006,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
Instruction ie = getinstruction(fs, e); Instruction ie = getinstruction(fs, e);
if (GET_OPCODE(ie) == OP_NOT) { if (GET_OPCODE(ie) == OP_NOT) {
removelastinstruction(fs); /* remove previous 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 */ /* else go through */
} }
discharge2anyreg(fs, e); discharge2anyreg(fs, e);
freeexp(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 ** 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) if (e->k == VKINT)
*i = e->u.ival; *i = e->u.ival;
else if (!(e->k == VKFLT && floatI(e->u.nval, i))) else if (!(e->k == VKFLT && floatI(e->u.nval, i)))
return 0; /* not a number */ return 0; /* not a number */
else
*isfloat = 1;
if (!hasjumps(e) && fitsC(*i)) { if (!hasjumps(e) && fitsC(*i)) {
*i += OFFSET_sC; *i += OFFSET_sC;
return 1; return 1;
@ -1372,21 +1375,20 @@ static void codeshift (FuncState *fs, OpCode op,
/* /*
** Emit code for order comparisons. ** Emit code for order comparisons. When using an immediate operand,
** When the first operand A is an integral value in the proper range, ** 'isfloat' tells whether the original value was a float.
** change (A < B) to (B > A) and (A <= B) to (B >= A) so that
** it can use an immediate operand.
*/ */
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
int r1, r2; int r1, r2;
lua_Integer im; lua_Integer im;
if (isSCnumber(e2, &im)) { int isfloat = 0;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */ /* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = cast_int(im); r2 = cast_int(im);
op = cast(OpCode, (op - OP_LT) + OP_LTI); 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) */ /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2); r1 = luaK_exp2anyreg(fs, e2);
r2 = cast_int(im); r2 = cast_int(im);
@ -1397,7 +1399,7 @@ static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
r2 = luaK_exp2anyreg(fs, e2); r2 = luaK_exp2anyreg(fs, e2);
} }
freeexps(fs, e1, 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; 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) { static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2; int r1, r2;
lua_Integer im; lua_Integer im;
int isfloat = 0; /* not needed here, but kept for symmetry */
OpCode op; OpCode op;
if (e1->k != VNONRELOC) { if (e1->k != VNONRELOC) {
lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT); lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT);
swapexps(e1, e2); swapexps(e1, e2);
} }
r1 = luaK_exp2anyreg(fs, e1); /* 1nd expression must be in register */ r1 = luaK_exp2anyreg(fs, e1); /* 1nd expression must be in register */
if (isSCnumber(e2, &im)) { if (isSCnumber(e2, &im, &isfloat)) {
op = OP_EQI; op = OP_EQI;
r2 = cast_int(im); /* immediate operand */ 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); r2 = luaK_exp2anyreg(fs, e2);
} }
freeexps(fs, e1, 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; e1->k = VJMP;
} }
@ -1489,7 +1492,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_LT: case OPR_LE: case OPR_LT: case OPR_LE:
case OPR_GT: case OPR_GE: { case OPR_GT: case OPR_GE: {
lua_Integer dummy; lua_Integer dummy;
if (!isSCnumber(v, &dummy)) int dummy2;
if (!isSCnumber(v, &dummy, &dummy2))
luaK_exp2anyreg(fs, v); luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be an immediate operand */ /* else keep numeral, which may be an immediate operand */
break; break;

View File

@ -107,7 +107,7 @@ static void *disptab[NUM_OPCODES] = {
&&L_OP_SETLIST, &&L_OP_SETLIST,
&&L_OP_CLOSURE, &&L_OP_CLOSURE,
&&L_OP_VARARG, &&L_OP_VARARG,
&&L_OP_PREPVARARG, &&L_OP_VARARGPREP,
&&L_OP_EXTRAARG &&L_OP_EXTRAARG
}; };

View File

@ -325,6 +325,8 @@ typedef l_uint32 Instruction;
#define luai_numeq(a,b) ((a)==(b)) #define luai_numeq(a,b) ((a)==(b))
#define luai_numlt(a,b) ((a)<(b)) #define luai_numlt(a,b) ((a)<(b))
#define luai_numle(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))) #define luai_numisnan(a) (!luai_numeq((a), (a)))
#endif #endif

View File

@ -101,7 +101,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, 0, 0, iABC) /* OP_SETLIST */ ,opmode(0, 1, 0, 0, iABC) /* OP_SETLIST */
,opmode(0, 0, 0, 1, iABx) /* OP_CLOSURE */ ,opmode(0, 0, 0, 1, iABx) /* OP_CLOSURE */
,opmode(1, 0, 0, 1, iABC) /* OP_VARARG */ ,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 */ ,opmode(0, 0, 0, 0, iAx) /* OP_EXTRAARG */
}; };

View File

@ -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_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 */ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
} 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 C > 0 means the function is vararg and (C - 1) is its number of
fixed parameters. fixed parameters.
(*) In comparisons with an immediate operand, C signals whether the
original operand was a float.
===========================================================================*/ ===========================================================================*/

View File

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

View File

@ -817,7 +817,7 @@ static void constructor (LexState *ls, expdesc *t) {
static void setvararg (FuncState *fs, int nparams) { static void setvararg (FuncState *fs, int nparams) {
fs->f->is_vararg = 1; fs->f->is_vararg = 1;
luaK_codeABC(fs, OP_PREPVARARG, nparams, 0, 0); luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0);
} }

8
ltm.c
View File

@ -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 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; TValue aux; const TValue *p2;
setivalue(&aux, v2); if (isfloat) {
setfltvalue(&aux, cast_num(v2));
}
else
setivalue(&aux, v2);
if (inv) { /* arguments were exchanged? */ if (inv) { /* arguments were exchanged? */
p2 = p1; p1 = &aux; /* correct them */ p2 = p1; p1 = &aux; /* correct them */
} }

2
ltm.h
View File

@ -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, LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
const TValue *p2, TMS event); const TValue *p2, TMS event);
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, 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, LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
struct CallInfo *ci, const Proto *p); struct CallInfo *ci, const Proto *p);

96
lvm.c
View File

@ -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_addi(L,a,b) intop(+, a, b)
#define l_subi(L,a,b) intop(-, a, b) #define l_subi(L,a,b) intop(-, a, b)
#define l_muli(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_bor(L,a,b) intop(|, a, b)
#define l_bxor(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 ** Auxiliary macro for arithmetic operations over floats and others
@ -916,6 +920,36 @@ void luaV_finishOp (lua_State *L) {
else \ else \
Protect(luaT_trybinTM(L, v1, v2, ra, tm)); } 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; pc = ci->u.l.savedpc;
if (trap) { if (trap) {
if (cl->p->is_vararg) 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)? */ else if (pc == cl->p->code) /* first instruction (not resuming)? */
luaD_hookcall(L, ci); luaD_hookcall(L, ci);
ci->u.l.trap = 1; /* there may be other hooks */ ci->u.l.trap = 1; /* there may be other hooks */
@ -1447,25 +1481,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_LT) { vmcase(OP_LT) {
TValue *rb = vRB(i); op_order(L, l_lti, LTnum, lessthanothers);
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();
vmbreak; vmbreak;
} }
vmcase(OP_LE) { vmcase(OP_LE) {
TValue *rb = vRB(i); op_order(L, l_lei, LEnum, lessequalothers);
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();
vmbreak; vmbreak;
} }
vmcase(OP_EQK) { vmcase(OP_EQK) {
@ -1487,47 +1507,19 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_LTI) { vmcase(OP_LTI) {
int im = GETARG_sB(i); op_orderI(L, l_lti, luai_numlt, 0, TM_LT);
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();
vmbreak; vmbreak;
} }
vmcase(OP_LEI) { vmcase(OP_LEI) {
int im = GETARG_sB(i); op_orderI(L, l_lei, luai_numle, 0, TM_LE);
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();
vmbreak; vmbreak;
} }
vmcase(OP_GTI) { vmcase(OP_GTI) {
int im = GETARG_sB(i); op_orderI(L, l_gti, luai_numgt, 1, TM_LT);
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();
vmbreak; vmbreak;
} }
vmcase(OP_GEI) { vmcase(OP_GEI) {
int im = GETARG_sB(i); op_orderI(L, l_gei, luai_numge, 1, TM_LE);
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();
vmbreak; vmbreak;
} }
vmcase(OP_TEST) { vmcase(OP_TEST) {
@ -1787,7 +1779,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
Protect(luaT_getvarargs(L, ci, ra, n)); Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak; vmbreak;
} }
vmcase(OP_PREPVARARG) { vmcase(OP_VARARGPREP) {
luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p); luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p);
updatetrap(ci); updatetrap(ci);
if (trap) { if (trap) {

107
onelua.c Normal file
View File

@ -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

View File

@ -162,7 +162,7 @@ test([[for i,v in pairs{'a','b'} do
end end
]], {1,2,1,2,1,3}) ]], {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 do -- testing line info/trace with large gaps in source

View File

@ -138,64 +138,55 @@ t.__bxor = f("bxor")
t.__shl = f("shl") t.__shl = f("shl")
t.__shr = f("shr") t.__shr = f("shr")
t.__bnot = f("bnot") 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 -- Some tests are done inside small anonymous functions to ensure
-- that constants go to constant table even in debug compilation, -- that constants go to constant table even in debug compilation,
-- when the constant table is very small. -- when the constant table is very small.
assert(b+5 == b) assert(b+5 == b); checkcap{"add", b, 5}
assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==undef) assert(5.2 + b == 5.2); checkcap{"add", 5.2, b}
assert(5.2 + b == 5.2) assert(b+'5' == b); checkcap{"add", b, '5'}
assert(cap[0] == "add" and cap[1] == 5.2 and cap[2] == b and cap[3]==undef) assert(5+b == 5); checkcap{"add", 5, b}
assert(b+'5' == b) assert('5'+b == '5'); checkcap{"add", '5', b}
assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==undef) b=b-3; assert(getmetatable(b) == t); checkcap{"sub", b, 3}
assert(5+b == 5) assert(5-a == 5); checkcap{"sub", 5, a}
assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==undef) assert('5'-a == '5'); checkcap{"sub", '5', a}
assert('5'+b == '5') assert(a*a == a); checkcap{"mul", a, a}
assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==undef) assert(a/0 == a); checkcap{"div", a, 0}
b=b-3; assert(getmetatable(b) == t) assert(a/0.0 == a); checkcap{"div", a, 0.0}
assert(cap[0] == "sub" and cap[1] == b and cap[2] == 3 and cap[3]==undef) assert(a%2 == a); checkcap{"mod", a, 2}
assert(5-a == 5) assert(a // (1/0) == a); checkcap{"idiv", a, 1/0}
assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==undef) ;(function () assert(a & "hi" == a) end)(); checkcap{"band", a, "hi"}
assert('5'-a == '5') ;(function () assert(10 & a == 10) end)(); checkcap{"band", 10, a}
assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==undef) ;(function () assert(a | 10 == a) end)(); checkcap{"bor", a, 10}
assert(a*a == a) assert(a | "hi" == a); checkcap{"bor", a, "hi"}
assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==undef) assert("hi" ~ a == "hi"); checkcap{"bxor", "hi", a}
assert(a/0 == a) ;(function () assert(10 ~ a == 10) end)(); checkcap{"bxor", 10, a}
assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==undef) assert(-a == a); checkcap{"unm", a, a}
assert(a%2 == a) assert(a^4.0 == a); checkcap{"pow", a, 4.0}
assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==undef) assert(a^'4' == a); checkcap{"pow", a, '4'}
assert(a // (1/0) == a) assert(4^a == 4); checkcap{"pow", 4, a}
assert(cap[0] == "idiv" and cap[1] == a and cap[2] == 1/0 and cap[3]==undef) assert('4'^a == '4'); checkcap{"pow", '4', a}
;(function () assert(a & "hi" == a) end)() assert(#a == a); checkcap{"len", a, a}
assert(cap[0] == "band" and cap[1] == a and cap[2] == "hi" and cap[3]==undef) assert(~a == a); checkcap{"bnot", a, a}
;(function () assert(10 & a == 10) end)() assert(a << 3 == a); checkcap{"shl", a, 3}
assert(cap[0] == "band" and cap[1] == 10 and cap[2] == a and cap[3]==undef) assert(1.5 >> a == 1.5); checkcap{"shr", 1.5, a}
;(function () assert(a | 10 == a) end)()
assert(cap[0] == "bor" and cap[1] == a and cap[2] == 10 and cap[3]==undef) -- for comparsion operators, all results are true
assert(a | "hi" == a) assert(5.0 > a); checkcap{"lt", a, 5.0}
assert(cap[0] == "bor" and cap[1] == a and cap[2] == "hi" and cap[3]==undef) assert(a >= 10); checkcap{"le", 10, a}
assert("hi" ~ a == "hi") assert(a <= -10.0); checkcap{"le", a, -10.0}
assert(cap[0] == "bxor" and cap[1] == "hi" and cap[2] == a and cap[3]==undef) assert(a < -10); checkcap{"lt", a, -10}
;(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)
-- test for rawlen -- test for rawlen