|
|
|
@ -66,108 +66,154 @@ typedef struct BlockCnt {
|
|
|
|
|
/* RAVI set debug level */
|
|
|
|
|
void ravi_set_debuglevel(int level) { ravi_parser_debug = level; }
|
|
|
|
|
|
|
|
|
|
/* RAVI - return the type name */
|
|
|
|
|
const char *raviY_typename(ravitype_t tt) {
|
|
|
|
|
switch (tt) {
|
|
|
|
|
case RAVI_TNIL:
|
|
|
|
|
return "nil";
|
|
|
|
|
case RAVI_TBOOLEAN:
|
|
|
|
|
return "boolean";
|
|
|
|
|
case RAVI_TNUMFLT:
|
|
|
|
|
return "number";
|
|
|
|
|
case RAVI_TNUMINT:
|
|
|
|
|
return "integer";
|
|
|
|
|
case RAVI_TSTRING:
|
|
|
|
|
return "string";
|
|
|
|
|
case RAVI_TFUNCTION:
|
|
|
|
|
return "function";
|
|
|
|
|
case RAVI_TARRAYINT:
|
|
|
|
|
return "integer[]";
|
|
|
|
|
case RAVI_TARRAYFLT:
|
|
|
|
|
return "number[]";
|
|
|
|
|
case RAVI_TUSERDATA:
|
|
|
|
|
return "userdata";
|
|
|
|
|
case RAVI_TTABLE:
|
|
|
|
|
return "table";
|
|
|
|
|
default:
|
|
|
|
|
return "?";
|
|
|
|
|
|
|
|
|
|
static char* raviY_buf_append(char* buf, const char* what) {
|
|
|
|
|
char c;
|
|
|
|
|
while((c=*what++)) {
|
|
|
|
|
*buf++ = c;
|
|
|
|
|
}
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void raviY_typemap_string(ravi_type_map tm, char* buf) {
|
|
|
|
|
if (tm == RAVI_TM_ANY) {
|
|
|
|
|
memcpy(buf, "any", 4);
|
|
|
|
|
return;
|
|
|
|
|
} else if (tm == 0) {
|
|
|
|
|
memcpy(buf, "?", 2);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
char* start = buf;
|
|
|
|
|
if (tm & RAVI_TM_NIL) {
|
|
|
|
|
buf = raviY_buf_append(buf, "nil|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_BOOLEAN) {
|
|
|
|
|
if ((tm & RAVI_TM_TRUE) == 0) {
|
|
|
|
|
buf = raviY_buf_append(buf, "false|");
|
|
|
|
|
} else if((tm & RAVI_TM_FALSE) == 0) {
|
|
|
|
|
buf = raviY_buf_append(buf, "true|");
|
|
|
|
|
} else {
|
|
|
|
|
buf = raviY_buf_append(buf, "boolean|");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_INTEGER) {
|
|
|
|
|
buf = raviY_buf_append(buf, "integer|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_FLOAT) {
|
|
|
|
|
buf = raviY_buf_append(buf, "number|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_INTEGER_ARRAY) {
|
|
|
|
|
buf = raviY_buf_append(buf, "integer[]|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_FLOAT_ARRAY) {
|
|
|
|
|
buf = raviY_buf_append(buf, "number[]|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_TABLE) {
|
|
|
|
|
buf = raviY_buf_append(buf, "table|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_STRING) {
|
|
|
|
|
buf = raviY_buf_append(buf, "string|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_FUNCTION) {
|
|
|
|
|
buf = raviY_buf_append(buf, "function|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_USERDATA) {
|
|
|
|
|
buf = raviY_buf_append(buf, "userdata|");
|
|
|
|
|
}
|
|
|
|
|
if (tm & RAVI_TM_OTHER) {
|
|
|
|
|
buf = raviY_buf_append(buf, "?|");
|
|
|
|
|
}
|
|
|
|
|
if (start == buf) {
|
|
|
|
|
memcpy(buf, "?", 2);
|
|
|
|
|
} else {
|
|
|
|
|
buf[-1] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* RAVI - prints a Lua expression node */
|
|
|
|
|
static void print_expdesc(FILE *fp, FuncState *fs, const expdesc *e) {
|
|
|
|
|
char buf[80] = {0};
|
|
|
|
|
char type_map_str[RAVI_TYPEMAP_MAX_LEN];
|
|
|
|
|
raviY_typemap_string(e->ravi_type_map, type_map_str);
|
|
|
|
|
switch (e->k) {
|
|
|
|
|
case VVOID:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VVOID, type=%s}", e, raviY_typename(e->ravi_type));
|
|
|
|
|
fprintf(fp, "{p=%p, k=VVOID, type=%s}", e, type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VNIL:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VNIL, type=%s}", e, raviY_typename(e->ravi_type));
|
|
|
|
|
fprintf(fp, "{p=%p, k=VNIL, type=%s}", e, type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VTRUE:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VTRUE, type=%s}", e, raviY_typename(e->ravi_type));
|
|
|
|
|
fprintf(fp, "{p=%p, k=VTRUE, type=%s}", e, type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VFALSE:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VFALSE, type=%s}", e, raviY_typename(e->ravi_type));
|
|
|
|
|
fprintf(fp, "{p=%p, k=VFALSE, type=%s}", e, type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VK:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VK, Kst=%d, type=%s}", e, e->u.info,
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VKFLT:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VKFLT, n=%f, type=%s}", e, e->u.nval,
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VKINT:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VKINT, n=%lld, type=%s}", e, (long long)e->u.ival,
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VNONRELOC:
|
|
|
|
|
{
|
|
|
|
|
char var_type_map_str[RAVI_TYPEMAP_MAX_LEN];
|
|
|
|
|
raviY_typemap_string(raviY_get_register_typeinfo(fs, e->u.info, NULL), var_type_map_str);
|
|
|
|
|
fprintf(fp, "{p=%p, k=VNONRELOC, register=%d %s, type=%s, pc=%d}", e, e->u.info,
|
|
|
|
|
raviY_typename(raviY_get_register_typeinfo(fs, e->u.info, NULL)),
|
|
|
|
|
raviY_typename(e->ravi_type),
|
|
|
|
|
var_type_map_str,
|
|
|
|
|
type_map_str,
|
|
|
|
|
e->pc);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case VLOCAL:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VLOCAL, register=%d, type=%s}", e, e->u.info,
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VUPVAL:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VUPVAL, idx=%d, type=%s}", e, e->u.info,
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VINDEXED:
|
|
|
|
|
fprintf(fp,
|
|
|
|
|
"{p=%p, k=VINDEXED, tablereg=%d, indexreg=%d, vtype=%s, type=%s}",
|
|
|
|
|
e, e->u.ind.t, e->u.ind.idx,
|
|
|
|
|
(e->u.ind.vt == VLOCAL) ? "VLOCAL" : "VUPVAL",
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VJMP:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VJMP, pc=%d, instruction=(%s), type=%s}", e,
|
|
|
|
|
e->u.info,
|
|
|
|
|
raviP_instruction_to_str(buf, sizeof buf, getinstruction(fs, e)),
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
case VRELOCABLE:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VRELOCABLE, pc=%d, instruction=(%s), type=%s, pc=%d}", e,
|
|
|
|
|
e->u.info,
|
|
|
|
|
raviP_instruction_to_str(buf, sizeof buf, getinstruction(fs, e)),
|
|
|
|
|
raviY_typename(e->ravi_type),
|
|
|
|
|
type_map_str,
|
|
|
|
|
e->pc);
|
|
|
|
|
break;
|
|
|
|
|
case VCALL:
|
|
|
|
|
{
|
|
|
|
|
char var_type_map_str[RAVI_TYPEMAP_MAX_LEN];
|
|
|
|
|
raviY_typemap_string(raviY_get_register_typeinfo(fs, GETARG_A(getinstruction(fs, e)), NULL), var_type_map_str);
|
|
|
|
|
fprintf(
|
|
|
|
|
fp, "{p=%p, k=VCALL, pc=%d, instruction=(%s %s), type=%s}", e,
|
|
|
|
|
e->u.info, raviP_instruction_to_str(buf, sizeof buf, getinstruction(fs, e)),
|
|
|
|
|
raviY_typename(raviY_get_register_typeinfo(fs, GETARG_A(getinstruction(fs, e)), NULL)),
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
var_type_map_str,
|
|
|
|
|
type_map_str);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case VVARARG:
|
|
|
|
|
fprintf(fp, "{p=%p, k=VVARARG, pc=%d, instruction=(%s), type=%s}", e,
|
|
|
|
|
e->u.info,
|
|
|
|
|
raviP_instruction_to_str(buf, sizeof buf, getinstruction(fs, e)),
|
|
|
|
|
raviY_typename(e->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -187,10 +233,12 @@ void raviY_printf(FuncState *fs, const char *format, ...) {
|
|
|
|
|
cp++;
|
|
|
|
|
} else if (cp[0] == '%' && cp[1] == 'v') {
|
|
|
|
|
LocVar *v;
|
|
|
|
|
char type_map_str[RAVI_TYPEMAP_MAX_LEN];
|
|
|
|
|
v = va_arg(ap, LocVar *);
|
|
|
|
|
const char *s = getstr(v->varname);
|
|
|
|
|
raviY_typemap_string(v->ravi_type_map, type_map_str);
|
|
|
|
|
printf("var={%s startpc=%d endpc=%d, type=%s}", s, v->startpc, v->endpc,
|
|
|
|
|
raviY_typename(v->ravi_type));
|
|
|
|
|
type_map_str);
|
|
|
|
|
cp++;
|
|
|
|
|
} else if (cp[0] == '%' && cp[1] == 'o') {
|
|
|
|
|
Instruction i;
|
|
|
|
@ -214,9 +262,11 @@ void raviY_printf(FuncState *fs, const char *format, ...) {
|
|
|
|
|
printf("%f", d);
|
|
|
|
|
cp++;
|
|
|
|
|
} else if (cp[0] == '%' && cp[1] == 't') {
|
|
|
|
|
ravitype_t i;
|
|
|
|
|
i = va_arg(ap, ravitype_t);
|
|
|
|
|
fputs(raviY_typename(i), stdout);
|
|
|
|
|
ravi_type_map i;
|
|
|
|
|
char type_map_str[RAVI_TYPEMAP_MAX_LEN];
|
|
|
|
|
i = va_arg(ap, ravi_type_map);
|
|
|
|
|
raviY_typemap_string(i, type_map_str);
|
|
|
|
|
fputs(type_map_str, stdout);
|
|
|
|
|
cp++;
|
|
|
|
|
} else {
|
|
|
|
|
fputc(*cp, stdout);
|
|
|
|
@ -314,12 +364,12 @@ static TString *str_checkname (LexState *ls) {
|
|
|
|
|
* expression kind in e->k, e->u.info may have a register
|
|
|
|
|
* or bytecode
|
|
|
|
|
*/
|
|
|
|
|
static void init_exp (expdesc *e, expkind k, int info, ravitype_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;
|
|
|
|
|
/* RAVI change; added type */
|
|
|
|
|
e->ravi_type = tt;
|
|
|
|
|
e->ravi_type_map = tt;
|
|
|
|
|
e->usertype = usertype;
|
|
|
|
|
e->pc = -1;
|
|
|
|
|
e->u.ind.usertype = NULL; /* Just for safey */
|
|
|
|
@ -329,7 +379,7 @@ static void init_exp (expdesc *e, expkind k, int info, ravitype_t tt, TString *u
|
|
|
|
|
* e->u.info, e->ravi_type = RAVI_TSTRING, e->k = VK
|
|
|
|
|
*/
|
|
|
|
|
static void codestring (LexState *ls, expdesc *e, TString *s) {
|
|
|
|
|
init_exp(e, VK, luaK_stringK(ls->fs, s), RAVI_TSTRING, NULL);
|
|
|
|
|
init_exp(e, VK, luaK_stringK(ls->fs, s), RAVI_TM_STRING, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* verify that current token is a string, create a string constant
|
|
|
|
@ -344,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, unsigned int ravi_type, 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;
|
|
|
|
@ -354,28 +404,25 @@ static int registerlocalvar (LexState *ls, TString *varname, unsigned int ravi_t
|
|
|
|
|
/* RAVI change initialize */
|
|
|
|
|
f->locvars[oldsize].startpc = -1;
|
|
|
|
|
f->locvars[oldsize].endpc = -1;
|
|
|
|
|
f->locvars[oldsize].ravi_type = RAVI_TANY;
|
|
|
|
|
f->locvars[oldsize].ravi_type_map = RAVI_TM_ANY;
|
|
|
|
|
f->locvars[oldsize].usertype = NULL;
|
|
|
|
|
f->locvars[oldsize++].varname = NULL;
|
|
|
|
|
}
|
|
|
|
|
f->locvars[fs->nlocvars].varname = varname;
|
|
|
|
|
f->locvars[fs->nlocvars].ravi_type = ravi_type;
|
|
|
|
|
if (ravi_type == RAVI_TUSERDATA && usertype != NULL) {
|
|
|
|
|
// Store a reference to the usertype name
|
|
|
|
|
f->locvars[fs->nlocvars].usertype = usertype;
|
|
|
|
|
}
|
|
|
|
|
f->locvars[fs->nlocvars].ravi_type_map = tm;
|
|
|
|
|
f->locvars[fs->nlocvars].usertype = usertype;
|
|
|
|
|
luaC_objbarrier(ls->L, f, varname);
|
|
|
|
|
return fs->nlocvars++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* create a new local variable in function scope, and set the
|
|
|
|
|
* variable type (RAVI - added type tt) */
|
|
|
|
|
static void new_localvar (LexState *ls, TString *name, ravitype_t tt, TString *usertype) {
|
|
|
|
|
static void new_localvar (LexState *ls, TString *name, ravi_type_map tm, TString *usertype) {
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
Dyndata *dyd = ls->dyd;
|
|
|
|
|
/* register variable and get its index */
|
|
|
|
|
/* RAVI change - record type info for local variable */
|
|
|
|
|
int reg = registerlocalvar(ls, name, tt, usertype);
|
|
|
|
|
int reg = registerlocalvar(ls, name, tm, usertype);
|
|
|
|
|
checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
|
|
|
|
|
MAXVARS, "local variables");
|
|
|
|
|
luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
|
|
|
|
@ -391,7 +438,7 @@ static void new_localvar (LexState *ls, TString *name, ravitype_t tt, TString *u
|
|
|
|
|
*/
|
|
|
|
|
static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
|
|
|
|
|
/* RAVI change - add type */
|
|
|
|
|
new_localvar(ls, luaX_newstring(ls, name, sz), RAVI_TANY, NULL);
|
|
|
|
|
new_localvar(ls, luaX_newstring(ls, name, sz), RAVI_TM_ANY, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* create a new local variable
|
|
|
|
@ -428,13 +475,13 @@ static int register_to_locvar_index(FuncState *fs, int reg) {
|
|
|
|
|
* return the type associated with the variable.
|
|
|
|
|
* This is a RAVI function
|
|
|
|
|
*/
|
|
|
|
|
ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg, TString **pusertype) {
|
|
|
|
|
ravi_type_map raviY_get_register_typeinfo(FuncState *fs, int reg, TString **pusertype) {
|
|
|
|
|
int idx;
|
|
|
|
|
LocVar *v;
|
|
|
|
|
/* Due to the way Lua parser works it is not safe to look beyond nactvar */
|
|
|
|
|
if (reg < 0 || reg >= fs->nactvar ||
|
|
|
|
|
(fs->firstlocal + reg) >= fs->ls->dyd->actvar.n) {
|
|
|
|
|
return RAVI_TANY;
|
|
|
|
|
return RAVI_TM_ANY;
|
|
|
|
|
}
|
|
|
|
|
/* Get the LocVar associated with the register */
|
|
|
|
|
idx = fs->ls->dyd->actvar.arr[fs->firstlocal + reg].idx;
|
|
|
|
@ -443,7 +490,7 @@ ravitype_t raviY_get_register_typeinfo(FuncState *fs, int reg, TString **puserty
|
|
|
|
|
if (pusertype != NULL)
|
|
|
|
|
*pusertype = v->usertype;
|
|
|
|
|
/* Variable in scope so return the type if we know it */
|
|
|
|
|
return v->ravi_type;
|
|
|
|
|
return v->ravi_type_map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* moves the active variable watermark (nactvar) to cover the
|
|
|
|
@ -497,7 +544,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|
|
|
|
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
|
|
|
|
|
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
|
|
|
|
|
f->upvalues[fs->nups].name = name;
|
|
|
|
|
f->upvalues[fs->nups].ravi_type = v->ravi_type;
|
|
|
|
|
f->upvalues[fs->nups].ravi_type_map = v->ravi_type_map;
|
|
|
|
|
f->upvalues[fs->nups].usertype = v->usertype;
|
|
|
|
|
luaC_objbarrier(fs->ls->L, f, name);
|
|
|
|
|
return fs->nups++;
|
|
|
|
@ -534,13 +581,13 @@ static void markupval (FuncState *fs, int level) {
|
|
|
|
|
*/
|
|
|
|
|
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
|
|
|
|
if (fs == NULL) /* no more levels? */
|
|
|
|
|
init_exp(var, VVOID, 0, RAVI_TANY, NULL); /* default is global */
|
|
|
|
|
init_exp(var, VVOID, 0, RAVI_TM_ANY, NULL); /* default is global */
|
|
|
|
|
else {
|
|
|
|
|
int v = searchvar(fs, n); /* look up locals at current level */
|
|
|
|
|
if (v >= 0) { /* found? */
|
|
|
|
|
/* RAVI set type of local var / expr if possible */
|
|
|
|
|
TString *usertype = NULL;
|
|
|
|
|
ravitype_t tt = raviY_get_register_typeinfo(fs, v, &usertype);
|
|
|
|
|
ravi_type_map tt = raviY_get_register_typeinfo(fs, v, &usertype);
|
|
|
|
|
init_exp(var, VLOCAL, v, tt, usertype); /* variable is local, RAVI set type */
|
|
|
|
|
if (!base)
|
|
|
|
|
markupval(fs, v); /* local will be used as an upval */
|
|
|
|
@ -554,7 +601,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
|
|
|
|
/* else was LOCAL or UPVAL */
|
|
|
|
|
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
|
|
|
|
}
|
|
|
|
|
init_exp(var, VUPVAL, idx, fs->f->upvalues[idx].ravi_type, fs->f->upvalues[idx].usertype); /* RAVI : set upvalue type */
|
|
|
|
|
init_exp(var, VUPVAL, idx, fs->f->upvalues[idx].ravi_type_map, fs->f->upvalues[idx].usertype); /* RAVI : set upvalue type */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -568,7 +615,7 @@ static void singlevar (LexState *ls, expdesc *var) {
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
singlevaraux(fs, varname, var, 1);
|
|
|
|
|
if (var->k == VVOID) { /* global name? */
|
|
|
|
|
expdesc key = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc key = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
|
|
|
|
lua_assert(var->k != VVOID); /* this one must exist */
|
|
|
|
|
codestring(ls, &key, varname); /* key is variable name */
|
|
|
|
@ -578,46 +625,40 @@ 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, ravitype_t ravi_type, 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 == RAVI_TNUMFLT || ravi_type == RAVI_TNUMINT)
|
|
|
|
|
if (tm == RAVI_TM_FLOAT || tm == RAVI_TM_INTEGER)
|
|
|
|
|
/* code an instruction to convert in place */
|
|
|
|
|
luaK_codeABC(ls->fs,
|
|
|
|
|
ravi_type == RAVI_TNUMFLT ? OP_RAVI_TOFLT : OP_RAVI_TOINT, reg,
|
|
|
|
|
0, 0);
|
|
|
|
|
else if (ravi_type == RAVI_TARRAYINT || ravi_type == RAVI_TARRAYFLT)
|
|
|
|
|
luaK_codeABC(ls->fs, ravi_type == RAVI_TARRAYINT ? OP_RAVI_TOIARRAY
|
|
|
|
|
: OP_RAVI_TOFARRAY,
|
|
|
|
|
reg, 0, 0);
|
|
|
|
|
else if (ravi_type == RAVI_TTABLE)
|
|
|
|
|
luaK_codeABC(ls->fs, OP_RAVI_TOTAB,
|
|
|
|
|
reg, 0, 0);
|
|
|
|
|
else if (ravi_type == RAVI_TUSERDATA)
|
|
|
|
|
luaK_codeABx(ls->fs, OP_RAVI_TOTYPE,
|
|
|
|
|
reg, luaK_stringK(ls->fs, typename));
|
|
|
|
|
else if (ravi_type == RAVI_TSTRING)
|
|
|
|
|
luaK_codeABC(ls->fs, OP_RAVI_TOSTRING,
|
|
|
|
|
reg, 0, 0);
|
|
|
|
|
else if (ravi_type == RAVI_TFUNCTION)
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* RAVI code an instruction to initialize a scalar typed value
|
|
|
|
|
For array and table types however raise an error as uninitialized value
|
|
|
|
|
would cause a null pointer and therefore memory fault
|
|
|
|
|
*/
|
|
|
|
|
static void ravi_code_setzero(FuncState *fs, int reg, ravitype_t ravi_type, TString *usertype) {
|
|
|
|
|
static void ravi_code_setzero(FuncState *fs, int reg, ravi_type_map ravi_type, TString *usertype) {
|
|
|
|
|
(void) usertype;
|
|
|
|
|
if (ravi_type == RAVI_TNUMFLT || ravi_type == RAVI_TNUMINT)
|
|
|
|
|
if (ravi_type == RAVI_TM_FLOAT || ravi_type == RAVI_TM_INTEGER)
|
|
|
|
|
/* code an instruction to convert in place */
|
|
|
|
|
luaK_codeABC(fs, ravi_type == RAVI_TNUMFLT ? OP_RAVI_LOADFZ : OP_RAVI_LOADIZ, reg, 0, 0);
|
|
|
|
|
else if (ravi_type == RAVI_TARRAYFLT)
|
|
|
|
|
luaX_syntaxerror(fs->ls, "uninitialized number[] in local variable");
|
|
|
|
|
else if (ravi_type == RAVI_TARRAYINT)
|
|
|
|
|
luaX_syntaxerror(fs->ls, "uninitialized integer[] in local variable");
|
|
|
|
|
else if (ravi_type == RAVI_TTABLE)
|
|
|
|
|
luaX_syntaxerror(fs->ls, "uninitialized table in local variable");
|
|
|
|
|
luaK_codeABC(fs, ravi_type == RAVI_TM_FLOAT ? OP_RAVI_LOADFZ : OP_RAVI_LOADIZ, reg, 0, 0);
|
|
|
|
|
else if ((ravi_type & RAVI_TM_NIL) == 0) {
|
|
|
|
|
char type_map_str[RAVI_TYPEMAP_MAX_LEN];
|
|
|
|
|
raviY_typemap_string(ravi_type, type_map_str);
|
|
|
|
|
|
|
|
|
|
luaX_syntaxerror(fs->ls, luaO_pushfstring(fs->ls->L, "uninitialized %s in local variable", type_map_str));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -647,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);
|
|
|
|
|
ravitype_t ravi_type = ls->fs->f->locvars[idx].ravi_type; /* 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, usertype);
|
|
|
|
|
ravi_code_typecoersion(ls, i, tm, usertype);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -664,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);
|
|
|
|
|
ravitype_t ravi_type = fs->f->locvars[idx].ravi_type; /* 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, usertype);
|
|
|
|
|
ravi_code_setzero(fs, i, tm, usertype);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -929,7 +970,7 @@ static void codeclosure (LexState *ls, expdesc *v, int deferred) {
|
|
|
|
|
if (deferred) {
|
|
|
|
|
pc = luaK_codeABC(fs, OP_RAVI_DEFER, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TFUNCTION, NULL);
|
|
|
|
|
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TM_FUNCTION, NULL);
|
|
|
|
|
luaK_exp2nextreg(fs, v); /* fix it at the last register */
|
|
|
|
|
if (deferred) {
|
|
|
|
|
SETARG_A(fs->f->code[pc], v->u.info);
|
|
|
|
@ -939,7 +980,7 @@ static void codeclosure (LexState *ls, expdesc *v, int deferred) {
|
|
|
|
|
#else
|
|
|
|
|
static void codeclosure (LexState *ls, expdesc *v) {
|
|
|
|
|
FuncState *fs = ls->fs->prev;
|
|
|
|
|
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TFUNCTION, NULL);
|
|
|
|
|
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TM_FUNCTION, NULL);
|
|
|
|
|
luaK_exp2nextreg(fs, v); /* fix it at the last register */
|
|
|
|
|
DEBUG_VARS(raviY_printf(ls->fs, "codeclosure -> closure created %e\n", v));
|
|
|
|
|
}
|
|
|
|
@ -1032,7 +1073,7 @@ static void statlist (LexState *ls) {
|
|
|
|
|
static void fieldsel (LexState *ls, expdesc *v) {
|
|
|
|
|
/* fieldsel -> ['.' | ':'] NAME */
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
expdesc key = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc key = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
luaK_exp2anyregup(fs, v);
|
|
|
|
|
luaX_next(ls); /* skip the dot or colon */
|
|
|
|
|
checkname(ls, &key);
|
|
|
|
@ -1069,8 +1110,8 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
|
|
|
|
|
/* recfield -> (NAME | '['exp1']') = exp1 */
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
int reg = ls->fs->freereg;
|
|
|
|
|
expdesc key = {.ravi_type = RAVI_TANY, .pc = -1},
|
|
|
|
|
val = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc key = {.ravi_type_map = RAVI_TM_ANY, .pc = -1},
|
|
|
|
|
val = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
int rkkey;
|
|
|
|
|
if (ls->t.token == TK_NAME) {
|
|
|
|
|
checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
|
|
|
|
@ -1153,9 +1194,9 @@ static void constructor (LexState *ls, expdesc *t) {
|
|
|
|
|
struct ConsControl cc;
|
|
|
|
|
cc.na = cc.nh = cc.tostore = 0;
|
|
|
|
|
cc.t = t;
|
|
|
|
|
init_exp(t, VRELOCABLE, pc, RAVI_TTABLE, NULL); /* RAVI initial type may be modified */
|
|
|
|
|
init_exp(t, VRELOCABLE, pc, RAVI_TM_TABLE, NULL); /* RAVI initial type may be modified */
|
|
|
|
|
t->pc = pc; /* RAVI save pc of OP_NEWTABLE instruction so that the correct type can be set later */
|
|
|
|
|
init_exp(&cc.v, VVOID, 0, RAVI_TANY, NULL); /* no value (yet) */
|
|
|
|
|
init_exp(&cc.v, VVOID, 0, RAVI_TM_ANY, NULL); /* no value (yet) */
|
|
|
|
|
luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */
|
|
|
|
|
checknext(ls, '{');
|
|
|
|
|
do {
|
|
|
|
@ -1213,11 +1254,11 @@ static TString *user_defined_type_name(LexState *ls, TString *typename) {
|
|
|
|
|
* where type is 'integer', 'integer[]',
|
|
|
|
|
* 'number', 'number[]'
|
|
|
|
|
*/
|
|
|
|
|
static ravitype_t declare_localvar(LexState *ls, TString **pusertype) {
|
|
|
|
|
static ravi_type_map declare_localvar(LexState *ls, TString **pusertype) {
|
|
|
|
|
/* RAVI change - add type */
|
|
|
|
|
TString *name = str_checkname(ls);
|
|
|
|
|
/* assume a dynamic type */
|
|
|
|
|
ravitype_t tt = RAVI_TANY;
|
|
|
|
|
ravi_type_map tm = RAVI_TM_ANY;
|
|
|
|
|
/* if the variable name is followed by a colon then we have a type
|
|
|
|
|
* specifier
|
|
|
|
|
*/
|
|
|
|
@ -1229,36 +1270,36 @@ static ravitype_t declare_localvar(LexState *ls, TString **pusertype) {
|
|
|
|
|
* the lexer doesn't need to be changed
|
|
|
|
|
*/
|
|
|
|
|
if (strcmp(str, "integer") == 0)
|
|
|
|
|
tt = RAVI_TNUMINT;
|
|
|
|
|
tm = RAVI_TM_INTEGER;
|
|
|
|
|
else if (strcmp(str, "number") == 0)
|
|
|
|
|
tt = RAVI_TNUMFLT;
|
|
|
|
|
tm = RAVI_TM_FLOAT;
|
|
|
|
|
else if (strcmp(str, "closure") == 0)
|
|
|
|
|
tt = RAVI_TFUNCTION;
|
|
|
|
|
tm = RAVI_TM_FUNCTION | RAVI_TM_NIL;
|
|
|
|
|
else if (strcmp(str, "table") == 0)
|
|
|
|
|
tt = RAVI_TTABLE;
|
|
|
|
|
tm = RAVI_TM_TABLE;
|
|
|
|
|
else if (strcmp(str, "string") == 0)
|
|
|
|
|
tt = RAVI_TSTRING;
|
|
|
|
|
tm = RAVI_TM_STRING | RAVI_TM_NIL;
|
|
|
|
|
//else if (strcmp(str, "boolean") == 0)
|
|
|
|
|
// tt = RAVI_TBOOLEAN;
|
|
|
|
|
// tm = RAVI_TM_BOOLEAN | RAVI_TM_NIL;
|
|
|
|
|
else if (strcmp(str, "any") == 0)
|
|
|
|
|
tt = RAVI_TANY;
|
|
|
|
|
tm = RAVI_TM_ANY;
|
|
|
|
|
else {
|
|
|
|
|
/* default is a userdata type */
|
|
|
|
|
tt = RAVI_TUSERDATA;
|
|
|
|
|
tm = RAVI_TM_USERDATA | RAVI_TM_NIL;
|
|
|
|
|
typename = user_defined_type_name(ls, typename);
|
|
|
|
|
str = getstr(typename);
|
|
|
|
|
*pusertype = typename;
|
|
|
|
|
}
|
|
|
|
|
if (tt == RAVI_TNUMFLT || tt == RAVI_TNUMINT) {
|
|
|
|
|
if (tm == RAVI_TM_FLOAT || tm == RAVI_TM_INTEGER) {
|
|
|
|
|
/* if we see [] then it is an array type */
|
|
|
|
|
if (testnext(ls, '[')) {
|
|
|
|
|
checknext(ls, ']');
|
|
|
|
|
tt = (tt == RAVI_TNUMFLT) ? RAVI_TARRAYFLT : RAVI_TARRAYINT;
|
|
|
|
|
tm = (tm == RAVI_TM_FLOAT) ? RAVI_TM_FLOAT_ARRAY : RAVI_TM_INTEGER_ARRAY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
new_localvar(ls, name, tt, *pusertype);
|
|
|
|
|
return tt;
|
|
|
|
|
new_localvar(ls, name, tm, *pusertype);
|
|
|
|
|
return tm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void parlist (LexState *ls) {
|
|
|
|
@ -1267,7 +1308,7 @@ static void parlist (LexState *ls) {
|
|
|
|
|
Proto *f = fs->f;
|
|
|
|
|
int nparams = 0;
|
|
|
|
|
enum { N = MAXVARS + 10 };
|
|
|
|
|
int vars[N] = { 0 };
|
|
|
|
|
ravi_type_map vars[N] = { 0 };
|
|
|
|
|
TString *typenames[N] = { NULL };
|
|
|
|
|
f->is_vararg = 0;
|
|
|
|
|
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
|
|
|
@ -1293,12 +1334,12 @@ static void parlist (LexState *ls) {
|
|
|
|
|
luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
|
|
|
|
|
for (int i = 0; i < f->numparams; i++) {
|
|
|
|
|
TString *usertype = NULL;
|
|
|
|
|
ravitype_t tt = raviY_get_register_typeinfo(fs, i, &usertype);
|
|
|
|
|
lua_assert((i < nparams && vars[i] == (int)tt) || 1);
|
|
|
|
|
ravi_type_map tm = raviY_get_register_typeinfo(fs, i, &usertype);
|
|
|
|
|
lua_assert((i < nparams && vars[i] == tm) || 1);
|
|
|
|
|
lua_assert((i < nparams && usertype == typenames[i]) || 1);
|
|
|
|
|
DEBUG_VARS(raviY_printf(fs, "Parameter [%d] = %v\n", i + 1, getlocvar(fs, i)));
|
|
|
|
|
/* do we need to convert ? */
|
|
|
|
|
ravi_code_typecoersion(ls, i, tt, usertype);
|
|
|
|
|
ravi_code_typecoersion(ls, i, tm, usertype);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1367,46 +1408,46 @@ 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) {
|
|
|
|
|
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 */
|
|
|
|
|
if (n >= nvars)
|
|
|
|
|
return;
|
|
|
|
|
ravitype_t vartype = var_types[n];
|
|
|
|
|
if (vartype == RAVI_TANY)
|
|
|
|
|
return;
|
|
|
|
|
ravitype_t v_type = v->ravi_type;
|
|
|
|
|
if (n >= nvars) return;
|
|
|
|
|
ravi_type_map vartype = var_types[n];
|
|
|
|
|
ravi_type_map v_type_map = v->ravi_type_map;
|
|
|
|
|
if (v->k == VINDEXED) {
|
|
|
|
|
if (v_type == RAVI_TARRAYINT) {
|
|
|
|
|
v_type = RAVI_TNUMINT;
|
|
|
|
|
}
|
|
|
|
|
else if (v_type == RAVI_TARRAYFLT) {
|
|
|
|
|
v_type = RAVI_TNUMFLT;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v_type = RAVI_TANY;
|
|
|
|
|
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 (v_type == vartype)
|
|
|
|
|
return;
|
|
|
|
|
if ((vartype == RAVI_TARRAYFLT || vartype == RAVI_TARRAYINT) && v->k == VNONRELOC) {
|
|
|
|
|
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
|
|
|
|
|
* 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 */
|
|
|
|
|
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;
|
|
|
|
|
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));
|
|
|
|
|
DEBUG_CODEGEN(
|
|
|
|
|
raviY_printf(ls->fs, "[%d]* %o ; modify opcode\n", v->pc, *pc));
|
|
|
|
|
ok = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1415,36 +1456,40 @@ static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, TString **u
|
|
|
|
|
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) {
|
|
|
|
|
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 */
|
|
|
|
|
* 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 */
|
|
|
|
|
* 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 */
|
|
|
|
|
* 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
|
|
|
|
|
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 -
|
|
|
|
@ -1462,7 +1507,7 @@ static void ravi_typecheck(LexState *ls, expdesc *v, int *var_types, TString **u
|
|
|
|
|
* types provided in vars array. This is a modified version of explist() to be
|
|
|
|
|
* used to local variable declaration statement only.
|
|
|
|
|
*/
|
|
|
|
|
static int localvar_explist(LexState *ls, expdesc *v, int *vars, TString** usertypes, int nvars) {
|
|
|
|
|
static int localvar_explist(LexState *ls, expdesc *v, ravi_type_map *vars, TString** usertypes, int nvars) {
|
|
|
|
|
/* explist -> expr { ',' expr } */
|
|
|
|
|
int n = 1; /* at least one expression */
|
|
|
|
|
expr(ls, v);
|
|
|
|
@ -1479,7 +1524,7 @@ static int localvar_explist(LexState *ls, expdesc *v, int *vars, TString** usert
|
|
|
|
|
/* parse function arguments */
|
|
|
|
|
static void funcargs (LexState *ls, expdesc *f, int line) {
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
expdesc args = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc args = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
int base, nparams;
|
|
|
|
|
switch (ls->t.token) {
|
|
|
|
|
case '(': { /* funcargs -> '(' [ explist ] ')' */
|
|
|
|
@ -1515,7 +1560,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
|
|
|
|
|
luaK_exp2nextreg(fs, &args); /* close last argument */
|
|
|
|
|
nparams = fs->freereg - (base+1);
|
|
|
|
|
}
|
|
|
|
|
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams + 1, 2), RAVI_TANY, NULL); /* RAVI TODO return value from function call not known */
|
|
|
|
|
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams + 1, 2), RAVI_TM_ANY, NULL); /* RAVI TODO return value from function call not known */
|
|
|
|
|
luaK_fixline(fs, line);
|
|
|
|
|
fs->freereg = base+1; /* call remove function and arguments and leaves
|
|
|
|
|
(unless changed) one result */
|
|
|
|
@ -1566,14 +1611,14 @@ static void suffixedexp (LexState *ls, expdesc *v) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case '[': { /* '[' exp1 ']' */
|
|
|
|
|
expdesc key = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc key = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
luaK_exp2anyregup(fs, v);
|
|
|
|
|
yindex(ls, &key);
|
|
|
|
|
luaK_indexed(fs, v, &key);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ':': { /* ':' NAME funcargs */
|
|
|
|
|
expdesc key = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc key = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
luaX_next(ls);
|
|
|
|
|
checkname(ls, &key);
|
|
|
|
|
luaK_self(fs, v, &key);
|
|
|
|
@ -1596,12 +1641,12 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
|
|
|
|
constructor | FUNCTION body | suffixedexp */
|
|
|
|
|
switch (ls->t.token) {
|
|
|
|
|
case TK_FLT: {
|
|
|
|
|
init_exp(v, VKFLT, 0, RAVI_TNUMFLT, NULL);
|
|
|
|
|
init_exp(v, VKFLT, 0, RAVI_TM_FLOAT, NULL);
|
|
|
|
|
v->u.nval = ls->t.seminfo.r;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TK_INT: {
|
|
|
|
|
init_exp(v, VKINT, 0, RAVI_TNUMINT, NULL);
|
|
|
|
|
init_exp(v, VKINT, 0, RAVI_TM_INTEGER, NULL);
|
|
|
|
|
v->u.ival = ls->t.seminfo.i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -1610,22 +1655,22 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TK_NIL: {
|
|
|
|
|
init_exp(v, VNIL, 0, RAVI_TNIL, NULL);
|
|
|
|
|
init_exp(v, VNIL, 0, RAVI_TM_NIL, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TK_TRUE: {
|
|
|
|
|
init_exp(v, VTRUE, 0, RAVI_TANY, NULL); /* RAVI TODO */
|
|
|
|
|
init_exp(v, VTRUE, 0, RAVI_TM_TRUE, NULL); /* RAVI TODO */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TK_FALSE: {
|
|
|
|
|
init_exp(v, VFALSE, 0, RAVI_TANY, NULL); /* RAVI TODO */
|
|
|
|
|
init_exp(v, VFALSE, 0, RAVI_TM_FALSE, NULL); /* RAVI TODO */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TK_DOTS: { /* vararg */
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
check_condition(ls, fs->f->is_vararg,
|
|
|
|
|
"cannot use '...' outside a vararg function");
|
|
|
|
|
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0), RAVI_TANY, NULL);
|
|
|
|
|
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0), RAVI_TM_ANY, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case '{': { /* constructor */
|
|
|
|
@ -1748,7 +1793,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
|
|
|
|
|
/* expand while operators have priorities higher than 'limit' */
|
|
|
|
|
op = getbinopr(ls->t.token);
|
|
|
|
|
while (op != OPR_NOBINOPR && priority[op].left > limit) {
|
|
|
|
|
expdesc v2 = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc v2 = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
BinOpr nextop;
|
|
|
|
|
int line = ls->linenumber;
|
|
|
|
|
luaX_next(ls);
|
|
|
|
@ -1839,10 +1884,10 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
|
|
|
|
|
* The final recursive call parses the rhs.
|
|
|
|
|
*/
|
|
|
|
|
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
|
|
|
|
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc e = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
check_condition(ls, vkisvar(lh->v.k), "syntax error");
|
|
|
|
|
if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */
|
|
|
|
|
struct LHS_assign nv = { .v.ravi_type = RAVI_TANY, .v.pc = -1 };
|
|
|
|
|
struct LHS_assign nv = { .v.ravi_type_map = RAVI_TM_ANY, .v.pc = -1 };
|
|
|
|
|
//nv.v.ravi_type = RAVI_TANY;
|
|
|
|
|
//nv.v.pc = -1;
|
|
|
|
|
nv.prev = lh;
|
|
|
|
@ -1869,7 +1914,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
|
|
|
|
return; /* avoid default */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
init_exp(&e, VNONRELOC, ls->fs->freereg-1, RAVI_TANY, NULL); /* default assignment */
|
|
|
|
|
init_exp(&e, VNONRELOC, ls->fs->freereg-1, RAVI_TM_ANY, NULL); /* default assignment */
|
|
|
|
|
luaK_storevar(ls->fs, &lh->v, &e);
|
|
|
|
|
DEBUG_EXPR(raviY_printf(ls->fs, "assignment lhs = %e, rhs = %e\n", &lh->v, &e));
|
|
|
|
|
}
|
|
|
|
@ -1879,7 +1924,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
|
|
|
|
*/
|
|
|
|
|
static int cond (LexState *ls) {
|
|
|
|
|
/* cond -> exp */
|
|
|
|
|
expdesc v = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc v = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
expr(ls, &v); /* read condition */
|
|
|
|
|
if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */
|
|
|
|
|
luaK_goiftrue(ls->fs, &v);
|
|
|
|
@ -1984,7 +2029,7 @@ static void repeatstat (LexState *ls, int line) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct Fornuminfo {
|
|
|
|
|
ravitype_t type;
|
|
|
|
|
ravi_type_map type_map;
|
|
|
|
|
int is_constant;
|
|
|
|
|
int int_value;
|
|
|
|
|
} Fornuminfo;
|
|
|
|
@ -1998,7 +2043,7 @@ static int exp1 (LexState *ls, Fornuminfo *info) {
|
|
|
|
|
* type - also the loop is already optimised so no point trying to
|
|
|
|
|
* optimise the iteration variable
|
|
|
|
|
*/
|
|
|
|
|
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc e = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
int reg;
|
|
|
|
|
int expect_int = 0;
|
|
|
|
|
if (ls->t.token == '#')
|
|
|
|
@ -2010,12 +2055,12 @@ static int exp1 (LexState *ls, Fornuminfo *info) {
|
|
|
|
|
luaK_exp2nextreg(ls->fs, &e);
|
|
|
|
|
lua_assert(e.k == VNONRELOC);
|
|
|
|
|
reg = e.u.info;
|
|
|
|
|
if (expect_int && e.ravi_type != RAVI_TNUMINT) {
|
|
|
|
|
if (expect_int && e.ravi_type_map != RAVI_TM_INTEGER) {
|
|
|
|
|
luaK_codeABC(ls->fs, OP_RAVI_TOINT, reg, 0, 0);
|
|
|
|
|
info->type = RAVI_TNUMINT;
|
|
|
|
|
info->type_map = RAVI_TM_INTEGER;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
info->type = e.ravi_type;
|
|
|
|
|
info->type_map = e.ravi_type_map;
|
|
|
|
|
}
|
|
|
|
|
return reg;
|
|
|
|
|
}
|
|
|
|
@ -2070,7 +2115,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
|
|
|
|
new_localvarliteral(ls, "(for index)");
|
|
|
|
|
new_localvarliteral(ls, "(for limit)");
|
|
|
|
|
new_localvarliteral(ls, "(for step)");
|
|
|
|
|
new_localvar(ls, varname, RAVI_TANY, NULL);
|
|
|
|
|
new_localvar(ls, varname, RAVI_TM_ANY, NULL);
|
|
|
|
|
/* The fornum sets up its own variables as above.
|
|
|
|
|
These are expected to hold numeric values - but from Ravi's
|
|
|
|
|
point of view we need to know if the variable is an integer or
|
|
|
|
@ -2081,7 +2126,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
|
|
|
|
int var_idx = fs->nlocvars - 4; /* note location of idx variable */
|
|
|
|
|
checknext(ls, '=');
|
|
|
|
|
/* get the type of each expression */
|
|
|
|
|
Fornuminfo tidx = { RAVI_TANY,0,0 }, tlimit = { RAVI_TANY,0,0 }, tstep = { RAVI_TNUMINT,0,0 };
|
|
|
|
|
Fornuminfo tidx = { RAVI_TM_ANY,0,0 }, tlimit = { RAVI_TM_ANY,0,0 }, tstep = { RAVI_TM_INTEGER,0,0 };
|
|
|
|
|
Fornuminfo *info = NULL;
|
|
|
|
|
exp1(ls, &tidx); /* initial value */
|
|
|
|
|
checknext(ls, ',');
|
|
|
|
@ -2094,10 +2139,10 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
|
|
|
|
luaK_codek(fs, fs->freereg, luaK_intK(fs, 1));
|
|
|
|
|
luaK_reserveregs(fs, 1);
|
|
|
|
|
}
|
|
|
|
|
if (tidx.type == tlimit.type && tlimit.type == tstep.type &&
|
|
|
|
|
(tidx.type == RAVI_TNUMFLT || tidx.type == RAVI_TNUMINT)) {
|
|
|
|
|
if (tidx.type_map == tlimit.type_map && tlimit.type_map == tstep.type_map &&
|
|
|
|
|
(tidx.type_map == RAVI_TM_FLOAT || tidx.type_map == RAVI_TM_INTEGER)) {
|
|
|
|
|
LocVar *vidx, *vlimit, *vstep, *vvar;
|
|
|
|
|
if (tidx.type == RAVI_TNUMINT && tstep.is_constant)
|
|
|
|
|
if (tidx.type_map == RAVI_TM_INTEGER && tstep.is_constant)
|
|
|
|
|
info = &tstep;
|
|
|
|
|
/* Note that as locvars may be reallocated while creating variables
|
|
|
|
|
therefore we access the variables here */
|
|
|
|
@ -2106,7 +2151,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
|
|
|
|
vstep = &fs->f->locvars[var_idx+2]; /* index variable - not yet active so get it from locvars*/
|
|
|
|
|
vvar = &fs->f->locvars[var_idx+3]; /* index variable - not yet active so get it from locvars*/
|
|
|
|
|
/* Ok so we have an integer or double */
|
|
|
|
|
vidx->ravi_type = vlimit->ravi_type = vstep->ravi_type = vvar->ravi_type = tidx.type;
|
|
|
|
|
vidx->ravi_type_map = vlimit->ravi_type_map = vstep->ravi_type_map = vvar->ravi_type_map = tidx.type_map;
|
|
|
|
|
DEBUG_VARS(raviY_printf(fs, "fornum -> setting type for index %v\n", vidx));
|
|
|
|
|
DEBUG_VARS(raviY_printf(fs, "fornum -> setting type for limit %v\n", vlimit));
|
|
|
|
|
DEBUG_VARS(raviY_printf(fs, "fornum -> setting type for step %v\n", vstep));
|
|
|
|
@ -2121,7 +2166,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
|
|
|
|
static void forlist (LexState *ls, TString *indexname) {
|
|
|
|
|
/* forlist -> NAME {,NAME} IN explist forbody */
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc e = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
int nvars = 4; /* gen, state, control, plus at least one declared var */
|
|
|
|
|
int line;
|
|
|
|
|
int base = fs->freereg;
|
|
|
|
@ -2130,9 +2175,9 @@ static void forlist (LexState *ls, TString *indexname) {
|
|
|
|
|
new_localvarliteral(ls, "(for state)");
|
|
|
|
|
new_localvarliteral(ls, "(for control)");
|
|
|
|
|
/* create declared variables */
|
|
|
|
|
new_localvar(ls, indexname, RAVI_TANY, NULL); /* RAVI TODO for name:type syntax? */
|
|
|
|
|
new_localvar(ls, indexname, RAVI_TM_ANY, NULL); /* RAVI TODO for name:type syntax? */
|
|
|
|
|
while (testnext(ls, ',')) {
|
|
|
|
|
new_localvar(ls, str_checkname(ls), RAVI_TANY, NULL); /* RAVI change - add type */
|
|
|
|
|
new_localvar(ls, str_checkname(ls), RAVI_TM_ANY, NULL); /* RAVI change - add type */
|
|
|
|
|
nvars++;
|
|
|
|
|
}
|
|
|
|
|
checknext(ls, TK_IN);
|
|
|
|
@ -2167,7 +2212,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
|
|
|
|
|
/* test_then_block -> [IF | ELSEIF] cond THEN block */
|
|
|
|
|
BlockCnt bl;
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
expdesc v = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc v = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
int jf; /* instruction to skip 'then' code (if condition is false) */
|
|
|
|
|
luaX_next(ls); /* skip IF or ELSEIF */
|
|
|
|
|
expr(ls, &v); /* read condition */
|
|
|
|
@ -2214,16 +2259,16 @@ static void ifstat (LexState *ls, int line) {
|
|
|
|
|
/* parse a local function statement - called from statement() */
|
|
|
|
|
#ifdef RAVI_DEFER_STATEMENT
|
|
|
|
|
static void localfunc (LexState *ls, int defer) {
|
|
|
|
|
expdesc b = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc b = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
if (defer) {
|
|
|
|
|
static const char funcname[] = "(deferred function)";
|
|
|
|
|
new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1), RAVI_TFUNCTION, NULL); /* new local variable */
|
|
|
|
|
new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1), RAVI_TM_FUNCTION, NULL); /* new local variable */
|
|
|
|
|
markupval(fs, fs->nactvar);
|
|
|
|
|
fs->bl->insidetbc = 1; /* in the scope of a defer closure variable */
|
|
|
|
|
} else {
|
|
|
|
|
/* RAVI change - add type */
|
|
|
|
|
new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
|
|
|
|
|
new_localvar(ls, str_checkname(ls), RAVI_TM_FUNCTION, NULL); /* new local variable */
|
|
|
|
|
}
|
|
|
|
|
adjustlocalvars(ls, 1); /* enter its scope */
|
|
|
|
|
body(ls, &b, 0, ls->linenumber, defer); /* function created in next register */
|
|
|
|
@ -2248,14 +2293,14 @@ static void localstat (LexState *ls) {
|
|
|
|
|
/* stat -> LOCAL NAME {',' NAME} ['=' explist] */
|
|
|
|
|
int nvars = 0;
|
|
|
|
|
int nexps;
|
|
|
|
|
expdesc e = { .ravi_type = RAVI_TANY,.pc = -1 };
|
|
|
|
|
expdesc e = { .ravi_type_map = RAVI_TM_ANY,.pc = -1 };
|
|
|
|
|
/* RAVI while declaring locals we need to gather the types
|
|
|
|
|
* so that we can check any assignments later on.
|
|
|
|
|
* TODO we may be able to use register_typeinfo() here
|
|
|
|
|
* instead.
|
|
|
|
|
*/
|
|
|
|
|
enum { N = MAXVARS + 10 };
|
|
|
|
|
int vars[N] = { 0 };
|
|
|
|
|
ravi_type_map vars[N] = { 0 };
|
|
|
|
|
TString *usertypes[N] = { NULL };
|
|
|
|
|
do {
|
|
|
|
|
/* RAVI changes start */
|
|
|
|
@ -2296,8 +2341,8 @@ static int funcname (LexState *ls, expdesc *v) {
|
|
|
|
|
static void funcstat (LexState *ls, int line) {
|
|
|
|
|
/* funcstat -> FUNCTION funcname body */
|
|
|
|
|
int ismethod;
|
|
|
|
|
expdesc v = {.ravi_type = RAVI_TANY, .pc = -1},
|
|
|
|
|
b = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc v = {.ravi_type_map = RAVI_TM_ANY, .pc = -1},
|
|
|
|
|
b = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
luaX_next(ls); /* skip FUNCTION */
|
|
|
|
|
ismethod = funcname(ls, &v);
|
|
|
|
|
DEBUG_VARS(raviY_printf(ls->fs, "funcstat -> declaring function %e\n", &v));
|
|
|
|
@ -2315,7 +2360,7 @@ static void exprstat (LexState *ls) {
|
|
|
|
|
/* stat -> func | assignment */
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
struct LHS_assign v;
|
|
|
|
|
v.v.ravi_type = RAVI_TANY;
|
|
|
|
|
v.v.ravi_type_map = RAVI_TM_ANY;
|
|
|
|
|
suffixedexp(ls, &v.v);
|
|
|
|
|
if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
|
|
|
|
|
v.prev = NULL;
|
|
|
|
@ -2331,7 +2376,7 @@ static void exprstat (LexState *ls) {
|
|
|
|
|
static void retstat (LexState *ls) {
|
|
|
|
|
/* stat -> RETURN [explist] [';'] */
|
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
|
expdesc e = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc e = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
int first, nret; /* registers with returned values */
|
|
|
|
|
if (block_follow(ls, 1) || ls->t.token == ';')
|
|
|
|
|
first = nret = 0; /* return no values */
|
|
|
|
@ -2449,10 +2494,10 @@ static void statement (LexState *ls) {
|
|
|
|
|
*/
|
|
|
|
|
static void mainfunc (LexState *ls, FuncState *fs) {
|
|
|
|
|
BlockCnt bl;
|
|
|
|
|
expdesc v = {.ravi_type = RAVI_TANY, .pc = -1};
|
|
|
|
|
expdesc v = {.ravi_type_map = RAVI_TM_ANY, .pc = -1};
|
|
|
|
|
open_func(ls, fs, &bl);
|
|
|
|
|
fs->f->is_vararg = 1; /* main function is always declared vararg */
|
|
|
|
|
init_exp(&v, VLOCAL, 0, RAVI_TANY, NULL); /* create and... - RAVI TODO var arg is unknown type */
|
|
|
|
|
init_exp(&v, VLOCAL, 0, RAVI_TM_ANY, NULL); /* create and... - RAVI TODO var arg is unknown type */
|
|
|
|
|
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
|
|
|
|
luaC_objbarrier(ls->L, fs->f, ls->envn);
|
|
|
|
|
luaX_next(ls); /* read first token */
|
|
|
|
|