|
|
|
@ -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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|