diff --git a/src/lapi.c b/src/lapi.c index e3b5027..f55874a 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, ravi_type_map *type) { + CClosure **owner, UpVal **uv, ravi_type_map *type, TString **usertype) { *type = RAVI_TM_ANY; + *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_map; + *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; ravi_type_map 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); @@ -1615,10 +1618,11 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { UpVal *uv = NULL; StkId fi; ravi_type_map 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 @@ -1626,7 +1630,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { */ StkId input = L->top - 1; - int compatible = ravi_checktype(input, type); + int compatible = ravi_checktype(L, input, type, usertype); if (!compatible) name = NULL; diff --git a/src/lcode.c b/src/lcode.c index 63bf720..0a7f406 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1415,7 +1415,7 @@ static void codebinexpval (FuncState *fs, OpCode op, } -static OpCode get_type_specific_comp_op(OpCode op, uint32_t o1_tm, uint32_t o2_tm) { +static OpCode get_type_specific_comp_op(OpCode op, ravi_type_map o1_tm, ravi_type_map o2_tm) { if (op == OP_EQ) { if (o1_tm == RAVI_TM_INTEGER && o2_tm == RAVI_TM_INTEGER) op = OP_RAVI_EQ_II; @@ -1445,9 +1445,9 @@ static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { DEBUG_EXPR(raviY_printf(fs, "Comparison of %e and %e\n", e1, e2)); int rk1 = (e1->k == VK) ? RKASK(e1->u.info) : check_exp(e1->k == VNONRELOC, e1->u.info); - uint32_t rk1_tm = e1->ravi_type_map; + ravi_type_map rk1_tm = e1->ravi_type_map; int rk2 = luaK_exp2RK(fs, e2); - uint32_t rk2_tm = e2->ravi_type_map; + ravi_type_map rk2_tm = e2->ravi_type_map; freeexps(fs, e1, e2); switch (opr) { case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ @@ -1508,7 +1508,7 @@ static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e, TString *us case VNONRELOC: { discharge2anyreg(fs, e); OpCode opcode; - uint32_t tm; + ravi_type_map tm; if (op == OPR_TO_NUMBER && e->ravi_type_map != RAVI_TM_FLOAT) { opcode = OP_RAVI_TOFLT; tm = RAVI_TM_FLOAT; diff --git a/src/ldebug.c b/src/ldebug.c index 6408a1f..4d0c1ff 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, ravi_type_map *type) { + StkId *pos, ravi_type_map *type, TString** usertype) { const char *name = NULL; StkId base; *type = RAVI_TM_ANY; + *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; ravi_type_map 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,17 +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; ravi_type_map 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 */ StkId input = L->top - 1; - int compatible = ravi_checktype(input, type); + int compatible = ravi_checktype(L, input, type, usertype); if (compatible) { setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ @@ -450,7 +453,8 @@ static const char *getobjname (Proto *p, int lastpc, int reg, const char **name) { int pc; ravi_type_map 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 */ @@ -481,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 e4bc138..0864e19 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, ravi_type_map *type) { +const char *luaF_getlocalname (const Proto *f, int local_number, int pc, ravi_type_map *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, ravi_ty if (f->locvars[i].varname == NULL) break; *type = f->locvars[i].ravi_type_map; + *usertype = f->locvars[i].usertype; return getstr(f->locvars[i].varname); } } } *type = RAVI_TM_ANY; + *usertype = NULL; return NULL; /* not found */ } diff --git a/src/lfunc.h b/src/lfunc.h index a945b0a..7f7b50d 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, ravi_type_map* type); + int pc, ravi_type_map* type, TString **usertype); #endif diff --git a/src/lobject.c b/src/lobject.c index b8bf65b..2b26be2 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -33,7 +33,7 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; -int ravi_checktype(StkId input, ravi_type_map type) { +int ravi_checktype(lua_State *L, StkId input, ravi_type_map type, TString* usertype) { if (type == RAVI_TM_ANY) return 1; if (type & RAVI_TM_NIL && ttisnil(input)) return 1; if (type & RAVI_TM_FALSE && ttisboolean(input) && l_isfalse(input)) return 1; @@ -45,7 +45,9 @@ int ravi_checktype(StkId input, ravi_type_map type) { if (type & RAVI_TM_TABLE && ttisLtable(input)) return 1; if (type & RAVI_TM_STRING && ttisstring(input)) return 1; if (type & RAVI_TM_FUNCTION && ttisclosure(input)) return 1; - // TODO if (type & RAVI_TM_USERDATA && ) + if (type & RAVI_TM_USERDATA) { + if (raviV_check_usertype(L, usertype, input)) return 1; + } return 0; } diff --git a/src/lobject.h b/src/lobject.h index 028d3d0..34ce3b5 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -72,18 +72,18 @@ typedef enum { typedef uint32_t ravi_type_map; -#define RAVI_TM_NIL (((uint32_t)1)<k, e->u.info may have a register * or bytecode */ -static void init_exp (expdesc *e, expkind k, int info, uint32_t tt, TString *usertype) { +static void init_exp (expdesc *e, expkind k, int info, ravi_type_map tt, TString *usertype) { e->f = e->t = NO_JUMP; e->k = k; e->u.info = info; @@ -394,7 +394,7 @@ static void checkname (LexState *ls, expdesc *e) { * variable's index in ls->f->locvars. * RAVI change - added the type of the variable. */ -static int registerlocalvar (LexState *ls, TString *varname, ravi_type_map ravi_type_map, TString *usertype) { +static int registerlocalvar (LexState *ls, TString *varname, ravi_type_map tm, TString *usertype) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizelocvars; @@ -409,7 +409,7 @@ static int registerlocalvar (LexState *ls, TString *varname, ravi_type_map ravi_ f->locvars[oldsize++].varname = NULL; } f->locvars[fs->nlocvars].varname = varname; - f->locvars[fs->nlocvars].ravi_type_map = ravi_type_map; + f->locvars[fs->nlocvars].ravi_type_map = tm; f->locvars[fs->nlocvars].usertype = usertype; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; @@ -625,29 +625,22 @@ static void singlevar (LexState *ls, expdesc *var) { /* RAVI code an instruction to coerce the type, reg is the register, and ravi_type is the type we want */ -static void ravi_code_typecoersion(LexState *ls, int reg, ravi_type_map ravi_type_map, TString *typename /* only if tt is USERDATA */) { +static void ravi_code_typecoersion(LexState *ls, int reg, ravi_type_map tm, + TString *typename /* only if tt is USERDATA */) { /* do we need to convert ? */ - if (ravi_type_map == RAVI_TM_FLOAT || ravi_type_map == RAVI_TM_INTEGER) + if (tm == RAVI_TM_FLOAT || tm == RAVI_TM_INTEGER) /* code an instruction to convert in place */ - luaK_codeABC(ls->fs, - ravi_type_map == RAVI_TM_FLOAT ? OP_RAVI_TOFLT : OP_RAVI_TOINT, reg, - 0, 0); - else if (ravi_type_map == RAVI_TM_INTEGER_ARRAY || ravi_type_map == RAVI_TM_FLOAT_ARRAY) - luaK_codeABC(ls->fs, ravi_type_map == RAVI_TM_INTEGER_ARRAY ? OP_RAVI_TOIARRAY - : OP_RAVI_TOFARRAY, - reg, 0, 0); - else if (ravi_type_map == RAVI_TM_TABLE) - luaK_codeABC(ls->fs, OP_RAVI_TOTAB, - reg, 0, 0); - else if (ravi_type_map == (RAVI_TM_USERDATA | RAVI_TM_NIL)) - luaK_codeABx(ls->fs, OP_RAVI_TOTYPE, - reg, luaK_stringK(ls->fs, typename)); - else if (ravi_type_map == (RAVI_TM_STRING | RAVI_TM_NIL)) - luaK_codeABC(ls->fs, OP_RAVI_TOSTRING, - reg, 0, 0); - else if (ravi_type_map == (RAVI_TM_FUNCTION | RAVI_TM_NIL)) - luaK_codeABC(ls->fs, OP_RAVI_TOCLOSURE, - reg, 0, 0); + luaK_codeABC(ls->fs, tm == RAVI_TM_FLOAT ? OP_RAVI_TOFLT : OP_RAVI_TOINT, reg, 0, 0); + else if (tm == RAVI_TM_INTEGER_ARRAY || tm == RAVI_TM_FLOAT_ARRAY) + luaK_codeABC(ls->fs, tm == RAVI_TM_INTEGER_ARRAY ? OP_RAVI_TOIARRAY : OP_RAVI_TOFARRAY, reg, 0, 0); + else if (tm == RAVI_TM_TABLE) + luaK_codeABC(ls->fs, OP_RAVI_TOTAB, reg, 0, 0); + else if (tm == (RAVI_TM_USERDATA | RAVI_TM_NIL)) + luaK_codeABx(ls->fs, OP_RAVI_TOTYPE, reg, luaK_stringK(ls->fs, typename)); + else if (tm == (RAVI_TM_STRING | RAVI_TM_NIL)) + luaK_codeABC(ls->fs, OP_RAVI_TOSTRING, reg, 0, 0); + else if (tm == (RAVI_TM_FUNCTION | RAVI_TM_NIL)) + luaK_codeABC(ls->fs, OP_RAVI_TOCLOSURE, reg, 0, 0); // TODO coerse to boolean } @@ -695,10 +688,10 @@ static void ravi_coercetype(LexState *ls, expdesc *v, int n) * first convert from local register to variable index. */ int idx = register_to_locvar_index(ls->fs, i); - ravi_type_map ravi_type_map = ls->fs->f->locvars[idx].ravi_type_map; /* get variable's type */ + ravi_type_map tm = ls->fs->f->locvars[idx].ravi_type_map; /* get variable's type */ TString *usertype = ls->fs->f->locvars[idx].usertype; /* do we need to convert ? */ - ravi_code_typecoersion(ls, i, ravi_type_map, usertype); + ravi_code_typecoersion(ls, i, tm, usertype); } } @@ -712,10 +705,10 @@ static void ravi_setzero(FuncState *fs, int from, int n) { * first convert from local register to variable index. */ int idx = register_to_locvar_index(fs, i); - ravi_type_map ravi_type_map = fs->f->locvars[idx].ravi_type_map; /* get variable's type */ + ravi_type_map tm = fs->f->locvars[idx].ravi_type_map; /* get variable's type */ TString *usertype = fs->f->locvars[idx].usertype; /* do we need to convert ? */ - ravi_code_setzero(fs, i, ravi_type_map, usertype); + ravi_code_setzero(fs, i, tm, usertype); } } @@ -1417,92 +1410,96 @@ static int explist (LexState *ls, expdesc *v) { */ static void ravi_typecheck(LexState *ls, expdesc *v, ravi_type_map *var_types, TString **usertypes, int nvars, int n) { - /* NOTE that 'v' may not have register assigned yet */ + /* NOTE that 'v' may not have register assigned yet */ + if (n >= nvars) return; ravi_type_map vartype = var_types[n]; - if (n < nvars && (v->ravi_type_map & ~vartype)) { - if ((vartype == RAVI_TM_FLOAT_ARRAY || vartype == RAVI_TM_INTEGER_ARRAY) && - 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_TM_INTEGER_ARRAY) ? 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"); + ravi_type_map v_type_map = v->ravi_type_map; + if (v->k == VINDEXED) { + if (v_type_map == RAVI_TM_INTEGER_ARRAY) { + v_type_map = RAVI_TM_INTEGER; + } else if (v_type_map == RAVI_TM_FLOAT_ARRAY) { + v_type_map = RAVI_TM_FLOAT; + } else { + v_type_map = RAVI_TM_ANY; } - /* if we are calling a function then convert return types */ - else if ((vartype == RAVI_TM_FLOAT || vartype == RAVI_TM_INTEGER || - vartype == RAVI_TM_FLOAT_ARRAY || vartype == RAVI_TM_INTEGER_ARRAY || - vartype == RAVI_TM_TABLE || vartype == (RAVI_TM_STRING | RAVI_TM_NIL) || - vartype == (RAVI_TM_FUNCTION | RAVI_TM_NIL) || vartype == (RAVI_TM_USERDATA | RAVI_TM_NIL)) && - 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. - */ + } + if ((v_type_map & ~vartype) == 0) return; + if ((vartype == RAVI_TM_FLOAT_ARRAY || vartype == RAVI_TM_INTEGER_ARRAY) && + 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 = - &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_TM_FLOAT || vartype == RAVI_TM_INTEGER) && - v->k == VINDEXED) { - if ((vartype == RAVI_TM_FLOAT && v->ravi_type_map != RAVI_TM_FLOAT_ARRAY) || - (vartype == RAVI_TM_INTEGER && v->ravi_type_map != RAVI_TM_INTEGER_ARRAY)) - luaX_syntaxerror(ls, "Invalid local assignment"); - } - else if ((vartype == (RAVI_TM_STRING | RAVI_TM_NIL) && v->ravi_type_map != RAVI_TM_STRING) || - (vartype == (RAVI_TM_FUNCTION | RAVI_TM_NIL) && v->ravi_type_map != RAVI_TM_FUNCTION) || - vartype == (RAVI_TM_USERDATA | RAVI_TM_NIL)) { // TODO this is wrong since nil is ignored - 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"); + &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_TM_INTEGER_ARRAY) ? 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_TM_FLOAT || vartype == RAVI_TM_INTEGER || + vartype == RAVI_TM_FLOAT_ARRAY || vartype == RAVI_TM_INTEGER_ARRAY || + vartype == RAVI_TM_TABLE || vartype == (RAVI_TM_STRING | RAVI_TM_NIL) || + vartype == (RAVI_TM_FUNCTION | RAVI_TM_NIL) || vartype == (RAVI_TM_USERDATA | RAVI_TM_NIL)) && + 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_TM_STRING | RAVI_TM_NIL) || + vartype == (RAVI_TM_FUNCTION | RAVI_TM_NIL) || + vartype == (RAVI_TM_USERDATA | RAVI_TM_NIL)) { + 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"); } } @@ -2032,7 +2029,7 @@ static void repeatstat (LexState *ls, int line) { } typedef struct Fornuminfo { - uint32_t type_map; + ravi_type_map type_map; int is_constant; int int_value; } Fornuminfo; diff --git a/src/lparser.h b/src/lparser.h index 6737962..2676766 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -66,14 +66,14 @@ typedef struct expdesc { short idx; /* index (R/K) */ lu_byte t; /* table (register or upvalue) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ - uint32_t key_ravi_type_map; /* Map of possible types the key could have */ + ravi_type_map key_ravi_type_map; /* Map of possible types the key could have */ // lu_byte key_ravi_type; /* RAVI change: key type */ TString *usertype; /* RAVI change: usertype name */ } ind; } u; int t; /* patch list of 'exit when true' */ int f; /* patch list of 'exit when false' */ - uint32_t ravi_type_map; /* Map of possible types this expression could have */ + ravi_type_map ravi_type_map; /* Map of possible types this expression could have */ // lu_byte ravi_type; /* RAVI change: type of the expression if known, else RAVI_TANY */ TString *usertype; /* RAVI change: usertype name */ int pc; /* RAVI change: holds the program counter for OP_NEWTABLE instruction when a constructor expression is parsed */ @@ -245,7 +245,7 @@ LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, /** RAVI extensions **/ #define RAVI_TYPEMAP_MAX_LEN (sizeof("nil|boolean|integer|number|integer[]|number[]|table|string|function|userdata|?|")) -LUAI_FUNC void raviY_typemap_string(uint32_t tm, char* buf); +LUAI_FUNC void raviY_typemap_string(ravi_type_map tm, char* buf); /* Special printf that recognises following conversions: * %e - expdesc * diff --git a/src/ltests.c b/src/ltests.c index b01e8d1..a88d527 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; ravi_type_map 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; }