mikepaul-LuaJIT/src/lj_parse.c

2253 lines
63 KiB
C
Raw Normal View History

2009-12-08 18:46:35 +00:00
/*
** Lua parser (source code -> bytecode).
2010-01-09 13:28:11 +00:00
** Copyright (C) 2005-2010 Mike Pall. See Copyright Notice in luajit.h
2009-12-08 18:46:35 +00:00
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lj_parse_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_func.h"
#include "lj_state.h"
#include "lj_bc.h"
#include "lj_lex.h"
#include "lj_parse.h"
#include "lj_vm.h"
#include "lj_vmevent.h"
/* -- Parser structures and definitions ----------------------------------- */
/* Expression kinds. */
typedef enum {
/* Constant expressions must be first and in this order: */
VKNIL,
VKFALSE,
VKTRUE,
VKSTR, /* sval = string value */
2010-02-06 07:18:32 +00:00
VKNUM, /* nval = number value */
2009-12-08 18:46:35 +00:00
VKLAST = VKNUM,
/* Non-constant expressions follow: */
VLOCAL, /* info = local register */
VUPVAL, /* info = upvalue index */
VGLOBAL, /* sval = string value */
VINDEXED, /* info = table register, aux = index reg/byte/string const */
VJMP, /* info = instruction PC */
VRELOCABLE, /* info = instruction PC */
VNONRELOC, /* info = result register */
VCALL, /* info = instruction PC, aux = base */
VVOID
} ExpKind;
/* Expression descriptor. */
typedef struct ExpDesc {
union {
2010-02-06 07:18:32 +00:00
struct {
uint32_t info; /* Primary info. */
uint32_t aux; /* Secondary info. */
} s;
TValue nval; /* Number value. */
GCstr *sval; /* String value. */
2009-12-08 18:46:35 +00:00
} u;
ExpKind k;
2010-02-06 07:18:32 +00:00
BCPos t; /* True condition jump list. */
BCPos f; /* False condition jump list. */
2009-12-08 18:46:35 +00:00
} ExpDesc;
2010-02-06 07:18:32 +00:00
/* Macros for expressions. */
#define expr_hasnojump(e) ((e)->t != (e)->f)
#define expr_isk(e) ((e)->k <= VKLAST)
#define expr_isk_nojump(e) (expr_isk(e) && !expr_hasnojump(e))
#define expr_isnumk(e) ((e)->k == VKNUM)
#define expr_isnumk_nojump(e) (expr_isnumk(e) && !expr_hasnojump(e))
#define expr_isstrk(e) ((e)->k == VKSTR)
#define expr_numV(e) check_exp(expr_isnumk((e)), numV(&(e)->u.nval))
/* Initialize expression. */
static LJ_AINLINE void expr_init(ExpDesc *e, ExpKind k, uint32_t info)
{
e->k = k;
e->u.s.info = info;
e->f = e->t = NO_JMP;
}
/* Per-function linked list of scope blocks. */
typedef struct FuncScope {
struct FuncScope *prev; /* Link to outer scope. */
BCPos breaklist; /* Jump list for loop breaks. */
uint8_t nactvar; /* Number of active vars outside the scope. */
uint8_t upval; /* Some variable in the scope is an upvalue. */
uint8_t isbreakable; /* Scope is a loop and allows a break. */
} FuncScope;
/* Index into variable stack. */
typedef uint16_t VarIndex;
#define LJ_MAX_VSTACK 65536
/* Upvalue map. */
typedef struct UVMap {
VarIndex vidx; /* Varinfo index. */
uint16_t slot; /* Slot or parent upvalue index. */
} UVMap;
2009-12-08 18:46:35 +00:00
/* Per-function state. */
typedef struct FuncState {
2010-02-06 07:18:32 +00:00
GCtab *kt; /* Hash table for constants. */
LexState *ls; /* Lexer state. */
lua_State *L; /* Lua state. */
FuncScope *bl; /* Current scope. */
struct FuncState *prev; /* Enclosing function. */
BCPos pc; /* Next bytecode position. */
BCPos lasttarget; /* Bytecode position of last jump target. */
BCPos jpc; /* Pending jump list to next bytecode. */
BCReg freereg; /* First free register. */
BCReg nactvar; /* Number of active local variables. */
2010-02-06 07:18:32 +00:00
BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */
BCLine linedefined; /* First line of the function definition. */
BCInsLine *bcbase; /* Base of bytecode stack. */
BCPos bclim; /* Limit of bytecode stack. */
MSize vbase; /* Base of variable stack for this function. */
2010-02-06 07:18:32 +00:00
uint8_t flags; /* Prototype flags. */
uint8_t numparams; /* Number of active local variables. */
2010-02-06 07:18:32 +00:00
uint8_t framesize; /* Fixed frame size. */
uint8_t nuv; /* Number of upvalues */
VarIndex varmap[LJ_MAX_LOCVAR]; /* Map from register to variable idx. */
UVMap uvloc[LJ_MAX_UPVAL]; /* Map from upvalue to variable idx and slot. */
2009-12-08 18:46:35 +00:00
} FuncState;
/* Binary and unary operators. ORDER OPR */
typedef enum BinOpr {
OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, /* ORDER ARITH */
OPR_CONCAT,
OPR_NE, OPR_EQ,
OPR_LT, OPR_GE, OPR_LE, OPR_GT,
OPR_AND, OPR_OR,
OPR_NOBINOPR
} BinOpr;
LJ_STATIC_ASSERT((int)BC_ISGE-(int)BC_ISLT == (int)OPR_GE-(int)OPR_LT);
LJ_STATIC_ASSERT((int)BC_ISLE-(int)BC_ISLT == (int)OPR_LE-(int)OPR_LT);
LJ_STATIC_ASSERT((int)BC_ISGT-(int)BC_ISLT == (int)OPR_GT-(int)OPR_LT);
LJ_STATIC_ASSERT((int)BC_SUBVV-(int)BC_ADDVV == (int)OPR_SUB-(int)OPR_ADD);
LJ_STATIC_ASSERT((int)BC_MULVV-(int)BC_ADDVV == (int)OPR_MUL-(int)OPR_ADD);
LJ_STATIC_ASSERT((int)BC_DIVVV-(int)BC_ADDVV == (int)OPR_DIV-(int)OPR_ADD);
LJ_STATIC_ASSERT((int)BC_MODVV-(int)BC_ADDVV == (int)OPR_MOD-(int)OPR_ADD);
/* -- Error handling ------------------------------------------------------ */
LJ_NORET LJ_NOINLINE static void err_syntax(LexState *ls, ErrMsg em)
{
lj_lex_error(ls, ls->token, em);
}
LJ_NORET LJ_NOINLINE static void err_token(LexState *ls, LexToken token)
{
lj_lex_error(ls, ls->token, LJ_ERR_XTOKEN, lj_lex_token2str(ls, token));
}
LJ_NORET static void err_limit(FuncState *fs, uint32_t limit, const char *what)
{
2010-02-06 07:18:32 +00:00
if (fs->linedefined == 0)
2009-12-08 18:46:35 +00:00
lj_lex_error(fs->ls, 0, LJ_ERR_XLIMM, limit, what);
else
2010-02-06 07:18:32 +00:00
lj_lex_error(fs->ls, 0, LJ_ERR_XLIMF, fs->linedefined, limit, what);
2009-12-08 18:46:35 +00:00
}
#define checklimit(fs, v, l, m) if ((v) >= (l)) err_limit(fs, l, m)
#define checklimitgt(fs, v, l, m) if ((v) > (l)) err_limit(fs, l, m)
#define checkcond(ls, c, em) { if (!(c)) err_syntax(ls, em); }
2010-02-06 07:18:32 +00:00
/* -- Management of constants --------------------------------------------- */
/* Return bytecode encoding for primitive constant. */
#define const_pri(e) check_exp((e)->k <= VKTRUE, (e)->k)
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Add a number constant. */
static BCReg const_num(FuncState *fs, ExpDesc *e)
{
lua_State *L = fs->L;
TValue *val;
lua_assert(expr_isnumk(e));
val = lj_tab_set(L, fs->kt, &e->u.nval);
if (tvisnum(val))
return val->u32.lo;
val->u64 = fs->nkn;
return fs->nkn++;
}
/* Add a GC object constant. */
static BCReg const_gc(FuncState *fs, GCobj *gc, uint32_t itype)
2010-02-06 07:18:32 +00:00
{
lua_State *L = fs->L;
TValue o, *val;
setgcV(L, &o, gc, itype);
/* NOBARRIER: the key is new or kept alive. */
2010-02-06 07:18:32 +00:00
val = lj_tab_set(L, fs->kt, &o);
if (tvisnum(val))
return val->u32.lo;
val->u64 = fs->nkgc;
return fs->nkgc++;
}
/* Add a string constant. */
static BCReg const_str(FuncState *fs, ExpDesc *e)
{
lua_assert(expr_isstrk(e) || e->k == VGLOBAL);
return const_gc(fs, obj2gco(e->u.sval), LJ_TSTR);
}
/* Anchor string constant to avoid GC. */
GCstr *lj_parse_keepstr(LexState *ls, const char *str, size_t len)
{
/* NOBARRIER: the key is new or kept alive. */
2010-02-06 07:18:32 +00:00
lua_State *L = ls->L;
GCstr *s = lj_str_new(L, str, len);
TValue *tv = lj_tab_setstr(L, ls->fs->kt, s);
if (tvisnil(tv)) setboolV(tv, 1);
lj_gc_check(L);
return s;
}
/* -- Jump list handling -------------------------------------------------- */
/* Get next element in jump list. */
static BCPos jmp_next(FuncState *fs, BCPos pc)
2009-12-08 18:46:35 +00:00
{
ptrdiff_t delta = bc_j(fs->bcbase[pc].ins);
2009-12-08 18:46:35 +00:00
if ((BCPos)delta == NO_JMP)
return NO_JMP;
else
return (BCPos)(((ptrdiff_t)pc+1)+delta);
}
2010-02-06 07:18:32 +00:00
/* Check if any of the instructions on the jump list produce no value. */
static int jmp_novalue(FuncState *fs, BCPos list)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
for (; list != NO_JMP; list = jmp_next(fs, list)) {
BCOp op = bc_op(fs->bcbase[list >= 1 ? list-1 : list].ins);
2009-12-08 18:46:35 +00:00
if (!(op == BC_ISTC || op == BC_ISFC)) return 1;
}
2010-02-06 07:18:32 +00:00
return 0;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Patch register of test instructions. */
static int jmp_patchtestreg(FuncState *fs, BCPos pc, BCReg reg)
2009-12-08 18:46:35 +00:00
{
BCIns *ip = &fs->bcbase[pc >= 1 ? pc-1 : pc].ins;
BCOp op = bc_op(*ip);
2009-12-08 18:46:35 +00:00
if (!(op == BC_ISTC || op == BC_ISFC))
2010-02-06 07:18:32 +00:00
return 0; /* Cannot patch other instructions. */
if (reg != NO_REG && reg != bc_d(*ip)) {
setbc_a(ip, reg);
2010-02-06 07:18:32 +00:00
} else { /* Nothing to store or already in the right register. */
setbc_op(ip, op+(BC_IST-BC_ISTC));
setbc_a(ip, 0);
2009-12-08 18:46:35 +00:00
}
return 1;
}
2010-02-06 07:18:32 +00:00
/* Drop values for all instructions on jump list. */
static void jmp_dropval(FuncState *fs, BCPos list)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
for (; list != NO_JMP; list = jmp_next(fs, list))
jmp_patchtestreg(fs, list, NO_REG);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Patch jump instruction to target. */
static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest)
2009-12-08 18:46:35 +00:00
{
BCIns *jmp = &fs->bcbase[pc].ins;
2009-12-08 18:46:35 +00:00
BCPos offset = dest-(pc+1)+BCBIAS_J;
lua_assert(dest != NO_JMP);
if (offset > BCMAX_D)
err_syntax(fs->ls, LJ_ERR_XJUMP);
setbc_d(jmp, offset);
}
2010-02-06 07:18:32 +00:00
/* Append to jump list. */
static void jmp_append(FuncState *fs, BCPos *l1, BCPos l2)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (l2 == NO_JMP) {
return;
} else if (*l1 == NO_JMP) {
2009-12-08 18:46:35 +00:00
*l1 = l2;
} else {
BCPos list = *l1;
BCPos next;
2010-02-06 07:18:32 +00:00
while ((next = jmp_next(fs, list)) != NO_JMP) /* Find last element. */
2009-12-08 18:46:35 +00:00
list = next;
2010-02-06 07:18:32 +00:00
jmp_patchins(fs, list, l2);
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Patch jump list and preserve produced values. */
static void jmp_patchval(FuncState *fs, BCPos list, BCPos vtarget,
BCReg reg, BCPos dtarget)
2009-12-08 18:46:35 +00:00
{
while (list != NO_JMP) {
2010-02-06 07:18:32 +00:00
BCPos next = jmp_next(fs, list);
if (jmp_patchtestreg(fs, list, reg))
jmp_patchins(fs, list, vtarget); /* Jump to target with value. */
2009-12-08 18:46:35 +00:00
else
2010-02-06 07:18:32 +00:00
jmp_patchins(fs, list, dtarget); /* Jump to default target. */
2009-12-08 18:46:35 +00:00
list = next;
}
}
2010-02-06 07:18:32 +00:00
/* Jump to following instruction. Append to list of pending jumps. */
static void jmp_tohere(FuncState *fs, BCPos list)
2009-12-08 18:46:35 +00:00
{
fs->lasttarget = fs->pc;
2010-02-06 07:18:32 +00:00
jmp_append(fs, &fs->jpc, list);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Patch jump list to target. */
static void jmp_patch(FuncState *fs, BCPos list, BCPos target)
2009-12-08 18:46:35 +00:00
{
if (target == fs->pc) {
2010-02-06 07:18:32 +00:00
jmp_tohere(fs, list);
2009-12-08 18:46:35 +00:00
} else {
lua_assert(target < fs->pc);
2010-02-06 07:18:32 +00:00
jmp_patchval(fs, list, target, NO_REG, target);
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* -- Bytecode register allocator ----------------------------------------- */
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Bump frame size. */
static void bcreg_bump(FuncState *fs, BCReg n)
2009-12-08 18:46:35 +00:00
{
BCReg sz = fs->freereg + n;
2010-02-06 07:18:32 +00:00
if (sz > fs->framesize) {
2009-12-08 18:46:35 +00:00
if (sz >= LJ_MAX_SLOTS)
err_syntax(fs->ls, LJ_ERR_XSLOTS);
2010-02-06 07:18:32 +00:00
fs->framesize = cast_byte(sz);
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Reserve registers. */
static void bcreg_reserve(FuncState *fs, BCReg n)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
bcreg_bump(fs, n);
2009-12-08 18:46:35 +00:00
fs->freereg += n;
}
2010-02-06 07:18:32 +00:00
/* Free register. */
static void bcreg_free(FuncState *fs, BCReg reg)
2009-12-08 18:46:35 +00:00
{
if (reg >= fs->nactvar) {
fs->freereg--;
lua_assert(reg == fs->freereg);
}
}
2010-02-06 07:18:32 +00:00
/* Free register for expression. */
static void expr_free(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
if (e->k == VNONRELOC)
2010-02-06 07:18:32 +00:00
bcreg_free(fs, e->u.s.info);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* -- Bytecode emitter ---------------------------------------------------- */
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Emit bytecode instruction. */
static BCPos bcemit_INS(FuncState *fs, BCIns ins)
2010-02-06 07:18:32 +00:00
{
BCPos pc = fs->pc;
LexState *ls = fs->ls;
jmp_patchval(fs, fs->jpc, pc, NO_REG, pc);
2010-02-06 07:18:32 +00:00
fs->jpc = NO_JMP;
if (LJ_UNLIKELY(pc >= fs->bclim)) {
ptrdiff_t base = fs->bcbase - ls->bcstack;
checklimit(fs, ls->sizebcstack, LJ_MAX_BCINS, "bytecode instructions");
lj_mem_growvec(fs->L, ls->bcstack, ls->sizebcstack, LJ_MAX_BCINS,BCInsLine);
fs->bclim = (BCPos)(ls->sizebcstack - base);
fs->bcbase = ls->bcstack + base;
}
fs->bcbase[pc].ins = ins;
fs->bcbase[pc].line = ls->lastline;
fs->pc = pc+1;
return pc;
2010-02-06 07:18:32 +00:00
}
#define bcemit_ABC(fs, o, a, b, c) bcemit_INS(fs, BCINS_ABC(o, a, b, c))
#define bcemit_AD(fs, o, a, d) bcemit_INS(fs, BCINS_AD(o, a, d))
#define bcemit_AJ(fs, o, a, j) bcemit_INS(fs, BCINS_AJ(o, a, j))
#define bcptr(fs, e) (&(fs)->bcbase[(e)->u.s.info].ins)
2010-02-06 07:18:32 +00:00
/* -- Bytecode emitter for expressions ------------------------------------ */
/* Discharge non-constant expression to any register. */
static void expr_discharge(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
BCIns ins;
2010-02-06 07:18:32 +00:00
if (e->k == VUPVAL) {
2009-12-08 18:46:35 +00:00
ins = BCINS_AD(BC_UGET, 0, e->u.s.info);
2010-02-06 07:18:32 +00:00
} else if (e->k == VGLOBAL) {
ins = BCINS_AD(BC_GGET, 0, const_str(fs, e));
} else if (e->k == VINDEXED) {
2009-12-08 18:46:35 +00:00
BCReg rc = e->u.s.aux;
if ((int32_t)rc < 0) {
ins = BCINS_ABC(BC_TGETS, 0, e->u.s.info, ~rc);
} else if (rc > BCMAX_C) {
ins = BCINS_ABC(BC_TGETB, 0, e->u.s.info, rc-(BCMAX_C+1));
} else {
2010-02-06 07:18:32 +00:00
bcreg_free(fs, rc);
2009-12-08 18:46:35 +00:00
ins = BCINS_ABC(BC_TGETV, 0, e->u.s.info, rc);
}
2010-02-06 07:18:32 +00:00
bcreg_free(fs, e->u.s.info);
} else if (e->k == VCALL) {
2009-12-08 18:46:35 +00:00
e->u.s.info = e->u.s.aux;
e->k = VNONRELOC;
2010-02-06 07:18:32 +00:00
return;
} else if (e->k == VLOCAL) {
e->k = VNONRELOC;
return;
} else {
2009-12-08 18:46:35 +00:00
return;
}
2010-02-06 07:18:32 +00:00
e->u.s.info = bcemit_INS(fs, ins);
2009-12-08 18:46:35 +00:00
e->k = VRELOCABLE;
}
/* Emit bytecode to set a range of registers to nil. */
static void bcemit_nil(FuncState *fs, BCReg from, BCReg n)
{
if (fs->pc > fs->lasttarget) { /* No jumps to current position? */
BCIns *ip = &fs->bcbase[fs->pc-1].ins;
BCReg pto, pfrom = bc_a(*ip);
switch (bc_op(*ip)) { /* Try to merge with the previous instruction. */
case BC_KPRI:
if (bc_d(*ip) != ~LJ_TNIL) break;
if (from == pfrom) {
if (n == 1) return;
} else if (from == pfrom+1) {
from = pfrom;
n++;
} else {
break;
}
fs->pc--; /* Drop KPRI. */
break;
case BC_KNIL:
pto = bc_d(*ip);
if (pfrom <= from && from <= pto+1) { /* Can we connect both ranges? */
if (from+n-1 > pto)
setbc_d(ip, from+n-1); /* Patch previous instruction range. */
return;
}
break;
default:
break;
}
}
/* Emit new instruction or replace old instruction. */
bcemit_INS(fs, n == 1 ? BCINS_AD(BC_KPRI, from, VKNIL) :
BCINS_AD(BC_KNIL, from, from+n-1));
}
2010-02-06 07:18:32 +00:00
/* Discharge an expression to a specific register. Ignore branches. */
static void expr_toreg_nobranch(FuncState *fs, ExpDesc *e, BCReg reg)
2009-12-08 18:46:35 +00:00
{
BCIns ins;
2010-02-06 07:18:32 +00:00
expr_discharge(fs, e);
if (e->k == VKSTR) {
2010-02-06 07:18:32 +00:00
ins = BCINS_AD(BC_KSTR, reg, const_str(fs, e));
} else if (e->k == VKNUM) {
lua_Number n = expr_numV(e);
2009-12-08 18:46:35 +00:00
int32_t k = lj_num2int(n);
if (checki16(k) && n == cast_num(k))
ins = BCINS_AD(BC_KSHORT, reg, (BCReg)(uint16_t)k);
else
2010-02-06 07:18:32 +00:00
ins = BCINS_AD(BC_KNUM, reg, const_num(fs, e));
} else if (e->k == VRELOCABLE) {
2009-12-08 18:46:35 +00:00
setbc_a(bcptr(fs, e), reg);
goto noins;
2010-02-06 07:18:32 +00:00
} else if (e->k == VNONRELOC) {
2009-12-08 18:46:35 +00:00
if (reg == e->u.s.info)
goto noins;
ins = BCINS_AD(BC_MOV, reg, e->u.s.info);
} else if (e->k == VKNIL) {
bcemit_nil(fs, reg, 1);
goto noins;
} else if (e->k <= VKTRUE) {
ins = BCINS_AD(BC_KPRI, reg, const_pri(e));
2010-02-06 07:18:32 +00:00
} else {
2009-12-08 18:46:35 +00:00
lua_assert(e->k == VVOID || e->k == VJMP);
2010-02-06 07:18:32 +00:00
return;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
bcemit_INS(fs, ins);
2009-12-08 18:46:35 +00:00
noins:
e->u.s.info = reg;
e->k = VNONRELOC;
}
2010-02-06 07:18:32 +00:00
/* Forward declaration. */
static BCPos bcemit_jmp(FuncState *fs);
/* Discharge an expression to a specific register. */
static void expr_toreg(FuncState *fs, ExpDesc *e, BCReg reg)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
expr_toreg_nobranch(fs, e, reg);
2009-12-08 18:46:35 +00:00
if (e->k == VJMP)
2010-02-06 07:18:32 +00:00
jmp_append(fs, &e->t, e->u.s.info); /* Add it to the true jump list. */
if (expr_hasnojump(e)) { /* Discharge expression with branches. */
BCPos jend, jfalse = NO_JMP, jtrue = NO_JMP;
if (jmp_novalue(fs, e->t) || jmp_novalue(fs, e->f)) {
BCPos jval = (e->k == VJMP) ? NO_JMP : bcemit_jmp(fs);
jfalse = bcemit_AD(fs, BC_KPRI, reg, VKFALSE);
bcemit_AJ(fs, BC_JMP, fs->freereg, 1);
jtrue = bcemit_AD(fs, BC_KPRI, reg, VKTRUE);
jmp_tohere(fs, jval);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
jend = fs->pc;
fs->lasttarget = jend;
jmp_patchval(fs, e->f, jend, reg, jfalse);
jmp_patchval(fs, e->t, jend, reg, jtrue);
2009-12-08 18:46:35 +00:00
}
e->f = e->t = NO_JMP;
e->u.s.info = reg;
e->k = VNONRELOC;
}
2010-02-06 07:18:32 +00:00
/* Discharge an expression to the next free register. */
static void expr_tonextreg(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
expr_discharge(fs, e);
expr_free(fs, e);
bcreg_reserve(fs, 1);
expr_toreg(fs, e, fs->freereg - 1);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Discharge an expression to any register. */
static BCReg expr_toanyreg(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
expr_discharge(fs, e);
2009-12-08 18:46:35 +00:00
if (e->k == VNONRELOC) {
2010-02-06 07:18:32 +00:00
if (!expr_hasnojump(e)) return e->u.s.info; /* Already in a register. */
if (e->u.s.info >= fs->nactvar) {
expr_toreg(fs, e, e->u.s.info); /* Discharge to temp. register. */
2009-12-08 18:46:35 +00:00
return e->u.s.info;
}
}
2010-02-06 07:18:32 +00:00
expr_tonextreg(fs, e); /* Discharge to next register. */
2009-12-08 18:46:35 +00:00
return e->u.s.info;
}
2010-02-06 07:18:32 +00:00
/* Partially discharge expression to a value. */
static void expr_toval(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (expr_hasnojump(e))
expr_toanyreg(fs, e);
2009-12-08 18:46:35 +00:00
else
2010-02-06 07:18:32 +00:00
expr_discharge(fs, e);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Emit store for LHS expression. */
static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
BCIns ins;
2010-02-06 07:18:32 +00:00
if (var->k == VLOCAL) {
expr_free(fs, e);
expr_toreg(fs, e, var->u.s.info);
2009-12-08 18:46:35 +00:00
return;
2010-02-06 07:18:32 +00:00
} else if (var->k == VUPVAL) {
expr_toval(fs, e);
if (e->k <= VKTRUE)
ins = BCINS_AD(BC_USETP, var->u.s.info, const_pri(e));
else if (e->k == VKSTR)
ins = BCINS_AD(BC_USETS, var->u.s.info, const_str(fs, e));
else if (e->k == VKNUM)
ins = BCINS_AD(BC_USETN, var->u.s.info, const_num(fs, e));
else
ins = BCINS_AD(BC_USETV, var->u.s.info, expr_toanyreg(fs, e));
} else if (var->k == VGLOBAL) {
BCReg ra = expr_toanyreg(fs, e);
ins = BCINS_AD(BC_GSET, ra, const_str(fs, var));
} else {
BCReg ra, rc;
lua_assert(var->k == VINDEXED);
ra = expr_toanyreg(fs, e);
rc = var->u.s.aux;
2009-12-08 18:46:35 +00:00
if ((int32_t)rc < 0) {
ins = BCINS_ABC(BC_TSETS, ra, var->u.s.info, ~rc);
} else if (rc > BCMAX_C) {
ins = BCINS_ABC(BC_TSETB, ra, var->u.s.info, rc-(BCMAX_C+1));
} else {
/* Free late alloced key reg to avoid assert on free of value reg. */
2010-02-06 07:18:32 +00:00
/* This can only happen when called from expr_table(). */
2009-12-08 18:46:35 +00:00
lua_assert(e->k != VNONRELOC || ra < fs->nactvar ||
2010-02-06 07:18:32 +00:00
rc < ra || (bcreg_free(fs, rc),1));
2009-12-08 18:46:35 +00:00
ins = BCINS_ABC(BC_TSETV, ra, var->u.s.info, rc);
}
}
2010-02-06 07:18:32 +00:00
bcemit_INS(fs, ins);
expr_free(fs, e);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Emit method lookup expression. */
static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
BCReg idx, func, obj = expr_toanyreg(fs, e);
expr_free(fs, e);
2009-12-08 18:46:35 +00:00
func = fs->freereg;
2010-02-06 07:18:32 +00:00
bcemit_AD(fs, BC_MOV, func+1, obj); /* Copy object to first argument. */
lua_assert(expr_isstrk(key));
idx = const_str(fs, key);
2009-12-08 18:46:35 +00:00
if (idx <= BCMAX_C) {
2010-02-06 07:18:32 +00:00
bcreg_reserve(fs, 2);
bcemit_ABC(fs, BC_TGETS, func, obj, idx);
2009-12-08 18:46:35 +00:00
} else {
2010-02-06 07:18:32 +00:00
bcreg_reserve(fs, 3);
bcemit_AD(fs, BC_KSTR, func+2, idx);
bcemit_ABC(fs, BC_TGETV, func, obj, func+2);
2009-12-08 18:46:35 +00:00
fs->freereg--;
}
e->u.s.info = func;
e->k = VNONRELOC;
}
2010-02-06 07:18:32 +00:00
/* -- Bytecode emitter for branches --------------------------------------- */
/* Emit unconditional branch. */
static BCPos bcemit_jmp(FuncState *fs)
{
BCPos jpc = fs->jpc;
BCPos j = fs->pc - 1;
2010-08-03 21:11:12 +00:00
BCIns *ip = &fs->bcbase[j].ins;
2010-02-06 07:18:32 +00:00
fs->jpc = NO_JMP;
if ((int32_t)j >= (int32_t)fs->lasttarget &&
2010-08-03 21:11:12 +00:00
bc_op(*ip) == BC_UCLO)
setbc_j(ip, NO_JMP);
2010-02-06 07:18:32 +00:00
else
j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP);
jmp_append(fs, &j, jpc);
return j;
}
/* Invert branch condition of bytecode instruction. */
static void invertcond(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
BCIns *ip = &fs->bcbase[e->u.s.info - 1].ins;
setbc_op(ip, bc_op(*ip)^1);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Emit conditional branch. */
static BCPos bcemit_branch(FuncState *fs, ExpDesc *e, int cond)
2009-12-08 18:46:35 +00:00
{
BCPos pc;
2009-12-08 18:46:35 +00:00
if (e->k == VRELOCABLE) {
BCIns *ip = bcptr(fs, e);
if (bc_op(*ip) == BC_NOT) {
*ip = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*ip));
2010-02-06 07:18:32 +00:00
return bcemit_jmp(fs);
2009-12-08 18:46:35 +00:00
}
}
if (e->k != VNONRELOC) {
2010-02-06 07:18:32 +00:00
bcreg_reserve(fs, 1);
expr_toreg_nobranch(fs, e, fs->freereg-1);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
bcemit_AD(fs, cond ? BC_ISTC : BC_ISFC, NO_REG, e->u.s.info);
pc = bcemit_jmp(fs);
expr_free(fs, e);
return pc;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Emit branch on true condition. */
static void bcemit_branch_t(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
BCPos pc;
expr_discharge(fs, e);
if (e->k == VKSTR || e->k == VKNUM || e->k == VKTRUE)
pc = NO_JMP; /* Never jump. */
else if (e->k == VJMP)
invertcond(fs, e), pc = e->u.s.info;
else if (e->k == VKFALSE && !expr_hasnojump(e))
pc = bcemit_jmp(fs); /* Always jump. */
else
pc = bcemit_branch(fs, e, 0);
jmp_append(fs, &e->f, pc);
jmp_tohere(fs, e->t);
2009-12-08 18:46:35 +00:00
e->t = NO_JMP;
}
2010-02-06 07:18:32 +00:00
/* Emit branch on false condition. */
static void bcemit_branch_f(FuncState *fs, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
BCPos pc;
expr_discharge(fs, e);
if (e->k == VKNIL || e->k == VKFALSE)
pc = NO_JMP; /* Never jump. */
else if (e->k == VJMP)
2009-12-08 18:46:35 +00:00
pc = e->u.s.info;
2010-02-06 07:18:32 +00:00
else if (e->k == VKTRUE && !expr_hasnojump(e))
pc = bcemit_jmp(fs); /* Always jump. */
else
pc = bcemit_branch(fs, e, 1);
jmp_append(fs, &e->t, pc);
jmp_tohere(fs, e->f);
2009-12-08 18:46:35 +00:00
e->f = NO_JMP;
}
2010-02-06 07:18:32 +00:00
/* -- Bytecode emitter for operators -------------------------------------- */
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Try constant-folding of arithmetic operators. */
2009-12-08 18:46:35 +00:00
static int foldarith(BinOpr opr, ExpDesc *e1, ExpDesc *e2)
{
TValue o;
2010-02-06 07:18:32 +00:00
if (!expr_isnumk_nojump(e1) || !expr_isnumk_nojump(e2)) return 0;
setnumV(&o, lj_vm_foldarith(expr_numV(e1), expr_numV(e2), (int)opr-OPR_ADD));
2009-12-08 18:46:35 +00:00
if (tvisnan(&o) || tvismzero(&o)) return 0; /* Avoid NaN and -0 as consts. */
setnumV(&e1->u.nval, numV(&o));
return 1;
}
2010-02-06 07:18:32 +00:00
/* Emit arithmetic operator. */
static void bcemit_arith(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2)
2009-12-08 18:46:35 +00:00
{
BCReg rb, rc, t;
uint32_t op;
if (foldarith(opr, e1, e2))
return;
if (opr == OPR_POW) {
op = BC_POW;
2010-02-06 07:18:32 +00:00
rc = expr_toanyreg(fs, e2);
rb = expr_toanyreg(fs, e1);
2009-12-08 18:46:35 +00:00
} else {
op = opr-OPR_ADD+BC_ADDVV;
2010-02-06 07:18:32 +00:00
/* Must discharge 2nd operand first since VINDEXED might free regs. */
expr_toval(fs, e2);
if (expr_isnumk(e2) && (rc = const_num(fs, e2)) <= BCMAX_C)
2009-12-08 18:46:35 +00:00
op -= BC_ADDVV-BC_ADDVN;
else
2010-02-06 07:18:32 +00:00
rc = expr_toanyreg(fs, e2);
/* 1st operand discharged by bcemit_binop_left, but need KNUM/KSHORT. */
lua_assert(expr_isnumk(e1) || e1->k == VNONRELOC);
expr_toval(fs, e1);
/* Avoid two consts to satisfy bytecode constraints. */
if (expr_isnumk(e1) && !expr_isnumk(e2) &&
(t = const_num(fs, e1)) <= BCMAX_B) {
2009-12-08 18:46:35 +00:00
rb = rc; rc = t; op -= BC_ADDVV-BC_ADDNV;
} else {
2010-02-06 07:18:32 +00:00
rb = expr_toanyreg(fs, e1);
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Using expr_free might cause asserts if the order is wrong. */
2009-12-08 18:46:35 +00:00
if (e1->k == VNONRELOC && e1->u.s.info >= fs->nactvar) fs->freereg--;
if (e2->k == VNONRELOC && e2->u.s.info >= fs->nactvar) fs->freereg--;
2010-02-06 07:18:32 +00:00
e1->u.s.info = bcemit_ABC(fs, op, 0, rb, rc);
2009-12-08 18:46:35 +00:00
e1->k = VRELOCABLE;
}
2010-02-06 07:18:32 +00:00
/* Emit comparison operator. */
static void bcemit_comp(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2)
2009-12-08 18:46:35 +00:00
{
ExpDesc *eret = e1;
BCIns ins;
2010-02-06 07:18:32 +00:00
expr_toval(fs, e1);
2009-12-08 18:46:35 +00:00
if (opr == OPR_EQ || opr == OPR_NE) {
BCOp op = opr == OPR_EQ ? BC_ISEQV : BC_ISNEV;
BCReg ra;
2010-02-06 07:18:32 +00:00
if (expr_isk(e1)) { e1 = e2; e2 = eret; } /* Need constant in 2nd arg. */
ra = expr_toanyreg(fs, e1); /* First arg must be in a reg. */
expr_toval(fs, e2);
2009-12-08 18:46:35 +00:00
switch (e2->k) {
case VKNIL: case VKFALSE: case VKTRUE:
2010-02-06 07:18:32 +00:00
ins = BCINS_AD(op+(BC_ISEQP-BC_ISEQV), ra, const_pri(e2));
2009-12-08 18:46:35 +00:00
break;
case VKSTR:
2010-02-06 07:18:32 +00:00
ins = BCINS_AD(op+(BC_ISEQS-BC_ISEQV), ra, const_str(fs, e2));
2009-12-08 18:46:35 +00:00
break;
case VKNUM:
2010-02-06 07:18:32 +00:00
ins = BCINS_AD(op+(BC_ISEQN-BC_ISEQV), ra, const_num(fs, e2));
2009-12-08 18:46:35 +00:00
break;
default:
2010-02-06 07:18:32 +00:00
ins = BCINS_AD(op, ra, expr_toanyreg(fs, e2));
2009-12-08 18:46:35 +00:00
break;
}
} else {
uint32_t op = opr-OPR_LT+BC_ISLT;
BCReg ra;
if ((op-BC_ISLT) & 1) { /* GT -> LT, GE -> LE */
2010-02-06 07:18:32 +00:00
e1 = e2; e2 = eret; /* Swap operands. */
2009-12-08 18:46:35 +00:00
op = ((op-BC_ISLT)^3)+BC_ISLT;
}
2010-02-06 07:18:32 +00:00
ra = expr_toanyreg(fs, e1);
ins = BCINS_AD(op, ra, expr_toanyreg(fs, e2));
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Using expr_free might cause asserts if the order is wrong. */
2009-12-08 18:46:35 +00:00
if (e1->k == VNONRELOC && e1->u.s.info >= fs->nactvar) fs->freereg--;
if (e2->k == VNONRELOC && e2->u.s.info >= fs->nactvar) fs->freereg--;
2010-02-06 07:18:32 +00:00
bcemit_INS(fs, ins);
eret->u.s.info = bcemit_jmp(fs);
2009-12-08 18:46:35 +00:00
eret->k = VJMP;
}
2010-02-06 07:18:32 +00:00
/* Fixup left side of binary operator. */
static void bcemit_binop_left(FuncState *fs, BinOpr op, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (op == OPR_AND) {
bcemit_branch_t(fs, e);
} else if (op == OPR_OR) {
bcemit_branch_f(fs, e);
} else if (op == OPR_CONCAT) {
expr_tonextreg(fs, e);
} else if (op == OPR_EQ || op == OPR_NE) {
if (!expr_isk_nojump(e)) expr_toanyreg(fs, e);
} else {
if (!expr_isnumk_nojump(e)) expr_toanyreg(fs, e);
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Emit binary operator. */
static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (op <= OPR_POW) {
bcemit_arith(fs, op, e1, e2);
} else if (op == OPR_AND) {
lua_assert(e1->t == NO_JMP); /* List must be closed. */
expr_discharge(fs, e2);
jmp_append(fs, &e2->f, e1->f);
2009-12-08 18:46:35 +00:00
*e1 = *e2;
2010-02-06 07:18:32 +00:00
} else if (op == OPR_OR) {
lua_assert(e1->f == NO_JMP); /* List must be closed. */
expr_discharge(fs, e2);
jmp_append(fs, &e2->t, e1->t);
2009-12-08 18:46:35 +00:00
*e1 = *e2;
2010-02-06 07:18:32 +00:00
} else if (op == OPR_CONCAT) {
expr_toval(fs, e2);
2009-12-08 18:46:35 +00:00
if (e2->k == VRELOCABLE && bc_op(*bcptr(fs, e2)) == BC_CAT) {
lua_assert(e1->u.s.info == bc_b(*bcptr(fs, e2))-1);
2010-02-06 07:18:32 +00:00
expr_free(fs, e1);
2009-12-08 18:46:35 +00:00
setbc_b(bcptr(fs, e2), e1->u.s.info);
e1->u.s.info = e2->u.s.info;
} else {
2010-02-06 07:18:32 +00:00
expr_tonextreg(fs, e2);
expr_free(fs, e2);
expr_free(fs, e1);
e1->u.s.info = bcemit_ABC(fs, BC_CAT, 0, e1->u.s.info, e2->u.s.info);
2009-12-08 18:46:35 +00:00
}
e1->k = VRELOCABLE;
2010-02-06 07:18:32 +00:00
} else {
lua_assert(op == OPR_NE || op == OPR_EQ ||
op == OPR_LT || op == OPR_GE || op == OPR_LE || op == OPR_GT);
bcemit_comp(fs, op, e1, e2);
}
}
/* Emit unary operator. */
static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e)
{
if (op == BC_NOT) {
/* Swap true and false lists. */
{ BCPos temp = e->f; e->f = e->t; e->t = temp; }
jmp_dropval(fs, e->f);
jmp_dropval(fs, e->t);
expr_discharge(fs, e);
if (e->k == VKNIL || e->k == VKFALSE) {
e->k = VKTRUE;
return;
} else if (expr_isk(e)) {
e->k = VKFALSE;
return;
} else if (e->k == VJMP) {
2010-02-06 07:18:32 +00:00
invertcond(fs, e);
return;
} else if (e->k == VRELOCABLE) {
bcreg_reserve(fs, 1);
setbc_a(bcptr(fs, e), fs->freereg-1);
e->u.s.info = fs->freereg-1;
e->k = VNONRELOC;
} else {
lua_assert(e->k == VNONRELOC);
}
} else {
lua_assert(op == BC_UNM || op == BC_LEN);
/* Constant-fold negations. But avoid folding to -0. */
if (op == BC_UNM && expr_isnumk_nojump(e) && expr_numV(e) != 0) {
setnumV(&e->u.nval, -expr_numV(e));
return;
}
expr_toanyreg(fs, e);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
expr_free(fs, e);
e->u.s.info = bcemit_AD(fs, op, 0, e->u.s.info);
e->k = VRELOCABLE;
2009-12-08 18:46:35 +00:00
}
/* -- Lexer support ------------------------------------------------------- */
2010-02-06 07:18:32 +00:00
/* Check and consume optional token. */
static int lex_opt(LexState *ls, LexToken tok)
2009-12-08 18:46:35 +00:00
{
if (ls->token == tok) {
lj_lex_next(ls);
return 1;
}
return 0;
}
2010-02-06 07:18:32 +00:00
/* Check and consume token. */
static void lex_check(LexState *ls, LexToken tok)
2009-12-08 18:46:35 +00:00
{
if (ls->token != tok)
err_token(ls, tok);
lj_lex_next(ls);
}
2010-02-06 07:18:32 +00:00
/* Check for matching token. */
static void lex_match(LexState *ls, LexToken what, LexToken who, BCLine line)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (!lex_opt(ls, what)) {
2009-12-08 18:46:35 +00:00
if (line == ls->linenumber) {
err_token(ls, what);
} else {
const char *swhat = lj_lex_token2str(ls, what);
const char *swho = lj_lex_token2str(ls, who);
lj_lex_error(ls, ls->token, LJ_ERR_XMATCH, swhat, swho, line);
}
}
}
2010-02-06 07:18:32 +00:00
/* Check for string token. */
static GCstr *lex_str(LexState *ls)
2009-12-08 18:46:35 +00:00
{
GCstr *s;
if (ls->token != TK_name)
err_token(ls, TK_name);
s = strV(&ls->tokenval);
lj_lex_next(ls);
return s;
}
/* -- Variable handling --------------------------------------------------- */
#define var_get(ls, fs, i) ((ls)->vstack[(fs)->varmap[(i)]])
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Define a new local variable. */
static void var_new(LexState *ls, BCReg n, GCstr *name)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
MSize vtop = ls->vtop;
2010-02-06 07:18:32 +00:00
checklimit(fs, fs->nactvar+n, LJ_MAX_LOCVAR, "local variables");
if (LJ_UNLIKELY(vtop >= ls->sizevstack)) {
if (ls->sizevstack >= LJ_MAX_VSTACK)
lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK);
lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo);
2009-12-08 18:46:35 +00:00
}
lua_assert(lj_tab_getstr(fs->kt, name) != NULL);
/* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */
setgcref(ls->vstack[vtop].name, obj2gco(name));
fs->varmap[fs->nactvar+n] = (uint16_t)vtop;
ls->vtop = vtop+1;
2009-12-08 18:46:35 +00:00
}
#define var_new_lit(ls, n, v) \
2010-02-06 07:18:32 +00:00
var_new(ls, (n), lj_parse_keepstr(ls, "" v, sizeof(v)-1))
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Add local variables. */
static void var_add(LexState *ls, BCReg nvars)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
fs->nactvar = cast_byte(fs->nactvar + nvars);
for (; nvars; nvars--)
var_get(ls, fs, fs->nactvar - nvars).startpc = fs->pc;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Remove local variables. */
static void var_remove(LexState *ls, BCReg tolevel)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
while (fs->nactvar > tolevel)
var_get(ls, fs, --fs->nactvar).endpc = fs->pc;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Lookup local variable name. */
static BCReg var_lookup_local(FuncState *fs, GCstr *n)
{
int i;
for (i = fs->nactvar-1; i >= 0; i--) {
if (n == gco2str(gcref(var_get(fs->ls, fs, i).name)))
2010-02-06 07:18:32 +00:00
return (BCReg)i;
}
return (BCReg)-1; /* Not found. */
}
/* Lookup or add upvalue index. */
static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
MSize i, n = fs->nuv;
for (i = 0; i < n; i++)
if (fs->uvloc[i].vidx == vidx)
return i; /* Already exists. */
/* Otherwise create a new one. */
checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues");
lua_assert(e->k == VLOCAL || e->k == VUPVAL);
fs->uvloc[n].vidx = (uint16_t)vidx;
fs->uvloc[n].slot = (uint16_t)(e->u.s.info | (e->k == VLOCAL ? 0x8000 : 0));
fs->nuv = n+1;
return n;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Forward declaration. */
static void scope_uvmark(FuncState *fs, BCReg level);
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Recursively lookup variables in enclosing functions. */
static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (fs) {
BCReg reg = var_lookup_local(fs, name);
if ((int32_t)reg >= 0) { /* Local in this function? */
expr_init(e, VLOCAL, reg);
2009-12-08 18:46:35 +00:00
if (!first)
2010-02-06 07:18:32 +00:00
scope_uvmark(fs, reg); /* Scope now has an upvalue. */
return (MSize)fs->varmap[reg];
} else {
MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */
if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */
e->u.s.info = (uint8_t)var_lookup_uv(fs, vidx, e);
e->k = VUPVAL;
return vidx;
}
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
} else { /* Not found in any function, must be a global. */
expr_init(e, VGLOBAL, 0);
e->u.sval = name;
2009-12-08 18:46:35 +00:00
}
return (MSize)-1; /* Global. */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Lookup variable name. */
#define var_lookup(ls, e) \
var_lookup_((ls)->fs, lex_str(ls), (e), 1)
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* -- Function state management ------------------------------------------- */
2009-12-08 18:46:35 +00:00
/* NYI: compress debug info. */
/* Fixup bytecode and lineinfo for prototype. */
static void fs_fixup_bc(FuncState *fs, GCproto *pt, BCIns *bc, BCLine *lineinfo)
{
MSize i, n = fs->pc;
BCInsLine *base = fs->bcbase;
setmref(pt->lineinfo, lineinfo);
pt->sizebc = n;
bc[n] = ~0u; /* Close potentially uninitialized gap between bc and kgc. */
bc[0] = BCINS_AD((fs->flags & PROTO_IS_VARARG) ? BC_FUNCV : BC_FUNCF,
fs->framesize, 0);
lineinfo[0] = fs->linedefined;
for (i = 1; i < n; i++) {
bc[i] = base[i].ins;
lineinfo[i] = base[i].line;
}
}
2010-02-06 07:18:32 +00:00
/* Fixup constants for prototype. */
static void fs_fixup_k(FuncState *fs, GCproto *pt, void *kptr)
2009-12-08 18:46:35 +00:00
{
GCtab *kt;
TValue *array;
Node *node;
MSize i, hmask;
2009-12-08 18:46:35 +00:00
checklimitgt(fs, fs->nkn, BCMAX_D+1, "constants");
checklimitgt(fs, fs->nkgc, BCMAX_D+1, "constants");
setmref(pt->k, kptr);
2009-12-08 18:46:35 +00:00
pt->sizekn = fs->nkn;
pt->sizekgc = fs->nkgc;
kt = fs->kt;
array = tvref(kt->array);
for (i = 0; i < kt->asize; i++)
if (tvisnum(&array[i]))
((lua_Number *)kptr)[array[i].u32.lo] = cast_num(i);
2009-12-08 18:46:35 +00:00
node = noderef(kt->node);
hmask = kt->hmask;
for (i = 0; i <= hmask; i++) {
Node *n = &node[i];
if (tvisnum(&n->val)) {
ptrdiff_t kidx = (ptrdiff_t)n->val.u32.lo;
if (tvisnum(&n->key)) {
((lua_Number *)kptr)[kidx] = numV(&n->key);
2009-12-08 18:46:35 +00:00
} else {
GCobj *o = gcV(&n->key);
setgcref(((GCRef *)kptr)[~kidx], o);
2009-12-08 18:46:35 +00:00
lj_gc_objbarrier(fs->L, pt, o);
}
}
}
}
2010-02-06 07:18:32 +00:00
/* Fixup upvalues for prototype. */
static void fs_fixup_uv(FuncState *fs, GCproto *pt, uint16_t *uv)
2009-12-08 18:46:35 +00:00
{
MSize i, n = fs->nuv;
setmref(pt->uv, uv);
pt->sizeuv = n;
for (i = 0; i < n; i++)
uv[i] = fs->uvloc[i].slot;
2009-12-08 18:46:35 +00:00
}
/* Fixup debug info for prototype. */
static void fs_fixup_dbg(FuncState *fs, GCproto *pt, VarInfo *vi, MSize sizevi)
{
MSize i, n = fs->nuv;
GCRef *uvname = (GCRef *)((char *)vi + sizevi*sizeof(VarInfo));
VarInfo *vstack = fs->ls->vstack;
setmref(pt->varinfo, vi);
setmref(pt->uvname, uvname);
pt->sizevarinfo = sizevi;
memcpy(vi, &vstack[fs->vbase], sizevi*sizeof(VarInfo));
for (i = 0; i < n; i++)
setgcref(uvname[i], gcref(vstack[fs->uvloc[i].vidx].name));
}
2010-02-06 07:18:32 +00:00
/* Check if bytecode op returns. */
static int bcopisret(BCOp op)
{
switch (op) {
case BC_CALLMT: case BC_CALLT:
case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1:
return 1;
default:
return 0;
}
}
/* Fixup return instruction for prototype. */
static void fs_fixup_ret(FuncState *fs)
2009-12-08 18:46:35 +00:00
{
BCPos lastpc = fs->pc;
if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) {
2010-02-06 07:18:32 +00:00
if (fs->flags & PROTO_HAS_FNEW)
bcemit_AJ(fs, BC_UCLO, 0, 0);
bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */
2009-12-08 18:46:35 +00:00
}
/* May need to fixup returns encoded before first function was created. */
2010-02-06 07:18:32 +00:00
if (fs->flags & PROTO_FIXUP_RETURN) {
2009-12-08 18:46:35 +00:00
BCPos pc;
for (pc = 0; pc < lastpc; pc++) {
BCIns ins = fs->bcbase[pc].ins;
2009-12-08 18:46:35 +00:00
BCPos offset;
switch (bc_op(ins)) {
2009-12-08 18:46:35 +00:00
case BC_CALLMT: case BC_CALLT:
case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1:
offset = bcemit_INS(fs, ins)-(pc+1)+BCBIAS_J; /* Copy return ins. */
2009-12-08 18:46:35 +00:00
if (offset > BCMAX_D)
err_syntax(fs->ls, LJ_ERR_XFIXUP);
/* Replace with UCLO plus branch. */
fs->bcbase[pc].ins = BCINS_AD(BC_UCLO, 0, offset);
2009-12-08 18:46:35 +00:00
break;
2010-02-06 07:18:32 +00:00
case BC_UCLO:
return; /* We're done. */
default:
break;
2009-12-08 18:46:35 +00:00
}
}
}
}
2010-02-06 07:18:32 +00:00
/* Finish a FuncState and return the new prototype. */
static GCproto *fs_finish(LexState *ls, BCLine line)
2009-12-08 18:46:35 +00:00
{
lua_State *L = ls->L;
FuncState *fs = ls->fs;
MSize sizevi;
size_t sizept, ofsk, ofsuv, ofsdbg, ofsli;
GCproto *pt;
2010-02-06 07:18:32 +00:00
/* Apply final fixups. */
lua_assert(fs->bl == NULL);
fs_fixup_ret(fs);
var_remove(ls, 0);
/* Calculate total size of prototype including all colocated arrays. */
sizept = sizeof(GCproto) + fs->pc*sizeof(BCIns) + fs->nkgc*sizeof(GCRef);
sizept = (sizept + sizeof(lua_Number)-1) & ~(sizeof(lua_Number)-1);
ofsk = sizept;
sizept += fs->nkn*sizeof(lua_Number);
ofsuv = sizept;
sizept += ((fs->nuv+1)&~1)*2;
ofsdbg = sizept;
sizevi = ls->vtop - fs->vbase;
sizept += sizevi*sizeof(VarInfo) + fs->nuv*sizeof(GCRef);
ofsli = sizept;
sizept += fs->pc*sizeof(BCLine);
/* Allocate prototype and initialize its fields. */
pt = (GCproto *)lj_mem_newgco(L, (MSize)sizept);
pt->gct = ~LJ_TPROTO;
pt->sizept = (MSize)sizept;
setgcref(pt->chunkname, obj2gco(ls->chunkname));
pt->trace = 0;
pt->flags = fs->flags;
pt->numparams = fs->numparams;
pt->framesize = fs->framesize;
pt->lastlinedefined = line;
fs_fixup_bc(fs, pt, (BCIns *)((char *)pt + sizeof(GCproto)),
(BCLine *)((char *)pt + ofsli));
fs_fixup_k(fs, pt, (void *)((char *)pt + ofsk));
fs_fixup_uv(fs, pt, (uint16_t *)((char *)pt + ofsuv));
fs_fixup_dbg(fs, pt, (VarInfo *)((char *)pt + ofsdbg), sizevi);
2010-02-06 07:18:32 +00:00
2009-12-08 18:46:35 +00:00
lj_vmevent_send(L, BC,
setprotoV(L, L->top++, pt);
);
2010-02-06 07:18:32 +00:00
L->top--; /* Pop table of constants. */
ls->vtop = fs->vbase; /* Reset variable stack. */
2009-12-08 18:46:35 +00:00
ls->fs = fs->prev;
lua_assert(ls->fs != NULL || ls->token == TK_eof);
2010-02-06 07:18:32 +00:00
/* Re-anchor last string token to avoid GC. */
if (ls->token == TK_name || ls->token == TK_string) {
/* NOBARRIER: the key is new or kept alive. */
2010-02-06 07:18:32 +00:00
TValue *tv = lj_tab_setstr(ls->L, ls->fs->kt, strV(&ls->tokenval));
if (tvisnil(tv)) setboolV(tv, 1);
}
return pt;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Initialize a new FuncState. */
static void fs_init(LexState *ls, FuncState *fs)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
lua_State *L = ls->L;
fs->prev = ls->fs; ls->fs = fs; /* Append to list. */
fs->ls = ls;
fs->vbase = ls->vtop;
2010-02-06 07:18:32 +00:00
fs->L = L;
fs->pc = 0;
fs->lasttarget = 0;
fs->jpc = NO_JMP;
fs->freereg = 0;
fs->nkgc = 0;
fs->nkn = 0;
fs->nactvar = 0;
fs->nuv = 0;
fs->bl = NULL;
fs->flags = 0;
fs->framesize = 2; /* Minimum frame size. */
fs->kt = lj_tab_new(L, 0, 0);
/* Anchor table of constants in stack to avoid being collected. */
2010-02-06 07:18:32 +00:00
settabV(L, L->top, fs->kt);
incr_top(L);
2009-12-08 18:46:35 +00:00
}
/* -- Expressions --------------------------------------------------------- */
2010-02-06 07:18:32 +00:00
/* Forward declaration. */
2009-12-08 18:46:35 +00:00
static void expr(LexState *ls, ExpDesc *v);
2010-02-06 07:18:32 +00:00
/* Return string expression. */
static void expr_str(LexState *ls, ExpDesc *e)
{
expr_init(e, VKSTR, 0);
e->u.sval = lex_str(ls);
}
/* Return index expression. */
static void expr_index(FuncState *fs, ExpDesc *t, ExpDesc *e)
{
/* Already called: expr_toval(fs, e). */
t->k = VINDEXED;
if (expr_isnumk(e)) {
lua_Number n = expr_numV(e);
int32_t k = lj_num2int(n);
if (checku8(k) && n == cast_num(k)) {
t->u.s.aux = BCMAX_C+1+(uint32_t)k; /* 256..511: const byte key */
return;
}
} else if (expr_isstrk(e)) {
BCReg idx = const_str(fs, e);
if (idx <= BCMAX_C) {
t->u.s.aux = ~idx; /* -256..-1: const string key */
return;
}
}
t->u.s.aux = expr_toanyreg(fs, e); /* 0..255: register */
}
/* Parse index expression with named field. */
static void expr_field(LexState *ls, ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
ExpDesc key;
2010-02-06 07:18:32 +00:00
expr_toanyreg(fs, v);
lj_lex_next(ls); /* Skip dot or colon. */
expr_str(ls, &key);
expr_index(fs, v, &key);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse index expression with brackets. */
static void expr_bracket(LexState *ls, ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
lj_lex_next(ls); /* Skip '['. */
2009-12-08 18:46:35 +00:00
expr(ls, v);
2010-02-06 07:18:32 +00:00
expr_toval(ls->fs, v);
lex_check(ls, ']');
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Get value of constant expression. */
static void expr_kvalue(TValue *v, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
if (e->k <= VKTRUE) {
setitype(v, ~(uint32_t)e->k);
2010-02-06 07:18:32 +00:00
} else if (e->k == VKSTR) {
setgcref(v->gcr, obj2gco(e->u.sval));
setitype(v, LJ_TSTR);
2010-02-06 07:18:32 +00:00
} else {
lua_assert(e->k == VKNUM);
setnumV(v, expr_numV(e));
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Parse table constructor expression. */
static void expr_table(LexState *ls, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
BCLine line = ls->linenumber;
GCtab *t = NULL;
int vcall = 0, needarr = 0;
2010-02-06 07:18:32 +00:00
int32_t narr = 1; /* First array index. */
uint32_t nhash = 0; /* Number of hash entries. */
2009-12-08 18:46:35 +00:00
BCReg freg = fs->freereg;
2010-02-06 07:18:32 +00:00
BCPos pc = bcemit_AD(fs, BC_TNEW, freg, 0);
expr_init(e, VNONRELOC, freg);
bcreg_reserve(fs, 1);
2009-12-08 18:46:35 +00:00
freg++;
2010-02-06 07:18:32 +00:00
lex_check(ls, '{');
2009-12-08 18:46:35 +00:00
while (ls->token != '}') {
ExpDesc key, val;
vcall = 0;
if (ls->token == '[') {
2010-02-06 07:18:32 +00:00
expr_bracket(ls, &key); /* Already calls expr_toval. */
if (!expr_isk(&key)) expr_index(fs, e, &key);
if (expr_isnumk(&key) && expr_numV(&key) == 0) needarr = 1; else nhash++;
lex_check(ls, '=');
2009-12-08 18:46:35 +00:00
} else if (ls->token == TK_name && lj_lex_lookahead(ls) == '=') {
2010-02-06 07:18:32 +00:00
expr_str(ls, &key);
lex_check(ls, '=');
2009-12-08 18:46:35 +00:00
nhash++;
} else {
2010-02-06 07:18:32 +00:00
expr_init(&key, VKNUM, 0);
2009-12-08 18:46:35 +00:00
setintV(&key.u.nval, narr);
narr++;
needarr = vcall = 1;
}
expr(ls, &val);
2010-02-06 07:18:32 +00:00
if (expr_isk_nojump(&val) && expr_isk(&key) && key.k != VKNIL) {
2009-12-08 18:46:35 +00:00
TValue k;
2010-02-06 07:18:32 +00:00
if (!t) { /* Create template table on demand. */
2009-12-08 18:46:35 +00:00
BCReg kidx;
t = lj_tab_new(fs->L, 0, 0);
2010-02-06 07:18:32 +00:00
kidx = const_gc(fs, obj2gco(t), LJ_TTAB);
fs->bcbase[pc].ins = BCINS_AD(BC_TDUP, freg-1, kidx);
2009-12-08 18:46:35 +00:00
}
vcall = 0;
2010-02-06 07:18:32 +00:00
expr_kvalue(&k, &key);
expr_kvalue(lj_tab_set(fs->L, t, &k), &val);
lj_gc_anybarriert(fs->L, t);
2009-12-08 18:46:35 +00:00
} else {
if (val.k != VCALL) { expr_toanyreg(fs, &val); vcall = 0; }
2010-02-06 07:18:32 +00:00
if (expr_isk(&key)) expr_index(fs, e, &key);
bcemit_store(fs, e, &val);
2009-12-08 18:46:35 +00:00
}
fs->freereg = freg;
2010-02-06 07:18:32 +00:00
if (!lex_opt(ls, ',') && !lex_opt(ls, ';')) break;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
lex_match(ls, '}', '{', line);
2009-12-08 18:46:35 +00:00
if (vcall) {
BCInsLine *ilp = &fs->bcbase[fs->pc-1];
2009-12-08 18:46:35 +00:00
ExpDesc en;
lua_assert(bc_a(ilp->ins) == freg &&
bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB));
2010-02-06 07:18:32 +00:00
expr_init(&en, VKNUM, 0);
2009-12-08 18:46:35 +00:00
setintV(&en.u.nval, narr-1);
if (narr > 256) { fs->pc--; ilp--; }
ilp->ins = BCINS_AD(BC_TSETM, freg, const_num(fs, &en));
setbc_b(&ilp[-1].ins, 0);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
if (pc == fs->pc-1) { /* Make expr relocable if possible. */
2009-12-08 18:46:35 +00:00
e->u.s.info = pc;
fs->freereg--;
e->k = VRELOCABLE;
} else {
2010-02-06 07:18:32 +00:00
e->k = VNONRELOC; /* May have been changed by expr_index. */
2009-12-08 18:46:35 +00:00
}
if (!t) { /* Construct TNEW RD: hhhhhaaaaaaaaaaa. */
2010-08-03 21:11:12 +00:00
BCIns *ip = &fs->bcbase[pc].ins;
2009-12-08 18:46:35 +00:00
if (!needarr) narr = 0;
else if (narr < 3) narr = 3;
else if (narr > 0x7ff) narr = 0x7ff;
2010-08-03 21:11:12 +00:00
setbc_d(ip, (uint32_t)narr|(hsize2hbits(nhash)<<11));
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Parse function parameters. */
static BCReg parse_params(LexState *ls, int needself)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
BCReg nparams = 0;
2010-02-06 07:18:32 +00:00
lex_check(ls, '(');
if (needself) {
var_new_lit(ls, 0, "self");
2010-02-06 07:18:32 +00:00
var_add(ls, 1);
}
if (ls->token != ')') {
2009-12-08 18:46:35 +00:00
do {
2010-02-06 07:18:32 +00:00
if (ls->token == TK_name) {
var_new(ls, nparams++, lex_str(ls));
} else if (ls->token == TK_dots) {
2009-12-08 18:46:35 +00:00
lj_lex_next(ls);
2010-02-06 07:18:32 +00:00
fs->flags |= PROTO_IS_VARARG;
2009-12-08 18:46:35 +00:00
break;
2010-02-06 07:18:32 +00:00
} else {
err_syntax(ls, LJ_ERR_XPARAM);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
} while (lex_opt(ls, ','));
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
var_add(ls, nparams);
bcreg_reserve(fs, fs->nactvar);
lex_check(ls, ')');
return fs->nactvar;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Forward declaration. */
static void parse_chunk(LexState *ls);
/* Parse body of a function. */
static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line)
2009-12-08 18:46:35 +00:00
{
FuncState fs, *pfs = ls->fs;
2009-12-08 18:46:35 +00:00
BCReg kidx;
2010-02-06 07:18:32 +00:00
BCLine lastline;
GCproto *pt;
ptrdiff_t oldbase = pfs->bcbase - ls->bcstack;
fs_init(ls, &fs);
fs.linedefined = line;
fs.numparams = (uint8_t)parse_params(ls, needself);
fs.bcbase = pfs->bcbase + pfs->pc;
fs.bclim = pfs->bclim - pfs->pc;
bcemit_AD(&fs, BC_FUNCF, 0, 0); /* Placeholder. */
2010-02-06 07:18:32 +00:00
parse_chunk(ls);
lastline = ls->linenumber;
lex_match(ls, TK_end, TK_function, line);
pt = fs_finish(ls, lastline);
pfs->bcbase = ls->bcstack + oldbase; /* May have been reallocated. */
pfs->bclim = (BCPos)(ls->sizebcstack - oldbase);
2010-02-06 07:18:32 +00:00
/* Store new prototype in the constant array of the parent. */
kidx = const_gc(pfs, obj2gco(pt), LJ_TPROTO);
expr_init(e, VRELOCABLE, bcemit_AD(pfs, BC_FNEW, 0, kidx));
if (!(pfs->flags & PROTO_HAS_FNEW)) {
if (pfs->flags & PROTO_HAS_RETURN)
pfs->flags |= PROTO_FIXUP_RETURN;
pfs->flags |= PROTO_HAS_FNEW;
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Parse expression list. Last expression is left open. */
static BCReg expr_list(LexState *ls, ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
BCReg n = 1;
2009-12-08 18:46:35 +00:00
expr(ls, v);
2010-02-06 07:18:32 +00:00
while (lex_opt(ls, ',')) {
expr_tonextreg(ls->fs, v);
2009-12-08 18:46:35 +00:00
expr(ls, v);
n++;
}
return n;
}
2010-02-06 07:18:32 +00:00
/* Parse function argument list. */
static void parse_args(LexState *ls, ExpDesc *e)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
ExpDesc args;
BCIns ins;
BCReg base;
BCLine line = ls->linenumber;
2010-02-06 07:18:32 +00:00
if (ls->token == '(') {
if (line != ls->lastline)
err_syntax(ls, LJ_ERR_XAMBIG);
lj_lex_next(ls);
if (ls->token == ')') { /* f(). */
args.k = VVOID;
} else {
expr_list(ls, &args);
if (args.k == VCALL) /* f(a, b, g()) or f(a, b, ...). */
setbc_b(bcptr(fs, &args), 0); /* Pass on multiple results. */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
lex_match(ls, ')', '(', line);
} else if (ls->token == '{') {
expr_table(ls, &args);
} else if (ls->token == TK_string) {
expr_init(&args, VKSTR, 0);
args.u.sval = strV(&ls->tokenval);
lj_lex_next(ls);
} else {
err_syntax(ls, LJ_ERR_XFUNARG);
return; /* Silence compiler. */
2009-12-08 18:46:35 +00:00
}
lua_assert(e->k == VNONRELOC);
2010-02-06 07:18:32 +00:00
base = e->u.s.info; /* Base register for call. */
2009-12-08 18:46:35 +00:00
if (args.k == VCALL) {
ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1);
} else {
if (args.k != VVOID)
2010-02-06 07:18:32 +00:00
expr_tonextreg(fs, &args);
2009-12-08 18:46:35 +00:00
ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base);
}
2010-02-06 07:18:32 +00:00
expr_init(e, VCALL, bcemit_INS(fs, ins));
2009-12-08 18:46:35 +00:00
e->u.s.aux = base;
fs->bcbase[fs->pc - 1].line = line;
2010-02-06 07:18:32 +00:00
fs->freereg = base+1; /* Leave one result by default. */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse primary expression. */
static void expr_primary(LexState *ls, ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
2010-02-06 07:18:32 +00:00
/* Parse prefix expression. */
if (ls->token == '(') {
BCLine line = ls->linenumber;
lj_lex_next(ls);
expr(ls, v);
lex_match(ls, ')', '(', line);
expr_discharge(ls->fs, v);
} else if (ls->token == TK_name) {
var_lookup(ls, v);
} else {
err_syntax(ls, LJ_ERR_XSYMBOL);
}
for (;;) { /* Parse multiple expression suffixes. */
if (ls->token == '.') {
expr_field(ls, v);
} else if (ls->token == '[') {
ExpDesc key;
expr_toanyreg(fs, v);
expr_bracket(ls, &key);
expr_index(fs, v, &key);
} else if (ls->token == ':') {
ExpDesc key;
lj_lex_next(ls);
expr_str(ls, &key);
bcemit_method(fs, v, &key);
parse_args(ls, v);
} else if (ls->token == '(' || ls->token == TK_string || ls->token == '{') {
expr_tonextreg(fs, v);
parse_args(ls, v);
} else {
break;
2009-12-08 18:46:35 +00:00
}
}
}
2010-02-06 07:18:32 +00:00
/* Parse simple expression. */
static void expr_simple(LexState *ls, ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
switch (ls->token) {
case TK_number:
2010-02-06 07:18:32 +00:00
expr_init(v, VKNUM, 0);
2009-12-08 18:46:35 +00:00
setnumV(&v->u.nval, numV(&ls->tokenval));
break;
case TK_string:
2010-02-06 07:18:32 +00:00
expr_init(v, VKSTR, 0);
2009-12-08 18:46:35 +00:00
v->u.sval = strV(&ls->tokenval);
break;
case TK_nil:
2010-02-06 07:18:32 +00:00
expr_init(v, VKNIL, 0);
2009-12-08 18:46:35 +00:00
break;
case TK_true:
2010-02-06 07:18:32 +00:00
expr_init(v, VKTRUE, 0);
2009-12-08 18:46:35 +00:00
break;
case TK_false:
2010-02-06 07:18:32 +00:00
expr_init(v, VKFALSE, 0);
2009-12-08 18:46:35 +00:00
break;
2010-02-06 07:18:32 +00:00
case TK_dots: { /* Vararg. */
2009-12-08 18:46:35 +00:00
FuncState *fs = ls->fs;
BCReg base;
2010-02-06 07:18:32 +00:00
checkcond(ls, fs->flags & PROTO_IS_VARARG, LJ_ERR_XDOTS);
bcreg_reserve(fs, 1);
2009-12-08 18:46:35 +00:00
base = fs->freereg-1;
2010-02-06 07:18:32 +00:00
expr_init(v, VCALL, bcemit_ABC(fs, BC_VARG, base, 2, 1));
2009-12-08 18:46:35 +00:00
v->u.s.aux = base;
break;
}
2010-02-06 07:18:32 +00:00
case '{': /* Table constructor. */
expr_table(ls, v);
2009-12-08 18:46:35 +00:00
return;
case TK_function:
lj_lex_next(ls);
2010-02-06 07:18:32 +00:00
parse_body(ls, v, 0, ls->linenumber);
2009-12-08 18:46:35 +00:00
return;
default:
2010-02-06 07:18:32 +00:00
expr_primary(ls, v);
2009-12-08 18:46:35 +00:00
return;
}
lj_lex_next(ls);
}
2010-02-06 07:18:32 +00:00
/* Manage syntactic levels to avoid blowing up the stack. */
static void synlevel_begin(LexState *ls)
2009-12-08 18:46:35 +00:00
{
if (++ls->level >= LJ_MAX_XLEVEL)
lj_lex_error(ls, 0, LJ_ERR_XLEVELS);
}
2010-02-06 07:18:32 +00:00
#define synlevel_end(ls) ((ls)->level--)
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Convert token to binary operator. */
static BinOpr token2binop(LexToken tok)
2009-12-08 18:46:35 +00:00
{
switch (tok) {
2010-02-06 07:18:32 +00:00
case '+': return OPR_ADD;
case '-': return OPR_SUB;
case '*': return OPR_MUL;
case '/': return OPR_DIV;
case '%': return OPR_MOD;
case '^': return OPR_POW;
2009-12-08 18:46:35 +00:00
case TK_concat: return OPR_CONCAT;
2010-02-06 07:18:32 +00:00
case TK_ne: return OPR_NE;
case TK_eq: return OPR_EQ;
case '<': return OPR_LT;
case TK_le: return OPR_LE;
case '>': return OPR_GT;
case TK_ge: return OPR_GE;
case TK_and: return OPR_AND;
case TK_or: return OPR_OR;
default: return OPR_NOBINOPR;
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Priorities for each binary operator. ORDER OPR. */
2009-12-08 18:46:35 +00:00
static const struct {
2010-02-06 07:18:32 +00:00
uint8_t left; /* Left priority. */
uint8_t right; /* Right priority. */
} priority[] = {
2009-12-08 18:46:35 +00:00
{6,6}, {6,6}, {7,7}, {7,7}, {7,7}, /* ADD SUB MUL DIV MOD */
{10,9}, {5,4}, /* POW CONCAT (right associative) */
{3,3}, {3,3}, /* EQ NE */
{3,3}, {3,3}, {3,3}, {3,3}, /* LT GE GT LE */
{2,2}, {1,1} /* AND OR */
};
2010-02-06 07:18:32 +00:00
#define UNARY_PRIORITY 8 /* Priority for unary operators. */
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Forward declaration. */
static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit);
/* Parse unary expression. */
static void expr_unop(LexState *ls, ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
BCOp op;
if (ls->token == TK_not) {
op = BC_NOT;
} else if (ls->token == '-') {
op = BC_UNM;
} else if (ls->token == '#') {
op = BC_LEN;
2009-12-08 18:46:35 +00:00
} else {
2010-02-06 07:18:32 +00:00
expr_simple(ls, v);
return;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
lj_lex_next(ls);
expr_binop(ls, v, UNARY_PRIORITY);
bcemit_unop(ls->fs, op, v);
}
/* Parse binary expressions with priority higher than the limit. */
static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit)
{
BinOpr op;
synlevel_begin(ls);
expr_unop(ls, v);
op = token2binop(ls->token);
2009-12-08 18:46:35 +00:00
while (op != OPR_NOBINOPR && priority[op].left > limit) {
ExpDesc v2;
BinOpr nextop;
lj_lex_next(ls);
2010-02-06 07:18:32 +00:00
bcemit_binop_left(ls->fs, op, v);
/* Parse binary expression with higher priority. */
nextop = expr_binop(ls, &v2, priority[op].right);
bcemit_binop(ls->fs, op, v, &v2);
2009-12-08 18:46:35 +00:00
op = nextop;
}
2010-02-06 07:18:32 +00:00
synlevel_end(ls);
return op; /* Return unconsumed binary operator (if any). */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse expression. */
2009-12-08 18:46:35 +00:00
static void expr(LexState *ls, ExpDesc *v)
{
2010-02-06 07:18:32 +00:00
expr_binop(ls, v, 0); /* Priority 0: parse whole expression. */
}
/* Assign expression to the next register. */
static void expr_next(LexState *ls)
{
ExpDesc e;
expr(ls, &e);
expr_tonextreg(ls->fs, &e);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse conditional expression. */
static BCPos expr_cond(LexState *ls)
2009-12-08 18:46:35 +00:00
{
ExpDesc v;
2010-02-06 07:18:32 +00:00
expr(ls, &v);
if (v.k == VKNIL) v.k = VKFALSE;
bcemit_branch_t(ls->fs, &v);
2009-12-08 18:46:35 +00:00
return v.f;
}
/* -- Scope handling ------------------------------------------------------ */
2010-02-06 07:18:32 +00:00
/* Begin a scope. */
static void scope_begin(FuncState *fs, FuncScope *bl, int isbreakable)
2009-12-08 18:46:35 +00:00
{
bl->breaklist = NO_JMP;
bl->isbreakable = (uint8_t)isbreakable;
bl->nactvar = (uint8_t)fs->nactvar;
2009-12-08 18:46:35 +00:00
bl->upval = 0;
2010-02-06 07:18:32 +00:00
bl->prev = fs->bl;
2009-12-08 18:46:35 +00:00
fs->bl = bl;
lua_assert(fs->freereg == fs->nactvar);
}
2010-02-06 07:18:32 +00:00
/* End a scope. */
static void scope_end(FuncState *fs)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
FuncScope *bl = fs->bl;
fs->bl = bl->prev;
var_remove(fs->ls, bl->nactvar);
fs->freereg = fs->nactvar;
2009-12-08 18:46:35 +00:00
lua_assert(bl->nactvar == fs->nactvar);
2010-02-06 07:18:32 +00:00
/* A scope is either breakable or has upvalues. */
2009-12-08 18:46:35 +00:00
lua_assert(!bl->isbreakable || !bl->upval);
if (bl->upval)
2010-02-06 07:18:32 +00:00
bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0);
else /* Avoid in upval case, it clears lasttarget and kills UCLO+JMP join. */
jmp_tohere(fs, bl->breaklist);
}
/* Mark scope as having an upvalue. */
static void scope_uvmark(FuncState *fs, BCReg level)
{
FuncScope *bl;
for (bl = fs->bl; bl && bl->nactvar > level; bl = bl->prev)
;
if (bl)
bl->upval = 1;
}
/* Parse 'break' statement. */
static void parse_break(LexState *ls)
{
FuncState *fs = ls->fs;
FuncScope *bl;
int upval = 0;
for (bl = fs->bl; bl && !bl->isbreakable; bl = bl->prev)
upval |= bl->upval; /* Collect upvalues in intervening scopes. */
if (!bl) /* Error if no breakable scope found. */
err_syntax(ls, LJ_ERR_XBREAK);
if (upval)
bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); /* Close upvalues. */
jmp_append(fs, &bl->breaklist, bcemit_jmp(fs));
}
/* Check for end of block. */
static int endofblock(LexToken token)
{
switch (token) {
case TK_else: case TK_elseif: case TK_end: case TK_until: case TK_eof:
return 1;
default:
return 0;
}
}
/* Parse 'return' statement. */
static void parse_return(LexState *ls)
{
BCIns ins;
FuncState *fs = ls->fs;
lj_lex_next(ls); /* Skip 'return'. */
fs->flags |= PROTO_HAS_RETURN;
if (endofblock(ls->token) || ls->token == ';') { /* Bare return. */
ins = BCINS_AD(BC_RET0, 0, 1);
} else { /* Return with one or more values. */
ExpDesc e; /* Receives the _last_ expression in the list. */
BCReg nret = expr_list(ls, &e);
if (nret == 1) { /* Return one result. */
if (e.k == VCALL) { /* Check for tail call. */
BCIns *ip = bcptr(fs, &e);
2010-02-06 07:18:32 +00:00
/* It doesn't pay off to add BC_VARGT just for 'return ...'. */
if (bc_op(*ip) == BC_VARG) goto notailcall;
2010-02-06 07:18:32 +00:00
fs->pc--;
ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT, bc_a(*ip), bc_c(*ip));
2010-02-06 07:18:32 +00:00
} else { /* Can return the result from any register. */
ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2);
}
} else {
if (e.k == VCALL) { /* Append all results from a call. */
notailcall:
setbc_b(bcptr(fs, &e), 0);
ins = BCINS_AD(BC_RETM, fs->nactvar, e.u.s.aux - fs->nactvar);
} else {
expr_tonextreg(fs, &e); /* Force contiguous registers. */
ins = BCINS_AD(BC_RET, fs->nactvar, nret+1);
}
}
}
if (fs->flags & PROTO_HAS_FNEW)
bcemit_AJ(fs, BC_UCLO, 0, 0); /* May need to close upvalues first. */
bcemit_INS(fs, ins);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse a block. */
static void parse_block(LexState *ls)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
2010-02-06 07:18:32 +00:00
FuncScope bl;
scope_begin(fs, &bl, 0);
parse_chunk(ls);
2009-12-08 18:46:35 +00:00
lua_assert(bl.breaklist == NO_JMP);
2010-02-06 07:18:32 +00:00
scope_end(fs);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* -- Assignments --------------------------------------------------------- */
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* List of LHS variables. */
typedef struct LHSVarList {
ExpDesc v; /* LHS variable. */
struct LHSVarList *prev; /* Link to previous LHS variable. */
} LHSVarList;
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Eliminate write-after-read hazards for local variable assignment. */
static void assign_hazard(LexState *ls, LHSVarList *lh, const ExpDesc *v)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
2010-02-06 07:18:32 +00:00
BCReg reg = v->u.s.info; /* Check against this variable. */
BCReg tmp = fs->freereg; /* Rename to this temp. register (if needed). */
int hazard = 0;
2009-12-08 18:46:35 +00:00
for (; lh; lh = lh->prev) {
if (lh->v.k == VINDEXED) {
2010-02-06 07:18:32 +00:00
if (lh->v.u.s.info == reg) { /* t[i], t = 1, 2 */
hazard = 1;
lh->v.u.s.info = tmp;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
if (lh->v.u.s.aux == reg) { /* t[i], i = 1, 2 */
hazard = 1;
lh->v.u.s.aux = tmp;
2009-12-08 18:46:35 +00:00
}
}
}
2010-02-06 07:18:32 +00:00
if (hazard) {
bcemit_AD(fs, BC_MOV, tmp, reg); /* Rename conflicting variable. */
bcreg_reserve(fs, 1);
}
}
/* Adjust LHS/RHS of an assignment. */
static void assign_adjust(LexState *ls, BCReg nvars, BCReg nexps, ExpDesc *e)
{
FuncState *fs = ls->fs;
int32_t extra = (int32_t)nvars - (int32_t)nexps;
if (e->k == VCALL) {
extra++; /* Compensate for the VCALL itself. */
if (extra < 0) extra = 0;
setbc_b(bcptr(fs, e), extra+1); /* Fixup call results. */
if (extra > 1) bcreg_reserve(fs, (BCReg)extra-1);
} else {
if (e->k != VVOID)
expr_tonextreg(fs, e); /* Close last expression. */
if (extra > 0) { /* Leftover LHS are set to nil. */
BCReg reg = fs->freereg;
bcreg_reserve(fs, (BCReg)extra);
bcemit_nil(fs, reg, (BCReg)extra);
}
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Recursively parse assignment statement. */
static void parse_assignment(LexState *ls, LHSVarList *lh, BCReg nvars)
2009-12-08 18:46:35 +00:00
{
ExpDesc e;
checkcond(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, LJ_ERR_XSYNTAX);
2010-02-06 07:18:32 +00:00
if (lex_opt(ls, ',')) { /* Collect LHS list and recurse upwards. */
LHSVarList vl;
vl.prev = lh;
expr_primary(ls, &vl.v);
if (vl.v.k == VLOCAL)
assign_hazard(ls, lh, &vl.v);
2009-12-08 18:46:35 +00:00
checklimit(ls->fs, ls->level + nvars, LJ_MAX_XLEVEL, "variable names");
2010-02-06 07:18:32 +00:00
parse_assignment(ls, &vl, nvars+1);
} else { /* Parse RHS. */
2009-12-08 18:46:35 +00:00
BCReg nexps;
2010-02-06 07:18:32 +00:00
lex_check(ls, '=');
nexps = expr_list(ls, &e);
2009-12-08 18:46:35 +00:00
if (nexps == nvars) {
if (e.k == VCALL) {
2010-02-06 07:18:32 +00:00
if (bc_op(*bcptr(ls->fs, &e)) == BC_VARG) { /* Vararg assignment. */
2009-12-08 18:46:35 +00:00
ls->fs->freereg--;
e.k = VRELOCABLE;
2010-02-06 07:18:32 +00:00
} else { /* Multiple call results. */
e.u.s.info = e.u.s.aux; /* Base of call is not relocatable. */
2009-12-08 18:46:35 +00:00
e.k = VNONRELOC;
}
}
2010-02-06 07:18:32 +00:00
bcemit_store(ls->fs, &lh->v, &e);
2009-12-08 18:46:35 +00:00
return;
}
2010-02-06 07:18:32 +00:00
assign_adjust(ls, nvars, nexps, &e);
2009-12-08 18:46:35 +00:00
if (nexps > nvars)
2010-02-06 07:18:32 +00:00
ls->fs->freereg -= nexps - nvars; /* Drop leftover regs. */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Assign RHS to LHS and recurse downwards. */
expr_init(&e, VNONRELOC, ls->fs->freereg-1);
bcemit_store(ls->fs, &lh->v, &e);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse call statement or assignment. */
static void parse_call_assign(LexState *ls)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
2010-02-06 07:18:32 +00:00
LHSVarList vl;
expr_primary(ls, &vl.v);
if (vl.v.k == VCALL) { /* Function call statement. */
setbc_b(bcptr(fs, &vl.v), 1); /* No results. */
} else { /* Start of an assignment. */
vl.prev = NULL;
parse_assignment(ls, &vl, 1);
2009-12-08 18:46:35 +00:00
}
}
2010-02-06 07:18:32 +00:00
/* Parse 'local' statement. */
static void parse_local(LexState *ls)
{
if (lex_opt(ls, TK_function)) { /* Local function declaration. */
ExpDesc v, b;
FuncState *fs = ls->fs;
var_new(ls, 0, lex_str(ls));
expr_init(&v, VLOCAL, fs->freereg);
bcreg_reserve(fs, 1);
var_add(ls, 1);
parse_body(ls, &b, 0, ls->linenumber);
bcemit_store(fs, &v, &b);
/* The upvalue is in scope, but the local is only valid after the store. */
var_get(ls, fs, fs->nactvar - 1).startpc = fs->pc;
2010-02-06 07:18:32 +00:00
} else { /* Local variable declaration. */
ExpDesc e;
BCReg nexps, nvars = 0;
do { /* Collect LHS. */
var_new(ls, nvars++, lex_str(ls));
} while (lex_opt(ls, ','));
if (lex_opt(ls, '=')) { /* Optional RHS. */
nexps = expr_list(ls, &e);
} else { /* Or implicitly set to nil. */
e.k = VVOID;
nexps = 0;
}
assign_adjust(ls, nvars, nexps, &e);
var_add(ls, nvars);
}
}
/* Parse 'function' statement. */
static void parse_func(LexState *ls, BCLine line)
{
FuncState *fs;
ExpDesc v, b;
int needself = 0;
lj_lex_next(ls); /* Skip 'function'. */
/* Parse function name. */
var_lookup(ls, &v);
while (ls->token == '.') /* Multiple dot-separated fields. */
expr_field(ls, &v);
if (ls->token == ':') { /* Optional colon to signify method call. */
needself = 1;
expr_field(ls, &v);
}
parse_body(ls, &b, needself, line);
fs = ls->fs;
bcemit_store(fs, &v, &b);
fs->bcbase[fs->pc - 1].line = line; /* Set line for the store. */
2010-02-06 07:18:32 +00:00
}
/* -- Loop and conditional statements ------------------------------------- */
/* Parse 'while' statement. */
static void parse_while(LexState *ls, BCLine line)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
BCPos start, loop, condexit;
2010-02-06 07:18:32 +00:00
FuncScope bl;
lj_lex_next(ls); /* Skip 'while'. */
2009-12-08 18:46:35 +00:00
start = fs->lasttarget = fs->pc;
2010-02-06 07:18:32 +00:00
condexit = expr_cond(ls);
scope_begin(fs, &bl, 1);
lex_check(ls, TK_do);
loop = bcemit_AD(fs, BC_LOOP, fs->nactvar, 0);
parse_block(ls);
jmp_patch(fs, bcemit_jmp(fs), start);
lex_match(ls, TK_end, TK_while, line);
scope_end(fs);
jmp_tohere(fs, condexit);
jmp_patchins(fs, loop, fs->pc);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse 'repeat' statement. */
static void parse_repeat(LexState *ls, BCLine line)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
BCPos loop = fs->lasttarget = fs->pc;
BCPos condexit;
2010-02-06 07:18:32 +00:00
FuncScope bl1, bl2;
scope_begin(fs, &bl1, 1); /* Breakable loop scope. */
scope_begin(fs, &bl2, 0); /* Inner scope. */
lj_lex_next(ls); /* Skip 'repeat'. */
bcemit_AD(fs, BC_LOOP, fs->nactvar, 0);
parse_chunk(ls);
lex_match(ls, TK_until, TK_repeat, line);
condexit = expr_cond(ls); /* Parse condition (still inside inner scope). */
if (!bl2.upval) { /* No upvalues? Just end inner scope. */
scope_end(fs);
} else { /* Otherwise generate: cond: UCLO+JMP out, !cond: UCLO+JMP loop. */
parse_break(ls); /* Break from loop and close upvalues. */
jmp_tohere(fs, condexit);
scope_end(fs); /* End inner scope and close upvalues. */
condexit = bcemit_jmp(fs);
}
jmp_patch(fs, condexit, loop); /* Jump backwards if !cond. */
jmp_patchins(fs, loop, fs->pc);
scope_end(fs); /* End loop scope. */
}
/* Parse body of a 'for' statement. */
static void parse_for_body(LexState *ls, BCReg base, BCLine line,
BCReg nvars, int isnum)
{
FuncScope bl;
2009-12-08 18:46:35 +00:00
FuncState *fs = ls->fs;
BCPos loop, loopend;
2010-02-06 07:18:32 +00:00
var_add(ls, 3); /* Hidden control variables. */
lex_check(ls, TK_do);
loop = isnum ? bcemit_AJ(fs, BC_FORI, base, NO_JMP) :
bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP);
scope_begin(fs, &bl, 0); /* Scope for visible variables. */
var_add(ls, nvars);
bcreg_reserve(fs, nvars);
parse_block(ls);
scope_end(fs);
/* Perform loop inversion. Loop control instructions are at the end. */
2009-12-08 18:46:35 +00:00
if (isnum) {
2010-02-06 07:18:32 +00:00
loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP);
jmp_patchins(fs, loop, fs->pc);
2009-12-08 18:46:35 +00:00
} else {
2010-02-06 07:18:32 +00:00
jmp_patchins(fs, loop, fs->pc);
bcemit_ABC(fs, BC_ITERC, base+3, nvars+1, 2+1);
loopend = bcemit_AJ(fs, BC_ITERL, base+3, NO_JMP);
fs->bcbase[loopend-1].line = line;
2009-12-08 18:46:35 +00:00
}
fs->bcbase[loopend].line = line; /* Fix line for control ins. */
2010-02-06 07:18:32 +00:00
jmp_patchins(fs, loopend, loop+1);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse numeric 'for'. */
static void parse_for_num(LexState *ls, GCstr *varname, BCLine line)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
BCReg base = fs->freereg;
2010-02-06 07:18:32 +00:00
/* Hidden control variables. */
var_new_lit(ls, FORL_IDX, "(for index)");
var_new_lit(ls, FORL_STOP, "(for limit)");
var_new_lit(ls, FORL_STEP, "(for step)");
2010-02-06 07:18:32 +00:00
/* Visible copy of index variable. */
var_new(ls, FORL_EXT, varname);
lex_check(ls, '=');
expr_next(ls);
lex_check(ls, ',');
expr_next(ls);
if (lex_opt(ls, ',')) {
expr_next(ls);
} else {
bcemit_AD(fs, BC_KSHORT, fs->freereg, 1); /* Default step is 1. */
bcreg_reserve(fs, 1);
}
parse_for_body(ls, base, line, 1, 1);
}
/* Parse 'for' iterator. */
static void parse_for_iter(LexState *ls, GCstr *indexname)
{
2009-12-08 18:46:35 +00:00
FuncState *fs = ls->fs;
ExpDesc e;
BCReg nvars = 0;
BCLine line;
BCReg base = fs->freereg;
2010-02-06 07:18:32 +00:00
/* Hidden control variables. */
var_new_lit(ls, nvars++, "(for generator)");
var_new_lit(ls, nvars++, "(for state)");
var_new_lit(ls, nvars++, "(for control)");
2010-02-06 07:18:32 +00:00
/* Visible variables returned from iterator. */
var_new(ls, nvars++, indexname);
while (lex_opt(ls, ','))
var_new(ls, nvars++, lex_str(ls));
lex_check(ls, TK_in);
2009-12-08 18:46:35 +00:00
line = ls->linenumber;
2010-02-06 07:18:32 +00:00
assign_adjust(ls, 3, expr_list(ls, &e), &e);
bcreg_bump(fs, 3); /* The iterator needs another 3 slots (func + 2 args). */
parse_for_body(ls, base, line, nvars - 3, 0);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse 'for' statement. */
static void parse_for(LexState *ls, BCLine line)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
GCstr *varname;
2010-02-06 07:18:32 +00:00
FuncScope bl;
scope_begin(fs, &bl, 1); /* Breakable loop scope. */
lj_lex_next(ls); /* Skip 'for'. */
varname = lex_str(ls); /* Get first variable name. */
if (ls->token == '=')
parse_for_num(ls, varname, line);
else if (ls->token == ',' || ls->token == TK_in)
parse_for_iter(ls, varname);
else
err_syntax(ls, LJ_ERR_XFOR);
lex_match(ls, TK_end, TK_for, line);
scope_end(fs); /* Resolve break list. */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* Parse condition and 'then' block. */
static BCPos parse_then(LexState *ls)
2009-12-08 18:46:35 +00:00
{
BCPos condexit;
2010-02-06 07:18:32 +00:00
lj_lex_next(ls); /* Skip 'if' or 'elseif'. */
condexit = expr_cond(ls);
lex_check(ls, TK_then);
parse_block(ls);
2009-12-08 18:46:35 +00:00
return condexit;
}
2010-02-06 07:18:32 +00:00
/* Parse 'if' statement. */
static void parse_if(LexState *ls, BCLine line)
2009-12-08 18:46:35 +00:00
{
FuncState *fs = ls->fs;
BCPos flist;
BCPos escapelist = NO_JMP;
2010-02-06 07:18:32 +00:00
flist = parse_then(ls);
while (ls->token == TK_elseif) { /* Parse multiple 'elseif' blocks. */
jmp_append(fs, &escapelist, bcemit_jmp(fs));
jmp_tohere(fs, flist);
flist = parse_then(ls);
}
if (ls->token == TK_else) { /* Parse optional 'else' block. */
jmp_append(fs, &escapelist, bcemit_jmp(fs));
jmp_tohere(fs, flist);
lj_lex_next(ls); /* Skip 'else'. */
parse_block(ls);
2009-12-08 18:46:35 +00:00
} else {
2010-02-06 07:18:32 +00:00
jmp_append(fs, &escapelist, flist);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
jmp_tohere(fs, escapelist);
lex_match(ls, TK_end, TK_if, line);
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* -- Parse statements ---------------------------------------------------- */
2009-12-08 18:46:35 +00:00
2010-02-06 07:18:32 +00:00
/* Parse a statement. Returns 1 if it must be the last one in a chunk. */
static int parse_stmt(LexState *ls)
2009-12-08 18:46:35 +00:00
{
2010-02-06 07:18:32 +00:00
BCLine line = ls->linenumber;
2009-12-08 18:46:35 +00:00
switch (ls->token) {
case TK_if:
2010-02-06 07:18:32 +00:00
parse_if(ls, line);
break;
2009-12-08 18:46:35 +00:00
case TK_while:
2010-02-06 07:18:32 +00:00
parse_while(ls, line);
break;
2009-12-08 18:46:35 +00:00
case TK_do:
2010-02-06 07:18:32 +00:00
lj_lex_next(ls);
parse_block(ls);
lex_match(ls, TK_end, TK_do, line);
break;
2009-12-08 18:46:35 +00:00
case TK_for:
2010-02-06 07:18:32 +00:00
parse_for(ls, line);
break;
2009-12-08 18:46:35 +00:00
case TK_repeat:
2010-02-06 07:18:32 +00:00
parse_repeat(ls, line);
break;
2009-12-08 18:46:35 +00:00
case TK_function:
2010-02-06 07:18:32 +00:00
parse_func(ls, line);
break;
2009-12-08 18:46:35 +00:00
case TK_local:
2010-02-06 07:18:32 +00:00
lj_lex_next(ls);
parse_local(ls);
break;
2009-12-08 18:46:35 +00:00
case TK_return:
2010-02-06 07:18:32 +00:00
parse_return(ls);
return 1; /* Must be last. */
2009-12-08 18:46:35 +00:00
case TK_break:
2010-02-06 07:18:32 +00:00
lj_lex_next(ls);
parse_break(ls);
return 1; /* Must be last. */
2009-12-08 18:46:35 +00:00
default:
2010-02-06 07:18:32 +00:00
parse_call_assign(ls);
break;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
return 0;
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
/* A chunk is a list of statements optionally separated by semicolons. */
static void parse_chunk(LexState *ls)
2009-12-08 18:46:35 +00:00
{
int islast = 0;
2010-02-06 07:18:32 +00:00
synlevel_begin(ls);
while (!islast && !endofblock(ls->token)) {
islast = parse_stmt(ls);
lex_opt(ls, ';');
lua_assert(ls->fs->framesize >= ls->fs->freereg &&
2009-12-08 18:46:35 +00:00
ls->fs->freereg >= ls->fs->nactvar);
2010-02-06 07:18:32 +00:00
ls->fs->freereg = ls->fs->nactvar; /* Free registers after each stmt. */
2009-12-08 18:46:35 +00:00
}
2010-02-06 07:18:32 +00:00
synlevel_end(ls);
}
/* Entry point of bytecode parser. */
GCproto *lj_parse(LexState *ls)
{
FuncState fs;
2010-02-06 07:18:32 +00:00
GCproto *pt;
lua_State *L = ls->L;
ls->chunkname = lj_str_newz(L, ls->chunkarg);
setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */
incr_top(L);
2010-02-06 07:18:32 +00:00
ls->level = 0;
fs_init(ls, &fs);
fs.linedefined = 0;
fs.numparams = 0;
fs.bcbase = NULL;
fs.bclim = 0;
2010-02-06 07:18:32 +00:00
fs.flags |= PROTO_IS_VARARG; /* Main chunk is always a vararg func. */
bcemit_AD(&fs, BC_FUNCV, 0, 0); /* Placeholder. */
2010-02-06 07:18:32 +00:00
lj_lex_next(ls); /* Read-ahead first token. */
parse_chunk(ls);
if (ls->token != TK_eof)
err_token(ls, TK_eof);
pt = fs_finish(ls, ls->linenumber);
L->top--; /* Drop chunkname. */
2010-02-06 07:18:32 +00:00
lua_assert(fs.prev == NULL);
lua_assert(ls->fs == NULL);
lua_assert(pt->sizeuv == 0);
return pt;
2009-12-08 18:46:35 +00:00
}