issue #146 Currently Ravi's code generator assumes that #operator returns an integer value, but if user has set a metamethod for __len the operator# might return a non-integer value. This issue came to light when testing lpeg, which redefines #operator to return userdata objects. We now try to only expect integer values when # is used in fornum loops, or applied to table or array. Additionally unless the target is an array, we also emit a TOINT opcode to validate at runtime that the value in integer type

pull/167/head
Dibyendu Majumdar 6 years ago
parent 6404c5a3be
commit 64a6a2372b

@ -13,7 +13,7 @@ function matrix.T(a: table)
end
function matrix.mul(a: table, b: table)
assert(#a[1] == #b);
assert(@integer(#a[1]) == #b);
local m: integer, n: integer, p: integer, x: table = #a, #a[1], #b[1], {};
local c: table = matrix.T(b); -- transpose for efficiency
for i = 1, m do

@ -634,11 +634,11 @@ z = function()
y=x()
y[1] = 99.67
assert(y[1], 99.67)
assert(#y == 1)
assert(@integer (#y) == 1)
end
check(z, 'CLOSURE', 'GETUPVAL', 'MOVE', 'CALL',
'MOVE', 'CALL', 'SETUPVAL', 'SETTABUP', 'GETTABUP_SK', 'GETTABUP',
'LOADK', 'CALL', 'GETTABUP_SK', 'GETUPVAL', 'LEN', 'EQ_II',
'LOADK', 'CALL', 'GETTABUP_SK', 'GETUPVAL', 'LEN', 'TOINT', 'EQ_II',
'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'RETURN')
z()
compile(z)
@ -665,7 +665,7 @@ z = function()
end
check(z, 'NEWTABLE', 'LOADK', 'LOADK', 'LOADK', 'LOADK',
'LOADK', 'LOADK', 'LOADK', 'SETLIST', 'GETTABUP_SK', 'GETTABLE_I',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP_SK', 'LEN',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP_SK', 'LEN', 'TOINT',
'EQ_II', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABUP_SK', 'GETTABLE_I',
'EQ', 'JMP', 'LOADBOOL', 'LOADBOOL', 'CALL', 'GETTABLE_I', 'LOADK',
'CONCAT', 'SETTABLE_I', 'CLOSURE', 'SETUPVAL', 'GETTABUP_SK', 'GETUPVAL',

@ -1262,14 +1262,22 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
** Expression to produce final result will be encoded in 'e'.
*/
static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
ravitype_t e_type = e->ravi_type;
int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
freeexp(fs, e);
if (op == OP_BNOT && e->ravi_type == RAVI_TNUMINT)
op = OP_RAVI_BNOT_I;
e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
e->k = VRELOCABLE; /* all those operations are relocatable */
if (op == OP_LEN)
e->ravi_type = RAVI_TNUMINT;
if (op == OP_LEN) {
if (e_type == RAVI_TARRAYINT || e_type == RAVI_TARRAYFLT)
e->ravi_type = RAVI_TNUMINT;
else if (e_type == RAVI_TTABLE) {
luaK_exp2anyreg(fs, e);
luaK_codeABC(fs, OP_RAVI_TOINT, e->u.info, 0, 0);
e->ravi_type = RAVI_TNUMINT;
}
}
luaK_fixline(fs, line);
}

@ -1920,6 +1920,9 @@ static int exp1 (LexState *ls, Fornuminfo *info) {
*/
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
int reg;
int expect_int = 0;
if (ls->t.token == '#')
expect_int = 1;
expr(ls, &e);
DEBUG_EXPR(raviY_printf(ls->fs, "fornum exp -> %e\n", &e));
info->is_constant = (e.k == VKINT);
@ -1927,7 +1930,13 @@ static int exp1 (LexState *ls, Fornuminfo *info) {
luaK_exp2nextreg(ls->fs, &e);
lua_assert(e.k == VNONRELOC);
reg = e.u.info;
info->type = e.ravi_type;
if (expect_int && e.ravi_type != RAVI_TNUMINT) {
luaK_codeABC(ls->fs, OP_RAVI_TOINT, reg, 0, 0);
info->type = RAVI_TNUMINT;
}
else {
info->type = e.ravi_type;
}
return reg;
}

Loading…
Cancel
Save