#define lcode_c
#define LUA_CORE
#include "lprefix.h"
#include <math.h>
#include <stdlib.h>
#include "lua.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
#define MAXREGS 255
#define hasjumps(e) ((e)->t != (e)->f)
static
int
tonumeral(expdesc *e, TValue *v) {
if
(hasjumps(e))
return
0;
switch
(e->k) {
case
VKINT:
if
(v) setivalue(v, e->u.ival);
return
1;
case
VKFLT:
if
(v) setfltvalue(v, e->u.nval);
return
1;
default
:
return
0;
}
}
void
luaK_nil (FuncState *fs,
int
from,
int
n) {
Instruction *previous;
int
l = from + n - 1;
if
(fs->pc > fs->lasttarget) {
previous = &fs->f->code[fs->pc-1];
if
(GET_OPCODE(*previous) == OP_LOADNIL) {
int
pfrom = GETARG_A(*previous);
int
pl = pfrom + GETARG_B(*previous);
if
((pfrom <= from && from <= pl + 1) ||
(from <= pfrom && pfrom <= l + 1)) {
if
(pfrom < from) from = pfrom;
if
(pl > l) l = pl;
SETARG_A(*previous, from);
SETARG_B(*previous, l - from);
return
;
}
}
}
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0);
}
int
luaK_jump (FuncState *fs) {
int
jpc = fs->jpc;
int
j;
fs->jpc = NO_JUMP;
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc);
return
j;
}
void
luaK_ret (FuncState *fs,
int
first,
int
nret) {
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
}
static
int
condjump (FuncState *fs, OpCode op,
int
A,
int
B,
int
C) {
luaK_codeABC(fs, op, A, B, C);
return
luaK_jump(fs);
}
static
void
fixjump (FuncState *fs,
int
pc,
int
dest) {
Instruction *jmp = &fs->f->code[pc];
int
offset = dest-(pc+1);
lua_assert(dest != NO_JUMP);
if
(
abs
(offset) > MAXARG_sBx)
luaX_syntaxerror(fs->ls,
"control structure too long"
);
SETARG_sBx(*jmp, offset);
}
int
luaK_getlabel (FuncState *fs) {
fs->lasttarget = fs->pc;
return
fs->pc;
}
static
int
getjump (FuncState *fs,
int
pc) {
int
offset = GETARG_sBx(fs->f->code[pc]);
if
(offset == NO_JUMP)
return
NO_JUMP;
else
return
(pc+1)+offset;
}
static
Instruction *getjumpcontrol (FuncState *fs,
int
pc) {
Instruction *pi = &fs->f->code[pc];
if
(pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
return
pi-1;
else
return
pi;
}
static
int
need_value (FuncState *fs,
int
list) {
for
(; list != NO_JUMP; list = getjump(fs, list)) {
Instruction i = *getjumpcontrol(fs, list);
if
(GET_OPCODE(i) != OP_TESTSET)
return
1;
}
return
0;
}
static
int
patchtestreg (FuncState *fs,
int
node,
int
reg) {
Instruction *i = getjumpcontrol(fs, node);
if
(GET_OPCODE(*i) != OP_TESTSET)
return
0;
if
(reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
else
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
return
1;
}
static
void
removevalues (FuncState *fs,
int
list) {
for
(; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG);
}
static
void
patchlistaux (FuncState *fs,
int
list,
int
vtarget,
int
reg,
int
dtarget) {
while
(list != NO_JUMP) {
int
next = getjump(fs, list);
if
(patchtestreg(fs, list, reg))
fixjump(fs, list, vtarget);
else
fixjump(fs, list, dtarget);
list = next;
}
}
static
void
dischargejpc (FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;
}
void
luaK_patchlist (FuncState *fs,
int
list,
int
target) {
if
(target == fs->pc)
luaK_patchtohere(fs, list);
else
{
lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target);
}
}
void
luaK_patchclose (FuncState *fs,
int
list,
int
level) {
level++;
while
(list != NO_JUMP) {
int
next = getjump(fs, list);
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
list = next;
}
}
void
luaK_patchtohere (FuncState *fs,
int
list) {
luaK_getlabel(fs);
luaK_concat(fs, &fs->jpc, list);
}
void
luaK_concat (FuncState *fs,
int
*l1,
int
l2) {
if
(l2 == NO_JUMP)
return
;
else
if
(*l1 == NO_JUMP)
*l1 = l2;
else
{
int
list = *l1;
int
next;
while
((next = getjump(fs, list)) != NO_JUMP)
list = next;
fixjump(fs, list, l2);
}
}
static
int
luaK_code (FuncState *fs, Instruction i) {
Proto *f = fs->f;
dischargejpc(fs);
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT,
"opcodes"
);
f->code[fs->pc] = i;
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo,
int
,
MAX_INT,
"opcodes"
);
f->lineinfo[fs->pc] = fs->ls->lastline;
return
fs->pc++;
}
int
luaK_codeABC (FuncState *fs, OpCode o,
int
a,
int
b,
int
c) {
lua_assert(getOpMode(o) == iABC);
lua_assert(getBMode(o) != OpArgN || b == 0);
lua_assert(getCMode(o) != OpArgN || c == 0);
lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
return
luaK_code(fs, CREATE_ABC(o, a, b, c));
}
int
luaK_codeABx (FuncState *fs, OpCode o,
int
a, unsigned
int
bc) {
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getCMode(o) == OpArgN);
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
return
luaK_code(fs, CREATE_ABx(o, a, bc));
}
static
int
codeextraarg (FuncState *fs,
int
a) {
lua_assert(a <= MAXARG_Ax);
return
luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
}
int
luaK_codek (FuncState *fs,
int
reg,
int
k) {
if
(k <= MAXARG_Bx)
return
luaK_codeABx(fs, OP_LOADK, reg, k);
else
{
int
p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
codeextraarg(fs, k);
return
p;
}
}
void
luaK_checkstack (FuncState *fs,
int
n) {
int
newstack = fs->freereg + n;
if
(newstack > fs->f->maxstacksize) {
if
(newstack >= MAXREGS)
luaX_syntaxerror(fs->ls,
"function or expression needs too many registers"
);
fs->f->maxstacksize = cast_byte(newstack);
}
}
void
luaK_reserveregs (FuncState *fs,
int
n) {
luaK_checkstack(fs, n);
fs->freereg += n;
}
static
void
freereg (FuncState *fs,
int
reg) {
if
(!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
lua_assert(reg == fs->freereg);
}
}
static
void
freeexp (FuncState *fs, expdesc *e) {
if
(e->k == VNONRELOC)
freereg(fs, e->u.info);
}
static
int
addk (FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
Proto *f = fs->f;
TValue *idx = luaH_set(L, fs->ls->h, key);
int
k, oldsize;
if
(ttisinteger(idx)) {
k = cast_int(ivalue(idx));
if
(k < fs->nk && ttype(&f->k[k]) == ttype(v) &&
luaV_rawequalobj(&f->k[k], v))
return
k;
}
oldsize = f->sizek;
k = fs->nk;
setivalue(idx, k);
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax,
"constants"
);
while
(oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v);
fs->nk++;
luaC_barrier(L, f, v);
return
k;
}
int
luaK_stringK (FuncState *fs, TString *s) {
TValue o;
setsvalue(fs->ls->L, &o, s);
return
addk(fs, &o, &o);
}
int
luaK_intK (FuncState *fs, lua_Integer n) {
TValue k, o;
setpvalue(&k, cast(
void
*, cast(
size_t
, n)));
setivalue(&o, n);
return
addk(fs, &k, &o);
}
static
int
luaK_numberK (FuncState *fs, lua_Number r) {
TValue o;
setfltvalue(&o, r);
return
addk(fs, &o, &o);
}
static
int
boolK (FuncState *fs,
int
b) {
TValue o;
setbvalue(&o, b);
return
addk(fs, &o, &o);
}
static
int
nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
sethvalue(fs->ls->L, &k, fs->ls->h);
return
addk(fs, &k, &v);
}
void
luaK_setreturns (FuncState *fs, expdesc *e,
int
nresults) {
if
(e->k == VCALL) {
SETARG_C(getcode(fs, e), nresults+1);
}
else
if
(e->k == VVARARG) {
SETARG_B(getcode(fs, e), nresults+1);
SETARG_A(getcode(fs, e), fs->freereg);
luaK_reserveregs(fs, 1);
}
}
void
luaK_setoneret (FuncState *fs, expdesc *e) {
if
(e->k == VCALL) {
e->k = VNONRELOC;
e->u.info = GETARG_A(getcode(fs, e));
}
else
if
(e->k == VVARARG) {
SETARG_B(getcode(fs, e), 2);
e->k = VRELOCABLE;
}
}
void
luaK_dischargevars (FuncState *fs, expdesc *e) {
switch
(e->k) {
case
VLOCAL: {
e->k = VNONRELOC;
break
;
}
case
VUPVAL: {
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break
;
}
case
VINDEXED: {
OpCode op = OP_GETTABUP;
freereg(fs, e->u.ind.idx);
if
(e->u.ind.vt == VLOCAL) {
freereg(fs, e->u.ind.t);
op = OP_GETTABLE;
}
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
break
;
}
case
VVARARG:
case
VCALL: {
luaK_setoneret(fs, e);
break
;
}
default
:
break
;
}
}
static
int
code_label (FuncState *fs,
int
A,
int
b,
int
jump) {
luaK_getlabel(fs);
return
luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
}
static
void
discharge2reg (FuncState *fs, expdesc *e,
int
reg) {
luaK_dischargevars(fs, e);
switch
(e->k) {
case
VNIL: {
luaK_nil(fs, reg, 1);
break
;
}
case
VFALSE:
case
VTRUE: {
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
break
;
}
case
VK: {
luaK_codek(fs, reg, e->u.info);
break
;
}
case
VKFLT: {
luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
break
;
}
case
VKINT: {
luaK_codek(fs, reg, luaK_intK(fs, e->u.ival));
break
;
}
case
VRELOCABLE: {
Instruction *pc = &getcode(fs, e);
SETARG_A(*pc, reg);
break
;
}
case
VNONRELOC: {
if
(reg != e->u.info)
luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
break
;
}
default
: {
lua_assert(e->k == VVOID || e->k == VJMP);
return
;
}
}
e->u.info = reg;
e->k = VNONRELOC;
}
static
void
discharge2anyreg (FuncState *fs, expdesc *e) {
if
(e->k != VNONRELOC) {
luaK_reserveregs(fs, 1);
discharge2reg(fs, e, fs->freereg-1);
}
}
static
void
exp2reg (FuncState *fs, expdesc *e,
int
reg) {
discharge2reg(fs, e, reg);
if
(e->k == VJMP)
luaK_concat(fs, &e->t, e->u.info);
if
(hasjumps(e)) {
int
final;
int
p_f = NO_JUMP;
int
p_t = NO_JUMP;
if
(need_value(fs, e->t) || need_value(fs, e->f)) {
int
fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
p_f = code_label(fs, reg, 0, 1);
p_t = code_label(fs, reg, 1, 0);
luaK_patchtohere(fs, fj);
}
final = luaK_getlabel(fs);
patchlistaux(fs, e->f, final, reg, p_f);
patchlistaux(fs, e->t, final, reg, p_t);
}
e->f = e->t = NO_JUMP;
e->u.info = reg;
e->k = VNONRELOC;
}
void
luaK_exp2nextreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
freeexp(fs, e);
luaK_reserveregs(fs, 1);
exp2reg(fs, e, fs->freereg - 1);
}
int
luaK_exp2anyreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
if
(e->k == VNONRELOC) {
if
(!hasjumps(e))
return
e->u.info;
if
(e->u.info >= fs->nactvar) {
exp2reg(fs, e, e->u.info);
return
e->u.info;
}
}
luaK_exp2nextreg(fs, e);
return
e->u.info;
}
void
luaK_exp2anyregup (FuncState *fs, expdesc *e) {
if
(e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
}
void
luaK_exp2val (FuncState *fs, expdesc *e) {
if
(hasjumps(e))
luaK_exp2anyreg(fs, e);
else
luaK_dischargevars(fs, e);
}
int
luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
switch
(e->k) {
case
VTRUE:
case
VFALSE:
case
VNIL: {
if
(fs->nk <= MAXINDEXRK) {
e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
e->k = VK;
return
RKASK(e->u.info);
}
else
break
;
}
case
VKINT: {
e->u.info = luaK_intK(fs, e->u.ival);
e->k = VK;
goto
vk;
}
case
VKFLT: {
e->u.info = luaK_numberK(fs, e->u.nval);
e->k = VK;
}
case
VK: {
vk:
if
(e->u.info <= MAXINDEXRK)
return
RKASK(e->u.info);
else
break
;
}
default
:
break
;
}
return
luaK_exp2anyreg(fs, e);
}
void
luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch
(var->k) {
case
VLOCAL: {
freeexp(fs, ex);
exp2reg(fs, ex, var->u.info);
return
;
}
case
VUPVAL: {
int
e = luaK_exp2anyreg(fs, ex);
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
break
;
}
case
VINDEXED: {
OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int
e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
break
;
}
default
: {
lua_assert(0);
break
;
}
}
freeexp(fs, ex);
}
void
luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int
ereg;
luaK_exp2anyreg(fs, e);
ereg = e->u.info;
freeexp(fs, e);
e->u.info = fs->freereg;
e->k = VNONRELOC;
luaK_reserveregs(fs, 2);
luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
freeexp(fs, key);
}
static
void
invertjump (FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST);
SETARG_A(*pc, !(GETARG_A(*pc)));
}
static
int
jumponcond (FuncState *fs, expdesc *e,
int
cond) {
if
(e->k == VRELOCABLE) {
Instruction ie = getcode(fs, e);
if
(GET_OPCODE(ie) == OP_NOT) {
fs->pc--;
return
condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
}
}
discharge2anyreg(fs, e);
freeexp(fs, e);
return
condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
}
void
luaK_goiftrue (FuncState *fs, expdesc *e) {
int
pc;
luaK_dischargevars(fs, e);
switch
(e->k) {
case
VJMP: {
invertjump(fs, e);
pc = e->u.info;
break
;
}
case
VK:
case
VKFLT:
case
VKINT:
case
VTRUE: {
pc = NO_JUMP;
break
;
}
default
: {
pc = jumponcond(fs, e, 0);
break
;
}
}
luaK_concat(fs, &e->f, pc);
luaK_patchtohere(fs, e->t);
e->t = NO_JUMP;
}
void
luaK_goiffalse (FuncState *fs, expdesc *e) {
int
pc;
luaK_dischargevars(fs, e);
switch
(e->k) {
case
VJMP: {
pc = e->u.info;
break
;
}
case
VNIL:
case
VFALSE: {
pc = NO_JUMP;
break
;
}
default
: {
pc = jumponcond(fs, e, 1);
break
;
}
}
luaK_concat(fs, &e->t, pc);
luaK_patchtohere(fs, e->f);
e->f = NO_JUMP;
}
static
void
codenot (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
switch
(e->k) {
case
VNIL:
case
VFALSE: {
e->k = VTRUE;
break
;
}
case
VK:
case
VKFLT:
case
VKINT:
case
VTRUE: {
e->k = VFALSE;
break
;
}
case
VJMP: {
invertjump(fs, e);
break
;
}
case
VRELOCABLE:
case
VNONRELOC: {
discharge2anyreg(fs, e);
freeexp(fs, e);
e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
e->k = VRELOCABLE;
break
;
}
default
: {
lua_assert(0);
break
;
}
}
{
int
temp = e->f; e->f = e->t; e->t = temp; }
removevalues(fs, e->f);
removevalues(fs, e->t);
}
void
luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
lua_assert(!hasjumps(t));
t->u.ind.t = t->u.info;
t->u.ind.idx = luaK_exp2RK(fs, k);
t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
: check_exp(vkisinreg(t->k), VLOCAL);
t->k = VINDEXED;
}
static
int
validop (
int
op, TValue *v1, TValue *v2) {
switch
(op) {
case
LUA_OPBAND:
case
LUA_OPBOR:
case
LUA_OPBXOR:
case
LUA_OPSHL:
case
LUA_OPSHR:
case
LUA_OPBNOT: {
lua_Integer i;
return
(tointeger(v1, &i) && tointeger(v2, &i));
}
case
LUA_OPDIV:
case
LUA_OPIDIV:
case
LUA_OPMOD:
return
(nvalue(v2) != 0);
default
:
return
1;
}
}
static
int
constfolding (FuncState *fs,
int
op, expdesc *e1, expdesc *e2) {
TValue v1, v2, res;
if
(!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
return
0;
luaO_arith(fs->ls->L, op, &v1, &v2, &res);
if
(ttisinteger(&res)) {
e1->k = VKINT;
e1->u.ival = ivalue(&res);
}
else
{
lua_Number n = fltvalue(&res);
if
(luai_numisnan(n) || n == 0)
return
0;
e1->k = VKFLT;
e1->u.nval = n;
}
return
1;
}
static
void
codeexpval (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2,
int
line) {
lua_assert(op >= OP_ADD);
if
(op <= OP_BNOT && constfolding(fs, (op - OP_ADD) + LUA_OPADD, e1, e2))
return
;
else
{
int
o1, o2;
if
(op == OP_UNM || op == OP_BNOT || op == OP_LEN) {
o2 = 0;
o1 = luaK_exp2anyreg(fs, e1);
}
else
{
o2 = luaK_exp2RK(fs, e2);
o1 = luaK_exp2RK(fs, e1);
}
if
(o1 > o2) {
freeexp(fs, e1);
freeexp(fs, e2);
}
else
{
freeexp(fs, e2);
freeexp(fs, e1);
}
e1->u.info = luaK_codeABC(fs, op, 0, o1, o2);
e1->k = VRELOCABLE;
luaK_fixline(fs, line);
}
}
static
void
codecomp (FuncState *fs, OpCode op,
int
cond, expdesc *e1,
expdesc *e2) {
int
o1 = luaK_exp2RK(fs, e1);
int
o2 = luaK_exp2RK(fs, e2);
freeexp(fs, e2);
freeexp(fs, e1);
if
(cond == 0 && op != OP_EQ) {
int
temp;
temp = o1; o1 = o2; o2 = temp;
cond = 1;
}
e1->u.info = condjump(fs, op, cond, o1, o2);
e1->k = VJMP;
}
void
luaK_prefix (FuncState *fs, UnOpr op, expdesc *e,
int
line) {
expdesc e2;
e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
switch
(op) {
case
OPR_MINUS:
case
OPR_BNOT:
case
OPR_LEN: {
codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line);
break
;
}
case
OPR_NOT: codenot(fs, e);
break
;
default
: lua_assert(0);
}
}
void
luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
switch
(op) {
case
OPR_AND: {
luaK_goiftrue(fs, v);
break
;
}
case
OPR_OR: {
luaK_goiffalse(fs, v);
break
;
}
case
OPR_CONCAT: {
luaK_exp2nextreg(fs, v);
break
;
}
case
OPR_ADD:
case
OPR_SUB:
case
OPR_MUL:
case
OPR_DIV:
case
OPR_IDIV:
case
OPR_MOD:
case
OPR_POW:
case
OPR_BAND:
case
OPR_BOR:
case
OPR_BXOR:
case
OPR_SHL:
case
OPR_SHR: {
if
(!tonumeral(v, NULL)) luaK_exp2RK(fs, v);
break
;
}
default
: {
luaK_exp2RK(fs, v);
break
;
}
}
}
void
luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2,
int
line) {
switch
(op) {
case
OPR_AND: {
lua_assert(e1->t == NO_JUMP);
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break
;
}
case
OPR_OR: {
lua_assert(e1->f == NO_JUMP);
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t);
*e1 = *e2;
break
;
}
case
OPR_CONCAT: {
luaK_exp2val(fs, e2);
if
(e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
freeexp(fs, e1);
SETARG_B(getcode(fs, e2), e1->u.info);
e1->k = VRELOCABLE; e1->u.info = e2->u.info;
}
else
{
luaK_exp2nextreg(fs, e2);
codeexpval(fs, OP_CONCAT, e1, e2, line);
}
break
;
}
case
OPR_ADD:
case
OPR_SUB:
case
OPR_MUL:
case
OPR_DIV:
case
OPR_IDIV:
case
OPR_MOD:
case
OPR_POW:
case
OPR_BAND:
case
OPR_BOR:
case
OPR_BXOR:
case
OPR_SHL:
case
OPR_SHR: {
codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line);
break
;
}
case
OPR_EQ:
case
OPR_LT:
case
OPR_LE: {
codecomp(fs, cast(OpCode, (op - OPR_EQ) + OP_EQ), 1, e1, e2);
break
;
}
case
OPR_NE:
case
OPR_GT:
case
OPR_GE: {
codecomp(fs, cast(OpCode, (op - OPR_NE) + OP_EQ), 0, e1, e2);
break
;
}
default
: lua_assert(0);
}
}
void
luaK_fixline (FuncState *fs,
int
line) {
fs->f->lineinfo[fs->pc - 1] = line;
}
void
luaK_setlist (FuncState *fs,
int
base,
int
nelems,
int
tostore) {
int
c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
int
b = (tostore == LUA_MULTRET) ? 0 : tostore;
lua_assert(tostore != 0);
if
(c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else
if
(c <= MAXARG_Ax) {
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
codeextraarg(fs, c);
}
else
luaX_syntaxerror(fs->ls,
"constructor too long"
);
fs->freereg = base + 1;
}