From cb6943a1eb8fb20330ea41e7612a24dd839e01b3 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 00:29:12 +0000 Subject: [PATCH 1/9] tests updated --- tests/comptests/inputs/25_bits.lua | 4 ++-- tests/language/ravi_tests1.ravi | 36 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tests/comptests/inputs/25_bits.lua b/tests/comptests/inputs/25_bits.lua index 722a926..bdd7f9a 100644 --- a/tests/comptests/inputs/25_bits.lua +++ b/tests/comptests/inputs/25_bits.lua @@ -1,5 +1,5 @@ f = compiler.load([[ -function doit(a, 25_bits.luawhat) +function doit(a, what) local f: integer = ~0 if what == '&' then return a&f @@ -25,4 +25,4 @@ assert(math.abs(doit(16, '|') - ~0) < 1e-15) assert(math.abs(doit(16, '<<') - 32) < 1e-15) assert(math.abs(doit(16, '>>') - 8) < 1e-15) assert(math.abs(doit(16, '~') - ~16) < 1e-15) -print 'Ok' \ No newline at end of file +print 'Ok' diff --git a/tests/language/ravi_tests1.ravi b/tests/language/ravi_tests1.ravi index d27cc2a..9767d0a 100644 --- a/tests/language/ravi_tests1.ravi +++ b/tests/language/ravi_tests1.ravi @@ -1842,6 +1842,42 @@ do end print 'Test 87 OK' +do + local function doit(a: integer, what) + local f: integer = ~0 + if what == '&' then + return a&f + elseif what == '|' then + return a|f + elseif what == '<<' then + return a<<1 + elseif what == '>>' then + return a>>1 + elseif what == '~' then + return ~a + else + return 0 + end + end + check(doit, 'TOINT', 'LOADK', 'EQ', 'JMP', 'BAND_II', + 'RETURN', 'JMP', 'EQ', 'JMP', 'BOR_II', 'RETURN', + 'JMP', 'EQ', 'JMP', 'SHL_II', 'RETURN', 'JMP', 'EQ', + 'JMP', 'SHR_II', 'RETURN', 'JMP', 'EQ', 'JMP', + 'BNOT_I', 'RETURN', 'JMP', 'LOADK', 'RETURN', 'RETURN') + assert(doit and type(doit) == 'function') + assert(math.abs(doit(16, '&') - 16) < 1e-15) + assert(math.abs(doit(16, '|') - ~0) < 1e-15) + assert(math.abs(doit(16, '<<') - 32) < 1e-15) + assert(math.abs(doit(16, '>>') - 8) < 1e-15) + assert(math.abs(doit(16, '~') - ~16) < 1e-15) + compile(doit) + assert(math.abs(doit(16, '&') - 16) < 1e-15) + assert(math.abs(doit(16, '|') - ~0) < 1e-15) + assert(math.abs(doit(16, '<<') - 32) < 1e-15) + assert(math.abs(doit(16, '>>') - 8) < 1e-15) + assert(math.abs(doit(16, '~') - ~16) < 1e-15) +end +print 'Test 88 OK' for k,v in pairs(opcodes_coverage) do From 4a206936719ac1ddbd1293adde74247a9097b482 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 12:24:16 +0000 Subject: [PATCH 2/9] refactoring via XmiliaH --- src/lcode.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/lcode.c b/src/lcode.c index 7cd379b..05cd51c 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -600,19 +600,21 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { freereg(fs, e->u.ind.t); /* TODO we should do this for upvalues too */ /* table access - set specialized op codes if array types are detected */ - if (e->ravi_type == RAVI_TARRAYFLT && e->u.ind.key_ravi_type == RAVI_TNUMINT) - op = OP_RAVI_FARRAY_GET; - else if (e->ravi_type == RAVI_TARRAYINT && e->u.ind.key_ravi_type == RAVI_TNUMINT) - op = OP_RAVI_IARRAY_GET; + if (e->u.ind.key_ravi_type == RAVI_TNUMINT) { + if (e->ravi_type == RAVI_TARRAYFLT) + op = OP_RAVI_FARRAY_GET; + else if (e->ravi_type == RAVI_TARRAYINT) + op = OP_RAVI_IARRAY_GET; + else + op = OP_RAVI_GETI; + } /* Check that we have a short string constant */ - else if (e->ravi_type == RAVI_TTABLE && e->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx)) - op = OP_RAVI_TABLE_GETFIELD; - else if (e->u.ind.key_ravi_type == RAVI_TNUMINT) - op = OP_RAVI_GETI; - else if (e->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx)) - op = OP_RAVI_GETFIELD; - else + else if (e->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, e->u.ind.idx)) { + op = e->ravi_type == RAVI_TTABLE ? OP_RAVI_TABLE_GETFIELD : OP_RAVI_GETFIELD; + } + else { op = OP_GETTABLE; + } } else { lua_assert(e->u.ind.vt == VUPVAL); From 248c730c43c8ddf4370b7e28f2c2c15eb07f037d Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 12:49:57 +0000 Subject: [PATCH 3/9] refactoring via XmiliaH --- src/lcode.c | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/lcode.c b/src/lcode.c index 05cd51c..fd909b0 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -993,38 +993,35 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { break; } case VINDEXED: { - OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; - if (op == OP_SETTABLE) { + OpCode op; + int e = luaK_exp2RK(fs, ex); + if (var->u.ind.vt == VLOCAL) { /* table value set - if array access then use specialized versions */ - if (var->ravi_type == RAVI_TARRAYFLT && - var->u.ind.key_ravi_type == RAVI_TNUMINT) { - if (!(ex->ravi_type == RAVI_TNUMFLT || (ex->k == VINDEXED && ex->ravi_type == RAVI_TARRAYFLT))) - /* input value may need conversion */ - op = OP_RAVI_FARRAY_SET; - else - /* input value is known to be number */ - op = OP_RAVI_FARRAY_SETF; - } else if (var->ravi_type == RAVI_TARRAYINT && - var->u.ind.key_ravi_type == RAVI_TNUMINT) { - if (!(ex->ravi_type == RAVI_TNUMINT || (ex->k == VINDEXED && ex->ravi_type == RAVI_TARRAYINT))) - /* input value may need conversion */ - op = OP_RAVI_IARRAY_SET; - else - /* input value is known to be integer */ - op = OP_RAVI_IARRAY_SETI; - } else if (var->u.ind.key_ravi_type == RAVI_TNUMINT) { - /* index op with integer key, target may not be a table */ - op = OP_RAVI_SETI; - } else if (var->ravi_type == RAVI_TTABLE && var->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, var->u.ind.idx)) { - /* table with string key */ - op = OP_RAVI_TABLE_SETFIELD; + if (var->u.ind.key_ravi_type == RAVI_TNUMINT) { + if (var->ravi_type == RAVI_TARRAYFLT) { + op = ex->ravi_type == RAVI_TNUMFLT ? OP_RAVI_FARRAY_SETF : /* input value is known to be number */ + OP_RAVI_FARRAY_SET; /* input value may need conversion */ + } + else if (var->ravi_type == RAVI_TARRAYINT) { + op = ex->ravi_type == RAVI_TNUMINT ? OP_RAVI_IARRAY_SETI : /* input value is known to be integer */ + OP_RAVI_IARRAY_SET; /* input value may need conversion */ + } + else { + /* index op with integer key, target may not be a table */ + op = OP_RAVI_SETI; + } } else if (var->u.ind.key_ravi_type == RAVI_TSTRING && isshortstr(fs, var->u.ind.idx)) { - /* index op with string key, target may not be a table */ - op = OP_RAVI_SETFIELD; + op = var->ravi_type == RAVI_TTABLE ? OP_RAVI_TABLE_SETFIELD : /* table with string key */ + OP_RAVI_SETFIELD; /* index op with string key, target may not be a table */ + } + else { + op = OP_SETTABLE; } } - int e = luaK_exp2RK(fs, ex); + else { + op = OP_SETTABUP; + } luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } From 5c30d255c7d69f079f42f5320cc2f565dd49cb8b Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 15:25:50 +0000 Subject: [PATCH 4/9] some improvements to type checking via XmiliaH --- src/lapi.c | 31 +++++++++++++------------------ src/ldebug.c | 29 +++++++++++++---------------- src/lfunc.c | 4 +++- src/lfunc.h | 2 +- src/ltests.c | 3 ++- src/lvm.c | 27 +++++++++++++++++++++++++++ src/lvm.h | 1 + 7 files changed, 60 insertions(+), 37 deletions(-) diff --git a/src/lapi.c b/src/lapi.c index 9eac09a..5c9e303 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1568,8 +1568,9 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { static const char *aux_upvalue (StkId fi, int n, TValue **val, - CClosure **owner, UpVal **uv, ravitype_t *type) { + CClosure **owner, UpVal **uv, ravitype_t *type, TString **usertype) { *type = RAVI_TANY; + *usertype = NULL; switch (ttype(fi)) { case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); @@ -1587,6 +1588,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, if (uv) *uv = f->upvals[n - 1]; name = p->upvalues[n-1].name; *type = p->upvalues[n - 1].ravi_type; + *usertype = p->upvalues[n - 1].usertype; return (name == NULL) ? "(*no name)" : getstr(name); } default: return NULL; /* not a closure */ @@ -1597,9 +1599,10 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; ravitype_t type; + TString *usertype; TValue *val = NULL; /* to avoid warnings */ lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL, &type); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL, &type, &usertype); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1616,30 +1619,22 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { UpVal *uv = NULL; StkId fi; ravitype_t type; /* RAVI upvalue type will be obtained if possible */ + TString *usertype; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner, &uv, &type); + name = aux_upvalue(fi, n, &val, &owner, &uv, &type, &usertype); if (name) { /* RAVI extension ** We need to ensure that this function does ** not subvert the types of local variables */ - if ( type == RAVI_TNUMFLT - || type == RAVI_TNUMINT - || type == RAVI_TARRAYFLT - || type == RAVI_TARRAYINT) { - StkId input = L->top - 1; - int compatible = - (type == RAVI_TNUMFLT && ttisfloat(input)) - || (type == RAVI_TNUMINT && ttisinteger(input)) - || (type == RAVI_TARRAYFLT && ttisfarray(input)) - || (type == RAVI_TARRAYINT && ttisiarray(input)) - || (type == RAVI_TTABLE && ttisLtable(input)) - ; - if (!compatible) - name = NULL; - } + + StkId input = L->top - 1; + int compatible = raviV_checktype(L, input, type, usertype); + + if (!compatible) + name = NULL; } if (name) { L->top--; diff --git a/src/ldebug.c b/src/ldebug.c index 13ba22b..5c4f2d3 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -147,16 +147,17 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) { static const char *findlocal (lua_State *L, CallInfo *ci, int n, - StkId *pos, ravitype_t *type) { + StkId *pos, ravitype_t *type, TString** usertype) { const char *name = NULL; StkId base; *type = RAVI_TANY; + *usertype = NULL; if (isLua(ci)) { if (n < 0) /* access to vararg values? */ return findvararg(ci, -n, pos); else { base = ci->u.l.base; - name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci), type); + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci), type, usertype); } } else @@ -176,17 +177,18 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n, LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; ravitype_t type; + TString *usertype; lua_lock(L); swapextra(L); if (ar == NULL) { /* information about non-active function? */ if (!isLfunction(L->top - 1)) /* not a Lua function? */ name = NULL; else /* consider live variables at function start (parameters) */ - name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0, &type); + name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0, &type, &usertype); } else { /* active function; get information through 'ar' */ StkId pos = NULL; /* to avoid warnings */ - name = findlocal(L, ar->i_ci, n, &pos, &type); + name = findlocal(L, ar->i_ci, n, &pos, &type, &usertype); if (name) { setobj2s(L, L->top, pos); api_incr_top(L); @@ -202,24 +204,18 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { StkId pos = NULL; /* to avoid warnings */ const char *name; ravitype_t type; + TString* usertype; int compatible = 1; lua_lock(L); swapextra(L); - name = findlocal(L, ar->i_ci, n, &pos, &type); + name = findlocal(L, ar->i_ci, n, &pos, &type, &usertype); if (name) { /* RAVI extension ** We need to ensure that this function does ** not subvert the types of local variables */ - if (type == RAVI_TNUMFLT || type == RAVI_TNUMINT || type == RAVI_TARRAYFLT || type == RAVI_TARRAYINT) { - StkId input = L->top - 1; - compatible = (type == RAVI_TNUMFLT && ttisfloat(input)) - || (type == RAVI_TNUMINT && ttisinteger(input)) - || (type == RAVI_TARRAYFLT && ttisfarray(input)) - || (type == RAVI_TARRAYINT && ttisiarray(input)) - || (type == RAVI_TTABLE && ttisLtable(input)) - ; - } + StkId input = L->top - 1; + int compatible = raviV_checktype(L, input, type, usertype); if (compatible) { setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ @@ -457,7 +453,8 @@ static const char *getobjname (Proto *p, int lastpc, int reg, const char **name) { int pc; ravitype_t type; - *name = luaF_getlocalname(p, reg + 1, lastpc, &type); + TString *usertype; + *name = luaF_getlocalname(p, reg + 1, lastpc, &type, &usertype); if (*name) /* is a local? */ return "local"; /* else try symbolic execution */ @@ -488,7 +485,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg, int k = GETARG_C(i); /* key index */ int t = GETARG_B(i); /* table index */ const char *vn = (op != OP_GETTABUP && op != OP_RAVI_GETTABUP_SK) /* name of indexed variable */ - ? luaF_getlocalname(p, t + 1, pc, &type) /* t+1 is the local variable number */ + ? luaF_getlocalname(p, t + 1, pc, &type, &usertype) /* t+1 is the local variable number */ : upvalname(p, t); kname(p, pc, k, name); return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; diff --git a/src/lfunc.c b/src/lfunc.c index 09db3d9..c8f817e 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -243,7 +243,7 @@ void luaF_freeproto (lua_State *L, Proto *f) { ** Returns NULL if not found. ** RAVI extension - also return the known type if any */ -const char *luaF_getlocalname (const Proto *f, int local_number, int pc, ravitype_t *type) { +const char *luaF_getlocalname (const Proto *f, int local_number, int pc, ravitype_t *type, TString **usertype) { int i; for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { if (pc < f->locvars[i].endpc) { /* is variable active? */ @@ -252,11 +252,13 @@ const char *luaF_getlocalname (const Proto *f, int local_number, int pc, ravityp if (f->locvars[i].varname == NULL) break; *type = f->locvars[i].ravi_type; + *usertype = f->locvars[i].usertype; return getstr(f->locvars[i].varname); } } } *type = RAVI_TANY; + *usertype = NULL; return NULL; /* not found */ } diff --git a/src/lfunc.h b/src/lfunc.h index 21f1aa2..778caff 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -57,7 +57,7 @@ LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); /* The additional type argument is a Ravi extension */ LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, - int pc, ravitype_t* type); + int pc, ravitype_t* type, TString **usertype); #endif diff --git a/src/ltests.c b/src/ltests.c index 174855e..188e43f 100644 --- a/src/ltests.c +++ b/src/ltests.c @@ -645,10 +645,11 @@ static int listlocals (lua_State *L) { int i = 0; const char *name; ravitype_t tt; + TString *usertype; luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); p = getproto(obj_at(L, 1)); - while ((name = luaF_getlocalname(p, ++i, pc, &tt)) != NULL) + while ((name = luaF_getlocalname(p, ++i, pc, &tt, &usertype)) != NULL) lua_pushstring(L, name); return i-1; } diff --git a/src/lvm.c b/src/lvm.c index 80e9894..868b1c4 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1204,6 +1204,33 @@ void luaV_finishOp (lua_State *L) { if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ Protect(luaV_finishset(L,t,k,v,slot)); } +int raviV_checktype(lua_State *L, TValue *input, ravitype_t type, TString *usertype) { + if (type == RAVI_TANY) + return 1; + if (type == RAVI_TNIL && ttisnil(input)) + return 1; + if (type == RAVI_TBOOLEAN && ttisboolean(input)) + return 1; + if (type == RAVI_TNUMINT && ttisinteger(input)) + return 1; + if (type == RAVI_TNUMFLT && ttisfloat(input)) + return 1; + if (type == RAVI_TARRAYINT && ttisiarray(input)) + return 1; + if (type == RAVI_TARRAYFLT && ttisfarray(input)) + return 1; + if (type == RAVI_TTABLE && ttisLtable(input)) + return 1; + if (type == RAVI_TSTRING && ttisstring(input)) + return 1; + if (type == RAVI_TFUNCTION && ttisclosure(input)) + return 1; + if (type == RAVI_TUSERDATA) { + if (raviV_check_usertype(L, usertype, input)) + return 1; + } + return 0; +} int raviV_check_usertype(lua_State *L, TString *name, const TValue *o) { diff --git a/src/lvm.h b/src/lvm.h index bf2bf6c..111211e 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -172,6 +172,7 @@ LUAI_FUNC void raviV_settable_sskey(lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void raviV_settable_i(lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void raviV_op_totype(lua_State *L, TValue *ra, TValue *rb); +LUAI_FUNC int raviV_checktype(lua_State *L, TValue *input, ravitype_t type, TString *usertype); LUAI_FUNC int raviV_check_usertype(lua_State *L, TString *name, const TValue *o); #ifdef RAVI_DEFER_STATEMENT LUAI_FUNC void raviV_op_defer(lua_State *L, TValue *ra); From 88ccaf34a04ffc11cff24c94aca14056e570629e Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 22:41:42 +0000 Subject: [PATCH 5/9] Reformat --- src/lparser.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/lparser.c b/src/lparser.c index cf2bee0..fc01ab8 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1182,30 +1182,30 @@ static void constructor (LexState *ls, expdesc *t) { * be anchored somewhere else by the time parsing finishes */ static TString *user_defined_type_name(LexState *ls, TString *typename) { - size_t len = 0; - if (testnext(ls, '.')) { - char buffer[128] = { 0 }; - const char *str = getstr(typename); - len = strlen(str); - if (len >= sizeof buffer) { - luaX_syntaxerror(ls, "User defined type name is too long"); - return typename; - } - snprintf(buffer, sizeof buffer, "%s", str); - do { - typename = str_checkname(ls); - str = getstr(typename); - size_t newlen = len + strlen(str) + 1; - if (newlen >= sizeof buffer) { - luaX_syntaxerror(ls, "User defined type name is too long"); - return typename; - } - snprintf(buffer + len, sizeof buffer - len, ".%s", str); - len = newlen; - } while (testnext(ls, '.')); - typename = luaX_newstring(ls, buffer, strlen(buffer)); - } - return typename; + size_t len = 0; + if (testnext(ls, '.')) { + char buffer[128] = {0}; + const char *str = getstr(typename); + len = strlen(str); + if (len >= sizeof buffer) { + luaX_syntaxerror(ls, "User defined type name is too long"); + return typename; + } + snprintf(buffer, sizeof buffer, "%s", str); + do { + typename = str_checkname(ls); + str = getstr(typename); + size_t newlen = len + strlen(str) + 1; + if (newlen >= sizeof buffer) { + luaX_syntaxerror(ls, "User defined type name is too long"); + return typename; + } + snprintf(buffer + len, sizeof buffer - len, ".%s", str); + len = newlen; + } while (testnext(ls, '.')); + typename = luaX_newstring(ls, buffer, strlen(buffer)); + } + return typename; } /* RAVI Parse From b5afdfaa4605f9112bd6c8d363f9e60ba5362118 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 22:47:01 +0000 Subject: [PATCH 6/9] issue #215 The top level check v->ravi_type != vartype is not correct as it means we miss out checking scenario where v->k == VINDEXED. --- src/lparser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lparser.c b/src/lparser.c index fc01ab8..4b742b8 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1371,7 +1371,7 @@ static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, TString **usertypes, int nvars, int n) { /* NOTE that 'v' may not have register assigned yet */ ravitype_t vartype = var_types[n]; - if (n < nvars && vartype != RAVI_TANY && v->ravi_type != vartype) { + if (n < nvars && vartype != RAVI_TANY) { if (v->ravi_type != vartype && (vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) && v->k == VNONRELOC) { @@ -1454,7 +1454,7 @@ static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, luaK_exp2nextreg(ls->fs, v); ravi_code_typecoersion(ls, v->u.info, vartype, usertype); } - else { + else if (vartype != v->ravi_type){ luaX_syntaxerror(ls, "Invalid local assignment"); } } From 8fd3a1bbabcd9dfba8d2b9c89d9569941df001e7 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 23:35:01 +0000 Subject: [PATCH 7/9] issue #214 since we haven't implemented boolean type annotation fully, the parser will no longer recognize the :boolean annotation. --- src/lparser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lparser.c b/src/lparser.c index 4b742b8..a73a7a2 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1238,8 +1238,8 @@ static ravitype_t declare_localvar(LexState *ls, TString **pusertype) { tt = RAVI_TTABLE; else if (strcmp(str, "string") == 0) tt = RAVI_TSTRING; - else if (strcmp(str, "boolean") == 0) - tt = RAVI_TBOOLEAN; + //else if (strcmp(str, "boolean") == 0) + // tt = RAVI_TBOOLEAN; else if (strcmp(str, "any") == 0) tt = RAVI_TANY; else { From 658f04c3d8702945b9d106e40ab71d16a8fbd7a3 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 20 Feb 2021 23:56:38 +0000 Subject: [PATCH 8/9] issue #215 adapt fix by XmiliaH from pull request --- src/lparser.c | 168 +++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 85 deletions(-) diff --git a/src/lparser.c b/src/lparser.c index a73a7a2..b282f8f 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1367,96 +1367,94 @@ static int explist (LexState *ls, expdesc *v) { * 'v' may be a function call returning multiple values, in which case * we need to check all returned values against the expected types. */ -static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, - TString **usertypes, int nvars, int n) { - /* NOTE that 'v' may not have register assigned yet */ +static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, TString **usertypes, int nvars, int n) { + /* NOTE that 'v' may not have register assigned yet */ + if (n >= nvars) + return; ravitype_t vartype = var_types[n]; - if (n < nvars && vartype != RAVI_TANY) { - if (v->ravi_type != vartype && - (vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) && - v->k == VNONRELOC) { - /* as the bytecode for generating a table is already emitted by this stage - * we have to amend the generated byte code - not sure if there is a - * better approach. The location of the OP_NEWTABLE instruction is in - * v->pc and we check that this has the same destination register as - * v->u.info which is our variable */ - // local a:int[] = { 1 } - // ^ We are just past this - // and about to assign to a - int ok = 0; - if (v->pc >= 0) { - Instruction *pc = - &ls->fs->f->code[v->pc]; /* Get the OP_NEWTABLE instruction */ - OpCode op = GET_OPCODE(*pc); - if (op == OP_NEWTABLE) { /* check before making changes */ - int reg = GETARG_A(*pc); - if (reg == - v->u.info) { /* double check that register is as expected */ - op = (vartype == RAVI_TARRAYINT) ? OP_RAVI_NEW_IARRAY - : OP_RAVI_NEW_FARRAY; - SET_OPCODE(*pc, op); /* modify opcode */ - DEBUG_CODEGEN( - raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc)); - ok = 1; - } - } - } - if (!ok) - luaX_syntaxerror(ls, "expecting array initializer"); + if (vartype == RAVI_TANY) + return; + ravitype_t v_type = v->ravi_type; + if (v->k == VINDEXED) { + if (v_type == RAVI_TARRAYINT) { + v_type = RAVI_TNUMINT; } - /* if we are calling a function then convert return types */ - else if (v->ravi_type != vartype && - (vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT || - vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT || - vartype == RAVI_TTABLE || vartype == RAVI_TSTRING || - vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) && - v->k == VCALL) { - /* For local variable declarations that call functions e.g. - * local i = func() - * Lua ensures that the function returns values to register assigned to - * variable i and above so that no separate OP_MOVE instruction is - * necessary. So that means that we need to coerce the return values - * in situ. - */ - Instruction *pc = - &getinstruction(ls->fs, v); /* Obtain the instruction for OP_CALL */ - lua_assert(GET_OPCODE(*pc) == OP_CALL); - int a = GETARG_A(*pc); /* function return values will be placed from - register pointed by A and upwards */ - int nrets = GETARG_C(*pc) - 1; - /* operand C contains number of return values expected */ - /* Note that at this stage nrets is always 1 - as Lua patches in the this - * value for the last function call in a - * variable declaration statement in adjust_assign and - * localvar_adjust_assign */ - /* all return values that are going to be assigned to typed local vars - * must be converted to the correct type */ - int i; - for (i = n; i < (n + nrets); i++) - /* do we need to convert ? */ - ravi_code_typecoersion(ls, a + (i - n), var_types[i], NULL); + else if (v_type == RAVI_TARRAYFLT) { + v_type = RAVI_TNUMFLT; } - else if ((vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT) && - v->k == VINDEXED) { - if ((vartype == RAVI_TNUMFLT && v->ravi_type != RAVI_TARRAYFLT) || - (vartype == RAVI_TNUMINT && v->ravi_type != RAVI_TARRAYINT)) - luaX_syntaxerror(ls, "Invalid local assignment"); - } - else if ((vartype == RAVI_TSTRING && v->ravi_type != RAVI_TSTRING) || - (vartype == RAVI_TFUNCTION && v->ravi_type != RAVI_TFUNCTION) || - vartype == RAVI_TUSERDATA) { - TString *usertype = usertypes[n]; // NULL if var_types[n] is not userdata - /* we need to make sure that a register is assigned to 'v' - so that we can emit type assertion instructions. This would have - normally happened in the calling function but we do it early here - - possibly missing some optimization opportunity (i.e. avoiding register - assignment) */ - luaK_exp2nextreg(ls->fs, v); - ravi_code_typecoersion(ls, v->u.info, vartype, usertype); + else { + v_type = RAVI_TANY; } - else if (vartype != v->ravi_type){ - luaX_syntaxerror(ls, "Invalid local assignment"); + } + if (v_type == vartype) + return; + if ((vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) && v->k == VNONRELOC) { + /* as the bytecode for generating a table is already emitted by this stage + * we have to amend the generated byte code - not sure if there is a + * better approach. The location of the OP_NEWTABLE instruction is in + * v->pc and we check that this has the same destination register as + * v->u.info which is our variable */ + // local a:int[] = { 1 } + // ^ We are just past this + // and about to assign to a + int ok = 0; + if (v->pc >= 0) { + Instruction *pc = &ls->fs->f->code[v->pc]; /* Get the OP_NEWTABLE instruction */ + OpCode op = GET_OPCODE(*pc); + if (op == OP_NEWTABLE) { /* check before making changes */ + int reg = GETARG_A(*pc); + if (reg == v->u.info) { /* double check that register is as expected */ + op = (vartype == RAVI_TARRAYINT) ? OP_RAVI_NEW_IARRAY : OP_RAVI_NEW_FARRAY; + SET_OPCODE(*pc, op); /* modify opcode */ + DEBUG_CODEGEN(raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc)); + ok = 1; + } + } } + if (!ok) + luaX_syntaxerror(ls, "expecting array initializer"); + } + /* if we are calling a function then convert return types */ + else if ((vartype == RAVI_TNUMFLT || vartype == RAVI_TNUMINT || vartype == RAVI_TARRAYFLT || + vartype == RAVI_TARRAYINT || vartype == RAVI_TTABLE || vartype == RAVI_TSTRING || + vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) && + v->k == VCALL) { + /* For local variable declarations that call functions e.g. + * local i = func() + * Lua ensures that the function returns values to register assigned to + * variable i and above so that no separate OP_MOVE instruction is + * necessary. So that means that we need to coerce the return values + * in situ. + */ + Instruction *pc = &getinstruction(ls->fs, v); /* Obtain the instruction for OP_CALL */ + lua_assert(GET_OPCODE(*pc) == OP_CALL); + int a = GETARG_A(*pc); /* function return values will be placed from + register pointed by A and upwards */ + int nrets = GETARG_C(*pc) - 1; + /* operand C contains number of return values expected */ + /* Note that at this stage nrets is always 1 - as Lua patches in the this + * value for the last function call in a + * variable declaration statement in adjust_assign and + * localvar_adjust_assign */ + /* all return values that are going to be assigned to typed local vars + * must be converted to the correct type */ + int i; + for (i = n; i < (n + nrets); i++) + /* do we need to convert ? */ + ravi_code_typecoersion(ls, a + (i - n), var_types[i], NULL); + } + else if (vartype == RAVI_TSTRING || vartype == RAVI_TFUNCTION || vartype == RAVI_TUSERDATA) { + TString *usertype = usertypes[n]; // NULL if var_types[n] is not userdata + /* we need to make sure that a register is assigned to 'v' + so that we can emit type assertion instructions. This would have + normally happened in the calling function but we do it early here - + possibly missing some optimization opportunity (i.e. avoiding register + assignment) */ + luaK_exp2nextreg(ls->fs, v); + ravi_code_typecoersion(ls, v->u.info, vartype, usertype); + } + else { + luaX_syntaxerror(ls, "Invalid local assignment"); } } From 8e815bd67aa653231b0263289c55db2110478a3f Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 21 Feb 2021 00:45:13 +0000 Subject: [PATCH 9/9] issue #215 adapt fix by XmiliaH from pull request --- src/lcode.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/lcode.c b/src/lcode.c index fd909b0..ce1a1d1 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -874,10 +874,20 @@ static void check_valid_store(FuncState *fs, expdesc *var, expdesc *ex) { /* handled by MOVEI, MOVEF, MOVEIARRAY, MOVEFARRAY at runtime */ return; } + ravitype_t ex_ravi_type = ex->ravi_type; + if (ex->k == VINDEXED) { + if (ex_ravi_type == RAVI_TARRAYINT) { + ex_ravi_type = RAVI_TNUMINT; + } + else if (ex_ravi_type == RAVI_TARRAYFLT) { + ex_ravi_type = RAVI_TNUMFLT; + } + else { + ex_ravi_type = RAVI_TANY; + } + } if (var->ravi_type == RAVI_TNUMFLT) { - if (ex->ravi_type == RAVI_TNUMFLT) - return; - if (ex->k == VINDEXED && ex->ravi_type == RAVI_TARRAYFLT) + if (ex_ravi_type == RAVI_TNUMFLT) return; luaX_syntaxerror( fs->ls, @@ -886,22 +896,18 @@ static void check_valid_store(FuncState *fs, expdesc *var, expdesc *ex) { "Invalid assignment: number expected")); } else if (var->ravi_type == RAVI_TNUMINT) { - if (ex->ravi_type == RAVI_TNUMINT) - return; - if (ex->k == VINDEXED && ex->ravi_type == RAVI_TARRAYINT) + if (ex_ravi_type == RAVI_TNUMINT) return; luaX_syntaxerror( fs->ls, luaO_pushfstring( fs->ls->L, - "Invalid assignment: integer expected", - var->ravi_type, - ex->ravi_type)); + "Invalid assignment: integer expected")); } else if (var->ravi_type == RAVI_TARRAYFLT || var->ravi_type == RAVI_TARRAYINT || var->ravi_type == RAVI_TTABLE) { - if (ex->ravi_type == var->ravi_type && ex->k != VINDEXED) + if (ex_ravi_type == var->ravi_type) return; luaX_syntaxerror( fs->ls, @@ -911,33 +917,33 @@ static void check_valid_store(FuncState *fs, expdesc *var, expdesc *ex) { var->ravi_type == RAVI_TTABLE ? "table" : (var->ravi_type == RAVI_TARRAYFLT ? "number[]" : "integer[]"))); } else if (var->ravi_type == RAVI_TSTRING) { - if (ex->ravi_type == RAVI_TNIL || (ex->ravi_type == var->ravi_type && ex->k != VINDEXED)) + if (ex_ravi_type == RAVI_TNIL || ex_ravi_type == RAVI_TSTRING) return; luaX_syntaxerror( fs->ls, luaO_pushfstring( fs->ls->L, - "Invalid assignment: string expected")); + "Invalid assignment: string expected")); } else if (var->ravi_type == RAVI_TFUNCTION) { - if (ex->ravi_type == RAVI_TNIL || (ex->ravi_type == var->ravi_type && ex->k != VINDEXED)) + if (ex_ravi_type == RAVI_TNIL || ex_ravi_type == RAVI_TFUNCTION) return; luaX_syntaxerror( fs->ls, luaO_pushfstring( fs->ls->L, - "Invalid assignment: function expected")); + "Invalid assignment: function expected")); } else if (var->ravi_type == RAVI_TUSERDATA) { - if (ex->ravi_type == RAVI_TNIL || - (ex->ravi_type == var->ravi_type && var->usertype && var->usertype == ex->usertype && ex->k != VINDEXED)) + if (ex_ravi_type == RAVI_TNIL || + (ex_ravi_type == RAVI_TUSERDATA && var->usertype && var->usertype == ex->usertype)) return; luaX_syntaxerror( fs->ls, luaO_pushfstring( fs->ls->L, - "Invalid assignment: usertype %s expected", (var->usertype ? getstr(var->usertype) : "UNKNOWN"))); - } + "Invalid assignment: usertype %s expected", (var->usertype ? getstr(var->usertype) : "UNKNOWN"))); + } } static OpCode check_valid_setupval(FuncState *fs, expdesc *var, expdesc *ex,